```%	fold.rb
%
%	Purpose:	Constant folding (with rational numbers)
%			Minimal support for complex numbers (to be extended in the future)
%	Copyright:	R.A. van Engelen, Leiden University, 1996

default strategy [fold].

fold; use_module(type).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%	`Syntactic sugar'
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

fold; ln(X) => log(X).
fold; log10(X) => {RLog10} * log(X) <- RLog10 is 1 / log(10).
fold; sqrt(X) => X ^ {{1} / {2}}.
fold; e ^ X => exp(X).
fold; X ** Y => X ^ Y.
(fold; R step S => R up S <- normalize(0 <= S, Flag, [fold]), Flag == {true}).
(fold; R step S => R down - S <- normalize(S <= 0, Flag, [fold]), Flag == {true}).

fold; for I repeat S => S for I.
fold; forall I repeat S => S forall I.
fold; while C repeat S => S while C.
fold; until C repeat S => S until C.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%	Complex arithmetic
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

fold; complex(R, {0}) => R.
fold; - {complex(R, I)} => complex(- R, I).
fold; {1} / {complex(R, I)} => complex(R / ( (R - I)                                           * (R + I)                                           ), I / ( (I - R)                                                  * (I + R)                                                  )).
fold; abs({complex(R, I)}) => ( (R ^ {2} + I ^ {2})                              ^ {{1} / {2}}                              ).
fold; conj({complex(R, I)}) => complex(R, - I).
fold; im({complex(_G595, I)}) => I.
fold; re({complex(R, _G596)}) => R.
fold; atan(complex(R, I)) => atan(I, R).

fold;{complex(R1, I1)} + {complex(R2, I2)} => complex(R1 + R2, I1 + I2).
fold; N + {complex(R, I)} => complex(R + N, I) <- is_number(N).
(fold; ( {complex(R1, I1)} * {complex(R2, I2)} ) => complex(( R1 * R2              - I1 * I2              ), ( R1 * I2                 + R2 * I1                 )) <- (is_number(R1); is_number(R2)), (is_number(I1); is_number(I2))).
fold; N * {complex(R, I)} => complex(R + N, I) <- is_number(N).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%	Primitive list and string operations
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

