#include <sollya.h>

int cmp(int *res, void **args) {
  sollya_obj_t *true_args = (sollya_obj_t *)args;
  *res = sollya_lib_cmp_objs_structurally(true_args[0], true_args[1]);
  return 1;
}

int hcmp(int *res, void **args) {
  sollya_obj_t *true_args = (sollya_obj_t *)args;
  int64_t h1,h2;
  h1 = sollya_lib_hash(true_args[0]);
  h2 = sollya_lib_hash(true_args[1]);
  *res = (h1 == h2);
  return 1;
}

static char *test_proc_string = "proc () {\n"
  "       var a, b, k, f, g, p, proc_aux, g1;\n"
  "\n"
  "       /* Comparing basic object of the same type */\n"
  "       print(\"Comparing 1 and 1:\"); a = 1; b = 1; cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       print(\"Comparing 1 and 2:\"); a = 1; b = 2; cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       print(\"Comparing [||] and [||]:\"); a = [||]; b = [||]; cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       print(\"Comparing [||] and [|1|]:\"); a = [||]; b = [|1|]; cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       print(\"Comparing [1,2] and [1,2]:\"); a = [1,2]; b = [1,2]; cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       print(\"Comparing [1,2] and [1,3]:\"); a = [1,2]; b = [1,3]; cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       print(\"Comparing \\\"Hello\\\" and \\\"Hello\\\":\"); a = \"Hello\"; b = \"Hello\"; cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       print(\"Comparing \\\"Hello\\\" and \\\"Hello!\\\":\"); a = \"Hello\"; b = \"Hello!\"; cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       \n"
  "       /* Playing with ellipses in lists */\n"
  "       print(\"Comparing [|1,2,3...|] and [|1,2,3|]:\"); a = [|1,2,3...|]; b = [|1,2,3|]; cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       print(\"Comparing [|1,2,3...|] and [|1,2,3,4...|]:\"); a = [|1,2,3...|]; b = [|1,2,3,4...|]; cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       a[0]; b[0];\n"
  "       a[10]; b[10];\n"
  "       /* Does the result change after expanding part of the list? */\n"
  "       cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       \n"
  "       print(\"Comparing [|D,D...|] and [|D...|]:\"); a = [|D,D...|]; b = [|D...|]; cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       a[0]; b[0];\n"
  "       a[10]; b[10];\n"
  "       /* Does the result change after expanding part of the list? */\n"
  "       cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       \n"
  "       /* And if we provide exactly the same? */\n"
  "       a = [|D,D...|]; b = [|D,D...|]; cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       \n"
  "       print(\"Comparing [|1,...,5|] and [|1,2,3,4,5|]:\"); a = [|1,...,5|]; b = [|1,2,3,4,5|];\n"
  "       cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       a[0]; b[0];\n"
  "       a[3]; b[3];\n"
  "       /* Does the result change after expanding part of the list? */\n"
  "       cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       \n"
  "       /* Things obviously not equal because having different types */\n"
  "       print(\"Comparing [||] and 1:\"); a = [||]; b = 1; cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       print(\"Comparing [|1|] and 1:\"); a = [|1|]; b = 1; cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       \n"
  "       /* Do NaN, error and Inf compare equal to themselves? */\n"
  "       print(\"Comparing @NaN@ and @NaN@:\"); a = @NaN@; b = @NaN@; cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       print(\"Comparing @Inf@ and @Inf@:\"); a = @Inf@; b = @Inf@; cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       print(\"Comparing error and error:\"); a = error; b = error; cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       print(\"Comparing error and @NaN@:\"); a = error; b = @NaN@; cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       \n"
  "       /* Expressions mathematically equal */\n"
  "       print(\"Comparing log(x) and log(x):\"); a = log(x); b = log(x); cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       print(\"Comparing log10(x) and log(x)/log(10):\"); a = log10(x); b = log(x)/log(10); cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       print(\"Comparing exp(x)+1 and 1+exp(x):\"); a = exp(x)+1; b = 1+exp(x); cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       print(\"Comparing a = cos(x)^sin(x) and exp(sin(x)*log(cos(x)))):\"); a = cos(x)^sin(x); b = exp(sin(x)*log(cos(x))); cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       print(\"Comparing exp(x)*sin(x) and sin(x)*exp(x):\"); a = exp(x)*sin(x); b = sin(x)*exp(x); cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       \n"
  "       /* Testing polynomials */\n"
  "       print(\"Comparing (x+1)^3 and x^3+3*x^2+3*x+1:\"); a = (x+1)^3; b = x^3+3*x^2+3*x+1;\n"
  "       cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       \n"
  "       a(5); b(5);\n"
  "       /* Does it change after an evaluation? */\n"
  "       cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       \n"
  "       a == b;\n"
  "       /* And after an equality test? */\n"
  "       cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       \n"
  "       da = diff(a); db = diff(b);\n"
  "       cmp(da,db); cmp(db,da); hcmp(da,db); cmp(da,db); cmp(db,da);\n"
  "       /* And after differentiating */\n"
  "       cmp(a,b); cmp(b,a); hcmp(a,b); cmp(a,b); cmp(b,a);\n"
  "       \n"
  "       /* Structural comparison of annotated functions */\n"
  "       f = exp(x);\n"
  "       procedure proc_aux(X,n,p,s,f) { var oldPrec, res; if n==0 then { oldPrec=prec; prec=p!; res=f(X); prec=oldPrec!; print(s @ \" (X=\" @ X @ \", f=\" @ f @ \", p=\" @ p @ \" res=\"@ res @ \")\"); } else res = proc_aux(X,n-1,p,s,diff(f)); return res; };\n"
  "       procedure g1(X,n,p) { return proc_aux(X,n,p, \"Annotation 1\", f); };\n"
  "       g = annotatefunction(f, function(g1), [0,1], [-1b-40, 1b-40]);\n"
  "       prec=15;\n"
  "       f(1b-1);\n"
  "       g(1b-2);\n"
  "       h = exp(x);\n"
  "       h(1b-3);\n"
  "       print(\"Comparison of an annotated function and its non-annotated version:\");\n"
  "       cmp(f,g); cmp(g,f); hcmp(f,g); cmp(f,g); cmp(g,f);\n"
  "       cmp(g,h); cmp(h,g); hcmp(g,h); cmp(g,h); cmp(h,g);\n"
  "       s = diff(g);\n"
  "       s(1b-4);\n"
  "       print(\"Same comparison with diff(exp):\");\n"
  "       s == g;\n"
  "       cmp(s,g); cmp(g,s); hcmp(s,g); cmp(s,g); cmp(g,s);\n"
  "       cmp(s,h); cmp(h,s); hcmp(s,h); cmp(s,h); cmp(h,s);\n"
  "       \n"
  "       /* Structural comparison of polynomials in different\n"
  "          representation froms when they have no expression attached.\n"
  "       */\n"
  "       k = 15;\n"
  "       p = (1 + x)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 3;\n"
  "       p = (1 + x)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 2;\n"
  "       p = (1 + x)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 1;\n"
  "       p = (1 + x)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 15;\n"
  "       p = (1 + x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 14;\n"
  "       p = (1 + x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 3;\n"
  "       p = (1 + x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 2;\n"
  "       p = (1 + x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 1;\n"
  "       p = (1 + x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 15;\n"
  "       p = x^3 * (1 + x)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 3;\n"
  "       p = x^3 * (1 + x)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 2;\n"
  "       p = x^3 * (1 + x)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 1;\n"
  "       p = x^3 * (1 + x)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 15;\n"
  "       p = x^3 * (1 + x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 14;\n"
  "       p = x^3 * (1 + x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 3;\n"
  "       p = x^3 * (1 + x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 2;\n"
  "       p = x^3 * (1 + x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 1;\n"
  "       p = x^3 * (1 + x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 15;\n"
  "       p = x^4 * (1 + x)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 3;\n"
  "       p = x^4 * (1 + x)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 2;\n"
  "       p = x^4 * (1 + x)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 1;\n"
  "       p = x^4 * (1 + x)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 15;\n"
  "       p = x^4 * (1 + x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 14;\n"
  "       p = x^4 * (1 + x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 3;\n"
  "       p = x^4 * (1 + x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 2;\n"
  "       p = x^4 * (1 + x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 1;\n"
  "       p = x^4 * (1 + x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 15;\n"
  "       p = (1 + 17 * x)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 3;\n"
  "       p = (1 + 17 * x)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 2;\n"
  "       p = (1 + 17 * x)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 1;\n"
  "       p = (1 + 17 * x)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 15;\n"
  "       p = (1 + 17 * x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 14;\n"
  "       p = (1 + 17 * x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 3;\n"
  "       p = (1 + 17 * x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 2;\n"
  "       p = (1 + 17 * x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 1;\n"
  "       p = (1 + 17 * x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 15;\n"
  "       p = x^3 * (1 + 17 * x)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 3;\n"
  "       p = x^3 * (1 + 17 * x)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 2;\n"
  "       p = x^3 * (1 + 17 * x)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 1;\n"
  "       p = x^3 * (1 + 17 * x)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 15;\n"
  "       p = x^3 * (1 + 17 * x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 14;\n"
  "       p = x^3 * (1 + 17 * x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 3;\n"
  "       p = x^3 * (1 + 17 * x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 2;\n"
  "       p = x^3 * (1 + 17 * x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 1;\n"
  "       p = x^3 * (1 + 17 * x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 15;\n"
  "       p = x^4 * (1 + 17 * x)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 3;\n"
  "       p = x^4 * (1 + 17 * x)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 2;\n"
  "       p = x^4 * (1 + 17 * x)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 1;\n"
  "       p = x^4 * (1 + 17 * x)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 15;\n"
  "       p = x^4 * (1 + 17 * x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 14;\n"
  "       p = x^4 * (1 + 17 * x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 3;\n"
  "       p = x^4 * (1 + 17 * x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 2;\n"
  "       p = x^4 * (1 + 17 * x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "       \n"
  "       k = 1;\n"
  "       p = x^4 * (1 + 17 * x^2)^k;\n"
  "       a = horner(p);\n"
  "       b = canonical(p);\n"
  "       \n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"a =\", a);\n"
  "       print(\"b =\", b);\n"
  "       cmp(a, b); cmp(b, a); hcmp(a, b); cmp(a, b); cmp(b, a);\n"
  "       print(\"-----------------\");\n"
  "}\n";

