3 * Implementation of GiNaC's sums of expressions. */
6 * GiNaC Copyright (C) 1999 Johannes Gutenberg University Mainz, Germany
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.
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.
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
33 // default constructor, destructor, copy constructor assignment operator and helpers
40 debugmsg("add default constructor",LOGLEVEL_CONSTRUCT);
41 tinfo_key = TINFO_add;
46 debugmsg("add destructor",LOGLEVEL_DESTRUCT);
50 add::add(add const & other)
52 debugmsg("add copy constructor",LOGLEVEL_CONSTRUCT);
56 add const & add::operator=(add const & other)
58 debugmsg("add operator=",LOGLEVEL_ASSIGNMENT);
68 void add::copy(add const & other)
70 expairseq::copy(other);
73 void add::destroy(bool call_parent)
75 if (call_parent) expairseq::destroy(call_parent);
84 add::add(ex const & lh, ex const & rh)
86 debugmsg("add constructor from ex,ex",LOGLEVEL_CONSTRUCT);
87 tinfo_key = TINFO_add;
88 overall_coeff=exZERO();
89 construct_from_2_ex(lh,rh);
90 ASSERT(is_canonical());
93 add::add(exvector const & v)
95 debugmsg("add constructor from exvector",LOGLEVEL_CONSTRUCT);
96 tinfo_key = TINFO_add;
97 overall_coeff=exZERO();
98 construct_from_exvector(v);
99 ASSERT(is_canonical());
103 add::add(epvector const & v, bool do_not_canonicalize)
105 debugmsg("add constructor from epvector,bool",LOGLEVEL_CONSTRUCT);
106 tinfo_key = TINFO_add;
107 if (do_not_canonicalize) {
109 #ifdef EXPAIRSEQ_USE_HASHTAB
110 combine_same_terms(); // to build hashtab
111 #endif // def EXPAIRSEQ_USE_HASHTAB
113 construct_from_epvector(v);
115 ASSERT(is_canonical());
119 add::add(epvector const & v)
121 debugmsg("add constructor from epvector",LOGLEVEL_CONSTRUCT);
122 tinfo_key = TINFO_add;
123 overall_coeff=exZERO();
124 construct_from_epvector(v);
125 ASSERT(is_canonical());
128 add::add(epvector const & v, ex const & oc)
130 debugmsg("add constructor from epvector,ex",LOGLEVEL_CONSTRUCT);
131 tinfo_key = TINFO_add;
133 construct_from_epvector(v);
134 ASSERT(is_canonical());
137 add::add(epvector * vp, ex const & oc)
139 debugmsg("add constructor from epvector *,ex",LOGLEVEL_CONSTRUCT);
140 tinfo_key = TINFO_add;
143 construct_from_epvector(*vp);
145 ASSERT(is_canonical());
149 // functions overriding virtual functions from bases classes
154 basic * add::duplicate() const
156 debugmsg("add duplicate",LOGLEVEL_DUPLICATE);
157 return new add(*this);
160 bool add::info(unsigned inf) const
163 if (inf==info_flags::polynomial || inf==info_flags::integer_polynomial || inf==info_flags::rational_polynomial || inf==info_flags::rational_function) {
164 for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
165 if (!(recombine_pair_to_ex(*it).info(inf)))
170 return expairseq::info(inf);
174 int add::degree(symbol const & s) const
177 if (!overall_coeff.is_equal(exZERO())) {
181 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
182 cur_deg=(*cit).rest.degree(s);
183 if (cur_deg>deg) deg=cur_deg;
188 int add::ldegree(symbol const & s) const
191 if (!overall_coeff.is_equal(exZERO())) {
195 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
196 cur_deg=(*cit).rest.ldegree(s);
197 if (cur_deg<deg) deg=cur_deg;
202 ex add::coeff(symbol const & s, int const n) const
205 coeffseq.reserve(seq.size());
207 epvector::const_iterator it=seq.begin();
208 while (it!=seq.end()) {
209 coeffseq.push_back(combine_ex_with_coeff_to_pair((*it).rest.coeff(s,n),
214 return (new add(coeffseq,overall_coeff))->setflag(status_flags::dynallocated);
216 return (new add(coeffseq))->setflag(status_flags::dynallocated);
220 ex add::eval(int level) const
222 // simplifications: +(...,x,c1,c2) -> +(...,x,c1+c2) (c1, c2 numeric())
223 // +(...,(c1,c2)) -> (...,(c1*c2,1)) (normalize)
224 // +(...,x,0) -> +(...,x)
228 debugmsg("add eval",LOGLEVEL_MEMBER_FUNCTION);
231 epvector::iterator it1,it2;
233 // +(...,x,c1,c2) -> +(...,x,c1+c2) (c1, c2 numeric())
236 while ((newseq.size()>=2)&&is_exactly_of_type(*(*it1).rest.bp,numeric)&&
237 is_exactly_of_type(*(*it2).rest.bp,numeric)) {
238 *it1=expair(ex_to_numeric((*it1).rest).mul(ex_to_numeric((*it1).coeff))
239 .add(ex_to_numeric((*it2).rest).mul(ex_to_numeric((*it2).coeff))),exONE());
245 if ((newseq.size()>=1)&&is_exactly_of_type(*(*it2).rest.bp,numeric)) {
246 // +(...,(c1,c2)) -> (...,(c1*c2,1)) (normalize)
247 *it2=expair(ex_to_numeric((*it2).rest).mul(ex_to_numeric((*it2).coeff)),exONE());
248 // +(...,x,0) -> +(...,x)
249 if (ex_to_numeric((*it2).rest).compare(0)==0) {
254 if (newseq.size()==0) {
257 } else if (newseq.size()==1) {
259 return recombine_pair_to_ex(*(newseq.begin()));
262 return (new add(newseq,1))->setflag(status_flags::dynallocated |
263 status_flags::evaluated );
268 ex add::eval(int level) const
270 // simplifications: +(...,x,c1,c2) -> +(...,x,c1+c2) (c1, c2 numeric())
271 // +(...,(c1,c2)) -> (...,(c1*c2,1)) (normalize)
272 // +(...,x,0) -> +(...,x)
276 debugmsg("add eval",LOGLEVEL_MEMBER_FUNCTION);
278 if ((level==1)&&(flags & status_flags::evaluated)) {
280 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
281 ASSERT(!is_ex_exactly_of_type((*cit).rest,add));
282 ASSERT(!(is_ex_exactly_of_type((*cit).rest,numeric)&&
283 (ex_to_numeric((*cit).coeff).compare(numONE())!=0)));
285 #endif // def DOASSERT
290 epvector::iterator it1,it2;
291 bool seq_copied=false;
293 epvector * evaled_seqp=evalchildren(level);
294 if (evaled_seqp!=0) {
295 // do more evaluation later
296 return (new add(evaled_seqp))->setflag(status_flags::dynallocated);
300 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
301 ASSERT(!is_ex_exactly_of_type((*cit).rest,add));
302 ASSERT(!(is_ex_exactly_of_type((*cit).rest,numeric)&&
303 (ex_to_numeric((*cit).coeff).compare(numONE())!=0)));
305 #endif // def DOASSERT
307 if (flags & status_flags::evaluated) {
311 expair const & last_expair=*(seq.end()-1);
312 expair const & next_to_last_expair=*(seq.end()-2);
313 int seq_size = seq.size();
315 // +(...,x,c1,c2) -> +(...,x,c1+c2) (c1, c2 numeric())
316 if ((!seq_copied)&&(seq_size>=2)&&
317 is_ex_exactly_of_type(last_expair.rest,numeric)&&
318 is_ex_exactly_of_type(next_to_last_expair.rest,numeric)) {
324 while (seq_copied&&(newseq.size()>=2)&&
325 is_ex_exactly_of_type((*it1).rest,numeric)&&
326 is_ex_exactly_of_type((*it2).rest,numeric)) {
327 *it1=expair(ex_to_numeric((*it1).rest).mul(ex_to_numeric((*it1).coeff))
328 .add_dyn(ex_to_numeric((*it2).rest).mul(ex_to_numeric((*it2).coeff))),exONE());
334 // +(...,(c1,c2)) -> (...,(c1*c2,1)) (normalize)
335 if ((!seq_copied)&&(seq_size>=1)&&
336 (is_ex_exactly_of_type(last_expair.rest,numeric))&&
337 (ex_to_numeric(last_expair.coeff).compare(numONE())!=0)) {
342 if (seq_copied&&(newseq.size()>=1)&&
343 (is_ex_exactly_of_type((*it2).rest,numeric))&&
344 (ex_to_numeric((*it2).coeff).compare(numONE())!=0)) {
345 *it2=expair(ex_to_numeric((*it2).rest).mul_dyn(ex_to_numeric((*it2).coeff)),exONE());
348 // +(...,x,0) -> +(...,x)
349 if ((!seq_copied)&&(seq_size>=1)&&
350 (is_ex_exactly_of_type(last_expair.rest,numeric))&&
351 (ex_to_numeric(last_expair.rest).is_zero())) {
356 if (seq_copied&&(newseq.size()>=1)&&
357 (is_ex_exactly_of_type((*it2).rest,numeric))&&
358 (ex_to_numeric((*it2).rest).is_zero())) {
363 if ((!seq_copied)&&(seq_size==0)) {
365 } else if (seq_copied&&(newseq.size()==0)) {
370 if ((!seq_copied)&&(seq_size==1)) {
371 return recombine_pair_to_ex(*(seq.begin()));
372 } else if (seq_copied&&(newseq.size()==1)) {
373 return recombine_pair_to_ex(*(newseq.begin()));
376 if (!seq_copied) return this->hold();
378 return (new add(newseq,1))->setflag(status_flags::dynallocated |
379 status_flags::evaluated );
383 ex add::eval(int level) const
385 // simplifications: +(;c) -> c
388 debugmsg("add eval",LOGLEVEL_MEMBER_FUNCTION);
390 epvector * evaled_seqp=evalchildren(level);
391 if (evaled_seqp!=0) {
392 // do more evaluation later
393 return (new add(evaled_seqp,overall_coeff))->
394 setflag(status_flags::dynallocated);
398 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
399 ASSERT(!is_ex_exactly_of_type((*cit).rest,add));
400 if (is_ex_exactly_of_type((*cit).rest,numeric)) {
403 ASSERT(!is_ex_exactly_of_type((*cit).rest,numeric));
405 #endif // def DOASSERT
407 if (flags & status_flags::evaluated) {
408 ASSERT(seq.size()>0);
409 ASSERT((seq.size()>1)||!overall_coeff.is_equal(exZERO()));
413 int seq_size=seq.size();
416 return overall_coeff;
417 } else if ((seq_size==1)&&overall_coeff.is_equal(exZERO())) {
419 return recombine_pair_to_ex(*(seq.begin()));
424 exvector add::get_indices(void) const
426 // FIXME: all terms in the sum should have the same indices (compatible
427 // tensors) however this is not checked, since there is no function yet
428 // which compares indices (idxvector can be unsorted)
432 return (seq.begin())->rest.get_indices();
435 ex add::simplify_ncmul(exvector const & v) const
438 return expairseq::simplify_ncmul(v);
440 return (*seq.begin()).rest.simplify_ncmul(v);
445 int add::compare_same_type(basic const & other) const
447 return expairseq::compare_same_type(other);
450 bool add::is_equal_same_type(basic const & other) const
452 return expairseq::is_equal_same_type(other);
455 unsigned add::return_type(void) const
458 return return_types::commutative;
460 return (*seq.begin()).rest.return_type();
463 unsigned add::return_type_tinfo(void) const
468 return (*seq.begin()).rest.return_type_tinfo();
471 ex add::thisexpairseq(epvector const & v, ex const & oc) const
473 return (new add(v,oc))->setflag(status_flags::dynallocated);
476 ex add::thisexpairseq(epvector * vp, ex const & oc) const
478 return (new add(vp,oc))->setflag(status_flags::dynallocated);
482 expair add::split_ex_to_pair(ex const & e) const
484 if (is_ex_exactly_of_type(e,mul)) {
485 mul const & mulref=ex_to_mul(e);
486 ASSERT(mulref.seq.size()>1);
487 ex const & lastfactor_rest=(*(mulref.seq.end()-1)).rest;
488 ex const & lastfactor_coeff=(*(mulref.seq.end()-1)).coeff;
489 if (is_ex_exactly_of_type(lastfactor_rest,numeric) &&
490 ex_to_numeric(lastfactor_coeff).is_equal(numONE())) {
491 epvector s=mulref.seq;
493 //return expair((new mul(s,1))->setflag(status_flags::dynallocated),
495 mul * mulp=static_cast<mul *>(mulref.duplicate());
496 #ifdef EXPAIRSEQ_USE_HASHTAB
497 mulp->remove_hashtab_entry(mulp->seq.end()-1);
498 #endif // def EXPAIRSEQ_USE_HASHTAB
499 mulp->seq.pop_back();
500 #ifdef EXPAIRSEQ_USE_HASHTAB
501 mulp->shrink_hashtab();
502 #endif // def EXPAIRSEQ_USE_HASHTAB
503 mulp->clearflag(status_flags::evaluated);
504 mulp->clearflag(status_flags::hash_calculated);
505 return expair(mulp->setflag(status_flags::dynallocated),lastfactor_rest);
508 return expair(e,exONE());
512 expair add::split_ex_to_pair(ex const & e) const
514 if (is_ex_exactly_of_type(e,mul)) {
515 mul const & mulref=ex_to_mul(e);
516 ex numfactor=mulref.overall_coeff;
517 // mul * mulcopyp=static_cast<mul *>(mulref.duplicate());
518 mul * mulcopyp=new mul(mulref);
519 mulcopyp->overall_coeff=exONE();
520 mulcopyp->clearflag(status_flags::evaluated);
521 mulcopyp->clearflag(status_flags::hash_calculated);
522 return expair(mulcopyp->setflag(status_flags::dynallocated),numfactor);
524 return expair(e,exONE());
528 expair add::combine_ex_with_coeff_to_pair(ex const & e,
531 ASSERT(is_ex_exactly_of_type(c,numeric));
532 if (is_ex_exactly_of_type(e,mul)) {
533 mul const & mulref=ex_to_mul(e);
534 ASSERT(mulref.seq.size()>1);
535 ex const & lastfactor_rest=(*(mulref.seq.end()-1)).rest;
536 ex const & lastfactor_coeff=(*(mulref.seq.end()-1)).coeff;
537 if (is_ex_exactly_of_type(lastfactor_rest,numeric) &&
538 ex_to_numeric(lastfactor_coeff).is_equal(numONE())) {
539 //epvector s=mulref.seq;
541 //return expair((new mul(s,1))->setflag(status_flags::dynallocated),
542 // ex_to_numeric(lastfactor).mul_dyn(ex_to_numeric(c)));
543 mul * mulp=static_cast<mul *>(mulref.duplicate());
544 #ifdef EXPAIRSEQ_USE_HASHTAB
545 mulp->remove_hashtab_entry(mulp->seq.end()-1);
546 #endif // def EXPAIRSEQ_USE_HASHTAB
547 mulp->seq.pop_back();
548 #ifdef EXPAIRSEQ_USE_HASHTAB
549 mulp->shrink_hashtab();
550 #endif // def EXPAIRSEQ_USE_HASHTAB
551 mulp->clearflag(status_flags::evaluated);
552 mulp->clearflag(status_flags::hash_calculated);
553 if (are_ex_trivially_equal(c,exONE())) {
554 return expair(mulp->setflag(status_flags::dynallocated),lastfactor_rest);
555 } else if (are_ex_trivially_equal(lastfactor_rest,exONE())) {
556 return expair(mulp->setflag(status_flags::dynallocated),c);
558 return expair(mulp->setflag(status_flags::dynallocated),
559 ex_to_numeric(lastfactor_rest).mul_dyn(ex_to_numeric(c)));
566 expair add::combine_ex_with_coeff_to_pair(ex const & e,
569 ASSERT(is_ex_exactly_of_type(c,numeric));
570 if (is_ex_exactly_of_type(e,mul)) {
571 mul const & mulref=ex_to_mul(e);
572 ex numfactor=mulref.overall_coeff;
573 //mul * mulcopyp=static_cast<mul *>(mulref.duplicate());
574 mul * mulcopyp=new mul(mulref);
575 mulcopyp->overall_coeff=exONE();
576 mulcopyp->clearflag(status_flags::evaluated);
577 mulcopyp->clearflag(status_flags::hash_calculated);
578 if (are_ex_trivially_equal(c,exONE())) {
579 return expair(mulcopyp->setflag(status_flags::dynallocated),numfactor);
580 } else if (are_ex_trivially_equal(numfactor,exONE())) {
581 return expair(mulcopyp->setflag(status_flags::dynallocated),c);
583 return expair(mulcopyp->setflag(status_flags::dynallocated),
584 ex_to_numeric(numfactor).mul_dyn(ex_to_numeric(c)));
585 } else if (is_ex_exactly_of_type(e,numeric)) {
586 if (are_ex_trivially_equal(c,exONE())) {
587 return expair(e,exONE());
589 return expair(ex_to_numeric(e).mul_dyn(ex_to_numeric(c)),exONE());
594 expair add::combine_pair_with_coeff_to_pair(expair const & p,
597 ASSERT(is_ex_exactly_of_type(p.coeff,numeric));
598 ASSERT(is_ex_exactly_of_type(c,numeric));
600 if (is_ex_exactly_of_type(p.rest,numeric)) {
601 ASSERT(ex_to_numeric(p.coeff).is_equal(numONE())); // should be normalized
602 return expair(ex_to_numeric(p.rest).mul_dyn(ex_to_numeric(c)),exONE());
605 return expair(p.rest,ex_to_numeric(p.coeff).mul_dyn(ex_to_numeric(c)));
608 ex add::recombine_pair_to_ex(expair const & p) const
610 //if (p.coeff.compare(exONE())==0) {
611 //if (are_ex_trivially_equal(p.coeff,exONE())) {
612 if (ex_to_numeric(p.coeff).is_equal(numONE())) {
615 return p.rest*p.coeff;
619 ex add::expand(unsigned options) const
621 epvector * vp=expandchildren(options);
625 return (new add(vp,overall_coeff))->setflag(status_flags::expanded |
626 status_flags::dynallocated );
630 // new virtual functions which can be overridden by derived classes
636 // non-virtual functions in this class
642 // static member variables
647 unsigned add::precedence=40;
654 type_info const & typeid_add=typeid(some_add);