1 /** @file exam_misc.cpp
2  *
3  */
5 /*
6  *  GiNaC Copyright (C) 1999-2005 Johannes Gutenberg University Mainz, Germany
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
24 #include "exams.h"
26 #define VECSIZE 30
27 static unsigned exam_expand_subs()
28 {
29         unsigned result = 0;
30         symbol a[VECSIZE];
31         ex e, aux;
33         for (unsigned i=0; i<VECSIZE; ++i)
34                 e = e + a[i];
36         // prepare aux so it will swallow anything but a1^2:
37         aux = -e + a + a;
38         e = expand(subs(expand(pow(e, 2)), a == aux));
40         if (e != pow(a,2)) {
41                 clog << "Denny Fliegner's quick consistency check erroneously returned "
42                      << e << "." << endl;
43                 ++result;
44         }
46         return result;
47 }
49 /*  A simple modification of Denny Fliegner's three step consistency test:
50  *  1)  e = (a0 + a1)^200
51  *  2)  expand e
52  *  3)  substitute a0 by -a1 in e
53  *  after which e should return 0 (without expanding). */
54 static unsigned exam_expand_subs2()
55 {
56         unsigned result = 0;
57         symbol a("a"), b("b");
58         ex e, f;
60         e = pow(a+b,200).expand();
61         f = e.subs(a == -b);
63         if (f != 0) {
64                 clog << "e = pow(a+b,200).expand(); f = e.subs(a == -b); erroneously returned "
65                      << f << " instead of simplifying to 0." << endl;
66                 ++result;
67         }
69         return result;
70 }
72 static unsigned exam_expand_power()
73 {
74         unsigned result = 0;
75         symbol x("x"), a("a"), b("b");
76         ex e;
78         e = pow(x,pow(a+b,2)-pow(a,2)-pow(b,2)-a*b*2).expand();
80         if (e != 1) {
81                 clog << "e = pow(x,pow(a+b,2)-pow(a,2)-pow(b,2)-a*b*2).expand(); erroneously returned "
82                      << e << " instead of simplifying to 1." << endl;
83                 ++result;
84         }
86         return result;
87 }
89 static unsigned exam_sqrfree()
90 {
91         unsigned result = 0;
92         symbol x("x"), y("y");
93         ex e1, e2;
95         e1 = (1+x)*pow((2+x),2)*pow((3+x),3)*pow((4+x),4);
96         e2 = sqrfree(expand(e1),lst(x));
97         if (e1 != e2) {
98                 clog << "sqrfree(expand(" << e1 << ")) erroneously returned "
99                      << e2 << endl;
100                 ++result;
101         }
103         e1 = (x+y)*pow((x+2*y),2)*pow((x+3*y),3)*pow((x+4*y),4);
104         e2 = sqrfree(expand(e1));
105         if (e1 != e2) {
106                 clog << "sqrfree(expand(" << e1 << ")) erroneously returned "
107                      << e2 << endl;
108                 ++result;
109         }
110         e2 = sqrfree(expand(e1),lst(x));
111         if (e1 != e2) {
112                 clog << "sqrfree(expand(" << e1 << "),[x]) erroneously returned "
113                      << e2 << endl;
114                 ++result;
115         }
116         e2 = sqrfree(expand(e1),lst(y));
117         if (e1 != e2) {
118                 clog << "sqrfree(expand(" << e1 << "),[y]) erroneously returned "
119                      << e2 << endl;
120                 ++result;
121         }
122         e2 = sqrfree(expand(e1),lst(x,y));
123         if (e1 != e2) {
124                 clog << "sqrfree(expand(" << e1 << "),[x,y]) erroneously returned "
125                      << e2 << endl;
126                 ++result;
127         }
129         return result;
130 }
132 /* Arithmetic Operators should behave just as one expects from built-in types.
133  * When somebody screws up the operators this routine will most probably fail
134  * to compile.  Unfortunately we can only test the stuff that is allowed, not
135  * what is forbidden (e.g. e1+e2 = 42) since that must not compile.  :-(   */
136 static unsigned exam_operator_semantics()
137 {
138         unsigned result = 0;
139         ex e1, e2;
140         int i1, i2;
142         // Assignment should not return const ex though it may be obfuscated:
143         e1 = 7; e2 = 4;
144         i1 = 7; i2 = 4;
145         (e1 = e2) = 2;
146         (i1 = i2) = 2;
147         if (e1!=i1 || e2!=i2) {
148                 clog << "Semantics of ex::operator=() screwed." << endl;
149                 ++result;
150         }
151         (e1 += e2) = 2;
152         (i1 += i2) = 2;
153         if (e1!=i1 || e2!=i2) {
154                 clog << "Semantics of ex::operator=() screwed." << endl;
155                 ++result;
156         }
157         (e1 -= e2) = 2;
158         (i1 -= i2) = 2;
159         if (e1!=i1 || e2!=i2) {
160                 clog << "Semantics of ex::operator=() screwed." << endl;
161                 ++result;
162         }
164         // Prefix/postfix increment/decrement behaviour:
165         e1 = 7; e2 = 4;
166         i1 = 7; i2 = 4;
167         e1 = (--e2 = 2)++;
168         i1 = (--i2 = 2)++;
169         if (e1!=i1 || e2!=i2) {
170                 clog << "Semantics of increment/decrement operators screwed." << endl;
171                 ++result;
172         }
173         e1 = (++e2 = 2)--;
174         i1 = (++i2 = 2)--;
175         if (e1!=i1 || e2!=i2) {
176                 clog << "Semantics of increment/decrement operators screwed." << endl;
177                 ++result;
178         }
180         // prefix increment/decrement must return an lvalue (contrary to postfix):
181         e1 = 7; e2 = 4;
182         i1 = 7; i2 = 4;
183         --++----e1;  ++(++++++++(++++e2));
184         --++----i1;  ++(++++++++(++++i2));
185         if (e1!=i1 || e2!=i2) {
186                 clog << "Semantics of prefix increment/decrement operators screwed." << endl;
187                 ++result;
188         }
190         // This one has a good chance of detecting problems in self-assignment:
191         // (which incidentally was severely broken from version 0.7.3 to 0.8.2).
192         ex selfprobe = numeric("65536");
193         selfprobe = selfprobe;
194         if (!is_exactly_a<numeric>(selfprobe)) {
195                 clog << "ex (of numeric) after self-assignment became " << selfprobe << endl;
196                 ++result;
197         }
199         return result;
200 }
202 /* This checks whether subs() works as intended in some special cases. */
203 static unsigned exam_subs()
204 {
205         unsigned result = 0;
206         symbol x("x");
207         ex e1, e2;
209         // This used to fail in GiNaC 1.0.5 because it first substituted
210         // x+1 -> (x-1)+1 -> x, and then substituted again x -> x-1, giving
211         // the wrong result
212         e1 = x+1;
213         e2 = e1.subs(x == x-1);
214         if (!e2.is_equal(x)) {
215                 clog << "(x+1).subs(x==x-1) erroneously returned " << e2 << " instead of x" << endl;
216                 ++result;
217         }
219         e1 = sin(1+sin(x));
220         e2 = e1.subs(sin(wild()) == cos(wild()));
221         if (!e2.is_equal(cos(1+cos(x)))) {
222                 clog << "sin(1+sin(x)).subs(sin(\$1)==cos(\$1)) erroneously returned " << e2 << " instead of cos(1+cos(x))" << endl;
223                 ++result;
224         }
226         return result;
227 }
229 /* Joris van der Hoeven (he of TeXmacs fame) is a funny guy.  He has his own
230  * ideas what a symbolic system should do.  Let's make sure we won't disappoint
231  * him some day.  Incidentally, this seems to always have worked. */
232 static unsigned exam_joris()
233 {
234         unsigned result = 0;
235         symbol x("x");
237         ex e = expand(pow(x, x-1) * x);
238         if (e != pow(x, x)) {
239                 clog << "x^(x-1)*x did not expand to x^x.  Please call Joris!" << endl;
240                 ++result;
241         }
243         return result;
244 }
246 /* Test Chris Dams' algebraic substitutions. */
247 static unsigned exam_subs_algebraic()
248 {
249         unsigned result = 0;
250         symbol x("x"), y("y");
252         ex e = ex(x*x*x*y*y).subs(x*y==2, subs_options::algebraic);
253         if (e != 4*x) {
254                 clog << "(x^3*y^2).subs(x*y==2,subs_options::algebraic) erroneously returned " << e << endl;
255                 ++result;
256         }
258         e = ex(x*x*x*x*x).subs(x*x==y, subs_options::algebraic);
259         if (e != y*y*x) {
260                 clog << "x^5.subs(x^2==y,subs_options::algebraic) erroneously returned " << e << endl;
261                 ++result;
262         }
264         e=x*x*y;
265         if (!e.has(x*y, has_options::algebraic))
266         {       clog << "(x^2*y).has(x*y, has_options::algebraic) erroneously returned false." << endl;
267                 ++result;
268         }
270         if (e.has(x*y*y, has_options::algebraic))
271         {       clog << "(x^2*y).has(x*y*y, has_options::algebraic) erroneously returned true." << endl;
272                 ++result;
273         }
275         e=x*x*x*y;
276         if (!e.has(x*x, has_options::algebraic))
277         {       clog << "(x^3*y).has(x*x, has_options::algebraic) erroneously returned false." << endl;
278                 ++result;
279         }
281         if (e.has(y*y, has_options::algebraic))
282         {       clog << "(x^3*y).has(y*y, has_options::algebraic) erroneously returned true." << endl;
283                 ++result;
284         }
286         return result;
287 }
289 unsigned exam_misc()
290 {
291         unsigned result = 0;
293         cout << "examining miscellaneous other things" << flush;
294         clog << "----------miscellaneous other things:" << endl;
296         result += exam_expand_subs();  cout << '.' << flush;
297         result += exam_expand_subs2();  cout << '.' << flush;
298         result += exam_expand_power(); cout << '.' << flush;
299         result += exam_sqrfree(); cout << '.' << flush;
300         result += exam_operator_semantics(); cout << '.' << flush;
301         result += exam_subs(); cout << '.' << flush;
302         result += exam_joris(); cout << '.' << flush;
303         result += exam_subs_algebraic(); cout << '.' << flush;
305         if (!result) {
306                 cout << " passed " << endl;
307                 clog << "(no output)" << endl;
308         } else {
309                 cout << " failed " << endl;
310         }
312         return result;
313 }