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