]> www.ginac.de Git - ginac.git/blob - ginac/ex.cpp
tiny optimization in subs()
[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-2003 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 "utils.h"
36
37 namespace GiNaC {
38
39 //////////
40 // other constructors
41 //////////
42
43 // none (all inlined)
44
45 //////////
46 // non-virtual functions in this class
47 //////////
48
49 // public
50         
51 /** Print expression to stream. The formatting of the output is determined
52  *  by the kind of print_context object that is passed. Possible formattings
53  *  include ginsh-parsable output (the default), tree-like output for
54  *  debugging, and C++ source.
55  *  @see print_context */
56 void ex::print(const print_context & c, unsigned level) const
57 {
58         bp->print(c, level);
59 }
60
61 /** Little wrapper arount print to be called within a debugger. */
62 void ex::dbgprint() const
63 {
64         bp->dbgprint();
65 }
66
67 /** Little wrapper arount printtree to be called within a debugger. */
68 void ex::dbgprinttree() const
69 {
70         bp->dbgprinttree();
71 }
72
73 ex ex::expand(unsigned options) const
74 {
75         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
76                 return *bp;
77         else
78                 return bp->expand(options);
79 }
80
81 /** Compute partial derivative of an expression.
82  *
83  *  @param s  symbol by which the expression is derived
84  *  @param nth  order of derivative (default 1)
85  *  @return partial derivative as a new expression */
86 ex ex::diff(const symbol & s, unsigned nth) const
87 {
88         if (!nth)
89                 return *this;
90         else
91                 return bp->diff(s, nth);
92 }
93
94 /** Check whether expression matches a specified pattern. */
95 bool ex::match(const ex & pattern) const
96 {
97         lst repl_lst;
98         return bp->match(pattern, repl_lst);
99 }
100
101 /** Find all occurrences of a pattern. The found matches are appended to
102  *  the "found" list. If the expression itself matches the pattern, the
103  *  children are not further examined. This function returns true when any
104  *  matches were found. */
105 bool ex::find(const ex & pattern, lst & found) const
106 {
107         if (match(pattern)) {
108                 found.append(*this);
109                 found.sort();
110                 found.unique();
111                 return true;
112         }
113         bool any_found = false;
114         for (size_t i=0; i<nops(); i++)
115                 if (op(i).find(pattern, found))
116                         any_found = true;
117         return any_found;
118 }
119
120 /** Traverse expression tree with given visitor, preorder traversal. */
121 void ex::traverse_preorder(visitor & v) const
122 {
123         accept(v);
124
125         size_t n = nops();
126         for (size_t i = 0; i < n; ++i)
127                 op(i).traverse_preorder(v);
128 }
129
130 /** Traverse expression tree with given visitor, postorder traversal. */
131 void ex::traverse_postorder(visitor & v) const
132 {
133         size_t n = nops();
134         for (size_t i = 0; i < n; ++i)
135                 op(i).traverse_postorder(v);
136
137         accept(v);
138 }
139
140 /** Return modifyable operand/member at position i. */
141 ex & ex::let_op(size_t i)
142 {
143         makewriteable();
144         return bp->let_op(i);
145 }
146
147 ex & ex::operator[](const ex & index)
148 {
149         makewriteable();
150         return (*bp)[index];
151 }
152
153 ex & ex::operator[](size_t i)
154 {
155         makewriteable();
156         return (*bp)[i];
157 }
158
159 /** Left hand side of relational expression. */
160 ex ex::lhs() const
161 {
162         if (!is_a<relational>(*this))
163                 throw std::runtime_error("ex::lhs(): not a relation");
164         return bp->op(0);
165 }
166
167 /** Right hand side of relational expression. */
168 ex ex::rhs() const
169 {
170         if (!is_a<relational>(*this))
171                 throw std::runtime_error("ex::rhs(): not a relation");
172         return bp->op(1);
173 }
174
175 // private
176
177 /** Make this ex writable (if more than one ex handle the same basic) by 
178  *  unlinking the object and creating an unshared copy of it. */
179 void ex::makewriteable()
180 {
181         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
182         bp.makewritable();
183         GINAC_ASSERT(bp->refcount == 1);
184 }
185
186 /** Helper function for the ex-from-basic constructor. This is where GiNaC's
187  *  automatic evaluator and memory management are implemented.
188  *  @see ex::ex(const basic &) */
189 ptr<basic> ex::construct_from_basic(const basic & other)
190 {
191         if (!(other.flags & status_flags::evaluated)) {
192
193                 // The object is not yet evaluated, so call eval() to evaluate
194                 // the top level. This will return either
195                 //  a) the original object with status_flags::evaluated set (when the
196                 //     eval() implementation calls hold())
197                 // or
198                 //  b) a different expression.
199                 //
200                 // eval() returns an ex, not a basic&, so this will go through
201                 // construct_from_basic() a second time. In case a) we end up in
202                 // the "else" branch below. In case b) we end up here again and
203                 // apply eval() once more. The recursion stops when eval() calls
204                 // hold() or returns an object that already has its "evaluated"
205                 // flag set, such as a symbol or a numeric.
206                 const ex & tmpex = other.eval(1);
207
208                 // Eventually, the eval() recursion goes through the "else" branch
209                 // below, which assures that the object pointed to by tmpex.bp is
210                 // allocated on the heap (either it was already on the heap or it
211                 // is a heap-allocated duplicate of another object).
212                 GINAC_ASSERT(tmpex.bp->flags & status_flags::dynallocated); 
213
214                 // If the original object is not referenced but heap-allocated,
215                 // it means that eval() hit case b) above. The original object is
216                 // no longer needed (it evaluated into something different), so we
217                 // delete it (because nobody else will).
218                 if ((other.refcount==0) && (other.flags & status_flags::dynallocated))
219                         delete &other; // yes, you can apply delete to a const pointer
220
221                 // We can't return a basic& here because the tmpex is destroyed as
222                 // soon as we leave the function, which would deallocate the
223                 // evaluated object.
224                 return tmpex.bp;
225
226         } else {
227
228                 // The easy case: making an "ex" out of an evaluated object.
229                 if (other.flags & status_flags::dynallocated) {
230
231                         // The object is already heap-allocated, so we can just make
232                         // another reference to it.
233                         return ptr<basic>(const_cast<basic &>(other));
234
235                 } else {
236
237                         // The object is not heap-allocated, so we create a duplicate
238                         // on the heap.
239                         basic *bp = other.duplicate();
240                         bp->setflag(status_flags::dynallocated);
241                         GINAC_ASSERT(bp->refcount == 0);
242                         return bp;
243                 }
244         }
245 }
246
247 basic & ex::construct_from_int(int i)
248 {
249         switch (i) {  // prefer flyweights over new objects
250         case -12:
251                 return const_cast<numeric &>(_num_12);
252         case -11:
253                 return const_cast<numeric &>(_num_11);
254         case -10:
255                 return const_cast<numeric &>(_num_10);
256         case -9:
257                 return const_cast<numeric &>(_num_9);
258         case -8:
259                 return const_cast<numeric &>(_num_8);
260         case -7:
261                 return const_cast<numeric &>(_num_7);
262         case -6:
263                 return const_cast<numeric &>(_num_6);
264         case -5:
265                 return const_cast<numeric &>(_num_5);
266         case -4:
267                 return const_cast<numeric &>(_num_4);
268         case -3:
269                 return const_cast<numeric &>(_num_3);
270         case -2:
271                 return const_cast<numeric &>(_num_2);
272         case -1:
273                 return const_cast<numeric &>(_num_1);
274         case 0:
275                 return const_cast<numeric &>(_num0);
276         case 1:
277                 return const_cast<numeric &>(_num1);
278         case 2:
279                 return const_cast<numeric &>(_num2);
280         case 3:
281                 return const_cast<numeric &>(_num3);
282         case 4:
283                 return const_cast<numeric &>(_num4);
284         case 5:
285                 return const_cast<numeric &>(_num5);
286         case 6:
287                 return const_cast<numeric &>(_num6);
288         case 7:
289                 return const_cast<numeric &>(_num7);
290         case 8:
291                 return const_cast<numeric &>(_num8);
292         case 9:
293                 return const_cast<numeric &>(_num9);
294         case 10:
295                 return const_cast<numeric &>(_num10);
296         case 11:
297                 return const_cast<numeric &>(_num11);
298         case 12:
299                 return const_cast<numeric &>(_num12);
300         default:
301                 basic *bp = new numeric(i);
302                 bp->setflag(status_flags::dynallocated);
303                 GINAC_ASSERT(bp->refcount == 0);
304                 return *bp;
305         }
306 }
307         
308 basic & ex::construct_from_uint(unsigned int i)
309 {
310         switch (i) {  // prefer flyweights over new objects
311         case 0:
312                 return const_cast<numeric &>(_num0);
313         case 1:
314                 return const_cast<numeric &>(_num1);
315         case 2:
316                 return const_cast<numeric &>(_num2);
317         case 3:
318                 return const_cast<numeric &>(_num3);
319         case 4:
320                 return const_cast<numeric &>(_num4);
321         case 5:
322                 return const_cast<numeric &>(_num5);
323         case 6:
324                 return const_cast<numeric &>(_num6);
325         case 7:
326                 return const_cast<numeric &>(_num7);
327         case 8:
328                 return const_cast<numeric &>(_num8);
329         case 9:
330                 return const_cast<numeric &>(_num9);
331         case 10:
332                 return const_cast<numeric &>(_num10);
333         case 11:
334                 return const_cast<numeric &>(_num11);
335         case 12:
336                 return const_cast<numeric &>(_num12);
337         default:
338                 basic *bp = new numeric(i);
339                 bp->setflag(status_flags::dynallocated);
340                 GINAC_ASSERT(bp->refcount == 0);
341                 return *bp;
342         }
343 }
344         
345 basic & ex::construct_from_long(long i)
346 {
347         switch (i) {  // prefer flyweights over new objects
348         case -12:
349                 return const_cast<numeric &>(_num_12);
350         case -11:
351                 return const_cast<numeric &>(_num_11);
352         case -10:
353                 return const_cast<numeric &>(_num_10);
354         case -9:
355                 return const_cast<numeric &>(_num_9);
356         case -8:
357                 return const_cast<numeric &>(_num_8);
358         case -7:
359                 return const_cast<numeric &>(_num_7);
360         case -6:
361                 return const_cast<numeric &>(_num_6);
362         case -5:
363                 return const_cast<numeric &>(_num_5);
364         case -4:
365                 return const_cast<numeric &>(_num_4);
366         case -3:
367                 return const_cast<numeric &>(_num_3);
368         case -2:
369                 return const_cast<numeric &>(_num_2);
370         case -1:
371                 return const_cast<numeric &>(_num_1);
372         case 0:
373                 return const_cast<numeric &>(_num0);
374         case 1:
375                 return const_cast<numeric &>(_num1);
376         case 2:
377                 return const_cast<numeric &>(_num2);
378         case 3:
379                 return const_cast<numeric &>(_num3);
380         case 4:
381                 return const_cast<numeric &>(_num4);
382         case 5:
383                 return const_cast<numeric &>(_num5);
384         case 6:
385                 return const_cast<numeric &>(_num6);
386         case 7:
387                 return const_cast<numeric &>(_num7);
388         case 8:
389                 return const_cast<numeric &>(_num8);
390         case 9:
391                 return const_cast<numeric &>(_num9);
392         case 10:
393                 return const_cast<numeric &>(_num10);
394         case 11:
395                 return const_cast<numeric &>(_num11);
396         case 12:
397                 return const_cast<numeric &>(_num12);
398         default:
399                 basic *bp = new numeric(i);
400                 bp->setflag(status_flags::dynallocated);
401                 GINAC_ASSERT(bp->refcount == 0);
402                 return *bp;
403         }
404 }
405         
406 basic & ex::construct_from_ulong(unsigned long i)
407 {
408         switch (i) {  // prefer flyweights over new objects
409         case 0:
410                 return const_cast<numeric &>(_num0);
411         case 1:
412                 return const_cast<numeric &>(_num1);
413         case 2:
414                 return const_cast<numeric &>(_num2);
415         case 3:
416                 return const_cast<numeric &>(_num3);
417         case 4:
418                 return const_cast<numeric &>(_num4);
419         case 5:
420                 return const_cast<numeric &>(_num5);
421         case 6:
422                 return const_cast<numeric &>(_num6);
423         case 7:
424                 return const_cast<numeric &>(_num7);
425         case 8:
426                 return const_cast<numeric &>(_num8);
427         case 9:
428                 return const_cast<numeric &>(_num9);
429         case 10:
430                 return const_cast<numeric &>(_num10);
431         case 11:
432                 return const_cast<numeric &>(_num11);
433         case 12:
434                 return const_cast<numeric &>(_num12);
435         default:
436                 basic *bp = new numeric(i);
437                 bp->setflag(status_flags::dynallocated);
438                 GINAC_ASSERT(bp->refcount == 0);
439                 return *bp;
440         }
441 }
442         
443 basic & ex::construct_from_double(double d)
444 {
445         basic *bp = new numeric(d);
446         bp->setflag(status_flags::dynallocated);
447         GINAC_ASSERT(bp->refcount == 0);
448         return *bp;
449 }
450
451 ptr<basic> ex::construct_from_string_and_lst(const std::string &s, const ex &l)
452 {
453         set_lexer_string(s);
454         set_lexer_symbols(l);
455         ginac_yyrestart(NULL);
456         if (ginac_yyparse())
457                 throw (std::runtime_error(get_parser_error()));
458         else
459                 return parsed_ex.bp;
460 }
461         
462 //////////
463 // static member variables
464 //////////
465
466 // none
467
468 //////////
469 // functions which are not member functions
470 //////////
471
472 // none
473
474 //////////
475 // global functions
476 //////////
477
478 // none
479
480
481 } // namespace GiNaC