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