3 * Implementation of GiNaC's sums of expressions. */
11 // default constructor, destructor, copy constructor assignment operator and helpers
18 debugmsg("add default constructor",LOGLEVEL_CONSTRUCT);
19 tinfo_key = TINFO_ADD;
24 debugmsg("add destructor",LOGLEVEL_DESTRUCT);
28 add::add(add const & other)
30 debugmsg("add copy constructor",LOGLEVEL_CONSTRUCT);
34 add const & add::operator=(add const & other)
36 debugmsg("add operator=",LOGLEVEL_ASSIGNMENT);
46 void add::copy(add const & other)
48 expairseq::copy(other);
51 void add::destroy(bool call_parent)
53 if (call_parent) expairseq::destroy(call_parent);
62 add::add(ex const & lh, ex const & rh)
64 debugmsg("add constructor from ex,ex",LOGLEVEL_CONSTRUCT);
65 tinfo_key = TINFO_ADD;
66 overall_coeff=exZERO();
67 construct_from_2_ex(lh,rh);
68 ASSERT(is_canonical());
71 add::add(exvector const & v)
73 debugmsg("add constructor from exvector",LOGLEVEL_CONSTRUCT);
74 tinfo_key = TINFO_ADD;
75 overall_coeff=exZERO();
76 construct_from_exvector(v);
77 ASSERT(is_canonical());
81 add::add(epvector const & v, bool do_not_canonicalize)
83 debugmsg("add constructor from epvector,bool",LOGLEVEL_CONSTRUCT);
84 tinfo_key = TINFO_ADD;
85 if (do_not_canonicalize) {
87 #ifdef EXPAIRSEQ_USE_HASHTAB
88 combine_same_terms(); // to build hashtab
89 #endif // def EXPAIRSEQ_USE_HASHTAB
91 construct_from_epvector(v);
93 ASSERT(is_canonical());
97 add::add(epvector const & v)
99 debugmsg("add constructor from epvector",LOGLEVEL_CONSTRUCT);
100 tinfo_key = TINFO_ADD;
101 overall_coeff=exZERO();
102 construct_from_epvector(v);
103 ASSERT(is_canonical());
106 add::add(epvector const & v, ex const & oc)
108 debugmsg("add constructor from epvector,ex",LOGLEVEL_CONSTRUCT);
109 tinfo_key = TINFO_ADD;
111 construct_from_epvector(v);
112 ASSERT(is_canonical());
115 add::add(epvector * vp, ex const & oc)
117 debugmsg("add constructor from epvector *,ex",LOGLEVEL_CONSTRUCT);
118 tinfo_key = TINFO_ADD;
121 construct_from_epvector(*vp);
123 ASSERT(is_canonical());
127 // functions overriding virtual functions from bases classes
132 basic * add::duplicate() const
134 debugmsg("add duplicate",LOGLEVEL_DUPLICATE);
135 return new add(*this);
138 bool add::info(unsigned inf) const
141 if (inf==info_flags::polynomial || inf==info_flags::integer_polynomial || inf==info_flags::rational_polynomial || inf==info_flags::rational_function) {
142 for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
143 if (!(recombine_pair_to_ex(*it).info(inf)))
148 return expairseq::info(inf);
152 int add::degree(symbol const & s) const
155 if (!overall_coeff.is_equal(exZERO())) {
159 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
160 cur_deg=(*cit).rest.degree(s);
161 if (cur_deg>deg) deg=cur_deg;
166 int add::ldegree(symbol const & s) const
169 if (!overall_coeff.is_equal(exZERO())) {
173 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
174 cur_deg=(*cit).rest.ldegree(s);
175 if (cur_deg<deg) deg=cur_deg;
180 ex add::coeff(symbol const & s, int const n) const
183 coeffseq.reserve(seq.size());
185 epvector::const_iterator it=seq.begin();
186 while (it!=seq.end()) {
187 coeffseq.push_back(combine_ex_with_coeff_to_pair((*it).rest.coeff(s,n),
192 return (new add(coeffseq,overall_coeff))->setflag(status_flags::dynallocated);
194 return (new add(coeffseq))->setflag(status_flags::dynallocated);
198 ex add::eval(int level) const
200 // simplifications: +(...,x,c1,c2) -> +(...,x,c1+c2) (c1, c2 numeric())
201 // +(...,(c1,c2)) -> (...,(c1*c2,1)) (normalize)
202 // +(...,x,0) -> +(...,x)
206 debugmsg("add eval",LOGLEVEL_MEMBER_FUNCTION);
209 epvector::iterator it1,it2;
211 // +(...,x,c1,c2) -> +(...,x,c1+c2) (c1, c2 numeric())
214 while ((newseq.size()>=2)&&is_exactly_of_type(*(*it1).rest.bp,numeric)&&
215 is_exactly_of_type(*(*it2).rest.bp,numeric)) {
216 *it1=expair(ex_to_numeric((*it1).rest).mul(ex_to_numeric((*it1).coeff))
217 .add(ex_to_numeric((*it2).rest).mul(ex_to_numeric((*it2).coeff))),exONE());
223 if ((newseq.size()>=1)&&is_exactly_of_type(*(*it2).rest.bp,numeric)) {
224 // +(...,(c1,c2)) -> (...,(c1*c2,1)) (normalize)
225 *it2=expair(ex_to_numeric((*it2).rest).mul(ex_to_numeric((*it2).coeff)),exONE());
226 // +(...,x,0) -> +(...,x)
227 if (ex_to_numeric((*it2).rest).compare(0)==0) {
232 if (newseq.size()==0) {
235 } else if (newseq.size()==1) {
237 return recombine_pair_to_ex(*(newseq.begin()));
240 return (new add(newseq,1))->setflag(status_flags::dynallocated |
241 status_flags::evaluated );
246 ex add::eval(int level) const
248 // simplifications: +(...,x,c1,c2) -> +(...,x,c1+c2) (c1, c2 numeric())
249 // +(...,(c1,c2)) -> (...,(c1*c2,1)) (normalize)
250 // +(...,x,0) -> +(...,x)
254 debugmsg("add eval",LOGLEVEL_MEMBER_FUNCTION);
256 if ((level==1)&&(flags & status_flags::evaluated)) {
258 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
259 ASSERT(!is_ex_exactly_of_type((*cit).rest,add));
260 ASSERT(!(is_ex_exactly_of_type((*cit).rest,numeric)&&
261 (ex_to_numeric((*cit).coeff).compare(numONE())!=0)));
263 #endif // def DOASSERT
268 epvector::iterator it1,it2;
269 bool seq_copied=false;
271 epvector * evaled_seqp=evalchildren(level);
272 if (evaled_seqp!=0) {
273 // do more evaluation later
274 return (new add(evaled_seqp))->setflag(status_flags::dynallocated);
278 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
279 ASSERT(!is_ex_exactly_of_type((*cit).rest,add));
280 ASSERT(!(is_ex_exactly_of_type((*cit).rest,numeric)&&
281 (ex_to_numeric((*cit).coeff).compare(numONE())!=0)));
283 #endif // def DOASSERT
285 if (flags & status_flags::evaluated) {
289 expair const & last_expair=*(seq.end()-1);
290 expair const & next_to_last_expair=*(seq.end()-2);
291 int seq_size = seq.size();
293 // +(...,x,c1,c2) -> +(...,x,c1+c2) (c1, c2 numeric())
294 if ((!seq_copied)&&(seq_size>=2)&&
295 is_ex_exactly_of_type(last_expair.rest,numeric)&&
296 is_ex_exactly_of_type(next_to_last_expair.rest,numeric)) {
302 while (seq_copied&&(newseq.size()>=2)&&
303 is_ex_exactly_of_type((*it1).rest,numeric)&&
304 is_ex_exactly_of_type((*it2).rest,numeric)) {
305 *it1=expair(ex_to_numeric((*it1).rest).mul(ex_to_numeric((*it1).coeff))
306 .add_dyn(ex_to_numeric((*it2).rest).mul(ex_to_numeric((*it2).coeff))),exONE());
312 // +(...,(c1,c2)) -> (...,(c1*c2,1)) (normalize)
313 if ((!seq_copied)&&(seq_size>=1)&&
314 (is_ex_exactly_of_type(last_expair.rest,numeric))&&
315 (ex_to_numeric(last_expair.coeff).compare(numONE())!=0)) {
320 if (seq_copied&&(newseq.size()>=1)&&
321 (is_ex_exactly_of_type((*it2).rest,numeric))&&
322 (ex_to_numeric((*it2).coeff).compare(numONE())!=0)) {
323 *it2=expair(ex_to_numeric((*it2).rest).mul_dyn(ex_to_numeric((*it2).coeff)),exONE());
326 // +(...,x,0) -> +(...,x)
327 if ((!seq_copied)&&(seq_size>=1)&&
328 (is_ex_exactly_of_type(last_expair.rest,numeric))&&
329 (ex_to_numeric(last_expair.rest).is_zero())) {
334 if (seq_copied&&(newseq.size()>=1)&&
335 (is_ex_exactly_of_type((*it2).rest,numeric))&&
336 (ex_to_numeric((*it2).rest).is_zero())) {
341 if ((!seq_copied)&&(seq_size==0)) {
343 } else if (seq_copied&&(newseq.size()==0)) {
348 if ((!seq_copied)&&(seq_size==1)) {
349 return recombine_pair_to_ex(*(seq.begin()));
350 } else if (seq_copied&&(newseq.size()==1)) {
351 return recombine_pair_to_ex(*(newseq.begin()));
354 if (!seq_copied) return this->hold();
356 return (new add(newseq,1))->setflag(status_flags::dynallocated |
357 status_flags::evaluated );
361 ex add::eval(int level) const
363 // simplifications: +(;c) -> c
366 debugmsg("add eval",LOGLEVEL_MEMBER_FUNCTION);
368 epvector * evaled_seqp=evalchildren(level);
369 if (evaled_seqp!=0) {
370 // do more evaluation later
371 return (new add(evaled_seqp,overall_coeff))->
372 setflag(status_flags::dynallocated);
376 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
377 ASSERT(!is_ex_exactly_of_type((*cit).rest,add));
378 if (is_ex_exactly_of_type((*cit).rest,numeric)) {
381 ASSERT(!is_ex_exactly_of_type((*cit).rest,numeric));
383 #endif // def DOASSERT
385 if (flags & status_flags::evaluated) {
386 ASSERT(seq.size()>0);
387 ASSERT((seq.size()>1)||!overall_coeff.is_equal(exZERO()));
391 int seq_size=seq.size();
394 return overall_coeff;
395 } else if ((seq_size==1)&&overall_coeff.is_equal(exZERO())) {
397 return recombine_pair_to_ex(*(seq.begin()));
402 exvector add::get_indices(void) const
404 // all terms in the sum should have the same indices (compatible tensors)
405 // however this is not checked, since there is no function yet which
406 // compares indices (idxvector can be unsorted) !!!!!!!!!!!
410 return (seq.begin())->rest.get_indices();
413 ex add::simplify_ncmul(exvector const & v) const
416 return expairseq::simplify_ncmul(v);
418 return (*seq.begin()).rest.simplify_ncmul(v);
423 int add::compare_same_type(basic const & other) const
425 return expairseq::compare_same_type(other);
428 bool add::is_equal_same_type(basic const & other) const
430 return expairseq::is_equal_same_type(other);
433 unsigned add::return_type(void) const
436 return return_types::commutative;
438 return (*seq.begin()).rest.return_type();
441 unsigned add::return_type_tinfo(void) const
446 return (*seq.begin()).rest.return_type_tinfo();
449 ex add::thisexpairseq(epvector const & v, ex const & oc) const
451 return (new add(v,oc))->setflag(status_flags::dynallocated);
454 ex add::thisexpairseq(epvector * vp, ex const & oc) const
456 return (new add(vp,oc))->setflag(status_flags::dynallocated);
460 expair add::split_ex_to_pair(ex const & e) const
462 if (is_ex_exactly_of_type(e,mul)) {
463 mul const & mulref=ex_to_mul(e);
464 ASSERT(mulref.seq.size()>1);
465 ex const & lastfactor_rest=(*(mulref.seq.end()-1)).rest;
466 ex const & lastfactor_coeff=(*(mulref.seq.end()-1)).coeff;
467 if (is_ex_exactly_of_type(lastfactor_rest,numeric) &&
468 ex_to_numeric(lastfactor_coeff).is_equal(numONE())) {
469 epvector s=mulref.seq;
471 //return expair((new mul(s,1))->setflag(status_flags::dynallocated),
473 mul * mulp=static_cast<mul *>(mulref.duplicate());
474 #ifdef EXPAIRSEQ_USE_HASHTAB
475 mulp->remove_hashtab_entry(mulp->seq.end()-1);
476 #endif // def EXPAIRSEQ_USE_HASHTAB
477 mulp->seq.pop_back();
478 #ifdef EXPAIRSEQ_USE_HASHTAB
479 mulp->shrink_hashtab();
480 #endif // def EXPAIRSEQ_USE_HASHTAB
481 mulp->clearflag(status_flags::evaluated);
482 mulp->clearflag(status_flags::hash_calculated);
483 return expair(mulp->setflag(status_flags::dynallocated),lastfactor_rest);
486 return expair(e,exONE());
490 expair add::split_ex_to_pair(ex const & e) const
492 if (is_ex_exactly_of_type(e,mul)) {
493 mul const & mulref=ex_to_mul(e);
494 ex numfactor=mulref.overall_coeff;
495 // mul * mulcopyp=static_cast<mul *>(mulref.duplicate());
496 mul * mulcopyp=new mul(mulref);
497 mulcopyp->overall_coeff=exONE();
498 mulcopyp->clearflag(status_flags::evaluated);
499 mulcopyp->clearflag(status_flags::hash_calculated);
500 return expair(mulcopyp->setflag(status_flags::dynallocated),numfactor);
502 return expair(e,exONE());
506 expair add::combine_ex_with_coeff_to_pair(ex const & e,
509 ASSERT(is_ex_exactly_of_type(c,numeric));
510 if (is_ex_exactly_of_type(e,mul)) {
511 mul const & mulref=ex_to_mul(e);
512 ASSERT(mulref.seq.size()>1);
513 ex const & lastfactor_rest=(*(mulref.seq.end()-1)).rest;
514 ex const & lastfactor_coeff=(*(mulref.seq.end()-1)).coeff;
515 if (is_ex_exactly_of_type(lastfactor_rest,numeric) &&
516 ex_to_numeric(lastfactor_coeff).is_equal(numONE())) {
517 //epvector s=mulref.seq;
519 //return expair((new mul(s,1))->setflag(status_flags::dynallocated),
520 // ex_to_numeric(lastfactor).mul_dyn(ex_to_numeric(c)));
521 mul * mulp=static_cast<mul *>(mulref.duplicate());
522 #ifdef EXPAIRSEQ_USE_HASHTAB
523 mulp->remove_hashtab_entry(mulp->seq.end()-1);
524 #endif // def EXPAIRSEQ_USE_HASHTAB
525 mulp->seq.pop_back();
526 #ifdef EXPAIRSEQ_USE_HASHTAB
527 mulp->shrink_hashtab();
528 #endif // def EXPAIRSEQ_USE_HASHTAB
529 mulp->clearflag(status_flags::evaluated);
530 mulp->clearflag(status_flags::hash_calculated);
531 if (are_ex_trivially_equal(c,exONE())) {
532 return expair(mulp->setflag(status_flags::dynallocated),lastfactor_rest);
533 } else if (are_ex_trivially_equal(lastfactor_rest,exONE())) {
534 return expair(mulp->setflag(status_flags::dynallocated),c);
536 return expair(mulp->setflag(status_flags::dynallocated),
537 ex_to_numeric(lastfactor_rest).mul_dyn(ex_to_numeric(c)));
544 expair add::combine_ex_with_coeff_to_pair(ex const & e,
547 ASSERT(is_ex_exactly_of_type(c,numeric));
548 if (is_ex_exactly_of_type(e,mul)) {
549 mul const & mulref=ex_to_mul(e);
550 ex numfactor=mulref.overall_coeff;
551 //mul * mulcopyp=static_cast<mul *>(mulref.duplicate());
552 mul * mulcopyp=new mul(mulref);
553 mulcopyp->overall_coeff=exONE();
554 mulcopyp->clearflag(status_flags::evaluated);
555 mulcopyp->clearflag(status_flags::hash_calculated);
556 if (are_ex_trivially_equal(c,exONE())) {
557 return expair(mulcopyp->setflag(status_flags::dynallocated),numfactor);
558 } else if (are_ex_trivially_equal(numfactor,exONE())) {
559 return expair(mulcopyp->setflag(status_flags::dynallocated),c);
561 return expair(mulcopyp->setflag(status_flags::dynallocated),
562 ex_to_numeric(numfactor).mul_dyn(ex_to_numeric(c)));
563 } else if (is_ex_exactly_of_type(e,numeric)) {
564 if (are_ex_trivially_equal(c,exONE())) {
565 return expair(e,exONE());
567 return expair(ex_to_numeric(e).mul_dyn(ex_to_numeric(c)),exONE());
572 expair add::combine_pair_with_coeff_to_pair(expair const & p,
575 ASSERT(is_ex_exactly_of_type(p.coeff,numeric));
576 ASSERT(is_ex_exactly_of_type(c,numeric));
578 if (is_ex_exactly_of_type(p.rest,numeric)) {
579 ASSERT(ex_to_numeric(p.coeff).is_equal(numONE())); // should be normalized
580 return expair(ex_to_numeric(p.rest).mul_dyn(ex_to_numeric(c)),exONE());
583 return expair(p.rest,ex_to_numeric(p.coeff).mul_dyn(ex_to_numeric(c)));
586 ex add::recombine_pair_to_ex(expair const & p) const
588 //if (p.coeff.compare(exONE())==0) {
589 //if (are_ex_trivially_equal(p.coeff,exONE())) {
590 if (ex_to_numeric(p.coeff).is_equal(numONE())) {
593 return p.rest*p.coeff;
597 ex add::expand(unsigned options) const
599 epvector * vp=expandchildren(options);
603 return (new add(vp,overall_coeff))->setflag(status_flags::expanded |
604 status_flags::dynallocated );
608 // new virtual functions which can be overridden by derived classes
614 // non-virtual functions in this class
620 // static member variables
625 unsigned add::precedence=40;
632 type_info const & typeid_add=typeid(some_add);