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