- unsigned result = 0;
-
- cout << "examining several historic failures just out of paranoia" << flush;
- clog << "----------several historic failures:" << endl;
-
- result += exam_paranoia1(); cout << '.' << flush;
- result += exam_paranoia2(); cout << '.' << flush;
- result += exam_paranoia3(); cout << '.' << flush;
- result += exam_paranoia4(); cout << '.' << flush;
- result += exam_paranoia5(); cout << '.' << flush;
- result += exam_paranoia6(); cout << '.' << flush;
- result += exam_paranoia7(); cout << '.' << flush;
- result += exam_paranoia8(); cout << '.' << flush;
- result += exam_paranoia9(); cout << '.' << flush;
- result += exam_paranoia10(); cout << '.' << flush;
- result += exam_paranoia11(); cout << '.' << flush;
-
- if (!result) {
- cout << " passed " << endl;
- clog << "(no output)" << endl;
- } else {
- cout << " failed " << endl;
- }
-
- return result;
+ unsigned result = 0;
+ symbol x("x");
+
+ ex e = 2-2*(1+x)/(-1-x);
+ ex f = e.normal();
+ ex d = 4;
+
+ if (!(f - d).expand().is_zero()) {
+ clog << "normal(" << e << ") returns " << f
+ << " instead of " << d << endl;
+ ++result;
+ }
+ return result;
+}
+
+// This one caused a division by 0 because heur_gcd() didn't check its
+// input polynomials against 0. Fixed on Aug 4th 2000.
+static unsigned exam_paranoia13()
+{
+ unsigned result = 0;
+ symbol a("a"), b("b"), c("c");
+
+ ex e = (b*a-c*a)/(4-a);
+ ex d = (c*a-b*a)/(a-4);
+
+ try {
+ ex f = e.normal();
+ if (!(f - d).expand().is_zero()) {
+ clog << "normal(" << e << ") returns " << f
+ << " instead of " << d << endl;
+ ++result;
+ }
+ } catch (const exception &err) {
+ clog << "normal(" << e << ") throws " << err.what() << endl;
+ ++result;
+ }
+ return result;
+}
+
+// A bug introduced on July 19, 2001. quo() and rem() would sometimes call
+// vector::reserve() with a negative argument. Fixed on Dec 20, 2001.
+static unsigned exam_paranoia14()
+{
+ unsigned result = 0;
+ symbol x("x");
+
+ ex q = quo(1, pow(x, 3), x);
+ if (!q.is_zero()) {
+ clog << "quo(1,x^3,x) erroneously returned " << q << " instead of 0\n";
+ ++result;
+ }
+
+ return result;
+}
+
+// Under certain conditions, power::expand_add_2() could produce non-canonical
+// numeric expairs. Fixed on Oct 24, 2002.
+static unsigned exam_paranoia15()
+{
+ unsigned result = 0;
+
+ ex q = (pow(pow(2, numeric(1, 2))*2+1, 2)).expand();
+ // this used to produce "1+4*sqrt(2)+4*2" which would never evaluate
+ // to "9+4*sqrt(2)"
+
+ if (!(q-9-4*pow(2, numeric(1, 2))).is_zero()) {
+ clog << "expand((sqrt(2)*2+1)^2) erroneously returned " << q << " instead of 9-4*sqrt(2)\n";
+ ++result;
+ }
+
+ return result;
+}
+
+// Expanding products containing powers of sums could return results that
+// were not fully expanded. Fixed on Dec 10, 2003.
+static unsigned exam_paranoia16()
+{
+ unsigned result = 0;
+ symbol a("a"), b("b"), c("c"), d("d"), e("e");
+ ex e1, e2, e3;
+
+ e1 = pow(1+a*sqrt(b+c), 2);
+ e2 = e1.expand();
+
+ if (e2.has(pow(a, 2)*(b+c))) {
+ clog << "expand(" << e1 << ") didn't fully expand\n";
+ ++result;
+ }
+
+ e1 = (d*sqrt(a+b)+a*sqrt(c+d))*(b*sqrt(a+b)+a*sqrt(c+d));
+ e2 = e1.expand();
+
+ if (e2.has(pow(a, 2)*(c+d))) {
+ clog << "expand(" << e1 << ") didn't fully expand\n";
+ ++result;
+ }
+
+ e1 = (a+sqrt(b+c))*sqrt(b+c)*(d+sqrt(b+c));
+ e2 = e1.expand();
+
+ if (e2.has(a*(b+c))) {
+ clog << "expand(" << e1 << ") didn't fully expand\n";
+ ++result;
+ }
+
+ e1 = pow(sqrt(a+b)+sqrt(c+d), 3);
+ e2 = e1.expand();
+
+ if (e2.has(3*(a+b)*sqrt(c+d)) || e2.has(3*(c+d)*sqrt(a+b))) {
+ clog << "expand(" << e1 << ") didn't fully expand\n";
+ ++result;
+ }
+
+ e1 = a*(b+c*(d+e));
+ e2 = e1.expand();
+
+ if (e2.has(c*(d+e))) {
+ clog << "expand(" << e1 << ") didn't fully expand\n";
+ ++result;
+ }
+
+ e1 = 2*pow(1+a, 2)/a;
+ e2 = e1.expand();
+
+ if (e2.has(pow(a, 2))) {
+ clog << "expand(" << e1 << ") didn't fully expand\n";
+ ++result;
+ }
+
+ e1 = a*(a+b);
+ e2 = pow(pow(e1, -1), -1);
+
+ if (e2.has(a*b)) {
+ clog << "double reciprocal expanded where it should not\n";
+ ++result;
+ }
+
+ return result;
+}
+
+unsigned exam_paranoia()
+{
+ unsigned result = 0;
+
+ cout << "examining several historic failures just out of paranoia" << flush;
+ clog << "----------several historic failures:" << endl;
+
+ result += exam_paranoia1(); cout << '.' << flush;
+ result += exam_paranoia2(); cout << '.' << flush;
+ result += exam_paranoia3(); cout << '.' << flush;
+ result += exam_paranoia4(); cout << '.' << flush;
+ result += exam_paranoia5(); cout << '.' << flush;
+ result += exam_paranoia6(); cout << '.' << flush;
+ result += exam_paranoia7(); cout << '.' << flush;
+ result += exam_paranoia8(); cout << '.' << flush;
+ result += exam_paranoia9(); cout << '.' << flush;
+ result += exam_paranoia10(); cout << '.' << flush;
+ result += exam_paranoia11(); cout << '.' << flush;
+ result += exam_paranoia12(); cout << '.' << flush;
+ result += exam_paranoia13(); cout << '.' << flush;
+ result += exam_paranoia14(); cout << '.' << flush;
+ result += exam_paranoia15(); cout << '.' << flush;
+ result += exam_paranoia16(); cout << '.' << flush;
+
+ if (!result) {
+ cout << " passed " << endl;
+ clog << "(no output)" << endl;
+ } else {
+ cout << " failed " << endl;
+ }
+
+ return result;