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