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