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