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