559bae47d95932793f49b9e87ecc9ec6d206012c
[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 std::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(std::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(std::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(std::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(std::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 both expression point to same basic they are trivially equal
414         if (bp==other.bp)
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                         // it's on the heap, so just copy bp:
486                         bp = &const_cast<basic &>(other);
487                 } else {
488                         // create a duplicate on the heap:
489                         bp = other.duplicate();
490                         bp->setflag(status_flags::dynallocated);
491                 }
492                 GINAC_ASSERT(bp!=0);
493                 // bp->clearflag(status_flags::evaluated);
494                 ++bp->refcount;
495         }
496         GINAC_ASSERT(bp!=0);
497         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
498 }
499
500 void ex::construct_from_int(int i)
501 {
502         switch (i) {  // some tiny efficiency-hack
503         case -2:
504                 bp = _ex_2().bp;
505                 ++bp->refcount;
506                 break;
507         case -1:
508                 bp = _ex_1().bp;
509                 ++bp->refcount;
510                 break;
511         case 0:
512                 bp = _ex0().bp;
513                 ++bp->refcount;
514                 break;
515         case 1:
516                 bp = _ex1().bp;
517                 ++bp->refcount;
518                 break;
519         case 2:
520                 bp = _ex2().bp;
521                 ++bp->refcount;
522                 break;
523         default:
524                 bp = new numeric(i);
525                 bp->setflag(status_flags::dynallocated);
526                 ++bp->refcount;
527                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
528                 GINAC_ASSERT(bp->refcount=1);
529         }
530 }
531         
532 void ex::construct_from_uint(unsigned int i)
533 {
534         switch (i) {  // some tiny efficiency-hack
535         case -2:
536                 bp = _ex_2().bp;
537                 ++bp->refcount;
538                 break;
539         case -1:
540                 bp = _ex_1().bp;
541                 ++bp->refcount;
542                 break;
543         case 0:
544                 bp = _ex0().bp;
545                 ++bp->refcount;
546                 break;
547         case 1:
548                 bp = _ex1().bp;
549                 ++bp->refcount;
550                 break;
551         case 2:
552                 bp = _ex2().bp;
553                 ++bp->refcount;
554                 break;
555         default:
556                 bp = new numeric(i);
557                 bp->setflag(status_flags::dynallocated);
558                 ++bp->refcount;
559                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
560                 GINAC_ASSERT(bp->refcount=1);
561         }
562 }
563         
564 void ex::construct_from_long(long i)
565 {
566         switch (i) {  // some tiny efficiency-hack
567         case -2:
568                 bp = _ex_2().bp;
569                 ++bp->refcount;
570                 break;
571         case -1:
572                 bp = _ex_1().bp;
573                 ++bp->refcount;
574                 break;
575         case 0:
576                 bp = _ex0().bp;
577                 ++bp->refcount;
578                 break;
579         case 1:
580                 bp = _ex1().bp;
581                 ++bp->refcount;
582                 break;
583         case 2:
584                 bp = _ex2().bp;
585                 ++bp->refcount;
586                 break;
587         default:
588                 bp = new numeric(i);
589                 bp->setflag(status_flags::dynallocated);
590                 ++bp->refcount;
591                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
592                 GINAC_ASSERT(bp->refcount=1);
593         }
594 }
595         
596 void ex::construct_from_ulong(unsigned long i)
597 {
598         switch (i) {  // some tiny efficiency-hack
599         case -2:
600                 bp = _ex_2().bp;
601                 ++bp->refcount;
602                 break;
603         case -1:
604                 bp = _ex_1().bp;
605                 ++bp->refcount;
606                 break;
607         case 0:
608                 bp = _ex0().bp;
609                 ++bp->refcount;
610                 break;
611         case 1:
612                 bp = _ex1().bp;
613                 ++bp->refcount;
614                 break;
615         case 2:
616                 bp = _ex2().bp;
617                 ++bp->refcount;
618                 break;
619         default:
620                 bp = new numeric(i);
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 void ex::construct_from_double(double d)
629 {
630         bp = new numeric(d);
631         bp->setflag(status_flags::dynallocated);
632         ++bp->refcount;
633         GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
634         GINAC_ASSERT(bp->refcount=1);
635 }
636
637 void ex::construct_from_string_and_lst(const std::string &s, const ex &l)
638 {
639         set_lexer_string(s);
640         set_lexer_symbols(l);
641         ginac_yyrestart(NULL);
642         if (ginac_yyparse())
643                 throw (std::runtime_error(get_parser_error()));
644         else {
645                 bp = parsed_ex.bp;
646                 GINAC_ASSERT(bp!=0);
647                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
648                 ++bp->refcount;
649         }
650 }
651         
652 //////////
653 // static member variables
654 //////////
655
656 // none
657
658 //////////
659 // functions which are not member functions
660 //////////
661
662 // none
663
664 //////////
665 // global functions
666 //////////
667
668 // none
669
670
671 #ifndef NO_NAMESPACE_GINAC
672 } // namespace GiNaC
673 #endif // ndef NO_NAMESPACE_GINAC