]> www.ginac.de Git - ginac.git/blob - ginac/ex.cpp
6acde9f97f1d58b952e4d53d6246bb06208789cf
[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 #if defined(VERBOSE)
27 #  define GINAC_CONDITIONAL_INLINE
28 #  include "ex.h"
29 #  undef GINAC_CONDITIONAL_INLINE
30 #else
31 #  include "ex.h"
32 #endif
33
34 #include "add.h"
35 #include "mul.h"
36 #include "ncmul.h"
37 #include "numeric.h"
38 #include "power.h"
39 #include "relational.h"
40 #include "input_lexer.h"
41 #include "debugmsg.h"
42 #include "utils.h"
43
44 namespace GiNaC {
45
46 //////////
47 // other ctors
48 //////////
49
50 // none (all inlined)
51
52 //////////
53 // functions overriding virtual functions from bases classes
54 //////////
55
56 // none
57
58 //////////
59 // new virtual functions which can be overridden by derived classes
60 //////////
61
62 // none
63
64 //////////
65 // non-virtual functions in this class
66 //////////
67
68 // public
69
70 /** Efficiently swap the contents of two expressions. */
71 void ex::swap(ex & other)
72 {
73         debugmsg("ex swap",LOGLEVEL_MEMBER_FUNCTION);
74
75         GINAC_ASSERT(bp!=0);
76         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
77         GINAC_ASSERT(other.bp!=0);
78         GINAC_ASSERT(other.bp->flags & status_flags::dynallocated);
79         
80         basic * tmpbp = bp;
81         bp = other.bp;
82         other.bp = tmpbp;
83 }
84
85 /** Output formatted to be useful as ginsh input. */
86 void ex::print(std::ostream & os, unsigned upper_precedence) const
87 {
88         debugmsg("ex print",LOGLEVEL_PRINT);
89         GINAC_ASSERT(bp!=0);
90         bp->print(os,upper_precedence);
91 }
92
93 /** Unreadable output with detailed type information. */
94 void ex::printraw(std::ostream & os) const
95 {
96         debugmsg("ex printraw",LOGLEVEL_PRINT);
97         GINAC_ASSERT(bp!=0);
98         os << "ex(";
99         bp->printraw(os);
100         os << ")";
101 }
102
103 /** Very detailed and unreadable output with type information and all this. */
104 void ex::printtree(std::ostream & os, unsigned indent) const
105 {
106         debugmsg("ex printtree",LOGLEVEL_PRINT);
107         GINAC_ASSERT(bp!=0);
108         // os << "refcount=" << bp->refcount << " ";
109         bp->printtree(os,indent);
110 }
111
112 /** Print expression as a C++ statement. The output looks like
113  *  "<type> <var_name> = <expression>;". The "type" parameter has an effect
114  *  on how number literals are printed.
115  *
116  *  @param os output stream
117  *  @param type variable type (one of the csrc_types)
118  *  @param var_name variable name to be printed */
119 void ex::printcsrc(std::ostream & os, unsigned type, const char *var_name) const
120 {
121         debugmsg("ex print csrc", LOGLEVEL_PRINT);
122         GINAC_ASSERT(bp!=0);
123         switch (type) {
124                 case csrc_types::ctype_float:
125                         os << "float ";
126                         break;
127                 case csrc_types::ctype_double:
128                         os << "double ";
129                         break;
130                 case csrc_types::ctype_cl_N:
131                         os << "cl_N ";
132                         break;
133         }
134         os << var_name << " = ";
135         bp->printcsrc(os, type, 0);
136         os << ";\n";
137 }
138
139 /** Little wrapper arount print to be called within a debugger. */
140 void ex::dbgprint(void) const
141 {
142         debugmsg("ex dbgprint",LOGLEVEL_PRINT);
143         GINAC_ASSERT(bp!=0);
144         bp->dbgprint();
145 }
146
147 /** Little wrapper arount printtree to be called within a debugger. */
148 void ex::dbgprinttree(void) const
149 {
150         debugmsg("ex dbgprinttree",LOGLEVEL_PRINT);
151         GINAC_ASSERT(bp!=0);
152         bp->dbgprinttree();
153 }
154
155 bool ex::info(unsigned inf) const
156 {
157         return bp->info(inf);
158 }
159
160 unsigned ex::nops() const
161 {
162         GINAC_ASSERT(bp!=0);
163         return bp->nops();
164 }
165
166 ex ex::expand(unsigned options) const
167 {
168         GINAC_ASSERT(bp!=0);
169         if (bp->flags & status_flags::expanded)
170                 return *bp;
171         else
172                 return bp->expand(options);
173 }
174
175 bool ex::has(const ex & other) const
176 {
177         GINAC_ASSERT(bp!=0);
178         return bp->has(other);
179 }
180
181 int ex::degree(const symbol & s) const
182 {
183         GINAC_ASSERT(bp!=0);
184         return bp->degree(s);
185 }
186
187 int ex::ldegree(const symbol & s) const
188 {
189         GINAC_ASSERT(bp!=0);
190         return bp->ldegree(s);
191 }
192
193 ex ex::coeff(const symbol & s, int n) const
194 {
195         GINAC_ASSERT(bp!=0);
196         return bp->coeff(s,n);
197 }
198
199 ex ex::collect(const symbol & s) const
200 {
201         GINAC_ASSERT(bp!=0);
202         return bp->collect(s);
203 }
204
205 ex ex::eval(int level) const
206 {
207         GINAC_ASSERT(bp!=0);
208         return bp->eval(level);
209 }
210
211 ex ex::evalf(int level) const
212 {
213         GINAC_ASSERT(bp!=0);
214         return bp->evalf(level);
215 }
216
217 /** Compute partial derivative of an expression.
218  *
219  *  @param s  symbol by which the expression is derived
220  *  @param nth  order of derivative (default 1)
221  *  @return partial derivative as a new expression */
222 ex ex::diff(const symbol & s, unsigned nth) const
223 {
224         GINAC_ASSERT(bp!=0);
225
226         if (!nth)
227                 return *this;
228         else
229                 return bp->diff(s, nth);
230 }
231
232 ex ex::subs(const lst & ls, const lst & lr) const
233 {
234         GINAC_ASSERT(bp!=0);
235         return bp->subs(ls,lr);
236 }
237
238 ex ex::subs(const ex & e) const
239 {
240         GINAC_ASSERT(bp!=0);
241         return bp->subs(e);
242 }
243
244 exvector ex::get_indices(void) const
245 {
246         GINAC_ASSERT(bp!=0);
247         return bp->get_indices();
248 }
249
250 ex ex::simplify_ncmul(const exvector & v) const
251 {
252         GINAC_ASSERT(bp!=0);
253         return bp->simplify_ncmul(v);
254 }
255
256 ex ex::operator[](const ex & index) const
257 {
258         debugmsg("ex operator[ex]",LOGLEVEL_OPERATOR);
259         GINAC_ASSERT(bp!=0);
260         return (*bp)[index];
261 }
262
263 ex ex::operator[](int i) const
264 {
265         debugmsg("ex operator[int]",LOGLEVEL_OPERATOR);
266         GINAC_ASSERT(bp!=0);
267         return (*bp)[i];
268 }
269
270 /** Return operand/member at position i. */
271 ex ex::op(int i) const
272 {
273         debugmsg("ex op()",LOGLEVEL_MEMBER_FUNCTION);
274         GINAC_ASSERT(bp!=0);
275         return bp->op(i);
276 }
277
278 /** Return modifyable operand/member at position i. */
279 ex & ex::let_op(int i)
280 {
281         debugmsg("ex let_op()",LOGLEVEL_MEMBER_FUNCTION);
282         makewriteable();
283         GINAC_ASSERT(bp!=0);
284         return bp->let_op(i);
285 }
286
287 /** Left hand side of relational expression. */
288 ex ex::lhs(void) const
289 {
290         debugmsg("ex lhs()",LOGLEVEL_MEMBER_FUNCTION);
291         GINAC_ASSERT(is_ex_of_type(*this,relational));
292         return (*static_cast<relational *>(bp)).lhs();
293 }
294
295 /** Right hand side of relational expression. */
296 ex ex::rhs(void) const
297 {
298         debugmsg("ex rhs()",LOGLEVEL_MEMBER_FUNCTION);
299         GINAC_ASSERT(is_ex_of_type(*this,relational));
300         return (*static_cast<relational *>(bp)).rhs();
301 }
302
303 unsigned ex::return_type(void) const
304 {
305         GINAC_ASSERT(bp!=0);
306         return bp->return_type();
307 }
308
309 unsigned ex::return_type_tinfo(void) const
310 {
311         GINAC_ASSERT(bp!=0);
312         return bp->return_type_tinfo();
313 }
314
315 unsigned ex::gethash(void) const
316 {
317         GINAC_ASSERT(bp!=0);
318         return bp->gethash();
319 }
320
321 ex ex::exadd(const ex & rh) const
322 {
323         return (new add(*this,rh))->setflag(status_flags::dynallocated);
324 }
325
326 ex ex::exmul(const ex & rh) const
327 {
328         return (new mul(*this,rh))->setflag(status_flags::dynallocated);
329 }
330
331 ex ex::exncmul(const ex & rh) const
332 {
333         return (new ncmul(*this,rh))->setflag(status_flags::dynallocated);
334 }
335
336 // private
337
338 /** Make this ex writable (if more than one ex handle the same basic) by 
339  *  unlinking the object and creating an unshared copy of it. */
340 void ex::makewriteable()
341 {
342         debugmsg("ex makewriteable",LOGLEVEL_MEMBER_FUNCTION);
343         GINAC_ASSERT(bp!=0);
344         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
345         if (bp->refcount > 1) {
346                 basic * bp2 = bp->duplicate();
347                 ++bp2->refcount;
348                 bp2->setflag(status_flags::dynallocated);
349                 --bp->refcount;
350                 bp = bp2;
351         }
352         GINAC_ASSERT(bp->refcount==1);
353 }
354
355 /** Ctor from basic implementation.
356  *  @see ex::ex(const basic &) */
357 void ex::construct_from_basic(const basic & other)
358 {
359         if ((other.flags & status_flags::evaluated)==0) {
360                 // cf. copy ctor
361                 const ex & tmpex = other.eval(1); // evaluate only one (top) level
362                 bp = tmpex.bp;
363                 GINAC_ASSERT(bp!=0);
364                 GINAC_ASSERT(bp->flags & status_flags::dynallocated);
365                 ++bp->refcount;
366                 if ((other.flags & status_flags::dynallocated)&&(other.refcount==0))
367                         delete &const_cast<basic &>(other);
368         } else {
369                 if (other.flags & status_flags::dynallocated) {
370                         // ok, it is already on the heap, so just copy bp:
371                         bp = &const_cast<basic &>(other);
372                 } else {
373                         // create a duplicate on the heap:
374                         bp = other.duplicate();
375                         bp->setflag(status_flags::dynallocated);
376                 }
377                 GINAC_ASSERT(bp!=0);
378                 // bp->clearflag(status_flags::evaluated);
379                 ++bp->refcount;
380         }
381         GINAC_ASSERT(bp!=0);
382         GINAC_ASSERT(bp->flags & status_flags::dynallocated);
383 }
384
385 void ex::construct_from_int(int i)
386 {
387         switch (i) {  // some tiny efficiency-hack
388         case -2:
389                 bp = _ex_2().bp;
390                 ++bp->refcount;
391                 break;
392         case -1:
393                 bp = _ex_1().bp;
394                 ++bp->refcount;
395                 break;
396         case 0:
397                 bp = _ex0().bp;
398                 ++bp->refcount;
399                 break;
400         case 1:
401                 bp = _ex1().bp;
402                 ++bp->refcount;
403                 break;
404         case 2:
405                 bp = _ex2().bp;
406                 ++bp->refcount;
407                 break;
408         default:
409                 bp = new numeric(i);
410                 bp->setflag(status_flags::dynallocated);
411                 ++bp->refcount;
412                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
413                 GINAC_ASSERT(bp->refcount==1);
414         }
415 }
416         
417 void ex::construct_from_uint(unsigned int i)
418 {
419         switch (i) {  // some tiny efficiency-hack
420         case 0:
421                 bp = _ex0().bp;
422                 ++bp->refcount;
423                 break;
424         case 1:
425                 bp = _ex1().bp;
426                 ++bp->refcount;
427                 break;
428         case 2:
429                 bp = _ex2().bp;
430                 ++bp->refcount;
431                 break;
432         default:
433                 bp = new numeric(i);
434                 bp->setflag(status_flags::dynallocated);
435                 ++bp->refcount;
436                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
437                 GINAC_ASSERT(bp->refcount==1);
438         }
439 }
440         
441 void ex::construct_from_long(long i)
442 {
443         switch (i) {  // some tiny efficiency-hack
444         case -2:
445                 bp = _ex_2().bp;
446                 ++bp->refcount;
447                 break;
448         case -1:
449                 bp = _ex_1().bp;
450                 ++bp->refcount;
451                 break;
452         case 0:
453                 bp = _ex0().bp;
454                 ++bp->refcount;
455                 break;
456         case 1:
457                 bp = _ex1().bp;
458                 ++bp->refcount;
459                 break;
460         case 2:
461                 bp = _ex2().bp;
462                 ++bp->refcount;
463                 break;
464         default:
465                 bp = new numeric(i);
466                 bp->setflag(status_flags::dynallocated);
467                 ++bp->refcount;
468                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
469                 GINAC_ASSERT(bp->refcount==1);
470         }
471 }
472         
473 void ex::construct_from_ulong(unsigned long i)
474 {
475         switch (i) {  // some tiny efficiency-hack
476         case 0:
477                 bp = _ex0().bp;
478                 ++bp->refcount;
479                 break;
480         case 1:
481                 bp = _ex1().bp;
482                 ++bp->refcount;
483                 break;
484         case 2:
485                 bp = _ex2().bp;
486                 ++bp->refcount;
487                 break;
488         default:
489                 bp = new numeric(i);
490                 bp->setflag(status_flags::dynallocated);
491                 ++bp->refcount;
492                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
493                 GINAC_ASSERT(bp->refcount==1);
494         }
495 }
496         
497 void ex::construct_from_double(double d)
498 {
499         bp = new numeric(d);
500         bp->setflag(status_flags::dynallocated);
501         ++bp->refcount;
502         GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
503         GINAC_ASSERT(bp->refcount==1);
504 }
505
506 void ex::construct_from_string_and_lst(const std::string &s, const ex &l)
507 {
508         set_lexer_string(s);
509         set_lexer_symbols(l);
510         ginac_yyrestart(NULL);
511         if (ginac_yyparse())
512                 throw (std::runtime_error(get_parser_error()));
513         else {
514                 bp = parsed_ex.bp;
515                 GINAC_ASSERT(bp!=0);
516                 GINAC_ASSERT((bp->flags) & status_flags::dynallocated);
517                 ++bp->refcount;
518         }
519 }
520         
521 //////////
522 // static member variables
523 //////////
524
525 // none
526
527 //////////
528 // functions which are not member functions
529 //////////
530
531 // none
532
533 //////////
534 // global functions
535 //////////
536
537 // none
538
539
540 } // namespace GiNaC