* Methods of class ex which do absolutely nothing than type dispatch should
[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 ex ex::expand(unsigned options) const
116 {
117         GINAC_ASSERT(bp!=0);
118         if (bp->flags & status_flags::expanded)
119                 return *bp;
120         else
121                 return bp->expand(options);
122 }
123
124 /** Compute partial derivative of an expression.
125  *
126  *  @param s  symbol by which the expression is derived
127  *  @param nth  order of derivative (default 1)
128  *  @return partial derivative as a new expression */
129 ex ex::diff(const symbol & s, unsigned nth) const
130 {
131         GINAC_ASSERT(bp!=0);
132
133         if (!nth)
134                 return *this;
135         else
136                 return bp->diff(s, nth);
137 }
138
139 /** Simplify/canonicalize expression containing indexed objects. This
140  *  performs contraction of dummy indices where possible and checks whether
141  *  the free indices in sums are consistent.
142  *
143  *  @return simplified expression */
144 ex ex::simplify_indexed(void) const
145 {
146         return GiNaC::simplify_indexed(*this);
147 }
148
149 /** Simplify/canonicalize expression containing indexed objects. This
150  *  performs contraction of dummy indices where possible, checks whether
151  *  the free indices in sums are consistent, and automatically replaces
152  *  scalar products by known values if desired.
153  *
154  *  @param sp Scalar products to be replaced automatically
155  *  @return simplified expression */
156 ex ex::simplify_indexed(const scalar_products & sp) const
157 {
158         return GiNaC::simplify_indexed(*this, sp);
159 }
160
161 ex ex::operator[](const ex & index) const
162 {
163         debugmsg("ex operator[ex]",LOGLEVEL_OPERATOR);
164         GINAC_ASSERT(bp!=0);
165         return (*bp)[index];
166 }
167
168 ex ex::operator[](int i) const
169 {
170         debugmsg("ex operator[int]",LOGLEVEL_OPERATOR);
171         GINAC_ASSERT(bp!=0);
172         return (*bp)[i];
173 }
174
175 /** Return modifyable operand/member at position i. */
176 ex & ex::let_op(int i)
177 {
178         debugmsg("ex let_op()",LOGLEVEL_MEMBER_FUNCTION);
179         makewriteable();
180         GINAC_ASSERT(bp!=0);
181         return bp->let_op(i);
182 }
183
184 /** Left hand side of relational expression. */
185 ex ex::lhs(void) const
186 {
187         debugmsg("ex lhs()",LOGLEVEL_MEMBER_FUNCTION);
188         if (!is_ex_of_type(*this,relational))
189                 throw std::runtime_error("ex::lhs(): not a relation");
190         return (*static_cast<relational *>(bp)).lhs();
191 }
192
193 /** Right hand side of relational expression. */
194 ex ex::rhs(void) const
195 {
196         debugmsg("ex rhs()",LOGLEVEL_MEMBER_FUNCTION);
197         if (!is_ex_of_type(*this,relational))
198                 throw std::runtime_error("ex::rhs(): not a relation");
199         return (*static_cast<relational *>(bp)).rhs();
200 }
201
202 /** Used internally by operator+() to add two ex objects together. */
203 ex ex::exadd(const ex & rh) const
204 {
205         return (new add(*this,rh))->setflag(status_flags::dynallocated);
206 }
207
208 /** Used internally by operator*() to multiply two ex objects together. */
209 ex ex::exmul(const ex & rh) const
210 {
211         // Check if we are constructing a mul object or a ncmul object.  Due to
212         // ncmul::eval()'s rule to pull out commutative elements we need to check
213         // only one of the elements.
214         if (rh.bp->return_type()==return_types::commutative ||
215             bp->return_type()==return_types::commutative)
216                 return (new mul(*this,rh))->setflag(status_flags::dynallocated);
217         else
218                 return (new ncmul(*this,rh))->setflag(status_flags::dynallocated);
219 }
220
221 // private
222
223 /** Make this ex writable (if more than one ex handle the same basic) by 
224  *  unlinking the object and creating an unshared copy of it. */
225 void ex::makewriteable()
226 {
227         debugmsg("ex makewriteable",LOGLEVEL_MEMBER_FUNCTION);
228         GINAC_ASSERT(bp!=0);
229         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
230         if (bp->refcount > 1) {
231                 basic * bp2 = bp->duplicate();
232                 ++bp2->refcount;
233                 bp2->setflag(status_flags::dynallocated);
234                 --bp->refcount;
235                 bp = bp2;
236         }
237         GINAC_ASSERT(bp->refcount==1);
238 }
239
240 /** Ctor from basic implementation.
241  *  @see ex::ex(const basic &) */
242 void ex::construct_from_basic(const basic & other)
243 {
244         if ((other.flags & status_flags::evaluated)==0) {
245                 // cf. copy ctor
246                 const ex & tmpex = other.eval(1); // evaluate only one (top) level
247                 bp = tmpex.bp;
248                 GINAC_ASSERT(bp!=0);
249                 GINAC_ASSERT(bp->flags & status_flags::dynallocated);
250                 ++bp->refcount;
251                 if ((other.flags & status_flags::dynallocated)&&(other.refcount==0))
252                         delete &const_cast<basic &>(other);
253         } else {
254                 if (other.flags & status_flags::dynallocated) {
255                         // ok, it is already on the heap, so just copy bp:
256                         bp = &const_cast<basic &>(other);
257                 } else {
258                         // create a duplicate on the heap:
259                         bp = other.duplicate();
260                         bp->setflag(status_flags::dynallocated);
261                 }
262                 GINAC_ASSERT(bp!=0);
263                 ++bp->refcount;
264         }
265         GINAC_ASSERT(bp!=0);
266         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
267 }
268
269 void ex::construct_from_int(int i)
270 {
271         switch (i) {  // some tiny efficiency-hack
272         case -2:
273                 bp = _ex_2().bp;
274                 ++bp->refcount;
275                 break;
276         case -1:
277                 bp = _ex_1().bp;
278                 ++bp->refcount;
279                 break;
280         case 0:
281                 bp = _ex0().bp;
282                 ++bp->refcount;
283                 break;
284         case 1:
285                 bp = _ex1().bp;
286                 ++bp->refcount;
287                 break;
288         case 2:
289                 bp = _ex2().bp;
290                 ++bp->refcount;
291                 break;
292         default:
293                 bp = new numeric(i);
294                 bp->setflag(status_flags::dynallocated);
295                 ++bp->refcount;
296                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
297                 GINAC_ASSERT(bp->refcount==1);
298         }
299 }
300         
301 void ex::construct_from_uint(unsigned int i)
302 {
303         switch (i) {  // some tiny efficiency-hack
304         case 0:
305                 bp = _ex0().bp;
306                 ++bp->refcount;
307                 break;
308         case 1:
309                 bp = _ex1().bp;
310                 ++bp->refcount;
311                 break;
312         case 2:
313                 bp = _ex2().bp;
314                 ++bp->refcount;
315                 break;
316         default:
317                 bp = new numeric(i);
318                 bp->setflag(status_flags::dynallocated);
319                 ++bp->refcount;
320                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
321                 GINAC_ASSERT(bp->refcount==1);
322         }
323 }
324         
325 void ex::construct_from_long(long i)
326 {
327         switch (i) {  // some tiny efficiency-hack
328         case -2:
329                 bp = _ex_2().bp;
330                 ++bp->refcount;
331                 break;
332         case -1:
333                 bp = _ex_1().bp;
334                 ++bp->refcount;
335                 break;
336         case 0:
337                 bp = _ex0().bp;
338                 ++bp->refcount;
339                 break;
340         case 1:
341                 bp = _ex1().bp;
342                 ++bp->refcount;
343                 break;
344         case 2:
345                 bp = _ex2().bp;
346                 ++bp->refcount;
347                 break;
348         default:
349                 bp = new numeric(i);
350                 bp->setflag(status_flags::dynallocated);
351                 ++bp->refcount;
352                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
353                 GINAC_ASSERT(bp->refcount==1);
354         }
355 }
356         
357 void ex::construct_from_ulong(unsigned long i)
358 {
359         switch (i) {  // some tiny efficiency-hack
360         case 0:
361                 bp = _ex0().bp;
362                 ++bp->refcount;
363                 break;
364         case 1:
365                 bp = _ex1().bp;
366                 ++bp->refcount;
367                 break;
368         case 2:
369                 bp = _ex2().bp;
370                 ++bp->refcount;
371                 break;
372         default:
373                 bp = new numeric(i);
374                 bp->setflag(status_flags::dynallocated);
375                 ++bp->refcount;
376                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
377                 GINAC_ASSERT(bp->refcount==1);
378         }
379 }
380         
381 void ex::construct_from_double(double d)
382 {
383         bp = new numeric(d);
384         bp->setflag(status_flags::dynallocated);
385         ++bp->refcount;
386         GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
387         GINAC_ASSERT(bp->refcount==1);
388 }
389
390 void ex::construct_from_string_and_lst(const std::string &s, const ex &l)
391 {
392         set_lexer_string(s);
393         set_lexer_symbols(l);
394         ginac_yyrestart(NULL);
395         if (ginac_yyparse())
396                 throw (std::runtime_error(get_parser_error()));
397         else {
398                 bp = parsed_ex.bp;
399                 GINAC_ASSERT(bp!=0);
400                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
401                 ++bp->refcount;
402         }
403 }
404         
405 //////////
406 // static member variables
407 //////////
408
409 // none
410
411 //////////
412 // functions which are not member functions
413 //////////
414
415 // none
416
417 //////////
418 // global functions
419 //////////
420
421 // none
422
423
424 } // namespace GiNaC