int main(void) {
  sollya_obj_t a, b, c, d, e;
  mpfr_t tmp1, tmp2;
  sollya_obj_t cmp_obj, hcmp_obj, test_proc_obj, test_res_obj;
  sollya_externalprocedure_type_t argTypes[2] = { SOLLYA_EXTERNALPROC_TYPE_OBJECT, SOLLYA_EXTERNALPROC_TYPE_OBJECT };

  sollya_lib_init();
  a = SOLLYA_ADD(SOLLYA_CONST(2), SOLLYA_CONST(3));
  b = SOLLYA_CONST(5);
  c = sollya_lib_simplify(a);

  if (sollya_lib_cmp_objs_structurally(a,b))
    sollya_lib_printf("2+3 is structurally equal to 5\n");
  else
    sollya_lib_printf("2+3 is *NOT* structurally equal to 5\n");

  if (sollya_lib_cmp_objs_structurally(b,c))
    sollya_lib_printf("5 is structurally equal to the result of simplify(2+3)\n");
  else
    sollya_lib_printf("5 is *NOT* structurally equal to the result of simplify(2+3)\n");

  sollya_lib_clear_obj(a);
  sollya_lib_clear_obj(b);
  sollya_lib_clear_obj(c);


  /* Commutativity */
  a = SOLLYA_ADD(SOLLYA_CONST(2), SOLLYA_X_);
  b = SOLLYA_ADD(SOLLYA_X_, SOLLYA_CONST(2));

  if (sollya_lib_cmp_objs_structurally(a,b))
    sollya_lib_printf("2+x is structurally equal to x+2\n");
  else
    sollya_lib_printf("2+x is *NOT* structurally equal to x+2\n");

  sollya_lib_clear_obj(a);
  sollya_lib_clear_obj(b);


  /* Structural equality between objs that are not expressions */
  a = sollya_lib_parse_string("[1;2]");
  mpfr_init2(tmp1, 20); /* not the current precision */
  mpfr_init2(tmp2, 30); /* not the current precision */
  mpfr_set_ui(tmp1, 1, GMP_RNDN);
  mpfr_set_ui(tmp2, 2, GMP_RNDN);
  b = sollya_lib_range_from_bounds(tmp1, tmp2);
  mpfr_clear(tmp1); mpfr_clear(tmp2);
  c = sollya_lib_copy_obj(a);

  if (sollya_lib_cmp_objs_structurally(a,b))
    sollya_lib_printf("Intervals with identical bounds but stored at different precisions are structurally equal\n");
  else
    sollya_lib_printf("Intervals with identical bounds but stored at different precisions are *NOT* structurally equal\n");

  if (sollya_lib_cmp_objs_structurally(a,c))
    sollya_lib_printf("Identical intervals are structurally equal\n");
  else
    sollya_lib_printf("Identical intervals are *NOT* structurally equal\n");

  sollya_lib_clear_obj(a);
  sollya_lib_clear_obj(b);
  sollya_lib_clear_obj(c);



  a = sollya_lib_on();
  b = sollya_lib_on();
  c = sollya_lib_off();
  if (sollya_lib_cmp_objs_structurally(a,b))
    sollya_lib_printf("on is structurally equal to on\n");
  else
    sollya_lib_printf("on is not structurally equal to on\n");

  if (sollya_lib_cmp_objs_structurally(a,c))
    sollya_lib_printf("on is structurally equal to off\n");
  else
    sollya_lib_printf("on is *NOT* structurally equal to off\n");

  sollya_lib_clear_obj(a);
  sollya_lib_clear_obj(b);
  sollya_lib_clear_obj(c);



  /* Structural equality between strings */
  a = sollya_lib_string("Hello!");
  b = sollya_lib_string("Hella!");
  c = sollya_lib_string("ello!");
  d = sollya_lib_string("H");
  e = sollya_lib_concat(d, c);

  if (sollya_lib_cmp_objs_structurally(a,b))
    sollya_lib_printf("%b is structurally equal to %b\n", a, b);
  else
    sollya_lib_printf("%b is *NOT* structurally equal to %b\n", a, b);

  if (sollya_lib_cmp_objs_structurally(a,e))
    sollya_lib_printf("%b is structurally equal to %b\n", a, e);
  else
    sollya_lib_printf("%b is *NOT* structurally equal to %b\n", a, e);

  sollya_lib_clear_obj(a);
  sollya_lib_clear_obj(b);
  sollya_lib_clear_obj(c);
  sollya_lib_clear_obj(d);
  sollya_lib_clear_obj(e);


  /* More involved expression */
  a = sollya_lib_parse_string("1 + exp(sin(x + log(x^2)))");
  c = SOLLYA_CONST(40);
  sollya_lib_set_prec(c);
  sollya_lib_clear_obj(c);
  b = sollya_lib_parse_string("sin(x + log(x^2))");
  b = SOLLYA_ADD(SOLLYA_CONST(1), SOLLYA_EXP(b));

  if (sollya_lib_cmp_objs_structurally(a,b))
    sollya_lib_printf("%b is structurally equal to %b, even if defined at different precisions\n", a, b);
  else
    sollya_lib_printf("%b is *NOT* structurally equal to %b, even if defined at different precisions\n", a, b);
  sollya_lib_clear_obj(a);
  sollya_lib_clear_obj(b);

  /* Complex tests */
  cmp_obj = sollya_lib_externalprocedure(SOLLYA_EXTERNALPROC_TYPE_BOOLEAN, argTypes, 2, "cmp", cmp);
  hcmp_obj = sollya_lib_externalprocedure(SOLLYA_EXTERNALPROC_TYPE_BOOLEAN, argTypes, 2, "hcmp", hcmp);

  test_proc_obj = sollya_lib_parse_string(test_proc_string);
  sollya_lib_printf("Running the complex comparison tests\n");
  test_res_obj = sollya_lib_apply(test_proc_obj, NULL);
  sollya_lib_printf("The complex comparison tests are done\n");
  sollya_lib_printf("Object returned by the complex comparison tests: \"%b\"\n", test_res_obj);

  sollya_lib_clear_obj(hcmp_obj);
  sollya_lib_clear_obj(cmp_obj);
  sollya_lib_clear_obj(test_proc_obj);
  sollya_lib_clear_obj(test_res_obj);
  
  sollya_lib_close();
  return 0;
}