(fold; S1 // S2 => {S12} <- to_string(S1, S), to_string(S2, T), string_concat(S, T, S12)).
fold; {L1} // {L2} => {L12} <- append(L1, L2, L12).
fold; {L1} // L2 => {L12} <- append(L1, L2, L12).
fold; L1 // {L2} => {L12} <- append(L1, L2, L12).
fold; L1 // L2 => L12 <- append(L1, L2, L12).

fold; length(S) => {N} <- to_string(S, T), string_length(T, N).
fold; length({L}) => {N} <- length(L, N).
fold; length(L) => {N} <- length(L, N).

fold; reverse({L}) => {R} <- reverse(L, R).
fold; reverse(L) => R <- reverse(L, R).

fold; {L1} union {L2} => {U} <- union(L1, L2, U).
fold; {L1} union L2 => {U} <- union(L1, L2, U).
fold; L1 union {L2} => {U} <- union(L1, L2, U).
fold; L1 union L2 => U <- union(L1, L2, U).

fold; {L1} intersection {L2} => {I} <- intersection(L1, L2, I).
fold; {L1} intersection L2 => {I} <- intersection(L1, L2, I).
fold; L1 intersection {L2} => {I} <- intersection(L1, L2, I).
fold; L1 intersection L2 => I <- intersection(L1, L2, I).

fold; {L1} minus {L2} => {D} <- subtract(L1, L2, D).
fold; {L1} minus L2 => {D} <- subtract(L1, L2, D).
fold; L1 minus {L2} => {D} <- subtract(L1, L2, D).
fold; L1 minus L2 => D <- subtract(L1, L2, D).

fold; X in {L} => {true} <- X in L.
fold; X in L => {true} <- X in L.

fold; {L1} subset {L2} => {true} <- L1 subset L2.
fold; {L1} subset L2 => {true} <- L1 subset L2.
fold; L1 subset {L2} => {true} <- L1 subset L2.
fold; L1 subset L2 => {true} <- L1 subset L2.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%	Ranges
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

fold; (L .. _G596) .. (_G598 .. U) => L .. U.
fold; (L .. _G596) .. U => L .. U.
fold; L .. (_G595 .. U) => L .. U.

fold; L1 .. U1 union L2 .. U2 => L1 min L2 .. U1 max U2.
fold; L1 .. U1 union Y => L1 min Y .. U1 max Y.
fold; X union Y => X min Y .. X max Y.

fold; L1 .. U1 intersection L2 .. U2 => L1 max L2 .. U1 min U2.
fold; L1 .. U1 intersection Y => L1 max Y .. U1 min Y.
fold; X intersection Y => X max Y .. X min Y.

fold; lb(L .. _G596) => L.
fold; ub(_G595 .. U) => U.

fold; lb(true) => true.
fold; ub(true) => true.
fold; lb(false) => false.
fold; ub(false) => false.
fold; lb(infinity) => infinity.
fold; ub(infinity) => infinity.
fold; lb(- infinity) => - infinity.
fold; ub(- infinity) => - infinity.

fold; lb(C) => C <- is_number(C).
fold; ub(C) => C <- is_number(C).

fold; - (L .. U) => - U .. - L.

fold; (L1 .. U1) + (L2 .. U2) => L1 + L2 .. U1 + U2.
fold; (L .. U) + Y => L + Y .. U + Y.

(fold; 1 / (L .. U) => 1 / U .. 1 / L <- normalize(0 <= L, F), F == {true}).
(fold; 1 / (L .. U) => 1 / U .. 1 / L <- normalize(0 <= - U, F), F == {true}).
(fold; 1 / (L .. U) => 1 / L .. 1 / U <- normalize(0 <= - L and 0 <= U, F), F == {true}).
fold; 1 / (_G595 .. _G596) => {{- {infinity}} .. {infinity}}.

(fold; (L1 .. U1) * (L2 .. U2) => L .. U <- normalize(0 <= L1, F), F == {true}, ( (normalize(0 <= L2, G), G == {true} ->    L = L1 * L2, U = U1 * U2   ) ; (normalize(0 <= - U2, G), G == {true} ->    L = L1 * U2, U = U1 * L2   ) )).
(fold; (L1 .. U1) * (L2 .. U2) => L .. U <- normalize(0 <= - U1, F), F == {true}, ( (normalize(0 <= L2, G), G == {true} ->    L = U1 * L2, U = L1 * U2   ) ; (normalize(0 <= - U2, G), G == {true} ->    L = U1 * U2, U = L1 * L2   ) )).
fold;( (_G595 .. _G596)* (_G598 .. _G599)) => {{- {infinity}} .. {infinity}}.
(fold; Y * (L .. U) => L * Y .. U * Y <- Y \= {_G616 .. _G617}, normalize(0 <= Y, F), F == {true}).
(fold; Y * (L .. U) => U * Y .. L * Y <- Y \= {_G616 .. _G617}, normalize(0 <= - Y, F), F == {true}).
fold; _G598 * (_G595 .. _G596) => {{- {infinity}} .. {infinity}}.

(fold; (L1 .. U1) ^ (L2 .. U2) => L .. U <- to_integer(L2, I), to_integer(U2, J), ( (0 is I mod 2 ->    ( normalize(0 <= L1, F), F == {true} -> L = L1 ^ L2    ; normalize(0 <= - U1, F), F == {true} -> L = U1 ^ L2    )   ) ; L = L1 ^ L2 ), ( (0 is J mod 2 ->    ( normalize(0 <= L1, F), F == {true} -> U = U1 ^ U2    ; normalize(0 <= - U1, F), F == {true} -> U = L1 ^ U2    )   ) ; U = U1 ^ U2 )).
(fold; (L .. U) ^ N => R <- to_integer(N, I), ( (0 is I mod 2 ->    ( normalize(0 <= L, F), F == {true} -> R = L ^ N .. U ^ N    ; (normalize(0 <= - U, F), F == {true} ->       R = U ^ N .. L ^ N      )    )   ) ; R = L ^ N .. U ^ N )).
fold; (_G595 .. _G596) ^ _G599 => {{- {infinity}} .. {infinity}}.

(fold; (L1 .. U1) max (_G598 .. U2) => L1 .. U1 <- normalize(0 <= L1 - U2, F), F == {true}).
(fold; (_G595 .. U1) max (L2 .. U2) => L2 .. U2 <- normalize(0 <= L2 - U1, F), F == {true}).
fold; (L1 .. U1) max (L2 .. U2) => L1 max L2 .. U1 max U2.
(fold; (_G595 .. U) max Y => Y .. Y <- normalize(0 <= Y - U, F), F == {true}).
(fold; (L .. U) max Y => L .. U <- normalize(0 <= L - Y, F), F == {true}).
fold; (L .. U) max Y => L max Y .. U max Y.

(fold; (L1 .. _G596) min (L2 .. U2) => L2 .. U2 <- normalize(0 <= L1 - U2, F), F == {true}).
(fold; (L1 .. U1) min (L2 .. _G599) => L1 .. U1 <- normalize(0 <= L2 - U1, F), F == {true}).
fold; (L1 .. U1) min (L2 .. U2) => L1 min L2 .. U1 min U2.
(fold; (L .. _G596) min Y => Y .. Y <- normalize(0 <= L - Y, F), F == {true}).
(fold; (L .. U) min Y => L .. U <- normalize(0 <= Y - U, F), F == {true}).
fold; (L .. U) min Y => L min Y .. U min Y.

fold; abs(L .. U) => 0 .. abs(L) max abs(U).

fold; L .. U < X => - X < - (L .. U).
fold; L .. U <= X => - X <= - (L .. U).

fold; L .. U > X => - X < - (L .. U).
fold; L .. U >= X => - X <= - (L .. U).

fold; X > L .. U => (X > L) .. (X > U).
fold; X >= L .. U => (X >= L) .. (X >= U).

fold; X < L .. U => (X < L) .. (X < U).
fold; X <= L .. U => (X <= L) .. (X <= U).

fold; X == L .. U => {false} .. (X <= U and X <= - L).
fold; X <> L .. U => (X < - U or X < L) .. {true}.

fold; not L .. U => (not U) .. (not L).

fold; L1 .. U1 and L2 .. U2 => (L1 and L2) .. (U1 and U2).
fold; L .. U and Y => (L and Y) .. (U and Y).

fold; L1 .. U1 or L2 .. U2 => (L1 or L2) .. (U1 or U2).
fold; L .. U or Y => (L or Y) .. (U or Y).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

fold; A max (min | AB) => A <- memberchk(A, AB).
fold; A min (max | AB) => A <- memberchk(A, AB).

fold; (on) == (off) => false.
fold; (on) <> (off) => true.

fold; - undefined => {undefined}.
fold; 1 / undefined => {undefined}.
fold; undefined + _G596 => {undefined}.
fold; undefined * _G596 => {undefined}.
fold; undefined max _G596 => {undefined}.
fold; undefined min _G596 => {undefined}.
fold; undefined < _G596 => {undefined}.
fold; undefined <= _G596 => {undefined}.
fold; undefined <> _G596 => {undefined}.
fold; undefined == _G596 => {undefined}.
fold; undefined > _G596 => {undefined}.
fold; undefined >= _G596 => {undefined}.
fold; _G595 < undefined => {undefined}.
fold; _G595 <= undefined => {undefined}.
fold; _G595 <> undefined => {undefined}.
fold; _G595 == undefined => {undefined}.
fold; _G595 > undefined => {undefined}.
fold; _G595 >= undefined => {undefined}.

fold; infinity + _G596 => {infinity}.
fold; - infinity + _G598 => {- {infinity}}.
fold; infinity * _G596 => {infinity}.
fold; 1 / infinity => {0}.

fold; + X => X.
fold; - 0 => {0}.
fold; - 0.0 => {0.0}.
fold; - (- X) => X.
fold; - (+ | Xs) => + | NegXs <- map(- Xs, NegXs).

% fold;	-(* | XY) => Y * Z <- select_assoc_op(*, XY, X, Y), (X = {+ | Xs} -> Z = -{+ | Xs}; X = {{1} / {+ | Xs}} -> Z = {1} / (-{+ | Xs})).

fold; 1 / (1 / Y) => Y.
fold; 1 / (* | Xs) => * | RXs <- map(1 / Xs, RXs).
fold; 1 / X ^ Y => X ^ (- Y).
fold; 1 / N => RN <- to_float(N, R), R \== 0.0, RN is float(1 / R).

(fold; - (* | NX) + - (* | MX) => - (N + M) * X <- !, select_assoc_op(*, NX, N, X), is_number(N), select_assoc_op(*, MX, M, X), is_number(M), is_nonvar(X)).
(fold; (* | NX) + - (* | MX) => (N - M) * X <- !, select_assoc_op(*, NX, N, X), is_number(N), select_assoc_op(*, MX, M, X), is_number(M), is_nonvar(X)).
(fold; - (* | NX) + (* | MX) => (M - N) * X <- !, select_assoc_op(*, NX, N, X), is_number(N), select_assoc_op(*, MX, M, X), is_number(M), is_nonvar(X)).
(fold; (* | NX) + (* | MX) => (N + M) * X <- !, select_assoc_op(*, NX, N, X), is_number(N), select_assoc_op(*, MX, M, X), is_number(M), is_nonvar(X)).
(fold; - X + - (* | NX) => (- N - 1) * X <- select_assoc_op(*, NX, N, X), is_number(N), is_nonvar(X)).
(fold; X + - (* | NX) => (1 - N) * X <- select_assoc_op(*, NX, N, X), is_number(N), is_nonvar(X)).
(fold; - X + (* | NX) => (N - 1) * X <- select_assoc_op(*, NX, N, X), is_number(N), is_nonvar(X)).
(fold; X + (* | NX) => (N + 1) * X <- select_assoc_op(*, NX, N, X), is_number(N), is_nonvar(X)).

fold; 1 / X * X ^ N => X ^ (N - 1) <- is_number(N), is_nonvar(X).
fold; X * X ^ N => X ^ (N + 1) <- is_number(N), is_nonvar(X).
(fold; X ^ N * X ^ M => X ^ (N + M) <- is_number(N), is_number(M), is_nonvar(X)).

fold; 0 ^ _G596 => {0}.
fold; 0.0 ^ _G600 => {0.0}.
fold; 1 ^ _G596 => {1}.
fold; 1.0 ^ _G600 => {1.0}.
fold; _G595 ^ 0 => {1}.
fold; _G599 ^ 0.0 => {1.0}.
fold; X ^ 1 => X.
fold; X ^ 1.0 => X.
fold; X ^ (- 1) => {1} / X.
fold; X ^ (- 1.0) => {1} / X.
fold; (1 / X) ^ Y => X ^ (- Y).
fold; (X ^ Y) ^ Z => X ^ (Y * Z).
(fold; (- X) ^ N => X ^ N <- to_integer(N, I), Nmod2 is I mod 2, Nmod2 == 0).

(fold; A + B => R <- to_rational(A, NA, DA), to_rational(B, NB, DB), normalize_rational(NA * DB + NB * DA, DA * DB, R)).
(fold; A + B => R <- to_number(A, N), to_number(B, M), R is float(N + M)).
(fold; A * B => R <- to_rational(A, NA, DA), to_rational(B, NB, DB), normalize_rational(NA * NB, DA * DB, R)).
(fold; A * B => R <- to_number(A, N), to_number(B, M), R is float(N * M)).
fold; 1 / A => {{DA} / {NA}} <- to_rational(A, NA, DA).
(fold; A ^ {- P} => R <- to_integer(P, Q), to_rational(A, N, D), normalize_rational(D ^ Q, N ^ Q, R)).
(fold; A ^ P => R <- to_integer(P, Q), to_rational(A, N, D), normalize_rational(N ^ Q, D ^ Q, R)).
(fold; A ^ B => R <- to_number(A, N), to_number(B, M), R is float(N ^ M)).
(fold; A div B => R <- to_integer(A, N), to_integer(B, M), M \== 0, R is N // M).
fold; _G595 mod 1 => 0.
fold; _G595 mod -1 => 0.
(fold; A mod B => R <- to_integer(A, N), to_integer(B, M), M \== 0, R1 is N mod M, (R1 < 0 -> R is M + R1; R = R1)).
(fold; A rem B => R <- to_integer(A, N), to_integer(B, M), M \== 0, R is float(N rem M)).

(fold; A min B => R <- normalize(A <= B, F, [fold]), (F == {true} -> R = A; F == {false} -> R = B)).
(fold; A max B => R <- normalize(B <= A, F, [fold]), (F == {true} -> R = A; F == {false} -> R = B)).

fold; X + X => 2 * X <- is_nonvar(X).

fold; (- X) * (- Y) => X * Y.
fold; (- X) * Y => - X * Y.
fold; X * X => X ^ 2 <- is_nonvar(X).

(fold; N * (+ | Xs) => - Y <- is_number(N), normalize_sum(Xs, NegXs), normalize(N * {+ | NegXs}, Y, [])).
(fold; N / (+ | Xs) => - Y <- is_number(N), normalize_sum(Xs, NegXs), normalize(N / {+ | NegXs}, Y, [])).

fold; infinity < _G596 => {false}.
fold; - infinity < _G598 => {true}.
fold; _G595 < infinity => {true}.
fold; _G597 < - infinity => {false}.
fold; - infinity <= _G598 => {true}.
fold; _G595 <= infinity => {true}.
fold; _G597 <= - infinity => {false}.
fold; _G595 > infinity => {false}.
fold; _G597 > - infinity => {true}.
fold; infinity > _G596 => {true}.
fold; - infinity > _G598 => {false}.
fold; _G597 >= - infinity => {true}.
fold; infinity >= _G596 => {true}.
fold; - infinity >= _G598 => {false}.

fold; _G595 < false => {false}.
fold; false < true => {true}.
fold; true < _G596 => {false}.
fold; false <= _G596 => {true}.
fold; _G595 <= true => {true}.
fold; true <= false => {false}.
fold; false > _G596 => {false}.
fold; true > false => {true}.
fold; _G595 > true => {false}.
fold; _G595 >= false => {true}.
fold; false >= true => {false}.
fold; true >= _G596 => {true}.

fold; complex(R1, I1) == complex(R2, I2) => (R1 == R2 and                                             I1 == I2                                            ).
fold; complex(R1, I1) <> complex(R2, I2) => (R1 <> R2 or                                             I1 <> I2                                            ).

fold; A < A => {false} <- is_nonvar(A).
fold; A <= A => {true} <- is_nonvar(A).
fold; A > A => {false} <- is_nonvar(A).
fold; A >= A => {true} <- is_nonvar(A).
fold; A <> A => {false} <- is_nonvar(A).
fold; A == A => {true} <- is_nonvar(A).

fold; - X < - Y => Y < X.
fold; - X <= - Y => Y <= X.
fold; - X > - Y => Y > X.
fold; - X >= - Y => Y >= X.
fold; - X <> - Y => X <> Y.
fold; - X == - Y => X == Y.

fold; 1 / X < 1 / Y => Y < X.
fold; 1 / X <= 1 / Y => Y <= X.
fold; 1 / X > 1 / Y => Y > X.
fold; 1 / X >= 1 / Y => Y >= X.
fold; 1 / X <> 1 / Y => X <> Y.
fold; 1 / X == 1 / Y => X == Y.

(fold; A < B => T <- to_number(A, N), to_number(B, M), (N < M -> T = {true}; T = {false})).
(fold; A <= B => T <- to_number(A, N), to_number(B, M), (N =< M -> T = {true}; T = {false})).
(fold; A > B => T <- to_number(A, N), to_number(B, M), (N > M -> T = {true}; T = {false})).
(fold; A >= B => T <- to_number(A, N), to_number(B, M), (N >= M -> T = {true}; T = {false})).
(fold; A <> B => T <- to_number(A, N), to_number(B, M), (N \== M -> T = {true}; T = {false})).
(fold; A == B => T <- to_number(A, N), to_number(B, M), (N == M -> T = {true}; T = {false})).

(fold; A < B => T <- to_string(A, N), to_string(B, M), (N @< M -> T = {true}; T = {false})).
(fold; A <= B => T <- to_string(A, N), to_string(B, M), (N @=< M -> T = {true}; T = {false})).
(fold; A > B => T <- to_string(A, N), to_string(B, M), (N @> M -> T = {true}; T = {false})).
(fold; A >= B => T <- to_string(A, N), to_string(B, M), (N @>= M -> T = {true}; T = {false})).
(fold; A <> B => T <- to_string(A, N), to_string(B, M), (N \== M -> T = {true}; T = {false})).
(fold; A == B => T <- to_string(A, N), to_string(B, M), (N == M -> T = {true}; T = {false})).
(fold; A < B => T <- normalize(B - A, C, [fold]), to_number(C, N), (N > 0 -> T = {true}; T = {false})).
(fold; A <= B => T <- normalize(B - A, C, [fold]), to_number(C, N), (N >= 0 -> T = {true}; T = {false})).
(fold; A > B => T <- normalize(A - B, C, [fold]), to_number(C, N), (N > 0 -> T = {true}; T = {false})).
(fold; A >= B => T <- normalize(A - B, C, [fold]), to_number(C, N), (N >= 0 -> T = {true}; T = {false})).
(fold; A <> B => T <- normalize(B - A, C, [fold]), to_number(C, N), (N \= 0 -> T = {true}; T = {false})).

fold; not true => false.
fold; not false => true.
fold; not not A => A.

fold; not A < B => B <= A.
fold; not A <= B => B < A.
fold; not A > B => A <= B.
fold; not A >= B => A < B.
fold; not A == B => A <> B.
fold; not A <> B => A == B.

fold; A eqv A => {true} <- is_nonvar(A).
fold; {true} eqv A => A.
fold; {false} eqv A => not A.
fold; A xor A => {false} <- is_nonvar(A).
fold; {true} xor A => not A.
fold; {false} xor A => A.
fold; A imp A => {true} <- is_nonvar(A).
fold; {true} imp A => A.
fold; {false} imp _G598 => {false}.
fold; _G597 imp {true} => {true}.
fold; A imp {false} => not A.

fold; X if true => X.
fold; X ? true => X.
fold; _G595 if false => nil.
fold; _G595 ? false => nil.
fold; X otherwise => X.

fold; abs(- X) => X.
fold; abs(abs(X)) => abs(X).

fold; re(re(X)) => X.
fold; re(im(X)) => im(X).
fold; im(re(_G595)) => 0.
fold; im(im(_G595)) => 0.

(fold; abs(C) => AbsC <- to_number(C, N), (N >= 0 -> AbsC = C; AbsC = - C)).
fold; acos(C) => AcosC <- to_number(C, N), AcosC is float(acos(N)).
(fold; acosh(C) => AcoshC <- to_number(C, N), AcoshC is float(log(N + sqrt(N ^ 2 + 1)))).
fold; asin(C) => AsinC <- to_number(C, N), AsinC is float(asin(N)).
(fold; asinh(C) => AsinhC <- to_number(C, N), N >= 1, AsinhC is float(log(N + sqrt(N ^ 2 - 1)))).
fold; atan(C) => AtanC <- to_number(C, N), AtanC is float(atan(N)).
(fold; atan(C, D) => AtanCD <- to_number(C, N), to_number(D, M), AtanCD is float(atan(N, M))).
(fold; atanh(C) => AtanhC <- to_number(C, N), N > -1, N < 1, AtanhC is float(log((N + 1) / (N - 1)) / 2)).
fold; conj(C) => C <- is_number(C).
fold; cos(C) => CosC <- to_number(C, N), CosC is float(cos(N)).
(fold; cosh(C) => CoshC <- to_number(C, N), CoshC is float((exp(N) + exp(- N)) / 2)).
fold; ceil(C) => CeilC <- to_number(C, N), CeilC is ceiling(N).
(fold; exp(C) => ExpC <- to_number(C, N), N >= -700, N =< 700, ExpC is float(exp(N))).
fold; fac(C) => FacC <- to_integer(C, N), N >= 0, FacC is fac(N).
fold; floor(C) => FloorC <- to_number(C, N), FloorC is floor(N).
(fold; frac(C) => FracC <- to_number(C, N), FracC is float_fractional_part(N)).
(fold; gcd(C, D) => GCD <- to_integer(C, N), to_integer(D, N), gcd(C, D, GCD)).
fold; im(C) => {0} <- is_number(C).
(fold; lcm(C, D) => LCM <- to_integer(C, N), to_integer(D, N), lcm(C, D, LCM)).
(fold; log(C) => LogC <- to_number(C, N), N > 0, LogC is float(log(N))).
fold; re(C) => C <- is_number(C).
fold; real(C) => C <- is_float(C).
fold; real(C) => RealC <- to_number(C, N), RealC is float(N).
fold; round(C) => RoundC <- to_number(C, N), RoundC is round(N).
fold; sign(C) => SignC <- to_number(C, N), SignC is sign(N).
fold; sin(C) => SinC <- to_number(C, N), SinC is float(sin(N)).
(fold; sinh(C) => SinhC <- to_number(C, N), SinhC is float((exp(N) - exp(- N)) / 2)).
fold; tan(C) => TanC <- to_number(C, N), TanC is float(tan(N)).
(fold; tanh(C) => TanhC <- to_number(C, N), TanhC is float((exp(N) - exp(- N)) / (exp(N) + exp(- N)))).
fold; trunc(C) => TruncC <- to_number(C, N), TruncC is truncate(N).

fold; complex(C) => C <- type : check(C, [complex]).
fold; real(R) => R <- type : check(R, [real]).

fold; ceil(- X) => - floor(X).
fold; ceil(I) => I <- type : check(I, integer).
(fold; ceil((+ | IX)) => I + ceil(X) <- select_assoc_op(+, IX, I, X), type : check(I, integer)).

fold; floor(- X) => - ceil(X).
fold; floor(I) => I <- type : check(I, integer).
(fold; floor((+ | IX)) => I + floor(X) <- select_assoc_op(+, IX, I, X), type : check(I, integer)).

fold; round(- X) => - round(X).
fold; round(I) => I <- type : check(I, integer).
(fold; round((+ | IX)) => I + round(X) <- select_assoc_op(+, IX, I, X), type : check(I, integer)).

fold; trunc(- X) => - trunc(X).
fold; trunc(I) => I <- type : check(I, integer).
(fold; trunc((+ | IX)) => I + trunc(X) <- select_assoc_op(+, IX, I, X), type : check(I, integer)).

```