]> www.ginac.de Git - ginac.git/blob - ginac/ex.cpp
- print 0 without parens.
[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     if (bp->flags & status_flags::expanded)
254         return *bp;
255     else
256         return bp->expand(options);
257 }
258
259 bool ex::has(const ex & other) const
260 {
261     GINAC_ASSERT(bp!=0);
262     return bp->has(other);
263 }
264
265 int ex::degree(const symbol & s) const
266 {
267     GINAC_ASSERT(bp!=0);
268     return bp->degree(s);
269 }
270
271 int ex::ldegree(const symbol & s) const
272 {
273     GINAC_ASSERT(bp!=0);
274     return bp->ldegree(s);
275 }
276
277 ex ex::coeff(const symbol & s, int n) const
278 {
279     GINAC_ASSERT(bp!=0);
280     return bp->coeff(s,n);
281 }
282
283 ex ex::collect(const symbol & s) const
284 {
285     GINAC_ASSERT(bp!=0);
286     return bp->collect(s);
287 }
288
289 ex ex::eval(int level) const
290 {
291     GINAC_ASSERT(bp!=0);
292     return bp->eval(level);
293 }
294
295 ex ex::evalf(int level) const
296 {
297     GINAC_ASSERT(bp!=0);
298     return bp->evalf(level);
299 }
300
301 /** Compute partial derivative of an expression.
302  *
303  *  @param s  symbol by which the expression is derived
304  *  @param nth  order of derivative (default 1)
305  *  @return partial derivative as a new expression */
306 ex ex::diff(const symbol & s, unsigned nth) const
307 {
308     GINAC_ASSERT(bp!=0);
309
310     if (!nth)
311         return *this;
312     else
313         return bp->diff(s, nth);
314 }
315
316 ex ex::subs(const lst & ls, const lst & lr) const
317 {
318     GINAC_ASSERT(bp!=0);
319     return bp->subs(ls,lr);
320 }
321
322 ex ex::subs(const ex & e) const
323 {
324     GINAC_ASSERT(bp!=0);
325     return bp->subs(e);
326 }
327
328 exvector ex::get_indices(void) const
329 {
330     GINAC_ASSERT(bp!=0);
331     return bp->get_indices();
332 }
333
334 ex ex::simplify_ncmul(const exvector & v) const
335 {
336     GINAC_ASSERT(bp!=0);
337     return bp->simplify_ncmul(v);
338 }
339
340 ex ex::operator[](const ex & index) const
341 {
342     debugmsg("ex operator[ex]",LOGLEVEL_OPERATOR);
343     GINAC_ASSERT(bp!=0);
344     return (*bp)[index];
345 }
346
347 ex ex::operator[](int i) const
348 {
349     debugmsg("ex operator[int]",LOGLEVEL_OPERATOR);
350     GINAC_ASSERT(bp!=0);
351     return (*bp)[i];
352 }
353
354 /** Return operand/member at position i. */
355 ex ex::op(int i) const
356 {
357     debugmsg("ex op()",LOGLEVEL_MEMBER_FUNCTION);
358     GINAC_ASSERT(bp!=0);
359     return bp->op(i);
360 }
361
362 /** Return modifyable operand/member at position i. */
363 ex & ex::let_op(int i)
364 {
365     debugmsg("ex let_op()",LOGLEVEL_MEMBER_FUNCTION);
366     makewriteable();
367     GINAC_ASSERT(bp!=0);
368     return bp->let_op(i);
369 }
370
371 /** Left hand side of relational expression. */
372 ex ex::lhs(void) const
373 {
374     debugmsg("ex lhs()",LOGLEVEL_MEMBER_FUNCTION);
375     GINAC_ASSERT(is_ex_of_type(*this,relational));
376     return (*static_cast<relational *>(bp)).lhs();
377 }
378
379 /** Right hand side of relational expression. */
380 ex ex::rhs(void) const
381 {
382     debugmsg("ex rhs()",LOGLEVEL_MEMBER_FUNCTION);
383     GINAC_ASSERT(is_ex_of_type(*this,relational));
384     return (*static_cast<relational *>(bp)).rhs();
385 }
386
387 #ifndef INLINE_EX_CONSTRUCTORS
388 int ex::compare(const ex & other) const
389 {
390     GINAC_ASSERT(bp!=0);
391     GINAC_ASSERT(other.bp!=0);
392     if (bp==other.bp) {
393         // special case: both expression point to same basic, trivially equal
394         return 0; 
395     }
396     return bp->compare(*other.bp);
397 }
398 #endif // ndef INLINE_EX_CONSTRUCTORS
399
400 #ifndef INLINE_EX_CONSTRUCTORS
401 bool ex::is_equal(const ex & other) const
402 {
403     GINAC_ASSERT(bp!=0);
404     GINAC_ASSERT(other.bp!=0);
405     if (bp==other.bp) {
406         // special case: both expression point to same basic, trivially equal
407         return true; 
408     }
409     return bp->is_equal(*other.bp);
410 }
411 #endif // ndef INLINE_EX_CONSTRUCTORS
412
413 unsigned ex::return_type(void) const
414 {
415     GINAC_ASSERT(bp!=0);
416     return bp->return_type();
417 }
418
419 unsigned ex::return_type_tinfo(void) const
420 {
421     GINAC_ASSERT(bp!=0);
422     return bp->return_type_tinfo();
423 }
424
425 unsigned ex::gethash(void) const
426 {
427     GINAC_ASSERT(bp!=0);
428     return bp->gethash();
429 }
430
431 ex ex::exadd(const ex & rh) const
432 {
433     return (new add(*this,rh))->setflag(status_flags::dynallocated);
434 }
435
436 ex ex::exmul(const ex & rh) const
437 {
438     return (new mul(*this,rh))->setflag(status_flags::dynallocated);
439 }
440
441 ex ex::exncmul(const ex & rh) const
442 {
443     return (new ncmul(*this,rh))->setflag(status_flags::dynallocated);
444 }
445
446 // private
447
448 void ex::makewriteable()
449 {
450     debugmsg("ex makewriteable",LOGLEVEL_MEMBER_FUNCTION);
451     GINAC_ASSERT(bp!=0);
452     GINAC_ASSERT(bp->flags & status_flags::dynallocated);
453     if (bp->refcount > 1) {
454         basic * bp2 = bp->duplicate();
455         ++bp2->refcount;
456         bp2->setflag(status_flags::dynallocated);
457         --bp->refcount;
458         bp = bp2;
459     }
460     GINAC_ASSERT(bp->refcount == 1);
461 }
462
463 void ex::construct_from_basic(const basic & other)
464 {
465     if ((other.flags & status_flags::evaluated)==0) {
466         // cf. copy constructor
467         const ex & tmpex = other.eval(1); // evaluate only one (top) level
468         bp = tmpex.bp;
469         GINAC_ASSERT(bp!=0);
470         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
471         ++bp->refcount;
472         if ((other.flags & status_flags::dynallocated)&&(other.refcount==0)) {
473             delete &const_cast<basic &>(other);
474         }
475     } else {
476         if (other.flags & status_flags::dynallocated) {
477             bp = &const_cast<basic &>(other);
478         } else {
479             bp = other.duplicate();
480             bp->setflag(status_flags::dynallocated);
481         }
482         GINAC_ASSERT(bp!=0);
483         // bp->clearflag(status_flags::evaluated);
484         ++bp->refcount;
485     }
486     GINAC_ASSERT(bp!=0);
487     GINAC_ASSERT(bp->flags & status_flags::dynallocated);
488 }
489
490 void ex::construct_from_int(int i)
491 {
492     switch (i) {  // some tiny efficiency-hack
493     case -2:
494         bp = _ex_2().bp;
495         ++bp->refcount;
496         break;
497     case -1:
498         bp = _ex_1().bp;
499         ++bp->refcount;
500         break;
501     case 0:
502         bp = _ex0().bp;
503         ++bp->refcount;
504         break;
505     case 1:
506         bp = _ex1().bp;
507         ++bp->refcount;
508         break;
509     case 2:
510         bp = _ex2().bp;
511         ++bp->refcount;
512         break;
513     default:
514         bp = new numeric(i);
515         bp->setflag(status_flags::dynallocated);
516         ++bp->refcount;
517         GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
518         GINAC_ASSERT(bp->refcount=1);
519     }
520 }
521     
522 void ex::construct_from_uint(unsigned int i)
523 {
524     switch (i) {  // some tiny efficiency-hack
525     case -2:
526         bp = _ex_2().bp;
527         ++bp->refcount;
528         break;
529     case -1:
530         bp = _ex_1().bp;
531         ++bp->refcount;
532         break;
533     case 0:
534         bp = _ex0().bp;
535         ++bp->refcount;
536         break;
537     case 1:
538         bp = _ex1().bp;
539         ++bp->refcount;
540         break;
541     case 2:
542         bp = _ex2().bp;
543         ++bp->refcount;
544         break;
545     default:
546         bp = new numeric(i);
547         bp->setflag(status_flags::dynallocated);
548         ++bp->refcount;
549         GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
550         GINAC_ASSERT(bp->refcount=1);
551     }
552 }
553     
554 void ex::construct_from_long(long i)
555 {
556     switch (i) {  // some tiny efficiency-hack
557     case -2:
558         bp = _ex_2().bp;
559         ++bp->refcount;
560         break;
561     case -1:
562         bp = _ex_1().bp;
563         ++bp->refcount;
564         break;
565     case 0:
566         bp = _ex0().bp;
567         ++bp->refcount;
568         break;
569     case 1:
570         bp = _ex1().bp;
571         ++bp->refcount;
572         break;
573     case 2:
574         bp = _ex2().bp;
575         ++bp->refcount;
576         break;
577     default:
578         bp = new numeric(i);
579         bp->setflag(status_flags::dynallocated);
580         ++bp->refcount;
581         GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
582         GINAC_ASSERT(bp->refcount=1);
583     }
584 }
585     
586 void ex::construct_from_ulong(unsigned long i)
587 {
588     switch (i) {  // some tiny efficiency-hack
589     case -2:
590         bp = _ex_2().bp;
591         ++bp->refcount;
592         break;
593     case -1:
594         bp = _ex_1().bp;
595         ++bp->refcount;
596         break;
597     case 0:
598         bp = _ex0().bp;
599         ++bp->refcount;
600         break;
601     case 1:
602         bp = _ex1().bp;
603         ++bp->refcount;
604         break;
605     case 2:
606         bp = _ex2().bp;
607         ++bp->refcount;
608         break;
609     default:
610         bp = new numeric(i);
611         bp->setflag(status_flags::dynallocated);
612         ++bp->refcount;
613         GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
614         GINAC_ASSERT(bp->refcount=1);
615     }
616 }
617     
618 void ex::construct_from_double(double d)
619 {
620     bp = new numeric(d);
621     bp->setflag(status_flags::dynallocated);
622     ++bp->refcount;
623     GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
624     GINAC_ASSERT(bp->refcount=1);
625 }
626     
627 //////////
628 // static member variables
629 //////////
630
631 // none
632
633 //////////
634 // functions which are not member functions
635 //////////
636
637 // none
638
639 //////////
640 // global functions
641 //////////
642
643 // none
644
645
646 #ifndef NO_NAMESPACE_GINAC
647 } // namespace GiNaC
648 #endif // ndef NO_NAMESPACE_GINAC