- modified the comment blocks so the copyright message no longer appears in
[ginac.git] / ginac / ex.cpp
1 /** @file ex.cpp
2  *
3  *  Implementation of GiNaC's light-weight expression handles. */
4
5 /*
6  *  GiNaC Copyright (C) 1999 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include <iostream>
24
25 #include "ex.h"
26 #include "add.h"
27 #include "mul.h"
28 #include "ncmul.h"
29 #include "numeric.h"
30 #include "power.h"
31
32 //////////
33 // default constructor, destructor, copy constructor assignment operator and helpers
34 //////////
35
36 // public
37
38 #ifndef INLINE_EX_CONSTRUCTORS
39
40 ex::ex() : bp(exZERO().bp)
41 {
42     debugmsg("ex default constructor",LOGLEVEL_CONSTRUCT);
43     ASSERT(exZERO().bp!=0);
44     ASSERT(exZERO().bp->flags & status_flags::dynallocated);
45     ASSERT(bp!=0);
46     ++bp->refcount;
47 }
48
49 ex::~ex()
50 {
51     debugmsg("ex destructor",LOGLEVEL_DESTRUCT);
52     ASSERT(bp!=0);
53     ASSERT(bp->flags & status_flags::dynallocated);
54     if (--bp->refcount == 0) {
55         delete bp;
56     }
57 }
58
59 ex::ex(ex const & other) : bp(other.bp)
60 {
61     debugmsg("ex copy constructor",LOGLEVEL_CONSTRUCT);
62     ASSERT(bp!=0);
63     ASSERT((bp->flags) & status_flags::dynallocated);
64     ++bp->refcount;
65 }
66
67 ex const & ex::operator=(ex const & other)
68 {
69     debugmsg("ex operator=",LOGLEVEL_ASSIGNMENT);
70     ASSERT(bp!=0);
71     ASSERT(bp->flags & status_flags::dynallocated);
72     ASSERT(other.bp!=0);
73     ASSERT(other.bp->flags & status_flags::dynallocated);
74     ++other.bp->refcount;
75     basic * tmpbp=other.bp;
76     if (--bp->refcount==0) {
77             delete bp;
78     }
79     bp=tmpbp;
80     return *this;
81 }
82
83 #endif // ndef INLINE_EX_CONSTRUCTORS
84
85 //////////
86 // other constructors
87 //////////
88
89 // public
90
91 #ifndef INLINE_EX_CONSTRUCTORS
92 ex::ex(basic const & other)
93 {
94     debugmsg("ex constructor from basic",LOGLEVEL_CONSTRUCT);
95     construct_from_basic(other);
96 }
97 #endif
98
99 ex::ex(int const i)
100 {
101     debugmsg("ex constructor from int",LOGLEVEL_CONSTRUCT);
102     construct_from_basic(numeric(i));
103 }
104
105 ex::ex(unsigned int const i)
106 {
107     debugmsg("ex constructor from unsigned int",LOGLEVEL_CONSTRUCT);
108     construct_from_basic(numeric(i));
109 }
110
111 ex::ex(long const i)
112 {
113     debugmsg("ex constructor from long",LOGLEVEL_CONSTRUCT);
114     construct_from_basic(numeric(i));
115 }
116
117 ex::ex(unsigned long const i)
118 {
119     debugmsg("ex constructor from unsigned long",LOGLEVEL_CONSTRUCT);
120     construct_from_basic(numeric(i));
121 }
122
123 ex::ex(double const d)
124 {
125     debugmsg("ex constructor from double",LOGLEVEL_CONSTRUCT);
126     construct_from_basic(numeric(d));
127 }
128     
129 //////////
130 // functions overriding virtual functions from bases classes
131 //////////
132
133 // none
134
135 //////////
136 // new virtual functions which can be overridden by derived classes
137 //////////
138
139 // none
140
141 //////////
142 // non-virtual functions in this class
143 //////////
144
145 // public
146
147 void ex::swap(ex & other)
148 {
149     debugmsg("ex swap",LOGLEVEL_MEMBER_FUNCTION);
150
151     ASSERT(bp!=0);
152     ASSERT(bp->flags & status_flags::dynallocated);
153     ASSERT(other.bp!=0);
154     ASSERT(other.bp->flags & status_flags::dynallocated);
155     
156     basic * tmpbp=bp;
157     bp=other.bp;
158     other.bp=tmpbp;
159 }
160
161 bool ex::info(unsigned inf) const
162 {
163     if (inf == info_flags::normal_form) {
164
165     // Polynomials are in normal form
166     if (info(info_flags::polynomial))
167         return true;
168
169     // polynomial^(-int) is in normal form
170     if (is_ex_exactly_of_type(*this, power))
171         return op(1).info(info_flags::negint);
172
173     // polynomial^(int) * polynomial^(int) * ... is in normal form
174     if (!is_ex_exactly_of_type(*this, mul))
175         return false;
176     for (int i=0; i<nops(); i++) {
177         if (is_ex_exactly_of_type(op(i), power)) {
178             if (!op(i).op(1).info(info_flags::integer))
179                 return false;
180             if (!op(i).op(0).info(info_flags::polynomial))
181                 return false;
182         } else
183             if (!op(i).info(info_flags::polynomial))
184                 return false;
185     }
186     return true;
187     } else {
188         return bp->info(inf);
189     }
190 }
191
192 int ex::nops() const
193 {
194     ASSERT(bp!=0);
195     return bp->nops();
196 }
197
198 ex ex::expand(unsigned options) const
199 {
200     ASSERT(bp!=0);
201     return bp->expand(options);
202 }
203
204 bool ex::has(ex const & other) const
205 {
206     ASSERT(bp!=0);
207     return bp->has(other);
208 }
209
210 int ex::degree(symbol const & s) const
211 {
212     ASSERT(bp!=0);
213     return bp->degree(s);
214 }
215
216 int ex::ldegree(symbol const & s) const
217 {
218     ASSERT(bp!=0);
219     return bp->ldegree(s);
220 }
221
222 ex ex::coeff(symbol const & s, int const n) const
223 {
224     ASSERT(bp!=0);
225     return bp->coeff(s,n);
226 }
227
228 ex ex::numer(bool normalize) const
229 {
230     ex n;
231     if (normalize && !info(info_flags::normal_form))
232         n = normal();
233     else
234         n = *this;
235
236     // polynomial
237     if (n.info(info_flags::polynomial))
238         return n;
239
240     // something^(-int)
241     if (is_ex_exactly_of_type(n, power) && n.op(1).info(info_flags::negint))
242         return exONE();
243
244     // something^(int) * something^(int) * ...
245     if (!is_ex_exactly_of_type(n, mul))
246         return n;
247     ex res = exONE();
248     for (int i=0; i<n.nops(); i++) {
249         if (!is_ex_exactly_of_type(n.op(i), power) || !n.op(i).op(1).info(info_flags::negint))
250             res *= n.op(i);
251     }
252     return res;
253 }
254
255 ex ex::denom(bool normalize) const
256 {
257     ex n;
258     if (normalize && !info(info_flags::normal_form))
259         n = normal();
260     else
261         n = *this;
262
263     // polynomial
264     if (n.info(info_flags::polynomial))
265         return exONE();
266
267     // something^(-int)
268     if (is_ex_exactly_of_type(n, power) && n.op(1).info(info_flags::negint))
269         return power(n.op(0), -(n.op(1)));
270
271     // something^(int) * something^(int) * ...
272     if (!is_ex_exactly_of_type(n, mul))
273         return exONE();
274     ex res = exONE();
275     for (int i=0; i<n.nops(); i++) {
276         if (is_ex_exactly_of_type(n.op(i), power) && n.op(i).op(1).info(info_flags::negint))
277             res *= power(n.op(i), -1);
278     }
279     return res;
280 }
281
282 ex ex::collect(symbol const & s) const
283 {
284     ASSERT(bp!=0);
285     return bp->collect(s);
286 }
287
288 ex ex::eval(int level) const
289 {
290     ASSERT(bp!=0);
291     return bp->eval(level);
292 }
293
294 ex ex::evalf(int level) const
295 {
296     ASSERT(bp!=0);
297     return bp->evalf(level);
298 }
299
300 ex ex::subs(lst const & ls, lst const & lr) const
301 {
302     ASSERT(bp!=0);
303     return bp->subs(ls,lr);
304 }
305
306 ex ex::subs(ex const & e) const
307 {
308     ASSERT(bp!=0);
309     return bp->subs(e);
310 }
311
312 exvector ex::get_indices(void) const
313 {
314     ASSERT(bp!=0);
315     return bp->get_indices();
316 }
317
318 ex ex::simplify_ncmul(exvector const & v) const
319 {
320     ASSERT(bp!=0);
321     return bp->simplify_ncmul(v);
322 }
323
324 ex ex::operator[](ex const & index) const
325 {
326     debugmsg("ex operator[ex]",LOGLEVEL_OPERATOR);
327     ASSERT(bp!=0);
328     return (*bp)[index];
329 }
330
331 ex ex::operator[](int const i) const
332 {
333     debugmsg("ex operator[int]",LOGLEVEL_OPERATOR);
334     ASSERT(bp!=0);
335     return (*bp)[i];
336 }
337
338 ex ex::op(int const i) const
339 {
340     debugmsg("ex op()",LOGLEVEL_MEMBER_FUNCTION);
341     ASSERT(bp!=0);
342     return bp->op(i);
343 }
344
345 ex & ex::let_op(int const i)
346 {
347     debugmsg("ex let_op()",LOGLEVEL_MEMBER_FUNCTION);
348     makewriteable();
349     ASSERT(bp!=0);
350     return bp->let_op(i);
351 }
352
353 #ifndef INLINE_EX_CONSTRUCTORS
354 int ex::compare(ex const & other) const
355 {
356     ASSERT(bp!=0);
357     ASSERT(other.bp!=0);
358     if (bp==other.bp) {
359         // special case: both expression point to same basic, trivially equal
360         return 0; 
361     }
362     return bp->compare(*other.bp);
363 }
364 #endif // ndef INLINE_EX_CONSTRUCTORS
365
366 #ifndef INLINE_EX_CONSTRUCTORS
367 bool ex::is_equal(ex const & other) const
368 {
369     ASSERT(bp!=0);
370     ASSERT(other.bp!=0);
371     if (bp==other.bp) {
372         // special case: both expression point to same basic, trivially equal
373         return true; 
374     }
375     return bp->is_equal(*other.bp);
376 }
377 #endif // ndef INLINE_EX_CONSTRUCTORS
378
379 unsigned ex::return_type(void) const
380 {
381     ASSERT(bp!=0);
382     return bp->return_type();
383 }
384
385 unsigned ex::return_type_tinfo(void) const
386 {
387     ASSERT(bp!=0);
388     return bp->return_type_tinfo();
389 }
390
391 unsigned ex::gethash(void) const
392 {
393     ASSERT(bp!=0);
394     return bp->gethash();
395 }
396
397 ex ex::exadd(ex const & rh) const
398 {
399     return (new add(*this,rh))->setflag(status_flags::dynallocated);
400 }
401
402 ex ex::exmul(ex const & rh) const
403 {
404     return (new mul(*this,rh))->setflag(status_flags::dynallocated);
405 }
406
407 ex ex::exncmul(ex const & rh) const
408 {
409     return (new ncmul(*this,rh))->setflag(status_flags::dynallocated);
410 }
411
412 // private
413
414 void ex::makewriteable()
415 {
416     debugmsg("ex makewriteable",LOGLEVEL_MEMBER_FUNCTION);
417     ASSERT(bp!=0);
418     ASSERT(bp->flags & status_flags::dynallocated);
419     if (bp->refcount > 1) {
420         basic * bp2=bp->duplicate();
421         ++bp2->refcount;
422         bp2->setflag(status_flags::dynallocated);
423         --bp->refcount;
424         bp=bp2;
425     }
426     ASSERT(bp->refcount == 1);
427 }    
428
429 void ex::construct_from_basic(basic const & other)
430 {
431     if ( (other.flags & status_flags::evaluated)==0 ) {
432         // cf. copy constructor
433         ex const & tmpex = other.eval(1); // evaluate only one (top) level
434         bp = tmpex.bp;
435         ASSERT(bp!=0);
436         ASSERT(bp->flags & status_flags::dynallocated);
437         ++bp->refcount;
438         if ((other.flags & status_flags::dynallocated)&&(other.refcount==0)) {
439             delete &const_cast<basic &>(other);
440         }
441     } else {
442         if (other.flags & status_flags::dynallocated) {
443             bp=&const_cast<basic &>(other);
444         } else {
445             bp=other.duplicate();
446             bp->setflag(status_flags::dynallocated);
447         }
448         ASSERT(bp!=0);
449         // bp->clearflag(status_flags::evaluated);
450         ++bp->refcount;
451     }
452     ASSERT(bp!=0);
453     ASSERT(bp->flags & status_flags::dynallocated);
454 }
455
456 //////////
457 // static member variables
458 //////////
459
460 // none
461
462 //////////
463 // functions which are not member functions
464 //////////
465
466 // none
467
468 //////////
469 // global functions
470 //////////
471
472 ex const & exZERO(void)
473 {
474     static ex * eZERO=new ex(numZERO());
475     return *eZERO;
476 }
477
478 ex const & exONE(void)
479 {
480     static ex * eONE=new ex(numONE());
481     return *eONE;
482 }
483
484 ex const & exTWO(void)
485 {
486     static ex * eTWO=new ex(numTWO());
487     return *eTWO;
488 }
489
490 ex const & exTHREE(void)
491 {
492     static ex * eTHREE=new ex(numTHREE());
493     return *eTHREE;
494 }
495
496 ex const & exMINUSONE(void)
497 {
498     static ex * eMINUSONE=new ex(numMINUSONE());
499     return *eMINUSONE;
500 }
501
502 ex const & exHALF(void)
503 {
504     static ex * eHALF=new ex(ex(1)/ex(2));
505     return *eHALF;
506 }
507
508 ex const & exMINUSHALF(void)
509 {
510     static ex * eMINUSHALF=new ex(numeric(-1,2));
511     return *eMINUSHALF;
512 }
513