]> www.ginac.de Git - ginac.git/blob - ginac/ex.cpp
cdef6254cb003f4935a49ec81fb5bbe9a6c6d078
[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 /** Swap the contents of two expressions. */
153 void ex::swap(ex & other)
154 {
155     debugmsg("ex swap",LOGLEVEL_MEMBER_FUNCTION);
156
157     GINAC_ASSERT(bp!=0);
158     GINAC_ASSERT(bp->flags & status_flags::dynallocated);
159     GINAC_ASSERT(other.bp!=0);
160     GINAC_ASSERT(other.bp->flags & status_flags::dynallocated);
161     
162     basic * tmpbp=bp;
163     bp=other.bp;
164     other.bp=tmpbp;
165 }
166
167 /** Output formatted to be useful as ginsh input. */
168 void ex::print(ostream & os, unsigned upper_precedence) const
169 {
170     debugmsg("ex print",LOGLEVEL_PRINT);
171     GINAC_ASSERT(bp!=0);
172     bp->print(os,upper_precedence);
173 }
174
175 void ex::printraw(ostream & os) const
176 {
177     debugmsg("ex printraw",LOGLEVEL_PRINT);
178     GINAC_ASSERT(bp!=0);
179     os << "ex(";
180     bp->printraw(os);
181     os << ")";
182 }
183
184 void ex::printtree(ostream & os, unsigned indent) const
185 {
186     debugmsg("ex printtree",LOGLEVEL_PRINT);
187     GINAC_ASSERT(bp!=0);
188     // os << "refcount=" << bp->refcount << " ";
189     bp->printtree(os,indent);
190 }
191
192 /** Print expression as a C++ statement. The output looks like
193  *  "<type> <var_name> = <expression>;". The "type" parameter has an effect
194  *  on how number literals are printed.
195  *
196  *  @param os output stream
197  *  @param type variable type (one of the csrc_types)
198  *  @param var_name variable name to be printed */
199 void ex::printcsrc(ostream & os, unsigned type, const char *var_name) const
200 {
201     debugmsg("ex print csrc", LOGLEVEL_PRINT);
202     GINAC_ASSERT(bp!=0);
203     switch (type) {
204         case csrc_types::ctype_float:
205             os << "float ";
206             break;
207         case csrc_types::ctype_double:
208             os << "double ";
209             break;
210         case csrc_types::ctype_cl_N:
211             os << "cl_N ";
212             break;
213     }
214     os << var_name << " = ";
215     bp->printcsrc(os, type, 0);
216     os << ";\n";
217 }
218
219 /** Little wrapper arount print to be called within a debugger. */
220 void ex::dbgprint(void) const
221 {
222     debugmsg("ex dbgprint",LOGLEVEL_PRINT);
223     GINAC_ASSERT(bp!=0);
224     bp->dbgprint();
225 }
226
227 /** Little wrapper arount printtree to be called within a debugger. */
228 void ex::dbgprinttree(void) const
229 {
230     debugmsg("ex dbgprinttree",LOGLEVEL_PRINT);
231     GINAC_ASSERT(bp!=0);
232     bp->dbgprinttree();
233 }
234
235 bool ex::info(unsigned inf) const
236 {
237     if (inf == info_flags::normal_form) {
238
239     // Polynomials are in normal form
240     if (info(info_flags::polynomial))
241         return true;
242
243     // polynomial^(-int) is in normal form
244     if (is_ex_exactly_of_type(*this, power))
245         return op(1).info(info_flags::negint);
246
247     // polynomial^(int) * polynomial^(int) * ... is in normal form
248     if (!is_ex_exactly_of_type(*this, mul))
249         return false;
250     for (int i=0; i<nops(); i++) {
251         if (is_ex_exactly_of_type(op(i), power)) {
252             if (!op(i).op(1).info(info_flags::integer))
253                 return false;
254             if (!op(i).op(0).info(info_flags::polynomial))
255                 return false;
256         } else
257             if (!op(i).info(info_flags::polynomial))
258                 return false;
259     }
260     return true;
261     } else {
262         return bp->info(inf);
263     }
264 }
265
266 int ex::nops() const
267 {
268     GINAC_ASSERT(bp!=0);
269     return bp->nops();
270 }
271
272 ex ex::expand(unsigned options) const
273 {
274     GINAC_ASSERT(bp!=0);
275     return bp->expand(options);
276 }
277
278 bool ex::has(ex const & other) const
279 {
280     GINAC_ASSERT(bp!=0);
281     return bp->has(other);
282 }
283
284 int ex::degree(symbol const & s) const
285 {
286     GINAC_ASSERT(bp!=0);
287     return bp->degree(s);
288 }
289
290 int ex::ldegree(symbol const & s) const
291 {
292     GINAC_ASSERT(bp!=0);
293     return bp->ldegree(s);
294 }
295
296 ex ex::coeff(symbol const & s, int const n) const
297 {
298     GINAC_ASSERT(bp!=0);
299     return bp->coeff(s,n);
300 }
301
302 ex ex::numer(bool normalize) const
303 {
304     ex n;
305     if (normalize && !info(info_flags::normal_form))
306         n = normal();
307     else
308         n = *this;
309
310     // polynomial
311     if (n.info(info_flags::polynomial))
312         return n;
313
314     // something^(-int)
315     if (is_ex_exactly_of_type(n, power) && n.op(1).info(info_flags::negint))
316         return exONE();
317
318     // something^(int) * something^(int) * ...
319     if (!is_ex_exactly_of_type(n, mul))
320         return n;
321     ex res = exONE();
322     for (int i=0; i<n.nops(); i++) {
323         if (!is_ex_exactly_of_type(n.op(i), power) || !n.op(i).op(1).info(info_flags::negint))
324             res *= n.op(i);
325     }
326     return res;
327 }
328
329 ex ex::denom(bool normalize) const
330 {
331     ex n;
332     if (normalize && !info(info_flags::normal_form))
333         n = normal();
334     else
335         n = *this;
336
337     // polynomial
338     if (n.info(info_flags::polynomial))
339         return exONE();
340
341     // something^(-int)
342     if (is_ex_exactly_of_type(n, power) && n.op(1).info(info_flags::negint))
343         return power(n.op(0), -(n.op(1)));
344
345     // something^(int) * something^(int) * ...
346     if (!is_ex_exactly_of_type(n, mul))
347         return exONE();
348     ex res = exONE();
349     for (int i=0; i<n.nops(); i++) {
350         if (is_ex_exactly_of_type(n.op(i), power) && n.op(i).op(1).info(info_flags::negint))
351             res *= power(n.op(i), -1);
352     }
353     return res;
354 }
355
356 ex ex::collect(symbol const & s) const
357 {
358     GINAC_ASSERT(bp!=0);
359     return bp->collect(s);
360 }
361
362 ex ex::eval(int level) const
363 {
364     GINAC_ASSERT(bp!=0);
365     return bp->eval(level);
366 }
367
368 ex ex::evalf(int level) const
369 {
370     GINAC_ASSERT(bp!=0);
371     return bp->evalf(level);
372 }
373
374 ex ex::subs(lst const & ls, lst const & lr) const
375 {
376     GINAC_ASSERT(bp!=0);
377     return bp->subs(ls,lr);
378 }
379
380 ex ex::subs(ex const & e) const
381 {
382     GINAC_ASSERT(bp!=0);
383     return bp->subs(e);
384 }
385
386 exvector ex::get_indices(void) const
387 {
388     GINAC_ASSERT(bp!=0);
389     return bp->get_indices();
390 }
391
392 ex ex::simplify_ncmul(exvector const & v) const
393 {
394     GINAC_ASSERT(bp!=0);
395     return bp->simplify_ncmul(v);
396 }
397
398 ex ex::operator[](ex const & index) const
399 {
400     debugmsg("ex operator[ex]",LOGLEVEL_OPERATOR);
401     GINAC_ASSERT(bp!=0);
402     return (*bp)[index];
403 }
404
405 ex ex::operator[](int const i) const
406 {
407     debugmsg("ex operator[int]",LOGLEVEL_OPERATOR);
408     GINAC_ASSERT(bp!=0);
409     return (*bp)[i];
410 }
411
412 ex ex::op(int const i) const
413 {
414     debugmsg("ex op()",LOGLEVEL_MEMBER_FUNCTION);
415     GINAC_ASSERT(bp!=0);
416     return bp->op(i);
417 }
418
419 ex & ex::let_op(int const i)
420 {
421     debugmsg("ex let_op()",LOGLEVEL_MEMBER_FUNCTION);
422     makewriteable();
423     GINAC_ASSERT(bp!=0);
424     return bp->let_op(i);
425 }
426
427 #ifndef INLINE_EX_CONSTRUCTORS
428 int ex::compare(ex const & other) const
429 {
430     GINAC_ASSERT(bp!=0);
431     GINAC_ASSERT(other.bp!=0);
432     if (bp==other.bp) {
433         // special case: both expression point to same basic, trivially equal
434         return 0; 
435     }
436     return bp->compare(*other.bp);
437 }
438 #endif // ndef INLINE_EX_CONSTRUCTORS
439
440 #ifndef INLINE_EX_CONSTRUCTORS
441 bool ex::is_equal(ex const & other) const
442 {
443     GINAC_ASSERT(bp!=0);
444     GINAC_ASSERT(other.bp!=0);
445     if (bp==other.bp) {
446         // special case: both expression point to same basic, trivially equal
447         return true; 
448     }
449     return bp->is_equal(*other.bp);
450 }
451 #endif // ndef INLINE_EX_CONSTRUCTORS
452
453 unsigned ex::return_type(void) const
454 {
455     GINAC_ASSERT(bp!=0);
456     return bp->return_type();
457 }
458
459 unsigned ex::return_type_tinfo(void) const
460 {
461     GINAC_ASSERT(bp!=0);
462     return bp->return_type_tinfo();
463 }
464
465 unsigned ex::gethash(void) const
466 {
467     GINAC_ASSERT(bp!=0);
468     return bp->gethash();
469 }
470
471 ex ex::exadd(ex const & rh) const
472 {
473     return (new add(*this,rh))->setflag(status_flags::dynallocated);
474 }
475
476 ex ex::exmul(ex const & rh) const
477 {
478     return (new mul(*this,rh))->setflag(status_flags::dynallocated);
479 }
480
481 ex ex::exncmul(ex const & rh) const
482 {
483     return (new ncmul(*this,rh))->setflag(status_flags::dynallocated);
484 }
485
486 // private
487
488 void ex::makewriteable()
489 {
490     debugmsg("ex makewriteable",LOGLEVEL_MEMBER_FUNCTION);
491     GINAC_ASSERT(bp!=0);
492     GINAC_ASSERT(bp->flags & status_flags::dynallocated);
493     if (bp->refcount > 1) {
494         basic * bp2=bp->duplicate();
495         ++bp2->refcount;
496         bp2->setflag(status_flags::dynallocated);
497         --bp->refcount;
498         bp=bp2;
499     }
500     GINAC_ASSERT(bp->refcount == 1);
501 }    
502
503 void ex::construct_from_basic(basic const & other)
504 {
505     if ((other.flags & status_flags::evaluated)==0) {
506         // cf. copy constructor
507         ex const & tmpex = other.eval(1); // evaluate only one (top) level
508         bp = tmpex.bp;
509         GINAC_ASSERT(bp!=0);
510         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
511         ++bp->refcount;
512         if ((other.flags & status_flags::dynallocated)&&(other.refcount==0)) {
513             delete &const_cast<basic &>(other);
514         }
515     } else {
516         if (other.flags & status_flags::dynallocated) {
517             bp=&const_cast<basic &>(other);
518         } else {
519             bp=other.duplicate();
520             bp->setflag(status_flags::dynallocated);
521         }
522         GINAC_ASSERT(bp!=0);
523         // bp->clearflag(status_flags::evaluated);
524         ++bp->refcount;
525     }
526     GINAC_ASSERT(bp!=0);
527     GINAC_ASSERT(bp->flags & status_flags::dynallocated);
528 }
529
530 //////////
531 // static member variables
532 //////////
533
534 // none
535
536 //////////
537 // functions which are not member functions
538 //////////
539
540 // none
541
542 //////////
543 // global functions
544 //////////
545
546 ex const & exZERO(void)
547 {
548     static ex * eZERO=new ex(numZERO());
549     return *eZERO;
550 }
551
552 ex const & exONE(void)
553 {
554     static ex * eONE=new ex(numONE());
555     return *eONE;
556 }
557
558 ex const & exTWO(void)
559 {
560     static ex * eTWO=new ex(numTWO());
561     return *eTWO;
562 }
563
564 ex const & exTHREE(void)
565 {
566     static ex * eTHREE=new ex(numTHREE());
567     return *eTHREE;
568 }
569
570 ex const & exMINUSONE(void)
571 {
572     static ex * eMINUSONE=new ex(numMINUSONE());
573     return *eMINUSONE;
574 }
575
576 ex const & exHALF(void)
577 {
578     static ex * eHALF=new ex(ex(1)/ex(2));
579     return *eHALF;
580 }
581
582 ex const & exMINUSHALF(void)
583 {
584     static ex * eMINUSHALF=new ex(numeric(-1,2));
585     return *eMINUSHALF;
586 }
587
588 #ifndef NO_GINAC_NAMESPACE
589 } // namespace GiNaC
590 #endif // ndef NO_GINAC_NAMESPACE