/* Plotting examples -- try these by hand.
plot2d (if x > 1 then log(x) else exp(x), [x, -1, 3]);
f(x) := if x < 0 then -x else sqrt(x);
plot2d (f(x), [x, -2, 2]);
 */

(kill (all), load (boolsimp), 0);
0;

/* Test 'if (noun).
 */
(expr: if a > b then if a > c then a else d else if b > c then b else c, 0);
0;

(assume (a > b), ev (expr));
'(if a > c then a else d);

(forget (a > b), assume (a > c), ev (expr));
'(if a > b then if a > c then a else d else if b > c then b else c);

block ([x : 17, y : 29], block ([a : 100, b : 'x + 'y, c : x, d : y], ev (expr)));
'(if 100 > x + y then if 100 > 17 then 100 else 29 else if x + y > 17 then x + y else 17);

(forget (a > c), ev (expr));
'(if a > b then (if a > c then a else d) else (if b > c then b else c));

(assume (b < c), ev (expr));
'(if a > b then (if a > c then a else d) else (if b > c then b else c));

(assume (a > c), ev (expr));
a;

(apply (forget, facts ()), []);
[];

(foo (x) := if numberp (x) then if oddp (x) and x > 100 then 'foop (x) else 'nofoop (x)
  else 'if 'oddp (x) and x > 100 then 'foop (x) else 'nofoop (x), 0);
0;

foo (17);
'nofoop (17);

foo (117);
'foop (117);

foo (x + y);
'if 'oddp (x + y) and x + y > 100 then 'foop (x + y) else 'nofoop (x + y);

(assume (x < 0, y < 0), foo (x + y));
'nofoop (x + y);

/* assume fails to deduce x + y > 100 given x + y > 1000, oh well.
 * (forget (x < 0, y < 0), assume (x + y > 1000), foo (x + y));
 */
(forget (x < 0, y < 0), assume (x > 200), foo (x - 50));
'if 'oddp (x - 50) then 'foop (x - 50) else 'nofoop (x - 50);

/* Some examples devised by Stavros Macrakis */

(apply (forget, facts ()), kill (all), 0);
0;

pp: if x > 0 then print(1) else print(2);
'(if x > 0 then print(1) else print(2));

''pp, x=1;
1;

''pp, x= -1;
2;

(f (x, y) := if equal (y, 0) then 0 else 1/x, [f (8, n), f (m, 7)]);
[if equal (n, 0) then 0 else 1/8, 1/m];

/* if equal (y, 0) then 0 else 1/0; => division by zero in simplification */
errcatch (f (0, y));
[];

(f(x) := if x <= 0 then 1 else x*f(x - 1), fy : f(y));
'(if y <= 0 then 1 else y*f(y - 1));

''fy, y=8;
40320;

if equal (x, 0) then 1 else 1/x, x=0;
1;

/* Further examples in the same vein */

pp: if x > 0 then qq1: 1 else qq2: 2;
'(if x > 0 then qq1: 1 else qq2: 2);

(kill (qq1, qq2), ev (pp, x=1));
1;

[qq1, qq2];
[1, 'qq2];

(kill (qq1, qq2), ev (pp, x= -1));
2;

[qq1, qq2];
['qq1, 2];

block ([aa : 2, bb : 3, cc], if cc > 1 then if aa > 0 then 10*aa else -10*aa else if bb > 0 then bb^2 else -bb^2);
'(if cc > 1 then (if 2 > 0 then 20 else -20) else (if 3 > 0 then 9 else -9));

block ([aa : 2, bb : 3, cc], if cc > 1 and aa > 0 then 10*aa elseif cc > 1 and not aa > 0 then -10*aa elseif  not cc > 1 and  bb > 0 then bb^2 elseif not cc > 1 and not bb > 0 then -bb^2);
'(if cc > 1 then 20 elseif cc <= 1 then 9);

print(FOO) or print(BAR); /* should print "FOO" and "BAR" on successive lines */
FOO or BAR;

print(true) or print(false); /* should print "true" */
true;

(push (a, L) ::= buildq ([a, L], L : cons (a, L)), 0);
0;

(L : [], push (FOO, L) or push (BAR, L));
[FOO] or [BAR, FOO];

L;
[BAR, FOO];

(L : [], '(push (FOO, L) or push (BAR, L)), [op(%%), op(first(%%)), args(first(%%)), op(second(%%)), args(second(%%))]);
["or", push, '[FOO, L], push, '[BAR, L]];

L;
[];

/* Should find that aa or bb or cc ... is equivalent to
 * (is(aa), if %% then %% else (is(bb), if %% then %% else (is(cc), if %% then %% else ...)))
 * when all aa, bb, cc, ... evaluate to true or false.
 */

(L : [], first (push (false, L)) or first (push (true, L)) or first (push (true, L)), [%%, L]);
[true, [true, false]];

(L : [], (is(first (push (false, L))), if %% then %% else (is(first (push (true, L))), if %% then %% else (is(first (push (true, L))), if %% then %%))), [%%, L]);
[true, [true, false]];

/* Translation of conditionals and boolean expressions.
 * Translating this file (rtest_boolsimp.mac) would be a good test,
 * but the translator is too broken to translate all of the file.
 */

/* Leave this mode_declare for later.
 * The effect which would be observable here would be
 * to trigger an error if some argument is not true or false.
 * But as it stands, the translation code doesn't exploit
 * the boolean mode_declare in any way.
mode_declare ([a%, b%, c%, d%], boolean);
[[a%, b%, c%, d%]];
 */

/* Example from mailing list 2006/05/04, tnx Barton */

(kill(blurf), blurf(x) := if x < 0 then -1 else 1, 0);
0;

blurf(a);
'if a < 0 then -1 else 1;

(translate(blurf), blurf(a));
'if -a > 0 then -1 else 1;

/* Other examples of translated functions */

(my_max (x, y, z) := if x > y and x > z then x elseif y > z then y else z, translate (my_max));
[my_max];

my_max (11, 33, 22);
33;

my_max (a + b, c, 1);
'if a + b - c > 0 and a + b - 1 > 0 then a + b elseif c - 1 > 0 then c else 1;

[assume (c < 1), my_max (a + b, c, 1), forget (c < 1)];
[[c < 1], 'if a + b - c > 0 and a + b - 1 > 0 then a + b else 1, [c < 1]];

/* explicit resimplification in evaluation (i.e. DEFMSPEC MCOND) not needed,
 * since simplification of branches will be handled after evaluation.
 */
(kill (a, b, c), b:2, c:2, if a > 0 then b + c else b - c);
if a > 0 then 4 else 0;

