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