]> www.ginac.de Git - ginac.git/blob - ginac/ex.cpp
- replaced the various print*() member functions by a single print() that
[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 "indexed.h"
34 #include "input_lexer.h"
35 #include "debugmsg.h"
36 #include "utils.h"
37
38 namespace GiNaC {
39
40 //////////
41 // other ctors
42 //////////
43
44 // none (all inlined)
45
46 //////////
47 // functions overriding virtual functions from bases classes
48 //////////
49
50 // none
51
52 //////////
53 // new virtual functions which can be overridden by derived classes
54 //////////
55
56 // none
57
58 //////////
59 // non-virtual functions in this class
60 //////////
61
62 // public
63
64 /** Efficiently swap the contents of two expressions. */
65 void ex::swap(ex & other)
66 {
67         debugmsg("ex swap",LOGLEVEL_MEMBER_FUNCTION);
68
69         GINAC_ASSERT(bp!=0);
70         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
71         GINAC_ASSERT(other.bp!=0);
72         GINAC_ASSERT(other.bp->flags & status_flags::dynallocated);
73         
74         basic * tmpbp = bp;
75         bp = other.bp;
76         other.bp = tmpbp;
77 }
78
79 /** Print expression to stream. The formatting of the output is determined
80  *  by the kind of print_context object that is passed. Possible formattings
81  *  include ginsh-parsable output (the default), tree-like output for
82  *  debugging, and C++ source.
83  *  @see print_context */
84 void ex::print(const print_context & c, unsigned level) const
85 {
86         debugmsg("ex print", LOGLEVEL_PRINT);
87         GINAC_ASSERT(bp!=0);
88         bp->print(c, level);
89 }
90
91 /** Print expression to stream in a tree-like format suitable for debugging. */
92 void ex::printtree(std::ostream & os) const
93 {
94         debugmsg("ex printtree", LOGLEVEL_PRINT);
95         GINAC_ASSERT(bp!=0);
96         bp->print(print_tree(os));
97 }
98
99 /** Little wrapper arount print to be called within a debugger. */
100 void ex::dbgprint(void) const
101 {
102         debugmsg("ex dbgprint", LOGLEVEL_PRINT);
103         GINAC_ASSERT(bp!=0);
104         bp->dbgprint();
105 }
106
107 /** Little wrapper arount printtree to be called within a debugger. */
108 void ex::dbgprinttree(void) const
109 {
110         debugmsg("ex dbgprinttree", LOGLEVEL_PRINT);
111         GINAC_ASSERT(bp!=0);
112         bp->dbgprinttree();
113 }
114
115 bool ex::info(unsigned inf) const
116 {
117         return bp->info(inf);
118 }
119
120 unsigned ex::nops() const
121 {
122         GINAC_ASSERT(bp!=0);
123         return bp->nops();
124 }
125
126 ex ex::expand(unsigned options) const
127 {
128         GINAC_ASSERT(bp!=0);
129         if (bp->flags & status_flags::expanded)
130                 return *bp;
131         else
132                 return bp->expand(options);
133 }
134
135 bool ex::has(const ex & other) const
136 {
137         GINAC_ASSERT(bp!=0);
138         return bp->has(other);
139 }
140
141 int ex::degree(const ex & s) const
142 {
143         GINAC_ASSERT(bp!=0);
144         return bp->degree(s);
145 }
146
147 int ex::ldegree(const ex & s) const
148 {
149         GINAC_ASSERT(bp!=0);
150         return bp->ldegree(s);
151 }
152
153 ex ex::coeff(const ex & s, int n) const
154 {
155         GINAC_ASSERT(bp!=0);
156         return bp->coeff(s,n);
157 }
158
159 ex ex::collect(const ex & s) const
160 {
161         GINAC_ASSERT(bp!=0);
162         return bp->collect(s);
163 }
164
165 ex ex::eval(int level) const
166 {
167         GINAC_ASSERT(bp!=0);
168         return bp->eval(level);
169 }
170
171 ex ex::evalf(int level) const
172 {
173         GINAC_ASSERT(bp!=0);
174         return bp->evalf(level);
175 }
176
177 /** Compute partial derivative of an expression.
178  *
179  *  @param s  symbol by which the expression is derived
180  *  @param nth  order of derivative (default 1)
181  *  @return partial derivative as a new expression */
182 ex ex::diff(const symbol & s, unsigned nth) const
183 {
184         GINAC_ASSERT(bp!=0);
185
186         if (!nth)
187                 return *this;
188         else
189                 return bp->diff(s, nth);
190 }
191
192 ex ex::subs(const lst & ls, const lst & lr) const
193 {
194         GINAC_ASSERT(bp!=0);
195         return bp->subs(ls,lr);
196 }
197
198 ex ex::subs(const ex & e) const
199 {
200         GINAC_ASSERT(bp!=0);
201         return bp->subs(e);
202 }
203
204 /** Return a vector containing the free indices of the object. */
205 exvector ex::get_free_indices(void) const
206 {
207         GINAC_ASSERT(bp!=0);
208         return bp->get_free_indices();
209 }
210
211 /** Simplify/canonicalize expression containing indexed objects. This
212  *  performs contraction of dummy indices where possible and checks whether
213  *  the free indices in sums are consistent.
214  *
215  *  @return simplified expression */
216 ex ex::simplify_indexed(void) const
217 {
218         return GiNaC::simplify_indexed(*this);
219 }
220
221 /** Simplify/canonicalize expression containing indexed objects. This
222  *  performs contraction of dummy indices where possible, checks whether
223  *  the free indices in sums are consistent, and automatically replaces
224  *  scalar products by known values if desired.
225  *
226  *  @param sp Scalar products to be replaced automatically
227  *  @return simplified expression */
228 ex ex::simplify_indexed(const scalar_products & sp) const
229 {
230         return GiNaC::simplify_indexed(*this, sp);
231 }
232
233 ex ex::simplify_ncmul(const exvector & v) const
234 {
235         GINAC_ASSERT(bp!=0);
236         return bp->simplify_ncmul(v);
237 }
238
239 ex ex::operator[](const ex & index) const
240 {
241         debugmsg("ex operator[ex]",LOGLEVEL_OPERATOR);
242         GINAC_ASSERT(bp!=0);
243         return (*bp)[index];
244 }
245
246 ex ex::operator[](int i) const
247 {
248         debugmsg("ex operator[int]",LOGLEVEL_OPERATOR);
249         GINAC_ASSERT(bp!=0);
250         return (*bp)[i];
251 }
252
253 /** Return operand/member at position i. */
254 ex ex::op(int i) const
255 {
256         debugmsg("ex op()",LOGLEVEL_MEMBER_FUNCTION);
257         GINAC_ASSERT(bp!=0);
258         return bp->op(i);
259 }
260
261 /** Return modifyable operand/member at position i. */
262 ex & ex::let_op(int i)
263 {
264         debugmsg("ex let_op()",LOGLEVEL_MEMBER_FUNCTION);
265         makewriteable();
266         GINAC_ASSERT(bp!=0);
267         return bp->let_op(i);
268 }
269
270 /** Left hand side of relational expression. */
271 ex ex::lhs(void) const
272 {
273         debugmsg("ex lhs()",LOGLEVEL_MEMBER_FUNCTION);
274         GINAC_ASSERT(is_ex_of_type(*this,relational));
275         return (*static_cast<relational *>(bp)).lhs();
276 }
277
278 /** Right hand side of relational expression. */
279 ex ex::rhs(void) const
280 {
281         debugmsg("ex rhs()",LOGLEVEL_MEMBER_FUNCTION);
282         GINAC_ASSERT(is_ex_of_type(*this,relational));
283         return (*static_cast<relational *>(bp)).rhs();
284 }
285
286 unsigned ex::return_type(void) const
287 {
288         GINAC_ASSERT(bp!=0);
289         return bp->return_type();
290 }
291
292 unsigned ex::return_type_tinfo(void) const
293 {
294         GINAC_ASSERT(bp!=0);
295         return bp->return_type_tinfo();
296 }
297
298 unsigned ex::gethash(void) const
299 {
300         GINAC_ASSERT(bp!=0);
301         return bp->gethash();
302 }
303
304 /** Used internally by operator+() to add two ex objects together. */
305 ex ex::exadd(const ex & rh) const
306 {
307         return (new add(*this,rh))->setflag(status_flags::dynallocated);
308 }
309
310 /** Used internally by operator*() to multiply two ex objects together. */
311 ex ex::exmul(const ex & rh) const
312 {
313         // Check if we are constructing a mul object or a ncmul object.  Due to
314         // ncmul::eval()'s rule to pull out commutative elements we need to check
315         // only one of the elements.
316         if (rh.bp->return_type()==return_types::commutative ||
317             bp->return_type()==return_types::commutative)
318                 return (new mul(*this,rh))->setflag(status_flags::dynallocated);
319         else
320                 return (new ncmul(*this,rh))->setflag(status_flags::dynallocated);
321 }
322
323 // private
324
325 /** Make this ex writable (if more than one ex handle the same basic) by 
326  *  unlinking the object and creating an unshared copy of it. */
327 void ex::makewriteable()
328 {
329         debugmsg("ex makewriteable",LOGLEVEL_MEMBER_FUNCTION);
330         GINAC_ASSERT(bp!=0);
331         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
332         if (bp->refcount > 1) {
333                 basic * bp2 = bp->duplicate();
334                 ++bp2->refcount;
335                 bp2->setflag(status_flags::dynallocated);
336                 --bp->refcount;
337                 bp = bp2;
338         }
339         GINAC_ASSERT(bp->refcount==1);
340 }
341
342 /** Ctor from basic implementation.
343  *  @see ex::ex(const basic &) */
344 void ex::construct_from_basic(const basic & other)
345 {
346         if ((other.flags & status_flags::evaluated)==0) {
347                 // cf. copy ctor
348                 const ex & tmpex = other.eval(1); // evaluate only one (top) level
349                 bp = tmpex.bp;
350                 GINAC_ASSERT(bp!=0);
351                 GINAC_ASSERT(bp->flags & status_flags::dynallocated);
352                 ++bp->refcount;
353                 if ((other.flags & status_flags::dynallocated)&&(other.refcount==0))
354                         delete &const_cast<basic &>(other);
355         } else {
356                 if (other.flags & status_flags::dynallocated) {
357                         // ok, it is already on the heap, so just copy bp:
358                         bp = &const_cast<basic &>(other);
359                 } else {
360                         // create a duplicate on the heap:
361                         bp = other.duplicate();
362                         bp->setflag(status_flags::dynallocated);
363                 }
364                 GINAC_ASSERT(bp!=0);
365                 ++bp->refcount;
366         }
367         GINAC_ASSERT(bp!=0);
368         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
369 }
370
371 void ex::construct_from_int(int i)
372 {
373         switch (i) {  // some tiny efficiency-hack
374         case -2:
375                 bp = _ex_2().bp;
376                 ++bp->refcount;
377                 break;
378         case -1:
379                 bp = _ex_1().bp;
380                 ++bp->refcount;
381                 break;
382         case 0:
383                 bp = _ex0().bp;
384                 ++bp->refcount;
385                 break;
386         case 1:
387                 bp = _ex1().bp;
388                 ++bp->refcount;
389                 break;
390         case 2:
391                 bp = _ex2().bp;
392                 ++bp->refcount;
393                 break;
394         default:
395                 bp = new numeric(i);
396                 bp->setflag(status_flags::dynallocated);
397                 ++bp->refcount;
398                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
399                 GINAC_ASSERT(bp->refcount==1);
400         }
401 }
402         
403 void ex::construct_from_uint(unsigned int i)
404 {
405         switch (i) {  // some tiny efficiency-hack
406         case 0:
407                 bp = _ex0().bp;
408                 ++bp->refcount;
409                 break;
410         case 1:
411                 bp = _ex1().bp;
412                 ++bp->refcount;
413                 break;
414         case 2:
415                 bp = _ex2().bp;
416                 ++bp->refcount;
417                 break;
418         default:
419                 bp = new numeric(i);
420                 bp->setflag(status_flags::dynallocated);
421                 ++bp->refcount;
422                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
423                 GINAC_ASSERT(bp->refcount==1);
424         }
425 }
426         
427 void ex::construct_from_long(long i)
428 {
429         switch (i) {  // some tiny efficiency-hack
430         case -2:
431                 bp = _ex_2().bp;
432                 ++bp->refcount;
433                 break;
434         case -1:
435                 bp = _ex_1().bp;
436                 ++bp->refcount;
437                 break;
438         case 0:
439                 bp = _ex0().bp;
440                 ++bp->refcount;
441                 break;
442         case 1:
443                 bp = _ex1().bp;
444                 ++bp->refcount;
445                 break;
446         case 2:
447                 bp = _ex2().bp;
448                 ++bp->refcount;
449                 break;
450         default:
451                 bp = new numeric(i);
452                 bp->setflag(status_flags::dynallocated);
453                 ++bp->refcount;
454                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
455                 GINAC_ASSERT(bp->refcount==1);
456         }
457 }
458         
459 void ex::construct_from_ulong(unsigned long i)
460 {
461         switch (i) {  // some tiny efficiency-hack
462         case 0:
463                 bp = _ex0().bp;
464                 ++bp->refcount;
465                 break;
466         case 1:
467                 bp = _ex1().bp;
468                 ++bp->refcount;
469                 break;
470         case 2:
471                 bp = _ex2().bp;
472                 ++bp->refcount;
473                 break;
474         default:
475                 bp = new numeric(i);
476                 bp->setflag(status_flags::dynallocated);
477                 ++bp->refcount;
478                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
479                 GINAC_ASSERT(bp->refcount==1);
480         }
481 }
482         
483 void ex::construct_from_double(double d)
484 {
485         bp = new numeric(d);
486         bp->setflag(status_flags::dynallocated);
487         ++bp->refcount;
488         GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
489         GINAC_ASSERT(bp->refcount==1);
490 }
491
492 void ex::construct_from_string_and_lst(const std::string &s, const ex &l)
493 {
494         set_lexer_string(s);
495         set_lexer_symbols(l);
496         ginac_yyrestart(NULL);
497         if (ginac_yyparse())
498                 throw (std::runtime_error(get_parser_error()));
499         else {
500                 bp = parsed_ex.bp;
501                 GINAC_ASSERT(bp!=0);
502                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
503                 ++bp->refcount;
504         }
505 }
506         
507 //////////
508 // static member variables
509 //////////
510
511 // none
512
513 //////////
514 // functions which are not member functions
515 //////////
516
517 // none
518
519 //////////
520 // global functions
521 //////////
522
523 // none
524
525
526 } // namespace GiNaC