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