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