]> www.ginac.de Git - ginac.git/blob - ginac/add.cpp
- Banned exZERO(), exONE(), exMINUSHALF() and all this from the interface.
[ginac.git] / ginac / add.cpp
1 /** @file add.cpp
2  *
3  *  Implementation of GiNaC's sums of expressions. */
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 #include <stdexcept>
25
26 #include "add.h"
27 #include "mul.h"
28 #include "debugmsg.h"
29 #include "utils.h"
30
31 #ifndef NO_GINAC_NAMESPACE
32 namespace GiNaC {
33 #endif // ndef NO_GINAC_NAMESPACE
34
35 //////////
36 // default constructor, destructor, copy constructor assignment operator and helpers
37 //////////
38
39 // public
40
41 add::add()
42 {
43     debugmsg("add default constructor",LOGLEVEL_CONSTRUCT);
44     tinfo_key = TINFO_add;
45 }
46
47 add::~add()
48 {
49     debugmsg("add destructor",LOGLEVEL_DESTRUCT);
50     destroy(0);
51 }
52
53 add::add(add const & other)
54 {
55     debugmsg("add copy constructor",LOGLEVEL_CONSTRUCT);
56     copy(other);
57 }
58
59 add const & add::operator=(add const & other)
60 {
61     debugmsg("add operator=",LOGLEVEL_ASSIGNMENT);
62     if (this != &other) {
63         destroy(1);
64         copy(other);
65     }
66     return *this;
67 }
68
69 // protected
70
71 void add::copy(add const & other)
72 {
73     expairseq::copy(other);
74 }
75
76 void add::destroy(bool call_parent)
77 {
78     if (call_parent) expairseq::destroy(call_parent);
79 }
80
81 //////////
82 // other constructors
83 //////////
84
85 // public
86
87 add::add(ex const & lh, ex const & rh)
88 {
89     debugmsg("add constructor from ex,ex",LOGLEVEL_CONSTRUCT);
90     tinfo_key = TINFO_add;
91     overall_coeff=_ex0();
92     construct_from_2_ex(lh,rh);
93     GINAC_ASSERT(is_canonical());
94 }
95
96 add::add(exvector const & v)
97 {
98     debugmsg("add constructor from exvector",LOGLEVEL_CONSTRUCT);
99     tinfo_key = TINFO_add;
100     overall_coeff=_ex0();
101     construct_from_exvector(v);
102     GINAC_ASSERT(is_canonical());
103 }
104
105 /*
106 add::add(epvector const & v, bool do_not_canonicalize)
107 {
108     debugmsg("add constructor from epvector,bool",LOGLEVEL_CONSTRUCT);
109     tinfo_key = TINFO_add;
110     if (do_not_canonicalize) {
111         seq=v;
112 #ifdef EXPAIRSEQ_USE_HASHTAB
113         combine_same_terms(); // to build hashtab
114 #endif // def EXPAIRSEQ_USE_HASHTAB
115     } else {
116         construct_from_epvector(v);
117     }
118     GINAC_ASSERT(is_canonical());
119 }
120 */
121
122 add::add(epvector const & v)
123 {
124     debugmsg("add constructor from epvector",LOGLEVEL_CONSTRUCT);
125     tinfo_key = TINFO_add;
126     overall_coeff=_ex0();
127     construct_from_epvector(v);
128     GINAC_ASSERT(is_canonical());
129 }
130
131 add::add(epvector const & v, ex const & oc)
132 {
133     debugmsg("add constructor from epvector,ex",LOGLEVEL_CONSTRUCT);
134     tinfo_key = TINFO_add;
135     overall_coeff=oc;
136     construct_from_epvector(v);
137     GINAC_ASSERT(is_canonical());
138 }
139
140 add::add(epvector * vp, ex const & oc)
141 {
142     debugmsg("add constructor from epvector *,ex",LOGLEVEL_CONSTRUCT);
143     tinfo_key = TINFO_add;
144     GINAC_ASSERT(vp!=0);
145     overall_coeff=oc;
146     construct_from_epvector(*vp);
147     delete vp;
148     GINAC_ASSERT(is_canonical());
149 }
150
151 //////////
152 // functions overriding virtual functions from bases classes
153 //////////
154
155 // public
156
157 basic * add::duplicate() const
158 {
159     debugmsg("add duplicate",LOGLEVEL_DUPLICATE);
160     return new add(*this);
161 }
162
163 void add::print(ostream & os, unsigned upper_precedence) const
164 {
165     debugmsg("add print",LOGLEVEL_PRINT);
166     if (precedence<=upper_precedence) os << "(";
167     numeric coeff;
168     bool first=true;
169     for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
170         coeff = ex_to_numeric(cit->coeff);
171         if (!first) {
172             if (coeff.csgn()==-1) os << '-'; else os << '+';
173         } else {
174             if (coeff.csgn()==-1) os << '-';
175             first=false;
176         }
177         if (!coeff.is_equal(_num1()) &&
178             !coeff.is_equal(_num_1())) {
179             if (coeff.csgn()==-1)
180                 (_num_1()*coeff).print(os, precedence);
181             else
182                 coeff.print(os, precedence);
183             os << '*';
184         }
185         os << cit->rest;
186     }
187     // print the overall numeric coefficient, if present:
188     if (!overall_coeff.is_zero()) {
189         if (overall_coeff.info(info_flags::positive)) os << '+';
190         os << overall_coeff;
191     }
192     if (precedence<=upper_precedence) os << ")";
193 }
194
195 void add::printraw(ostream & os) const
196 {
197     debugmsg("add printraw",LOGLEVEL_PRINT);
198
199     os << "+(";
200     for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
201         os << "(";
202         (*it).rest.bp->printraw(os);
203         os << ",";
204         (*it).coeff.bp->printraw(os);        
205         os << "),";
206     }
207     os << ",hash=" << hashvalue << ",flags=" << flags;
208     os << ")";
209 }
210
211 void add::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
212 {
213     debugmsg("add print csrc", LOGLEVEL_PRINT);
214     if (precedence <= upper_precedence)
215         os << "(";
216
217     // Print arguments, separated by "+"
218     epvector::const_iterator it = seq.begin();
219     epvector::const_iterator itend = seq.end();
220     while (it != itend) {
221
222         // If the coefficient is -1, it is replaced by a single minus sign
223         if (it->coeff.compare(_num1()) == 0) {
224             it->rest.bp->printcsrc(os, type, precedence);
225         } else if (it->coeff.compare(_num_1()) == 0) {
226             os << "-";
227             it->rest.bp->printcsrc(os, type, precedence);
228         } else if (ex_to_numeric(it->coeff).numer().compare(_num1()) == 0) {
229             it->rest.bp->printcsrc(os, type, precedence);
230             os << "/";
231             ex_to_numeric(it->coeff).denom().printcsrc(os, type, precedence);
232         } else if (ex_to_numeric(it->coeff).numer().compare(_num_1()) == 0) {
233             os << "-";
234             it->rest.bp->printcsrc(os, type, precedence);
235             os << "/";
236             ex_to_numeric(it->coeff).denom().printcsrc(os, type, precedence);
237         } else {
238             it->coeff.bp->printcsrc(os, type, precedence);
239             os << "*";
240             it->rest.bp->printcsrc(os, type, precedence);
241         }
242
243         // Separator is "+", except if the following expression would have a leading minus sign
244         it++;
245         if (it != itend && !(it->coeff.compare(_num0()) < 0 || (it->coeff.compare(_num1()) == 0 && is_ex_exactly_of_type(it->rest, numeric) && it->rest.compare(_num0()) < 0)))
246             os << "+";
247     }
248     
249     if (!overall_coeff.is_equal(_ex0())) {
250         if (overall_coeff.info(info_flags::positive)) os << '+';
251         overall_coeff.bp->printcsrc(os,type,precedence);
252     }
253     
254     if (precedence <= upper_precedence)
255         os << ")";
256 }
257
258 bool add::info(unsigned inf) const
259 {
260     // TODO: optimize
261     if (inf==info_flags::polynomial ||
262         inf==info_flags::integer_polynomial ||
263         inf==info_flags::cinteger_polynomial ||
264         inf==info_flags::rational_polynomial ||
265         inf==info_flags::crational_polynomial ||
266         inf==info_flags::rational_function) {
267         for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
268             if (!(recombine_pair_to_ex(*it).info(inf)))
269                 return false;
270         }
271         return overall_coeff.info(inf);
272     } else {
273         return expairseq::info(inf);
274     }
275 }
276
277 int add::degree(symbol const & s) const
278 {
279     int deg=INT_MIN;
280     if (!overall_coeff.is_equal(_ex0())) {
281         deg=0;
282     }
283     int cur_deg;
284     for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
285         cur_deg=(*cit).rest.degree(s);
286         if (cur_deg>deg) deg=cur_deg;
287     }
288     return deg;
289 }
290
291 int add::ldegree(symbol const & s) const
292 {
293     int deg=INT_MAX;
294     if (!overall_coeff.is_equal(_ex0())) {
295         deg=0;
296     }
297     int cur_deg;
298     for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
299         cur_deg=(*cit).rest.ldegree(s);
300         if (cur_deg<deg) deg=cur_deg;
301     }
302     return deg;
303 }
304
305 ex add::coeff(symbol const & s, int const n) const
306 {
307     epvector coeffseq;
308     coeffseq.reserve(seq.size());
309
310     epvector::const_iterator it=seq.begin();
311     while (it!=seq.end()) {
312         coeffseq.push_back(combine_ex_with_coeff_to_pair((*it).rest.coeff(s,n),
313                                                          (*it).coeff));
314         ++it;
315     }
316     if (n==0) {
317         return (new add(coeffseq,overall_coeff))->setflag(status_flags::dynallocated);
318     }
319     return (new add(coeffseq))->setflag(status_flags::dynallocated);
320 }
321
322 ex add::eval(int level) const
323 {
324     // simplifications: +(;c) -> c
325     //                  +(x;1) -> x
326
327     debugmsg("add eval",LOGLEVEL_MEMBER_FUNCTION);
328
329     epvector * evaled_seqp=evalchildren(level);
330     if (evaled_seqp!=0) {
331         // do more evaluation later
332         return (new add(evaled_seqp,overall_coeff))->
333                    setflag(status_flags::dynallocated);
334     }
335
336 #ifdef DO_GINAC_ASSERT
337     for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
338         GINAC_ASSERT(!is_ex_exactly_of_type((*cit).rest,add));
339         if (is_ex_exactly_of_type((*cit).rest,numeric)) {
340             dbgprint();
341         }
342         GINAC_ASSERT(!is_ex_exactly_of_type((*cit).rest,numeric));
343     }
344 #endif // def DO_GINAC_ASSERT
345
346     if (flags & status_flags::evaluated) {
347         GINAC_ASSERT(seq.size()>0);
348         GINAC_ASSERT((seq.size()>1)||!overall_coeff.is_equal(_ex0()));
349         return *this;
350     }
351
352     int seq_size=seq.size();
353     if (seq_size==0) {
354         // +(;c) -> c
355         return overall_coeff;
356     } else if ((seq_size==1)&&overall_coeff.is_equal(_ex0())) {
357         // +(x;0) -> x
358         return recombine_pair_to_ex(*(seq.begin()));
359     }
360     return this->hold();
361 }
362
363 exvector add::get_indices(void) const
364 {
365     // FIXME: all terms in the sum should have the same indices (compatible
366     // tensors) however this is not checked, since there is no function yet
367     // which compares indices (idxvector can be unsorted)
368     if (seq.size()==0) {
369         return exvector();
370     }
371     return (seq.begin())->rest.get_indices();
372 }    
373
374 ex add::simplify_ncmul(exvector const & v) const
375 {
376     if (seq.size()==0) {
377         return expairseq::simplify_ncmul(v);
378     }
379     return (*seq.begin()).rest.simplify_ncmul(v);
380 }    
381
382 // protected
383
384 int add::compare_same_type(basic const & other) const
385 {
386     return expairseq::compare_same_type(other);
387 }
388
389 bool add::is_equal_same_type(basic const & other) const
390 {
391     return expairseq::is_equal_same_type(other);
392 }
393
394 unsigned add::return_type(void) const
395 {
396     if (seq.size()==0) {
397         return return_types::commutative;
398     }
399     return (*seq.begin()).rest.return_type();
400 }
401    
402 unsigned add::return_type_tinfo(void) const
403 {
404     if (seq.size()==0) {
405         return tinfo_key;
406     }
407     return (*seq.begin()).rest.return_type_tinfo();
408 }
409
410 ex add::thisexpairseq(epvector const & v, ex const & oc) const
411 {
412     return (new add(v,oc))->setflag(status_flags::dynallocated);
413 }
414
415 ex add::thisexpairseq(epvector * vp, ex const & oc) const
416 {
417     return (new add(vp,oc))->setflag(status_flags::dynallocated);
418 }
419
420 expair add::split_ex_to_pair(ex const & e) const
421 {
422     if (is_ex_exactly_of_type(e,mul)) {
423         mul const & mulref=ex_to_mul(e);
424         ex numfactor=mulref.overall_coeff;
425         // mul * mulcopyp=static_cast<mul *>(mulref.duplicate());
426         mul * mulcopyp=new mul(mulref);
427         mulcopyp->overall_coeff=_ex1();
428         mulcopyp->clearflag(status_flags::evaluated);
429         mulcopyp->clearflag(status_flags::hash_calculated);
430         return expair(mulcopyp->setflag(status_flags::dynallocated),numfactor);
431     }
432     return expair(e,_ex1());
433 }
434
435 expair add::combine_ex_with_coeff_to_pair(ex const & e,
436                                           ex const & c) const
437 {
438     GINAC_ASSERT(is_ex_exactly_of_type(c,numeric));
439     if (is_ex_exactly_of_type(e,mul)) {
440         mul const & mulref=ex_to_mul(e);
441         ex numfactor=mulref.overall_coeff;
442         //mul * mulcopyp=static_cast<mul *>(mulref.duplicate());
443         mul * mulcopyp=new mul(mulref);
444         mulcopyp->overall_coeff=_ex1();
445         mulcopyp->clearflag(status_flags::evaluated);
446         mulcopyp->clearflag(status_flags::hash_calculated);
447         if (are_ex_trivially_equal(c,_ex1())) {
448             return expair(mulcopyp->setflag(status_flags::dynallocated),numfactor);
449         } else if (are_ex_trivially_equal(numfactor,_ex1())) {
450             return expair(mulcopyp->setflag(status_flags::dynallocated),c);
451         }
452         return expair(mulcopyp->setflag(status_flags::dynallocated),
453                           ex_to_numeric(numfactor).mul_dyn(ex_to_numeric(c)));
454     } else if (is_ex_exactly_of_type(e,numeric)) {
455         if (are_ex_trivially_equal(c,_ex1())) {
456             return expair(e,_ex1());
457         }
458         return expair(ex_to_numeric(e).mul_dyn(ex_to_numeric(c)),_ex1());
459     }
460     return expair(e,c);
461 }
462     
463 expair add::combine_pair_with_coeff_to_pair(expair const & p,
464                                             ex const & c) const
465 {
466     GINAC_ASSERT(is_ex_exactly_of_type(p.coeff,numeric));
467     GINAC_ASSERT(is_ex_exactly_of_type(c,numeric));
468
469     if (is_ex_exactly_of_type(p.rest,numeric)) {
470         GINAC_ASSERT(ex_to_numeric(p.coeff).is_equal(_num1())); // should be normalized
471         return expair(ex_to_numeric(p.rest).mul_dyn(ex_to_numeric(c)),_ex1());
472     }
473
474     return expair(p.rest,ex_to_numeric(p.coeff).mul_dyn(ex_to_numeric(c)));
475 }
476     
477 ex add::recombine_pair_to_ex(expair const & p) const
478 {
479     //if (p.coeff.compare(_ex1())==0) {
480     //if (are_ex_trivially_equal(p.coeff,_ex1())) {
481     if (ex_to_numeric(p.coeff).is_equal(_num1())) {
482         return p.rest;
483     } else {
484         return p.rest*p.coeff;
485     }
486 }
487
488 ex add::expand(unsigned options) const
489 {
490     epvector * vp=expandchildren(options);
491     if (vp==0) {
492         return *this;
493     }
494     return (new add(vp,overall_coeff))->setflag(status_flags::expanded    |
495                                                 status_flags::dynallocated );
496 }
497
498 //////////
499 // new virtual functions which can be overridden by derived classes
500 //////////
501
502 // none
503
504 //////////
505 // non-virtual functions in this class
506 //////////
507
508 // none
509
510 //////////
511 // static member variables
512 //////////
513
514 // protected
515
516 unsigned add::precedence=40;
517
518 //////////
519 // global constants
520 //////////
521
522 const add some_add;
523 type_info const & typeid_add=typeid(some_add);
524
525 #ifndef NO_GINAC_NAMESPACE
526 } // namespace GiNaC
527 #endif // ndef NO_GINAC_NAMESPACE