]> www.ginac.de Git - ginac.git/blob - ginac/ex.cpp
- enforced GiNaC coding standards :-)
[ginac.git] / ginac / ex.cpp
1 /** @file ex.cpp
2  *
3  *  Implementation of GiNaC's light-weight expression handles.
4  *
5  *  GiNaC Copyright (C) 1999 Johannes Gutenberg University Mainz, Germany
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <iostream>
23
24 #include "ginac.h"
25
26 //////////
27 // default constructor, destructor, copy constructor assignment operator and helpers
28 //////////
29
30 // public
31
32 #ifndef INLINE_EX_CONSTRUCTORS
33
34 ex::ex() : bp(exZERO().bp)
35 {
36     debugmsg("ex default constructor",LOGLEVEL_CONSTRUCT);
37     ASSERT(exZERO().bp!=0);
38     ASSERT(exZERO().bp->flags & status_flags::dynallocated);
39     ASSERT(bp!=0);
40     ++bp->refcount;
41 }
42
43 ex::~ex()
44 {
45     debugmsg("ex destructor",LOGLEVEL_DESTRUCT);
46     ASSERT(bp!=0);
47     ASSERT(bp->flags & status_flags::dynallocated);
48     if (--bp->refcount == 0) {
49         delete bp;
50     }
51 }
52
53 ex::ex(ex const & other) : bp(other.bp)
54 {
55     debugmsg("ex copy constructor",LOGLEVEL_CONSTRUCT);
56     ASSERT(bp!=0);
57     ASSERT((bp->flags) & status_flags::dynallocated);
58     ++bp->refcount;
59 }
60
61 ex const & ex::operator=(ex const & other)
62 {
63     debugmsg("ex operator=",LOGLEVEL_ASSIGNMENT);
64     ASSERT(bp!=0);
65     ASSERT(bp->flags & status_flags::dynallocated);
66     ASSERT(other.bp!=0);
67     ASSERT(other.bp->flags & status_flags::dynallocated);
68     ++other.bp->refcount;
69     basic * tmpbp=other.bp;
70     if (--bp->refcount==0) {
71             delete bp;
72     }
73     bp=tmpbp;
74     return *this;
75 }
76
77 #endif // ndef INLINE_EX_CONSTRUCTORS
78
79 //////////
80 // other constructors
81 //////////
82
83 // public
84
85 #ifndef INLINE_EX_CONSTRUCTORS
86 ex::ex(basic const & other)
87 {
88     debugmsg("ex constructor from basic",LOGLEVEL_CONSTRUCT);
89     construct_from_basic(other);
90 }
91 #endif
92
93 ex::ex(int const i)
94 {
95     debugmsg("ex constructor from int",LOGLEVEL_CONSTRUCT);
96     construct_from_basic(numeric(i));
97 }
98
99 ex::ex(unsigned int const i)
100 {
101     debugmsg("ex constructor from unsigned int",LOGLEVEL_CONSTRUCT);
102     construct_from_basic(numeric(i));
103 }
104
105 ex::ex(long const i)
106 {
107     debugmsg("ex constructor from long",LOGLEVEL_CONSTRUCT);
108     construct_from_basic(numeric(i));
109 }
110
111 ex::ex(unsigned long const i)
112 {
113     debugmsg("ex constructor from unsigned long",LOGLEVEL_CONSTRUCT);
114     construct_from_basic(numeric(i));
115 }
116
117 ex::ex(double const d)
118 {
119     debugmsg("ex constructor from double",LOGLEVEL_CONSTRUCT);
120     construct_from_basic(numeric(d));
121 }
122     
123 //////////
124 // functions overriding virtual functions from bases classes
125 //////////
126
127 // none
128
129 //////////
130 // new virtual functions which can be overridden by derived classes
131 //////////
132
133 // none
134
135 //////////
136 // non-virtual functions in this class
137 //////////
138
139 // public
140
141 void ex::swap(ex & other)
142 {
143     debugmsg("ex swap",LOGLEVEL_MEMBER_FUNCTION);
144
145     ASSERT(bp!=0);
146     ASSERT(bp->flags & status_flags::dynallocated);
147     ASSERT(other.bp!=0);
148     ASSERT(other.bp->flags & status_flags::dynallocated);
149     
150     basic * tmpbp=bp;
151     bp=other.bp;
152     other.bp=tmpbp;
153 }
154
155 bool ex::info(unsigned inf) const
156 {
157     if (inf == info_flags::normal_form) {
158
159     // Polynomials are in normal form
160     if (info(info_flags::polynomial))
161         return true;
162
163     // polynomial^(-int) is in normal form
164     if (is_ex_exactly_of_type(*this, power))
165         return op(1).info(info_flags::negint);
166
167     // polynomial^(int) * polynomial^(int) * ... is in normal form
168     if (!is_ex_exactly_of_type(*this, mul))
169         return false;
170     for (int i=0; i<nops(); i++) {
171         if (is_ex_exactly_of_type(op(i), power)) {
172             if (!op(i).op(1).info(info_flags::integer))
173                 return false;
174             if (!op(i).op(0).info(info_flags::polynomial))
175                 return false;
176         } else
177             if (!op(i).info(info_flags::polynomial))
178                 return false;
179     }
180     return true;
181     } else {
182         return bp->info(inf);
183     }
184 }
185
186 int ex::nops() const
187 {
188     ASSERT(bp!=0);
189     return bp->nops();
190 }
191
192 ex ex::expand(unsigned options) const
193 {
194     ASSERT(bp!=0);
195     return bp->expand(options);
196 }
197
198 bool ex::has(ex const & other) const
199 {
200     ASSERT(bp!=0);
201     return bp->has(other);
202 }
203
204 int ex::degree(symbol const & s) const
205 {
206     ASSERT(bp!=0);
207     return bp->degree(s);
208 }
209
210 int ex::ldegree(symbol const & s) const
211 {
212     ASSERT(bp!=0);
213     return bp->ldegree(s);
214 }
215
216 ex ex::coeff(symbol const & s, int const n) const
217 {
218     ASSERT(bp!=0);
219     return bp->coeff(s,n);
220 }
221
222 ex ex::numer(bool normalize) const
223 {
224     ex n;
225     if (normalize && !info(info_flags::normal_form))
226         n = normal();
227     else
228         n = *this;
229
230     // polynomial
231     if (n.info(info_flags::polynomial))
232         return n;
233
234     // something^(-int)
235     if (is_ex_exactly_of_type(n, power) && n.op(1).info(info_flags::negint))
236         return exONE();
237
238     // something^(int) * something^(int) * ...
239     if (!is_ex_exactly_of_type(n, mul))
240         return n;
241     ex res = exONE();
242     for (int i=0; i<n.nops(); i++) {
243         if (!is_ex_exactly_of_type(n.op(i), power) || !n.op(i).op(1).info(info_flags::negint))
244             res *= n.op(i);
245     }
246     return res;
247 }
248
249 ex ex::denom(bool normalize) const
250 {
251     ex n;
252     if (normalize && !info(info_flags::normal_form))
253         n = normal();
254     else
255         n = *this;
256
257     // polynomial
258     if (n.info(info_flags::polynomial))
259         return exONE();
260
261     // something^(-int)
262     if (is_ex_exactly_of_type(n, power) && n.op(1).info(info_flags::negint))
263         return power(n.op(0), -(n.op(1)));
264
265     // something^(int) * something^(int) * ...
266     if (!is_ex_exactly_of_type(n, mul))
267         return exONE();
268     ex res = exONE();
269     for (int i=0; i<n.nops(); i++) {
270         if (is_ex_exactly_of_type(n.op(i), power) && n.op(i).op(1).info(info_flags::negint))
271             res *= power(n.op(i), -1);
272     }
273     return res;
274 }
275
276 ex ex::collect(symbol const & s) const
277 {
278     ASSERT(bp!=0);
279     return bp->collect(s);
280 }
281
282 ex ex::eval(int level) const
283 {
284     ASSERT(bp!=0);
285     return bp->eval(level);
286 }
287
288 ex ex::evalf(int level) const
289 {
290     ASSERT(bp!=0);
291     return bp->evalf(level);
292 }
293
294 ex ex::subs(lst const & ls, lst const & lr) const
295 {
296     ASSERT(bp!=0);
297     return bp->subs(ls,lr);
298 }
299
300 ex ex::subs(ex const & e) const
301 {
302     ASSERT(bp!=0);
303     return bp->subs(e);
304 }
305
306 exvector ex::get_indices(void) const
307 {
308     ASSERT(bp!=0);
309     return bp->get_indices();
310 }
311
312 ex ex::simplify_ncmul(exvector const & v) const
313 {
314     ASSERT(bp!=0);
315     return bp->simplify_ncmul(v);
316 }
317
318 ex ex::operator[](ex const & index) const
319 {
320     debugmsg("ex operator[ex]",LOGLEVEL_OPERATOR);
321     ASSERT(bp!=0);
322     return (*bp)[index];
323 }
324
325 ex ex::operator[](int const i) const
326 {
327     debugmsg("ex operator[int]",LOGLEVEL_OPERATOR);
328     ASSERT(bp!=0);
329     return (*bp)[i];
330 }
331
332 ex ex::op(int const i) const
333 {
334     debugmsg("ex op()",LOGLEVEL_MEMBER_FUNCTION);
335     ASSERT(bp!=0);
336     return bp->op(i);
337 }
338
339 ex & ex::let_op(int const i)
340 {
341     debugmsg("ex let_op()",LOGLEVEL_MEMBER_FUNCTION);
342     makewriteable();
343     ASSERT(bp!=0);
344     return bp->let_op(i);
345 }
346
347 #ifndef INLINE_EX_CONSTRUCTORS
348 int ex::compare(ex const & other) const
349 {
350     ASSERT(bp!=0);
351     ASSERT(other.bp!=0);
352     if (bp==other.bp) {
353         // special case: both expression point to same basic, trivially equal
354         return 0; 
355     }
356     return bp->compare(*other.bp);
357 }
358 #endif // ndef INLINE_EX_CONSTRUCTORS
359
360 #ifndef INLINE_EX_CONSTRUCTORS
361 bool ex::is_equal(ex const & other) const
362 {
363     ASSERT(bp!=0);
364     ASSERT(other.bp!=0);
365     if (bp==other.bp) {
366         // special case: both expression point to same basic, trivially equal
367         return true; 
368     }
369     return bp->is_equal(*other.bp);
370 }
371 #endif // ndef INLINE_EX_CONSTRUCTORS
372
373 unsigned ex::return_type(void) const
374 {
375     ASSERT(bp!=0);
376     return bp->return_type();
377 }
378
379 unsigned ex::return_type_tinfo(void) const
380 {
381     ASSERT(bp!=0);
382     return bp->return_type_tinfo();
383 }
384
385 unsigned ex::gethash(void) const
386 {
387     ASSERT(bp!=0);
388     return bp->gethash();
389 }
390
391 ex ex::exadd(ex const & rh) const
392 {
393     return (new add(*this,rh))->setflag(status_flags::dynallocated);
394 }
395
396 ex ex::exmul(ex const & rh) const
397 {
398     return (new mul(*this,rh))->setflag(status_flags::dynallocated);
399 }
400
401 ex ex::exncmul(ex const & rh) const
402 {
403     return (new ncmul(*this,rh))->setflag(status_flags::dynallocated);
404 }
405
406 // private
407
408 void ex::makewriteable()
409 {
410     debugmsg("ex makewriteable",LOGLEVEL_MEMBER_FUNCTION);
411     ASSERT(bp!=0);
412     ASSERT(bp->flags & status_flags::dynallocated);
413     if (bp->refcount > 1) {
414         basic * bp2=bp->duplicate();
415         ++bp2->refcount;
416         bp2->setflag(status_flags::dynallocated);
417         --bp->refcount;
418         bp=bp2;
419     }
420     ASSERT(bp->refcount == 1);
421 }    
422
423 void ex::construct_from_basic(basic const & other)
424 {
425     if ( (other.flags & status_flags::evaluated)==0 ) {
426         // cf. copy constructor
427         ex const & tmpex = other.eval(1); // evaluate only one (top) level
428         bp = tmpex.bp;
429         ASSERT(bp!=0);
430         ASSERT(bp->flags & status_flags::dynallocated);
431         ++bp->refcount;
432         if ((other.flags & status_flags::dynallocated)&&(other.refcount==0)) {
433             delete &const_cast<basic &>(other);
434         }
435     } else {
436         if (other.flags & status_flags::dynallocated) {
437             bp=&const_cast<basic &>(other);
438         } else {
439             bp=other.duplicate();
440             bp->setflag(status_flags::dynallocated);
441         }
442         ASSERT(bp!=0);
443         // bp->clearflag(status_flags::evaluated);
444         ++bp->refcount;
445     }
446     ASSERT(bp!=0);
447     ASSERT(bp->flags & status_flags::dynallocated);
448 }
449
450 //////////
451 // static member variables
452 //////////
453
454 // none
455
456 //////////
457 // functions which are not member functions
458 //////////
459
460 // none
461
462 //////////
463 // global functions
464 //////////
465
466 ex const & exZERO(void)
467 {
468     static ex * eZERO=new ex(numZERO());
469     return *eZERO;
470 }
471
472 ex const & exONE(void)
473 {
474     static ex * eONE=new ex(numONE());
475     return *eONE;
476 }
477
478 ex const & exTWO(void)
479 {
480     static ex * eTWO=new ex(numTWO());
481     return *eTWO;
482 }
483
484 ex const & exTHREE(void)
485 {
486     static ex * eTHREE=new ex(numTHREE());
487     return *eTHREE;
488 }
489
490 ex const & exMINUSONE(void)
491 {
492     static ex * eMINUSONE=new ex(numMINUSONE());
493     return *eMINUSONE;
494 }
495
496 ex const & exHALF(void)
497 {
498     static ex * eHALF=new ex(ex(1)/ex(2));
499     return *eHALF;
500 }
501
502 ex const & exMINUSHALF(void)
503 {
504     static ex * eMINUSHALF=new ex(numeric(-1,2));
505     return *eMINUSHALF;
506 }
507