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