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