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