e8ce2da1eabce3e5ba12b0ad1e60f415ceb62d42
[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 "lst.h"
35 #include "input_lexer.h"
36 #include "debugmsg.h"
37 #include "utils.h"
38
39 namespace GiNaC {
40
41 //////////
42 // other ctors
43 //////////
44
45 // none (all inlined)
46
47 //////////
48 // functions overriding virtual functions from bases classes
49 //////////
50
51 // none
52
53 //////////
54 // new virtual functions which can be overridden by derived classes
55 //////////
56
57 // none
58
59 //////////
60 // non-virtual functions in this class
61 //////////
62
63 // public
64
65 /** Efficiently swap the contents of two expressions. */
66 void ex::swap(ex & other)
67 {
68         debugmsg("ex swap",LOGLEVEL_MEMBER_FUNCTION);
69
70         GINAC_ASSERT(bp!=0);
71         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
72         GINAC_ASSERT(other.bp!=0);
73         GINAC_ASSERT(other.bp->flags & status_flags::dynallocated);
74         
75         basic * tmpbp = bp;
76         bp = other.bp;
77         other.bp = tmpbp;
78 }
79
80 /** Print expression to stream. The formatting of the output is determined
81  *  by the kind of print_context object that is passed. Possible formattings
82  *  include ginsh-parsable output (the default), tree-like output for
83  *  debugging, and C++ source.
84  *  @see print_context */
85 void ex::print(const print_context & c, unsigned level) const
86 {
87         debugmsg("ex print", LOGLEVEL_PRINT);
88         GINAC_ASSERT(bp!=0);
89         bp->print(c, level);
90 }
91
92 /** Print expression to stream in a tree-like format suitable for debugging. */
93 void ex::printtree(std::ostream & os) const
94 {
95         debugmsg("ex printtree", LOGLEVEL_PRINT);
96         GINAC_ASSERT(bp!=0);
97         bp->print(print_tree(os));
98 }
99
100 /** Little wrapper arount print to be called within a debugger. */
101 void ex::dbgprint(void) const
102 {
103         debugmsg("ex dbgprint", LOGLEVEL_PRINT);
104         GINAC_ASSERT(bp!=0);
105         bp->dbgprint();
106 }
107
108 /** Little wrapper arount printtree to be called within a debugger. */
109 void ex::dbgprinttree(void) const
110 {
111         debugmsg("ex dbgprinttree", LOGLEVEL_PRINT);
112         GINAC_ASSERT(bp!=0);
113         bp->dbgprinttree();
114 }
115
116 ex ex::expand(unsigned options) const
117 {
118         GINAC_ASSERT(bp!=0);
119         if (bp->flags & status_flags::expanded)
120                 return *bp;
121         else
122                 return bp->expand(options);
123 }
124
125 /** Compute partial derivative of an expression.
126  *
127  *  @param s  symbol by which the expression is derived
128  *  @param nth  order of derivative (default 1)
129  *  @return partial derivative as a new expression */
130 ex ex::diff(const symbol & s, unsigned nth) const
131 {
132         GINAC_ASSERT(bp!=0);
133
134         if (!nth)
135                 return *this;
136         else
137                 return bp->diff(s, nth);
138 }
139
140 /** Check whether expression matches a specified pattern. */
141 bool ex::match(const ex & pattern) const
142 {
143         lst repl_lst;
144         return bp->match(pattern, repl_lst);
145 }
146
147 /** Simplify/canonicalize expression containing indexed objects. This
148  *  performs contraction of dummy indices where possible and checks whether
149  *  the free indices in sums are consistent.
150  *
151  *  @return simplified expression */
152 ex ex::simplify_indexed(void) const
153 {
154         return GiNaC::simplify_indexed(*this);
155 }
156
157 /** Simplify/canonicalize expression containing indexed objects. This
158  *  performs contraction of dummy indices where possible, checks whether
159  *  the free indices in sums are consistent, and automatically replaces
160  *  scalar products by known values if desired.
161  *
162  *  @param sp Scalar products to be replaced automatically
163  *  @return simplified expression */
164 ex ex::simplify_indexed(const scalar_products & sp) const
165 {
166         return GiNaC::simplify_indexed(*this, sp);
167 }
168
169 ex ex::operator[](const ex & index) const
170 {
171         debugmsg("ex operator[ex]",LOGLEVEL_OPERATOR);
172         GINAC_ASSERT(bp!=0);
173         return (*bp)[index];
174 }
175
176 ex ex::operator[](int i) const
177 {
178         debugmsg("ex operator[int]",LOGLEVEL_OPERATOR);
179         GINAC_ASSERT(bp!=0);
180         return (*bp)[i];
181 }
182
183 /** Return modifyable operand/member at position i. */
184 ex & ex::let_op(int i)
185 {
186         debugmsg("ex let_op()",LOGLEVEL_MEMBER_FUNCTION);
187         makewriteable();
188         GINAC_ASSERT(bp!=0);
189         return bp->let_op(i);
190 }
191
192 /** Left hand side of relational expression. */
193 ex ex::lhs(void) const
194 {
195         debugmsg("ex lhs()",LOGLEVEL_MEMBER_FUNCTION);
196         if (!is_ex_of_type(*this,relational))
197                 throw std::runtime_error("ex::lhs(): not a relation");
198         return (*static_cast<relational *>(bp)).lhs();
199 }
200
201 /** Right hand side of relational expression. */
202 ex ex::rhs(void) const
203 {
204         debugmsg("ex rhs()",LOGLEVEL_MEMBER_FUNCTION);
205         if (!is_ex_of_type(*this,relational))
206                 throw std::runtime_error("ex::rhs(): not a relation");
207         return (*static_cast<relational *>(bp)).rhs();
208 }
209
210 // private
211
212 /** Make this ex writable (if more than one ex handle the same basic) by 
213  *  unlinking the object and creating an unshared copy of it. */
214 void ex::makewriteable()
215 {
216         debugmsg("ex makewriteable",LOGLEVEL_MEMBER_FUNCTION);
217         GINAC_ASSERT(bp!=0);
218         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
219         if (bp->refcount > 1) {
220                 basic * bp2 = bp->duplicate();
221                 ++bp2->refcount;
222                 bp2->setflag(status_flags::dynallocated);
223                 --bp->refcount;
224                 bp = bp2;
225         }
226         GINAC_ASSERT(bp->refcount==1);
227 }
228
229 /** Ctor from basic implementation.
230  *  @see ex::ex(const basic &) */
231 void ex::construct_from_basic(const basic & other)
232 {
233         if ((other.flags & status_flags::evaluated)==0) {
234                 // cf. copy ctor
235                 const ex & tmpex = other.eval(1); // evaluate only one (top) level
236                 bp = tmpex.bp;
237                 GINAC_ASSERT(bp!=0);
238                 GINAC_ASSERT(bp->flags & status_flags::dynallocated);
239                 ++bp->refcount;
240                 if ((other.flags & status_flags::dynallocated)&&(other.refcount==0))
241                         delete &const_cast<basic &>(other);
242         } else {
243                 if (other.flags & status_flags::dynallocated) {
244                         // ok, it is already on the heap, so just copy bp:
245                         bp = &const_cast<basic &>(other);
246                 } else {
247                         // create a duplicate on the heap:
248                         bp = other.duplicate();
249                         bp->setflag(status_flags::dynallocated);
250                 }
251                 GINAC_ASSERT(bp!=0);
252                 ++bp->refcount;
253         }
254         GINAC_ASSERT(bp!=0);
255         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
256 }
257
258 void ex::construct_from_int(int i)
259 {
260         switch (i) {  // some tiny efficiency-hack
261         case -2:
262                 bp = _ex_2().bp;
263                 ++bp->refcount;
264                 break;
265         case -1:
266                 bp = _ex_1().bp;
267                 ++bp->refcount;
268                 break;
269         case 0:
270                 bp = _ex0().bp;
271                 ++bp->refcount;
272                 break;
273         case 1:
274                 bp = _ex1().bp;
275                 ++bp->refcount;
276                 break;
277         case 2:
278                 bp = _ex2().bp;
279                 ++bp->refcount;
280                 break;
281         default:
282                 bp = new numeric(i);
283                 bp->setflag(status_flags::dynallocated);
284                 ++bp->refcount;
285                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
286                 GINAC_ASSERT(bp->refcount==1);
287         }
288 }
289         
290 void ex::construct_from_uint(unsigned int i)
291 {
292         switch (i) {  // some tiny efficiency-hack
293         case 0:
294                 bp = _ex0().bp;
295                 ++bp->refcount;
296                 break;
297         case 1:
298                 bp = _ex1().bp;
299                 ++bp->refcount;
300                 break;
301         case 2:
302                 bp = _ex2().bp;
303                 ++bp->refcount;
304                 break;
305         default:
306                 bp = new numeric(i);
307                 bp->setflag(status_flags::dynallocated);
308                 ++bp->refcount;
309                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
310                 GINAC_ASSERT(bp->refcount==1);
311         }
312 }
313         
314 void ex::construct_from_long(long i)
315 {
316         switch (i) {  // some tiny efficiency-hack
317         case -2:
318                 bp = _ex_2().bp;
319                 ++bp->refcount;
320                 break;
321         case -1:
322                 bp = _ex_1().bp;
323                 ++bp->refcount;
324                 break;
325         case 0:
326                 bp = _ex0().bp;
327                 ++bp->refcount;
328                 break;
329         case 1:
330                 bp = _ex1().bp;
331                 ++bp->refcount;
332                 break;
333         case 2:
334                 bp = _ex2().bp;
335                 ++bp->refcount;
336                 break;
337         default:
338                 bp = new numeric(i);
339                 bp->setflag(status_flags::dynallocated);
340                 ++bp->refcount;
341                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
342                 GINAC_ASSERT(bp->refcount==1);
343         }
344 }
345         
346 void ex::construct_from_ulong(unsigned long i)
347 {
348         switch (i) {  // some tiny efficiency-hack
349         case 0:
350                 bp = _ex0().bp;
351                 ++bp->refcount;
352                 break;
353         case 1:
354                 bp = _ex1().bp;
355                 ++bp->refcount;
356                 break;
357         case 2:
358                 bp = _ex2().bp;
359                 ++bp->refcount;
360                 break;
361         default:
362                 bp = new numeric(i);
363                 bp->setflag(status_flags::dynallocated);
364                 ++bp->refcount;
365                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
366                 GINAC_ASSERT(bp->refcount==1);
367         }
368 }
369         
370 void ex::construct_from_double(double d)
371 {
372         bp = new numeric(d);
373         bp->setflag(status_flags::dynallocated);
374         ++bp->refcount;
375         GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
376         GINAC_ASSERT(bp->refcount==1);
377 }
378
379 void ex::construct_from_string_and_lst(const std::string &s, const ex &l)
380 {
381         set_lexer_string(s);
382         set_lexer_symbols(l);
383         ginac_yyrestart(NULL);
384         if (ginac_yyparse())
385                 throw (std::runtime_error(get_parser_error()));
386         else {
387                 bp = parsed_ex.bp;
388                 GINAC_ASSERT(bp!=0);
389                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
390                 ++bp->refcount;
391         }
392 }
393         
394 //////////
395 // static member variables
396 //////////
397
398 // none
399
400 //////////
401 // functions which are not member functions
402 //////////
403
404 // none
405
406 //////////
407 // global functions
408 //////////
409
410 // none
411
412
413 } // namespace GiNaC