- ++version_major.
[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 "lst.h"
33 #include "relational.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 /** Check whether expression matches a specified pattern. */
140 bool ex::match(const ex & pattern) const
141 {
142         lst repl_lst;
143         return bp->match(pattern, repl_lst);
144 }
145
146 ex ex::operator[](const ex & index) const
147 {
148         debugmsg("ex operator[ex]",LOGLEVEL_OPERATOR);
149         GINAC_ASSERT(bp!=0);
150         return (*bp)[index];
151 }
152
153 ex ex::operator[](int i) const
154 {
155         debugmsg("ex operator[int]",LOGLEVEL_OPERATOR);
156         GINAC_ASSERT(bp!=0);
157         return (*bp)[i];
158 }
159
160 /** Return modifyable operand/member at position i. */
161 ex & ex::let_op(int i)
162 {
163         debugmsg("ex let_op()",LOGLEVEL_MEMBER_FUNCTION);
164         makewriteable();
165         GINAC_ASSERT(bp!=0);
166         return bp->let_op(i);
167 }
168
169 /** Left hand side of relational expression. */
170 ex ex::lhs(void) const
171 {
172         debugmsg("ex lhs()",LOGLEVEL_MEMBER_FUNCTION);
173         if (!is_ex_of_type(*this,relational))
174                 throw std::runtime_error("ex::lhs(): not a relation");
175         return (*static_cast<relational *>(bp)).lhs();
176 }
177
178 /** Right hand side of relational expression. */
179 ex ex::rhs(void) const
180 {
181         debugmsg("ex rhs()",LOGLEVEL_MEMBER_FUNCTION);
182         if (!is_ex_of_type(*this,relational))
183                 throw std::runtime_error("ex::rhs(): not a relation");
184         return (*static_cast<relational *>(bp)).rhs();
185 }
186
187 // private
188
189 /** Make this ex writable (if more than one ex handle the same basic) by 
190  *  unlinking the object and creating an unshared copy of it. */
191 void ex::makewriteable()
192 {
193         debugmsg("ex makewriteable",LOGLEVEL_MEMBER_FUNCTION);
194         GINAC_ASSERT(bp!=0);
195         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
196         if (bp->refcount > 1) {
197                 basic * bp2 = bp->duplicate();
198                 ++bp2->refcount;
199                 bp2->setflag(status_flags::dynallocated);
200                 --bp->refcount;
201                 bp = bp2;
202         }
203         GINAC_ASSERT(bp->refcount==1);
204 }
205
206 /** Ctor from basic implementation.
207  *  @see ex::ex(const basic &) */
208 void ex::construct_from_basic(const basic & other)
209 {
210         if (!(other.flags & status_flags::evaluated)) {
211                 const ex & tmpex(other.eval(1)); // evaluate only one (top) level
212                 bp = tmpex.bp;
213                 GINAC_ASSERT(bp->flags & status_flags::dynallocated);
214                 ++bp->refcount;
215                 if ((other.refcount==0) && (other.flags & status_flags::dynallocated))
216                         delete &const_cast<basic &>(other);
217         } else {
218                 if (other.flags & status_flags::dynallocated) {
219                         // ok, it is already on the heap, so just copy bp:
220                         bp = &const_cast<basic &>(other);
221                 } else {
222                         // create a duplicate on the heap:
223                         bp = other.duplicate();
224                         bp->setflag(status_flags::dynallocated);
225                 }
226                 GINAC_ASSERT(bp!=0);
227                 ++bp->refcount;
228         }
229         GINAC_ASSERT(bp!=0);
230         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
231 }
232
233 void ex::construct_from_int(int i)
234 {
235         switch (i) {  // some tiny efficiency-hack
236         case -2:
237                 bp = _ex_2().bp;
238                 ++bp->refcount;
239                 break;
240         case -1:
241                 bp = _ex_1().bp;
242                 ++bp->refcount;
243                 break;
244         case 0:
245                 bp = _ex0().bp;
246                 ++bp->refcount;
247                 break;
248         case 1:
249                 bp = _ex1().bp;
250                 ++bp->refcount;
251                 break;
252         case 2:
253                 bp = _ex2().bp;
254                 ++bp->refcount;
255                 break;
256         default:
257                 bp = new numeric(i);
258                 bp->setflag(status_flags::dynallocated);
259                 ++bp->refcount;
260                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
261                 GINAC_ASSERT(bp->refcount==1);
262         }
263 }
264         
265 void ex::construct_from_uint(unsigned int i)
266 {
267         switch (i) {  // some tiny efficiency-hack
268         case 0:
269                 bp = _ex0().bp;
270                 ++bp->refcount;
271                 break;
272         case 1:
273                 bp = _ex1().bp;
274                 ++bp->refcount;
275                 break;
276         case 2:
277                 bp = _ex2().bp;
278                 ++bp->refcount;
279                 break;
280         default:
281                 bp = new numeric(i);
282                 bp->setflag(status_flags::dynallocated);
283                 ++bp->refcount;
284                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
285                 GINAC_ASSERT(bp->refcount==1);
286         }
287 }
288         
289 void ex::construct_from_long(long i)
290 {
291         switch (i) {  // some tiny efficiency-hack
292         case -2:
293                 bp = _ex_2().bp;
294                 ++bp->refcount;
295                 break;
296         case -1:
297                 bp = _ex_1().bp;
298                 ++bp->refcount;
299                 break;
300         case 0:
301                 bp = _ex0().bp;
302                 ++bp->refcount;
303                 break;
304         case 1:
305                 bp = _ex1().bp;
306                 ++bp->refcount;
307                 break;
308         case 2:
309                 bp = _ex2().bp;
310                 ++bp->refcount;
311                 break;
312         default:
313                 bp = new numeric(i);
314                 bp->setflag(status_flags::dynallocated);
315                 ++bp->refcount;
316                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
317                 GINAC_ASSERT(bp->refcount==1);
318         }
319 }
320         
321 void ex::construct_from_ulong(unsigned long i)
322 {
323         switch (i) {  // some tiny efficiency-hack
324         case 0:
325                 bp = _ex0().bp;
326                 ++bp->refcount;
327                 break;
328         case 1:
329                 bp = _ex1().bp;
330                 ++bp->refcount;
331                 break;
332         case 2:
333                 bp = _ex2().bp;
334                 ++bp->refcount;
335                 break;
336         default:
337                 bp = new numeric(i);
338                 bp->setflag(status_flags::dynallocated);
339                 ++bp->refcount;
340                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
341                 GINAC_ASSERT(bp->refcount==1);
342         }
343 }
344         
345 void ex::construct_from_double(double d)
346 {
347         bp = new numeric(d);
348         bp->setflag(status_flags::dynallocated);
349         ++bp->refcount;
350         GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
351         GINAC_ASSERT(bp->refcount==1);
352 }
353
354 void ex::construct_from_string_and_lst(const std::string &s, const ex &l)
355 {
356         set_lexer_string(s);
357         set_lexer_symbols(l);
358         ginac_yyrestart(NULL);
359         if (ginac_yyparse())
360                 throw (std::runtime_error(get_parser_error()));
361         else {
362                 bp = parsed_ex.bp;
363                 GINAC_ASSERT(bp!=0);
364                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
365                 ++bp->refcount;
366         }
367 }
368         
369 //////////
370 // static member variables
371 //////////
372
373 // none
374
375 //////////
376 // functions which are not member functions
377 //////////
378
379 // none
380
381 //////////
382 // global functions
383 //////////
384
385 // none
386
387
388 } // namespace GiNaC