]> www.ginac.de Git - ginac.git/blob - ginac/ex.cpp
- added skeleton implementation of color and clifford classes (don't bother
[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 /** Used internally by operator+() to add two ex objects together. */
346 ex ex::exadd(const ex & rh) const
347 {
348         return (new add(*this,rh))->setflag(status_flags::dynallocated);
349 }
350
351 /** Used internally by operator*() to multiply two ex objects together. */
352 ex ex::exmul(const ex & rh) const
353 {
354         // Check if we are constructing a mul object or a ncmul object.  Due to
355         // ncmul::eval()'s rule to pull out commutative elements we need to check
356         // only one of the elements.
357         if (rh.bp->return_type()==return_types::commutative ||
358             bp->return_type()==return_types::commutative)
359                 return (new mul(*this,rh))->setflag(status_flags::dynallocated);
360         else
361                 return (new ncmul(*this,rh))->setflag(status_flags::dynallocated);
362 }
363
364 // private
365
366 /** Make this ex writable (if more than one ex handle the same basic) by 
367  *  unlinking the object and creating an unshared copy of it. */
368 void ex::makewriteable()
369 {
370         debugmsg("ex makewriteable",LOGLEVEL_MEMBER_FUNCTION);
371         GINAC_ASSERT(bp!=0);
372         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
373         if (bp->refcount > 1) {
374                 basic * bp2 = bp->duplicate();
375                 ++bp2->refcount;
376                 bp2->setflag(status_flags::dynallocated);
377                 --bp->refcount;
378                 bp = bp2;
379         }
380         GINAC_ASSERT(bp->refcount==1);
381 }
382
383 /** Ctor from basic implementation.
384  *  @see ex::ex(const basic &) */
385 void ex::construct_from_basic(const basic & other)
386 {
387         if ((other.flags & status_flags::evaluated)==0) {
388                 // cf. copy ctor
389                 const ex & tmpex = other.eval(1); // evaluate only one (top) level
390                 bp = tmpex.bp;
391                 GINAC_ASSERT(bp!=0);
392                 GINAC_ASSERT(bp->flags & status_flags::dynallocated);
393                 ++bp->refcount;
394                 if ((other.flags & status_flags::dynallocated)&&(other.refcount==0))
395                         delete &const_cast<basic &>(other);
396         } else {
397                 if (other.flags & status_flags::dynallocated) {
398                         // ok, it is already on the heap, so just copy bp:
399                         bp = &const_cast<basic &>(other);
400                 } else {
401                         // create a duplicate on the heap:
402                         bp = other.duplicate();
403                         bp->setflag(status_flags::dynallocated);
404                 }
405                 GINAC_ASSERT(bp!=0);
406                 // bp->clearflag(status_flags::evaluated);
407                 ++bp->refcount;
408         }
409         GINAC_ASSERT(bp!=0);
410         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
411 }
412
413 void ex::construct_from_int(int i)
414 {
415         switch (i) {  // some tiny efficiency-hack
416         case -2:
417                 bp = _ex_2().bp;
418                 ++bp->refcount;
419                 break;
420         case -1:
421                 bp = _ex_1().bp;
422                 ++bp->refcount;
423                 break;
424         case 0:
425                 bp = _ex0().bp;
426                 ++bp->refcount;
427                 break;
428         case 1:
429                 bp = _ex1().bp;
430                 ++bp->refcount;
431                 break;
432         case 2:
433                 bp = _ex2().bp;
434                 ++bp->refcount;
435                 break;
436         default:
437                 bp = new numeric(i);
438                 bp->setflag(status_flags::dynallocated);
439                 ++bp->refcount;
440                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
441                 GINAC_ASSERT(bp->refcount==1);
442         }
443 }
444         
445 void ex::construct_from_uint(unsigned int i)
446 {
447         switch (i) {  // some tiny efficiency-hack
448         case 0:
449                 bp = _ex0().bp;
450                 ++bp->refcount;
451                 break;
452         case 1:
453                 bp = _ex1().bp;
454                 ++bp->refcount;
455                 break;
456         case 2:
457                 bp = _ex2().bp;
458                 ++bp->refcount;
459                 break;
460         default:
461                 bp = new numeric(i);
462                 bp->setflag(status_flags::dynallocated);
463                 ++bp->refcount;
464                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
465                 GINAC_ASSERT(bp->refcount==1);
466         }
467 }
468         
469 void ex::construct_from_long(long i)
470 {
471         switch (i) {  // some tiny efficiency-hack
472         case -2:
473                 bp = _ex_2().bp;
474                 ++bp->refcount;
475                 break;
476         case -1:
477                 bp = _ex_1().bp;
478                 ++bp->refcount;
479                 break;
480         case 0:
481                 bp = _ex0().bp;
482                 ++bp->refcount;
483                 break;
484         case 1:
485                 bp = _ex1().bp;
486                 ++bp->refcount;
487                 break;
488         case 2:
489                 bp = _ex2().bp;
490                 ++bp->refcount;
491                 break;
492         default:
493                 bp = new numeric(i);
494                 bp->setflag(status_flags::dynallocated);
495                 ++bp->refcount;
496                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
497                 GINAC_ASSERT(bp->refcount==1);
498         }
499 }
500         
501 void ex::construct_from_ulong(unsigned long i)
502 {
503         switch (i) {  // some tiny efficiency-hack
504         case 0:
505                 bp = _ex0().bp;
506                 ++bp->refcount;
507                 break;
508         case 1:
509                 bp = _ex1().bp;
510                 ++bp->refcount;
511                 break;
512         case 2:
513                 bp = _ex2().bp;
514                 ++bp->refcount;
515                 break;
516         default:
517                 bp = new numeric(i);
518                 bp->setflag(status_flags::dynallocated);
519                 ++bp->refcount;
520                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
521                 GINAC_ASSERT(bp->refcount==1);
522         }
523 }
524         
525 void ex::construct_from_double(double d)
526 {
527         bp = new numeric(d);
528         bp->setflag(status_flags::dynallocated);
529         ++bp->refcount;
530         GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
531         GINAC_ASSERT(bp->refcount==1);
532 }
533
534 void ex::construct_from_string_and_lst(const std::string &s, const ex &l)
535 {
536         set_lexer_string(s);
537         set_lexer_symbols(l);
538         ginac_yyrestart(NULL);
539         if (ginac_yyparse())
540                 throw (std::runtime_error(get_parser_error()));
541         else {
542                 bp = parsed_ex.bp;
543                 GINAC_ASSERT(bp!=0);
544                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
545                 ++bp->refcount;
546         }
547 }
548         
549 //////////
550 // static member variables
551 //////////
552
553 // none
554
555 //////////
556 // functions which are not member functions
557 //////////
558
559 // none
560
561 //////////
562 // global functions
563 //////////
564
565 // none
566
567
568 } // namespace GiNaC