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