]> www.ginac.de Git - ginac.git/blob - ginac/ex.cpp
- ex::numer() and ex::denom() now make use of the new normal()
[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-2000 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 "relational.h"
32 #include "debugmsg.h"
33 #include "utils.h"
34
35 #ifndef NO_NAMESPACE_GINAC
36 namespace GiNaC {
37 #endif // ndef NO_NAMESPACE_GINAC
38
39 //////////
40 // default constructor, destructor, copy constructor assignment operator and helpers
41 //////////
42
43 // public
44
45 #ifndef INLINE_EX_CONSTRUCTORS
46
47 ex::ex() : bp(ex0().bp)
48 {
49     debugmsg("ex default constructor",LOGLEVEL_CONSTRUCT);
50     GINAC_ASSERT(ex0().bp!=0);
51     GINAC_ASSERT(ex0().bp->flags & status_flags::dynallocated);
52     GINAC_ASSERT(bp!=0);
53     ++bp->refcount;
54 }
55
56 ex::~ex()
57 {
58     debugmsg("ex destructor",LOGLEVEL_DESTRUCT);
59     GINAC_ASSERT(bp!=0);
60     GINAC_ASSERT(bp->flags & status_flags::dynallocated);
61     if (--bp->refcount == 0) {
62         delete bp;
63     }
64 }
65
66 ex::ex(const ex & other) : bp(other.bp)
67 {
68     debugmsg("ex copy constructor",LOGLEVEL_CONSTRUCT);
69     GINAC_ASSERT(bp!=0);
70     GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
71     ++bp->refcount;
72 }
73
74 const ex & ex::operator=(const ex & other)
75 {
76     debugmsg("ex operator=",LOGLEVEL_ASSIGNMENT);
77     GINAC_ASSERT(bp!=0);
78     GINAC_ASSERT(bp->flags & status_flags::dynallocated);
79     GINAC_ASSERT(other.bp!=0);
80     GINAC_ASSERT(other.bp->flags & status_flags::dynallocated);
81     ++other.bp->refcount;
82     basic * tmpbp=other.bp;
83     if (--bp->refcount==0) {
84             delete bp;
85     }
86     bp=tmpbp;
87     return *this;
88 }
89
90 #endif // ndef INLINE_EX_CONSTRUCTORS
91
92 //////////
93 // other constructors
94 //////////
95
96 // public
97
98 #ifndef INLINE_EX_CONSTRUCTORS
99
100 ex::ex(const basic & other)
101 {
102     debugmsg("ex constructor from basic",LOGLEVEL_CONSTRUCT);
103     construct_from_basic(other);
104 }
105
106 ex::ex(int i)
107 {
108     debugmsg("ex constructor from int",LOGLEVEL_CONSTRUCT);
109     construct_from_int(i);
110 }
111
112 ex::ex(unsigned int i)
113 {
114     debugmsg("ex constructor from unsigned int",LOGLEVEL_CONSTRUCT);
115     construct_from_uint(i);
116 }
117
118 ex::ex(long i)
119 {
120     debugmsg("ex constructor from long",LOGLEVEL_CONSTRUCT);
121     construct_from_long(i);
122 }
123
124 ex::ex(unsigned long i)
125 {
126     debugmsg("ex constructor from unsigned long",LOGLEVEL_CONSTRUCT);
127     construct_from_ulong(i);
128 }
129
130 ex::ex(double const d)
131 {
132     debugmsg("ex constructor from double",LOGLEVEL_CONSTRUCT);
133     construct_from_double(d);
134 }
135
136 #endif // ndef INLINE_EX_CONSTRUCTORS
137
138 //////////
139 // functions overriding virtual functions from bases classes
140 //////////
141
142 // none
143
144 //////////
145 // new virtual functions which can be overridden by derived classes
146 //////////
147
148 // none
149
150 //////////
151 // non-virtual functions in this class
152 //////////
153
154 // public
155
156 /** Swap the contents of two expressions. */
157 void ex::swap(ex & other)
158 {
159     debugmsg("ex swap",LOGLEVEL_MEMBER_FUNCTION);
160
161     GINAC_ASSERT(bp!=0);
162     GINAC_ASSERT(bp->flags & status_flags::dynallocated);
163     GINAC_ASSERT(other.bp!=0);
164     GINAC_ASSERT(other.bp->flags & status_flags::dynallocated);
165     
166     basic * tmpbp=bp;
167     bp=other.bp;
168     other.bp=tmpbp;
169 }
170
171 /** Output formatted to be useful as ginsh input. */
172 void ex::print(ostream & os, unsigned upper_precedence) const
173 {
174     debugmsg("ex print",LOGLEVEL_PRINT);
175     GINAC_ASSERT(bp!=0);
176     bp->print(os,upper_precedence);
177 }
178
179 void ex::printraw(ostream & os) const
180 {
181     debugmsg("ex printraw",LOGLEVEL_PRINT);
182     GINAC_ASSERT(bp!=0);
183     os << "ex(";
184     bp->printraw(os);
185     os << ")";
186 }
187
188 void ex::printtree(ostream & os, unsigned indent) const
189 {
190     debugmsg("ex printtree",LOGLEVEL_PRINT);
191     GINAC_ASSERT(bp!=0);
192     // os << "refcount=" << bp->refcount << " ";
193     bp->printtree(os,indent);
194 }
195
196 /** Print expression as a C++ statement. The output looks like
197  *  "<type> <var_name> = <expression>;". The "type" parameter has an effect
198  *  on how number literals are printed.
199  *
200  *  @param os output stream
201  *  @param type variable type (one of the csrc_types)
202  *  @param var_name variable name to be printed */
203 void ex::printcsrc(ostream & os, unsigned type, const char *var_name) const
204 {
205     debugmsg("ex print csrc", LOGLEVEL_PRINT);
206     GINAC_ASSERT(bp!=0);
207     switch (type) {
208         case csrc_types::ctype_float:
209             os << "float ";
210             break;
211         case csrc_types::ctype_double:
212             os << "double ";
213             break;
214         case csrc_types::ctype_cl_N:
215             os << "cl_N ";
216             break;
217     }
218     os << var_name << " = ";
219     bp->printcsrc(os, type, 0);
220     os << ";\n";
221 }
222
223 /** Little wrapper arount print to be called within a debugger. */
224 void ex::dbgprint(void) const
225 {
226     debugmsg("ex dbgprint",LOGLEVEL_PRINT);
227     GINAC_ASSERT(bp!=0);
228     bp->dbgprint();
229 }
230
231 /** Little wrapper arount printtree to be called within a debugger. */
232 void ex::dbgprinttree(void) const
233 {
234     debugmsg("ex dbgprinttree",LOGLEVEL_PRINT);
235     GINAC_ASSERT(bp!=0);
236     bp->dbgprinttree();
237 }
238
239 bool ex::info(unsigned inf) const
240 {
241     return bp->info(inf);
242 }
243
244 unsigned ex::nops() const
245 {
246     GINAC_ASSERT(bp!=0);
247     return bp->nops();
248 }
249
250 ex ex::expand(unsigned options) const
251 {
252     GINAC_ASSERT(bp!=0);
253     return bp->expand(options);
254 }
255
256 bool ex::has(const ex & other) const
257 {
258     GINAC_ASSERT(bp!=0);
259     return bp->has(other);
260 }
261
262 int ex::degree(const symbol & s) const
263 {
264     GINAC_ASSERT(bp!=0);
265     return bp->degree(s);
266 }
267
268 int ex::ldegree(const symbol & s) const
269 {
270     GINAC_ASSERT(bp!=0);
271     return bp->ldegree(s);
272 }
273
274 ex ex::coeff(const symbol & s, int n) const
275 {
276     GINAC_ASSERT(bp!=0);
277     return bp->coeff(s,n);
278 }
279
280 ex ex::collect(const symbol & s) const
281 {
282     GINAC_ASSERT(bp!=0);
283     return bp->collect(s);
284 }
285
286 ex ex::eval(int level) const
287 {
288     GINAC_ASSERT(bp!=0);
289     return bp->eval(level);
290 }
291
292 ex ex::evalf(int level) const
293 {
294     GINAC_ASSERT(bp!=0);
295     return bp->evalf(level);
296 }
297
298 /** Compute partial derivative of an expression.
299  *
300  *  @param s  symbol by which the expression is derived
301  *  @param nth  order of derivative (default 1)
302  *  @return partial derivative as a new expression */
303 ex ex::diff(const symbol & s, unsigned nth) const
304 {
305     GINAC_ASSERT(bp!=0);
306
307     if (!nth)
308         return *this;
309     else
310         return bp->diff(s, nth);
311 }
312
313 ex ex::subs(const lst & ls, const lst & lr) const
314 {
315     GINAC_ASSERT(bp!=0);
316     return bp->subs(ls,lr);
317 }
318
319 ex ex::subs(const ex & e) const
320 {
321     GINAC_ASSERT(bp!=0);
322     return bp->subs(e);
323 }
324
325 exvector ex::get_indices(void) const
326 {
327     GINAC_ASSERT(bp!=0);
328     return bp->get_indices();
329 }
330
331 ex ex::simplify_ncmul(const exvector & v) const
332 {
333     GINAC_ASSERT(bp!=0);
334     return bp->simplify_ncmul(v);
335 }
336
337 ex ex::operator[](const ex & index) const
338 {
339     debugmsg("ex operator[ex]",LOGLEVEL_OPERATOR);
340     GINAC_ASSERT(bp!=0);
341     return (*bp)[index];
342 }
343
344 ex ex::operator[](int i) const
345 {
346     debugmsg("ex operator[int]",LOGLEVEL_OPERATOR);
347     GINAC_ASSERT(bp!=0);
348     return (*bp)[i];
349 }
350
351 /** Return operand/member at position i. */
352 ex ex::op(int i) const
353 {
354     debugmsg("ex op()",LOGLEVEL_MEMBER_FUNCTION);
355     GINAC_ASSERT(bp!=0);
356     return bp->op(i);
357 }
358
359 /** Return modifyable operand/member at position i. */
360 ex & ex::let_op(int i)
361 {
362     debugmsg("ex let_op()",LOGLEVEL_MEMBER_FUNCTION);
363     makewriteable();
364     GINAC_ASSERT(bp!=0);
365     return bp->let_op(i);
366 }
367
368 /** Left hand side of relational expression. */
369 ex ex::lhs(void) const
370 {
371     debugmsg("ex lhs()",LOGLEVEL_MEMBER_FUNCTION);
372     GINAC_ASSERT(is_ex_of_type(*this,relational));
373     return (*static_cast<relational *>(bp)).lhs();
374 }
375
376 /** Right hand side of relational expression. */
377 ex ex::rhs(void) const
378 {
379     debugmsg("ex rhs()",LOGLEVEL_MEMBER_FUNCTION);
380     GINAC_ASSERT(is_ex_of_type(*this,relational));
381     return (*static_cast<relational *>(bp)).rhs();
382 }
383
384 #ifndef INLINE_EX_CONSTRUCTORS
385 int ex::compare(const ex & other) const
386 {
387     GINAC_ASSERT(bp!=0);
388     GINAC_ASSERT(other.bp!=0);
389     if (bp==other.bp) {
390         // special case: both expression point to same basic, trivially equal
391         return 0; 
392     }
393     return bp->compare(*other.bp);
394 }
395 #endif // ndef INLINE_EX_CONSTRUCTORS
396
397 #ifndef INLINE_EX_CONSTRUCTORS
398 bool ex::is_equal(const ex & other) const
399 {
400     GINAC_ASSERT(bp!=0);
401     GINAC_ASSERT(other.bp!=0);
402     if (bp==other.bp) {
403         // special case: both expression point to same basic, trivially equal
404         return true; 
405     }
406     return bp->is_equal(*other.bp);
407 }
408 #endif // ndef INLINE_EX_CONSTRUCTORS
409
410 unsigned ex::return_type(void) const
411 {
412     GINAC_ASSERT(bp!=0);
413     return bp->return_type();
414 }
415
416 unsigned ex::return_type_tinfo(void) const
417 {
418     GINAC_ASSERT(bp!=0);
419     return bp->return_type_tinfo();
420 }
421
422 unsigned ex::gethash(void) const
423 {
424     GINAC_ASSERT(bp!=0);
425     return bp->gethash();
426 }
427
428 ex ex::exadd(const ex & rh) const
429 {
430     return (new add(*this,rh))->setflag(status_flags::dynallocated);
431 }
432
433 ex ex::exmul(const ex & rh) const
434 {
435     return (new mul(*this,rh))->setflag(status_flags::dynallocated);
436 }
437
438 ex ex::exncmul(const ex & rh) const
439 {
440     return (new ncmul(*this,rh))->setflag(status_flags::dynallocated);
441 }
442
443 // private
444
445 void ex::makewriteable()
446 {
447     debugmsg("ex makewriteable",LOGLEVEL_MEMBER_FUNCTION);
448     GINAC_ASSERT(bp!=0);
449     GINAC_ASSERT(bp->flags & status_flags::dynallocated);
450     if (bp->refcount > 1) {
451         basic * bp2 = bp->duplicate();
452         ++bp2->refcount;
453         bp2->setflag(status_flags::dynallocated);
454         --bp->refcount;
455         bp = bp2;
456     }
457     GINAC_ASSERT(bp->refcount == 1);
458 }
459
460 void ex::construct_from_basic(const basic & other)
461 {
462     if ((other.flags & status_flags::evaluated)==0) {
463         // cf. copy constructor
464         const ex & tmpex = other.eval(1); // evaluate only one (top) level
465         bp = tmpex.bp;
466         GINAC_ASSERT(bp!=0);
467         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
468         ++bp->refcount;
469         if ((other.flags & status_flags::dynallocated)&&(other.refcount==0)) {
470             delete &const_cast<basic &>(other);
471         }
472     } else {
473         if (other.flags & status_flags::dynallocated) {
474             bp = &const_cast<basic &>(other);
475         } else {
476             bp = other.duplicate();
477             bp->setflag(status_flags::dynallocated);
478         }
479         GINAC_ASSERT(bp!=0);
480         // bp->clearflag(status_flags::evaluated);
481         ++bp->refcount;
482     }
483     GINAC_ASSERT(bp!=0);
484     GINAC_ASSERT(bp->flags & status_flags::dynallocated);
485 }
486
487 void ex::construct_from_int(int i)
488 {
489     switch (i) {  // some tiny efficiency-hack
490     case -2:
491         bp = _ex_2().bp;
492         ++bp->refcount;
493         break;
494     case -1:
495         bp = _ex_1().bp;
496         ++bp->refcount;
497         break;
498     case 0:
499         bp = _ex0().bp;
500         ++bp->refcount;
501         break;
502     case 1:
503         bp = _ex1().bp;
504         ++bp->refcount;
505         break;
506     case 2:
507         bp = _ex2().bp;
508         ++bp->refcount;
509         break;
510     default:
511         bp = new numeric(i);
512         bp->setflag(status_flags::dynallocated);
513         ++bp->refcount;
514         GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
515         GINAC_ASSERT(bp->refcount=1);
516     }
517 }
518     
519 void ex::construct_from_uint(unsigned int i)
520 {
521     switch (i) {  // some tiny efficiency-hack
522     case -2:
523         bp = _ex_2().bp;
524         ++bp->refcount;
525         break;
526     case -1:
527         bp = _ex_1().bp;
528         ++bp->refcount;
529         break;
530     case 0:
531         bp = _ex0().bp;
532         ++bp->refcount;
533         break;
534     case 1:
535         bp = _ex1().bp;
536         ++bp->refcount;
537         break;
538     case 2:
539         bp = _ex2().bp;
540         ++bp->refcount;
541         break;
542     default:
543         bp = new numeric(i);
544         bp->setflag(status_flags::dynallocated);
545         ++bp->refcount;
546         GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
547         GINAC_ASSERT(bp->refcount=1);
548     }
549 }
550     
551 void ex::construct_from_long(long i)
552 {
553     switch (i) {  // some tiny efficiency-hack
554     case -2:
555         bp = _ex_2().bp;
556         ++bp->refcount;
557         break;
558     case -1:
559         bp = _ex_1().bp;
560         ++bp->refcount;
561         break;
562     case 0:
563         bp = _ex0().bp;
564         ++bp->refcount;
565         break;
566     case 1:
567         bp = _ex1().bp;
568         ++bp->refcount;
569         break;
570     case 2:
571         bp = _ex2().bp;
572         ++bp->refcount;
573         break;
574     default:
575         bp = new numeric(i);
576         bp->setflag(status_flags::dynallocated);
577         ++bp->refcount;
578         GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
579         GINAC_ASSERT(bp->refcount=1);
580     }
581 }
582     
583 void ex::construct_from_ulong(unsigned long i)
584 {
585     switch (i) {  // some tiny efficiency-hack
586     case -2:
587         bp = _ex_2().bp;
588         ++bp->refcount;
589         break;
590     case -1:
591         bp = _ex_1().bp;
592         ++bp->refcount;
593         break;
594     case 0:
595         bp = _ex0().bp;
596         ++bp->refcount;
597         break;
598     case 1:
599         bp = _ex1().bp;
600         ++bp->refcount;
601         break;
602     case 2:
603         bp = _ex2().bp;
604         ++bp->refcount;
605         break;
606     default:
607         bp = new numeric(i);
608         bp->setflag(status_flags::dynallocated);
609         ++bp->refcount;
610         GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
611         GINAC_ASSERT(bp->refcount=1);
612     }
613 }
614     
615 void ex::construct_from_double(double d)
616 {
617     bp = new numeric(d);
618     bp->setflag(status_flags::dynallocated);
619     ++bp->refcount;
620     GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
621     GINAC_ASSERT(bp->refcount=1);
622 }
623     
624 //////////
625 // static member variables
626 //////////
627
628 // none
629
630 //////////
631 // functions which are not member functions
632 //////////
633
634 // none
635
636 //////////
637 // global functions
638 //////////
639
640 // none
641
642
643 #ifndef NO_NAMESPACE_GINAC
644 } // namespace GiNaC
645 #endif // ndef NO_NAMESPACE_GINAC