3 * Implementation of GiNaC's sums of expressions.
5 * GiNaC Copyright (C) 1999 Johannes Gutenberg University Mainz, Germany
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.
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.
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
29 // default constructor, destructor, copy constructor assignment operator and helpers
36 debugmsg("add default constructor",LOGLEVEL_CONSTRUCT);
37 tinfo_key = TINFO_add;
42 debugmsg("add destructor",LOGLEVEL_DESTRUCT);
46 add::add(add const & other)
48 debugmsg("add copy constructor",LOGLEVEL_CONSTRUCT);
52 add const & add::operator=(add const & other)
54 debugmsg("add operator=",LOGLEVEL_ASSIGNMENT);
64 void add::copy(add const & other)
66 expairseq::copy(other);
69 void add::destroy(bool call_parent)
71 if (call_parent) expairseq::destroy(call_parent);
80 add::add(ex const & lh, ex const & rh)
82 debugmsg("add constructor from ex,ex",LOGLEVEL_CONSTRUCT);
83 tinfo_key = TINFO_add;
84 overall_coeff=exZERO();
85 construct_from_2_ex(lh,rh);
86 ASSERT(is_canonical());
89 add::add(exvector const & v)
91 debugmsg("add constructor from exvector",LOGLEVEL_CONSTRUCT);
92 tinfo_key = TINFO_add;
93 overall_coeff=exZERO();
94 construct_from_exvector(v);
95 ASSERT(is_canonical());
99 add::add(epvector const & v, bool do_not_canonicalize)
101 debugmsg("add constructor from epvector,bool",LOGLEVEL_CONSTRUCT);
102 tinfo_key = TINFO_add;
103 if (do_not_canonicalize) {
105 #ifdef EXPAIRSEQ_USE_HASHTAB
106 combine_same_terms(); // to build hashtab
107 #endif // def EXPAIRSEQ_USE_HASHTAB
109 construct_from_epvector(v);
111 ASSERT(is_canonical());
115 add::add(epvector const & v)
117 debugmsg("add constructor from epvector",LOGLEVEL_CONSTRUCT);
118 tinfo_key = TINFO_add;
119 overall_coeff=exZERO();
120 construct_from_epvector(v);
121 ASSERT(is_canonical());
124 add::add(epvector const & v, ex const & oc)
126 debugmsg("add constructor from epvector,ex",LOGLEVEL_CONSTRUCT);
127 tinfo_key = TINFO_add;
129 construct_from_epvector(v);
130 ASSERT(is_canonical());
133 add::add(epvector * vp, ex const & oc)
135 debugmsg("add constructor from epvector *,ex",LOGLEVEL_CONSTRUCT);
136 tinfo_key = TINFO_add;
139 construct_from_epvector(*vp);
141 ASSERT(is_canonical());
145 // functions overriding virtual functions from bases classes
150 basic * add::duplicate() const
152 debugmsg("add duplicate",LOGLEVEL_DUPLICATE);
153 return new add(*this);
156 bool add::info(unsigned inf) const
159 if (inf==info_flags::polynomial || inf==info_flags::integer_polynomial || inf==info_flags::rational_polynomial || inf==info_flags::rational_function) {
160 for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
161 if (!(recombine_pair_to_ex(*it).info(inf)))
166 return expairseq::info(inf);
170 int add::degree(symbol const & s) const
173 if (!overall_coeff.is_equal(exZERO())) {
177 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
178 cur_deg=(*cit).rest.degree(s);
179 if (cur_deg>deg) deg=cur_deg;
184 int add::ldegree(symbol const & s) const
187 if (!overall_coeff.is_equal(exZERO())) {
191 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
192 cur_deg=(*cit).rest.ldegree(s);
193 if (cur_deg<deg) deg=cur_deg;
198 ex add::coeff(symbol const & s, int const n) const
201 coeffseq.reserve(seq.size());
203 epvector::const_iterator it=seq.begin();
204 while (it!=seq.end()) {
205 coeffseq.push_back(combine_ex_with_coeff_to_pair((*it).rest.coeff(s,n),
210 return (new add(coeffseq,overall_coeff))->setflag(status_flags::dynallocated);
212 return (new add(coeffseq))->setflag(status_flags::dynallocated);
216 ex add::eval(int level) const
218 // simplifications: +(...,x,c1,c2) -> +(...,x,c1+c2) (c1, c2 numeric())
219 // +(...,(c1,c2)) -> (...,(c1*c2,1)) (normalize)
220 // +(...,x,0) -> +(...,x)
224 debugmsg("add eval",LOGLEVEL_MEMBER_FUNCTION);
227 epvector::iterator it1,it2;
229 // +(...,x,c1,c2) -> +(...,x,c1+c2) (c1, c2 numeric())
232 while ((newseq.size()>=2)&&is_exactly_of_type(*(*it1).rest.bp,numeric)&&
233 is_exactly_of_type(*(*it2).rest.bp,numeric)) {
234 *it1=expair(ex_to_numeric((*it1).rest).mul(ex_to_numeric((*it1).coeff))
235 .add(ex_to_numeric((*it2).rest).mul(ex_to_numeric((*it2).coeff))),exONE());
241 if ((newseq.size()>=1)&&is_exactly_of_type(*(*it2).rest.bp,numeric)) {
242 // +(...,(c1,c2)) -> (...,(c1*c2,1)) (normalize)
243 *it2=expair(ex_to_numeric((*it2).rest).mul(ex_to_numeric((*it2).coeff)),exONE());
244 // +(...,x,0) -> +(...,x)
245 if (ex_to_numeric((*it2).rest).compare(0)==0) {
250 if (newseq.size()==0) {
253 } else if (newseq.size()==1) {
255 return recombine_pair_to_ex(*(newseq.begin()));
258 return (new add(newseq,1))->setflag(status_flags::dynallocated |
259 status_flags::evaluated );
264 ex add::eval(int level) const
266 // simplifications: +(...,x,c1,c2) -> +(...,x,c1+c2) (c1, c2 numeric())
267 // +(...,(c1,c2)) -> (...,(c1*c2,1)) (normalize)
268 // +(...,x,0) -> +(...,x)
272 debugmsg("add eval",LOGLEVEL_MEMBER_FUNCTION);
274 if ((level==1)&&(flags & status_flags::evaluated)) {
276 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
277 ASSERT(!is_ex_exactly_of_type((*cit).rest,add));
278 ASSERT(!(is_ex_exactly_of_type((*cit).rest,numeric)&&
279 (ex_to_numeric((*cit).coeff).compare(numONE())!=0)));
281 #endif // def DOASSERT
286 epvector::iterator it1,it2;
287 bool seq_copied=false;
289 epvector * evaled_seqp=evalchildren(level);
290 if (evaled_seqp!=0) {
291 // do more evaluation later
292 return (new add(evaled_seqp))->setflag(status_flags::dynallocated);
296 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
297 ASSERT(!is_ex_exactly_of_type((*cit).rest,add));
298 ASSERT(!(is_ex_exactly_of_type((*cit).rest,numeric)&&
299 (ex_to_numeric((*cit).coeff).compare(numONE())!=0)));
301 #endif // def DOASSERT
303 if (flags & status_flags::evaluated) {
307 expair const & last_expair=*(seq.end()-1);
308 expair const & next_to_last_expair=*(seq.end()-2);
309 int seq_size = seq.size();
311 // +(...,x,c1,c2) -> +(...,x,c1+c2) (c1, c2 numeric())
312 if ((!seq_copied)&&(seq_size>=2)&&
313 is_ex_exactly_of_type(last_expair.rest,numeric)&&
314 is_ex_exactly_of_type(next_to_last_expair.rest,numeric)) {
320 while (seq_copied&&(newseq.size()>=2)&&
321 is_ex_exactly_of_type((*it1).rest,numeric)&&
322 is_ex_exactly_of_type((*it2).rest,numeric)) {
323 *it1=expair(ex_to_numeric((*it1).rest).mul(ex_to_numeric((*it1).coeff))
324 .add_dyn(ex_to_numeric((*it2).rest).mul(ex_to_numeric((*it2).coeff))),exONE());
330 // +(...,(c1,c2)) -> (...,(c1*c2,1)) (normalize)
331 if ((!seq_copied)&&(seq_size>=1)&&
332 (is_ex_exactly_of_type(last_expair.rest,numeric))&&
333 (ex_to_numeric(last_expair.coeff).compare(numONE())!=0)) {
338 if (seq_copied&&(newseq.size()>=1)&&
339 (is_ex_exactly_of_type((*it2).rest,numeric))&&
340 (ex_to_numeric((*it2).coeff).compare(numONE())!=0)) {
341 *it2=expair(ex_to_numeric((*it2).rest).mul_dyn(ex_to_numeric((*it2).coeff)),exONE());
344 // +(...,x,0) -> +(...,x)
345 if ((!seq_copied)&&(seq_size>=1)&&
346 (is_ex_exactly_of_type(last_expair.rest,numeric))&&
347 (ex_to_numeric(last_expair.rest).is_zero())) {
352 if (seq_copied&&(newseq.size()>=1)&&
353 (is_ex_exactly_of_type((*it2).rest,numeric))&&
354 (ex_to_numeric((*it2).rest).is_zero())) {
359 if ((!seq_copied)&&(seq_size==0)) {
361 } else if (seq_copied&&(newseq.size()==0)) {
366 if ((!seq_copied)&&(seq_size==1)) {
367 return recombine_pair_to_ex(*(seq.begin()));
368 } else if (seq_copied&&(newseq.size()==1)) {
369 return recombine_pair_to_ex(*(newseq.begin()));
372 if (!seq_copied) return this->hold();
374 return (new add(newseq,1))->setflag(status_flags::dynallocated |
375 status_flags::evaluated );
379 ex add::eval(int level) const
381 // simplifications: +(;c) -> c
384 debugmsg("add eval",LOGLEVEL_MEMBER_FUNCTION);
386 epvector * evaled_seqp=evalchildren(level);
387 if (evaled_seqp!=0) {
388 // do more evaluation later
389 return (new add(evaled_seqp,overall_coeff))->
390 setflag(status_flags::dynallocated);
394 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
395 ASSERT(!is_ex_exactly_of_type((*cit).rest,add));
396 if (is_ex_exactly_of_type((*cit).rest,numeric)) {
399 ASSERT(!is_ex_exactly_of_type((*cit).rest,numeric));
401 #endif // def DOASSERT
403 if (flags & status_flags::evaluated) {
404 ASSERT(seq.size()>0);
405 ASSERT((seq.size()>1)||!overall_coeff.is_equal(exZERO()));
409 int seq_size=seq.size();
412 return overall_coeff;
413 } else if ((seq_size==1)&&overall_coeff.is_equal(exZERO())) {
415 return recombine_pair_to_ex(*(seq.begin()));
420 exvector add::get_indices(void) const
422 // all terms in the sum should have the same indices (compatible tensors)
423 // however this is not checked, since there is no function yet which
424 // compares indices (idxvector can be unsorted) !!!!!!!!!!!
428 return (seq.begin())->rest.get_indices();
431 ex add::simplify_ncmul(exvector const & v) const
434 return expairseq::simplify_ncmul(v);
436 return (*seq.begin()).rest.simplify_ncmul(v);
441 int add::compare_same_type(basic const & other) const
443 return expairseq::compare_same_type(other);
446 bool add::is_equal_same_type(basic const & other) const
448 return expairseq::is_equal_same_type(other);
451 unsigned add::return_type(void) const
454 return return_types::commutative;
456 return (*seq.begin()).rest.return_type();
459 unsigned add::return_type_tinfo(void) const
464 return (*seq.begin()).rest.return_type_tinfo();
467 ex add::thisexpairseq(epvector const & v, ex const & oc) const
469 return (new add(v,oc))->setflag(status_flags::dynallocated);
472 ex add::thisexpairseq(epvector * vp, ex const & oc) const
474 return (new add(vp,oc))->setflag(status_flags::dynallocated);
478 expair add::split_ex_to_pair(ex const & e) const
480 if (is_ex_exactly_of_type(e,mul)) {
481 mul const & mulref=ex_to_mul(e);
482 ASSERT(mulref.seq.size()>1);
483 ex const & lastfactor_rest=(*(mulref.seq.end()-1)).rest;
484 ex const & lastfactor_coeff=(*(mulref.seq.end()-1)).coeff;
485 if (is_ex_exactly_of_type(lastfactor_rest,numeric) &&
486 ex_to_numeric(lastfactor_coeff).is_equal(numONE())) {
487 epvector s=mulref.seq;
489 //return expair((new mul(s,1))->setflag(status_flags::dynallocated),
491 mul * mulp=static_cast<mul *>(mulref.duplicate());
492 #ifdef EXPAIRSEQ_USE_HASHTAB
493 mulp->remove_hashtab_entry(mulp->seq.end()-1);
494 #endif // def EXPAIRSEQ_USE_HASHTAB
495 mulp->seq.pop_back();
496 #ifdef EXPAIRSEQ_USE_HASHTAB
497 mulp->shrink_hashtab();
498 #endif // def EXPAIRSEQ_USE_HASHTAB
499 mulp->clearflag(status_flags::evaluated);
500 mulp->clearflag(status_flags::hash_calculated);
501 return expair(mulp->setflag(status_flags::dynallocated),lastfactor_rest);
504 return expair(e,exONE());
508 expair add::split_ex_to_pair(ex const & e) const
510 if (is_ex_exactly_of_type(e,mul)) {
511 mul const & mulref=ex_to_mul(e);
512 ex numfactor=mulref.overall_coeff;
513 // mul * mulcopyp=static_cast<mul *>(mulref.duplicate());
514 mul * mulcopyp=new mul(mulref);
515 mulcopyp->overall_coeff=exONE();
516 mulcopyp->clearflag(status_flags::evaluated);
517 mulcopyp->clearflag(status_flags::hash_calculated);
518 return expair(mulcopyp->setflag(status_flags::dynallocated),numfactor);
520 return expair(e,exONE());
524 expair add::combine_ex_with_coeff_to_pair(ex const & e,
527 ASSERT(is_ex_exactly_of_type(c,numeric));
528 if (is_ex_exactly_of_type(e,mul)) {
529 mul const & mulref=ex_to_mul(e);
530 ASSERT(mulref.seq.size()>1);
531 ex const & lastfactor_rest=(*(mulref.seq.end()-1)).rest;
532 ex const & lastfactor_coeff=(*(mulref.seq.end()-1)).coeff;
533 if (is_ex_exactly_of_type(lastfactor_rest,numeric) &&
534 ex_to_numeric(lastfactor_coeff).is_equal(numONE())) {
535 //epvector s=mulref.seq;
537 //return expair((new mul(s,1))->setflag(status_flags::dynallocated),
538 // ex_to_numeric(lastfactor).mul_dyn(ex_to_numeric(c)));
539 mul * mulp=static_cast<mul *>(mulref.duplicate());
540 #ifdef EXPAIRSEQ_USE_HASHTAB
541 mulp->remove_hashtab_entry(mulp->seq.end()-1);
542 #endif // def EXPAIRSEQ_USE_HASHTAB
543 mulp->seq.pop_back();
544 #ifdef EXPAIRSEQ_USE_HASHTAB
545 mulp->shrink_hashtab();
546 #endif // def EXPAIRSEQ_USE_HASHTAB
547 mulp->clearflag(status_flags::evaluated);
548 mulp->clearflag(status_flags::hash_calculated);
549 if (are_ex_trivially_equal(c,exONE())) {
550 return expair(mulp->setflag(status_flags::dynallocated),lastfactor_rest);
551 } else if (are_ex_trivially_equal(lastfactor_rest,exONE())) {
552 return expair(mulp->setflag(status_flags::dynallocated),c);
554 return expair(mulp->setflag(status_flags::dynallocated),
555 ex_to_numeric(lastfactor_rest).mul_dyn(ex_to_numeric(c)));
562 expair add::combine_ex_with_coeff_to_pair(ex const & e,
565 ASSERT(is_ex_exactly_of_type(c,numeric));
566 if (is_ex_exactly_of_type(e,mul)) {
567 mul const & mulref=ex_to_mul(e);
568 ex numfactor=mulref.overall_coeff;
569 //mul * mulcopyp=static_cast<mul *>(mulref.duplicate());
570 mul * mulcopyp=new mul(mulref);
571 mulcopyp->overall_coeff=exONE();
572 mulcopyp->clearflag(status_flags::evaluated);
573 mulcopyp->clearflag(status_flags::hash_calculated);
574 if (are_ex_trivially_equal(c,exONE())) {
575 return expair(mulcopyp->setflag(status_flags::dynallocated),numfactor);
576 } else if (are_ex_trivially_equal(numfactor,exONE())) {
577 return expair(mulcopyp->setflag(status_flags::dynallocated),c);
579 return expair(mulcopyp->setflag(status_flags::dynallocated),
580 ex_to_numeric(numfactor).mul_dyn(ex_to_numeric(c)));
581 } else if (is_ex_exactly_of_type(e,numeric)) {
582 if (are_ex_trivially_equal(c,exONE())) {
583 return expair(e,exONE());
585 return expair(ex_to_numeric(e).mul_dyn(ex_to_numeric(c)),exONE());
590 expair add::combine_pair_with_coeff_to_pair(expair const & p,
593 ASSERT(is_ex_exactly_of_type(p.coeff,numeric));
594 ASSERT(is_ex_exactly_of_type(c,numeric));
596 if (is_ex_exactly_of_type(p.rest,numeric)) {
597 ASSERT(ex_to_numeric(p.coeff).is_equal(numONE())); // should be normalized
598 return expair(ex_to_numeric(p.rest).mul_dyn(ex_to_numeric(c)),exONE());
601 return expair(p.rest,ex_to_numeric(p.coeff).mul_dyn(ex_to_numeric(c)));
604 ex add::recombine_pair_to_ex(expair const & p) const
606 //if (p.coeff.compare(exONE())==0) {
607 //if (are_ex_trivially_equal(p.coeff,exONE())) {
608 if (ex_to_numeric(p.coeff).is_equal(numONE())) {
611 return p.rest*p.coeff;
615 ex add::expand(unsigned options) const
617 epvector * vp=expandchildren(options);
621 return (new add(vp,overall_coeff))->setflag(status_flags::expanded |
622 status_flags::dynallocated );
626 // new virtual functions which can be overridden by derived classes
632 // non-virtual functions in this class
638 // static member variables
643 unsigned add::precedence=40;
650 type_info const & typeid_add=typeid(some_add);