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
30 #ifndef NO_GINAC_NAMESPACE
32 #endif // ndef NO_GINAC_NAMESPACE
35 // default constructor, destructor, copy constructor assignment operator and helpers
42 debugmsg("add default constructor",LOGLEVEL_CONSTRUCT);
43 tinfo_key = TINFO_add;
48 debugmsg("add destructor",LOGLEVEL_DESTRUCT);
52 add::add(add const & other)
54 debugmsg("add copy constructor",LOGLEVEL_CONSTRUCT);
58 add const & add::operator=(add const & other)
60 debugmsg("add operator=",LOGLEVEL_ASSIGNMENT);
70 void add::copy(add const & other)
72 expairseq::copy(other);
75 void add::destroy(bool call_parent)
77 if (call_parent) expairseq::destroy(call_parent);
86 add::add(ex const & lh, ex const & rh)
88 debugmsg("add constructor from ex,ex",LOGLEVEL_CONSTRUCT);
89 tinfo_key = TINFO_add;
90 overall_coeff=exZERO();
91 construct_from_2_ex(lh,rh);
92 GINAC_ASSERT(is_canonical());
95 add::add(exvector const & v)
97 debugmsg("add constructor from exvector",LOGLEVEL_CONSTRUCT);
98 tinfo_key = TINFO_add;
99 overall_coeff=exZERO();
100 construct_from_exvector(v);
101 GINAC_ASSERT(is_canonical());
105 add::add(epvector const & v, bool do_not_canonicalize)
107 debugmsg("add constructor from epvector,bool",LOGLEVEL_CONSTRUCT);
108 tinfo_key = TINFO_add;
109 if (do_not_canonicalize) {
111 #ifdef EXPAIRSEQ_USE_HASHTAB
112 combine_same_terms(); // to build hashtab
113 #endif // def EXPAIRSEQ_USE_HASHTAB
115 construct_from_epvector(v);
117 GINAC_ASSERT(is_canonical());
121 add::add(epvector const & v)
123 debugmsg("add constructor from epvector",LOGLEVEL_CONSTRUCT);
124 tinfo_key = TINFO_add;
125 overall_coeff=exZERO();
126 construct_from_epvector(v);
127 GINAC_ASSERT(is_canonical());
130 add::add(epvector const & v, ex const & oc)
132 debugmsg("add constructor from epvector,ex",LOGLEVEL_CONSTRUCT);
133 tinfo_key = TINFO_add;
135 construct_from_epvector(v);
136 GINAC_ASSERT(is_canonical());
139 add::add(epvector * vp, ex const & oc)
141 debugmsg("add constructor from epvector *,ex",LOGLEVEL_CONSTRUCT);
142 tinfo_key = TINFO_add;
145 construct_from_epvector(*vp);
147 GINAC_ASSERT(is_canonical());
151 // functions overriding virtual functions from bases classes
156 basic * add::duplicate() const
158 debugmsg("add duplicate",LOGLEVEL_DUPLICATE);
159 return new add(*this);
162 bool add::info(unsigned inf) const
165 if (inf==info_flags::polynomial || inf==info_flags::integer_polynomial || inf==info_flags::rational_polynomial || inf==info_flags::rational_function) {
166 for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
167 if (!(recombine_pair_to_ex(*it).info(inf)))
172 return expairseq::info(inf);
176 int add::degree(symbol const & s) const
179 if (!overall_coeff.is_equal(exZERO())) {
183 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
184 cur_deg=(*cit).rest.degree(s);
185 if (cur_deg>deg) deg=cur_deg;
190 int add::ldegree(symbol const & s) const
193 if (!overall_coeff.is_equal(exZERO())) {
197 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
198 cur_deg=(*cit).rest.ldegree(s);
199 if (cur_deg<deg) deg=cur_deg;
204 ex add::coeff(symbol const & s, int const n) const
207 coeffseq.reserve(seq.size());
209 epvector::const_iterator it=seq.begin();
210 while (it!=seq.end()) {
211 coeffseq.push_back(combine_ex_with_coeff_to_pair((*it).rest.coeff(s,n),
216 return (new add(coeffseq,overall_coeff))->setflag(status_flags::dynallocated);
218 return (new add(coeffseq))->setflag(status_flags::dynallocated);
222 ex add::eval(int level) const
224 // simplifications: +(...,x,c1,c2) -> +(...,x,c1+c2) (c1, c2 numeric())
225 // +(...,(c1,c2)) -> (...,(c1*c2,1)) (normalize)
226 // +(...,x,0) -> +(...,x)
230 debugmsg("add eval",LOGLEVEL_MEMBER_FUNCTION);
233 epvector::iterator it1,it2;
235 // +(...,x,c1,c2) -> +(...,x,c1+c2) (c1, c2 numeric())
238 while ((newseq.size()>=2)&&is_exactly_of_type(*(*it1).rest.bp,numeric)&&
239 is_exactly_of_type(*(*it2).rest.bp,numeric)) {
240 *it1=expair(ex_to_numeric((*it1).rest).mul(ex_to_numeric((*it1).coeff))
241 .add(ex_to_numeric((*it2).rest).mul(ex_to_numeric((*it2).coeff))),exONE());
247 if ((newseq.size()>=1)&&is_exactly_of_type(*(*it2).rest.bp,numeric)) {
248 // +(...,(c1,c2)) -> (...,(c1*c2,1)) (normalize)
249 *it2=expair(ex_to_numeric((*it2).rest).mul(ex_to_numeric((*it2).coeff)),exONE());
250 // +(...,x,0) -> +(...,x)
251 if (ex_to_numeric((*it2).rest).compare(0)==0) {
256 if (newseq.size()==0) {
259 } else if (newseq.size()==1) {
261 return recombine_pair_to_ex(*(newseq.begin()));
264 return (new add(newseq,1))->setflag(status_flags::dynallocated |
265 status_flags::evaluated );
270 ex add::eval(int level) const
272 // simplifications: +(...,x,c1,c2) -> +(...,x,c1+c2) (c1, c2 numeric())
273 // +(...,(c1,c2)) -> (...,(c1*c2,1)) (normalize)
274 // +(...,x,0) -> +(...,x)
278 debugmsg("add eval",LOGLEVEL_MEMBER_FUNCTION);
280 if ((level==1)&&(flags & status_flags::evaluated)) {
281 #ifdef DO_GINAC_ASSERT
282 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
283 GINAC_ASSERT(!is_ex_exactly_of_type((*cit).rest,add));
284 GINAC_ASSERT(!(is_ex_exactly_of_type((*cit).rest,numeric)&&
285 (ex_to_numeric((*cit).coeff).compare(numONE())!=0)));
287 #endif // def DO_GINAC_ASSERT
292 epvector::iterator it1,it2;
293 bool seq_copied=false;
295 epvector * evaled_seqp=evalchildren(level);
296 if (evaled_seqp!=0) {
297 // do more evaluation later
298 return (new add(evaled_seqp))->setflag(status_flags::dynallocated);
301 #ifdef DO_GINAC_ASSERT
302 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
303 GINAC_ASSERT(!is_ex_exactly_of_type((*cit).rest,add));
304 GINAC_ASSERT(!(is_ex_exactly_of_type((*cit).rest,numeric)&&
305 (ex_to_numeric((*cit).coeff).compare(numONE())!=0)));
307 #endif // def DO_GINAC_ASSERT
309 if (flags & status_flags::evaluated) {
313 expair const & last_expair=*(seq.end()-1);
314 expair const & next_to_last_expair=*(seq.end()-2);
315 int seq_size = seq.size();
317 // +(...,x,c1,c2) -> +(...,x,c1+c2) (c1, c2 numeric())
318 if ((!seq_copied)&&(seq_size>=2)&&
319 is_ex_exactly_of_type(last_expair.rest,numeric)&&
320 is_ex_exactly_of_type(next_to_last_expair.rest,numeric)) {
326 while (seq_copied&&(newseq.size()>=2)&&
327 is_ex_exactly_of_type((*it1).rest,numeric)&&
328 is_ex_exactly_of_type((*it2).rest,numeric)) {
329 *it1=expair(ex_to_numeric((*it1).rest).mul(ex_to_numeric((*it1).coeff))
330 .add_dyn(ex_to_numeric((*it2).rest).mul(ex_to_numeric((*it2).coeff))),exONE());
336 // +(...,(c1,c2)) -> (...,(c1*c2,1)) (normalize)
337 if ((!seq_copied)&&(seq_size>=1)&&
338 (is_ex_exactly_of_type(last_expair.rest,numeric))&&
339 (ex_to_numeric(last_expair.coeff).compare(numONE())!=0)) {
344 if (seq_copied&&(newseq.size()>=1)&&
345 (is_ex_exactly_of_type((*it2).rest,numeric))&&
346 (ex_to_numeric((*it2).coeff).compare(numONE())!=0)) {
347 *it2=expair(ex_to_numeric((*it2).rest).mul_dyn(ex_to_numeric((*it2).coeff)),exONE());
350 // +(...,x,0) -> +(...,x)
351 if ((!seq_copied)&&(seq_size>=1)&&
352 (is_ex_exactly_of_type(last_expair.rest,numeric))&&
353 (ex_to_numeric(last_expair.rest).is_zero())) {
358 if (seq_copied&&(newseq.size()>=1)&&
359 (is_ex_exactly_of_type((*it2).rest,numeric))&&
360 (ex_to_numeric((*it2).rest).is_zero())) {
365 if ((!seq_copied)&&(seq_size==0)) {
367 } else if (seq_copied&&(newseq.size()==0)) {
372 if ((!seq_copied)&&(seq_size==1)) {
373 return recombine_pair_to_ex(*(seq.begin()));
374 } else if (seq_copied&&(newseq.size()==1)) {
375 return recombine_pair_to_ex(*(newseq.begin()));
378 if (!seq_copied) return this->hold();
380 return (new add(newseq,1))->setflag(status_flags::dynallocated |
381 status_flags::evaluated );
385 ex add::eval(int level) const
387 // simplifications: +(;c) -> c
390 debugmsg("add eval",LOGLEVEL_MEMBER_FUNCTION);
392 epvector * evaled_seqp=evalchildren(level);
393 if (evaled_seqp!=0) {
394 // do more evaluation later
395 return (new add(evaled_seqp,overall_coeff))->
396 setflag(status_flags::dynallocated);
399 #ifdef DO_GINAC_ASSERT
400 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
401 GINAC_ASSERT(!is_ex_exactly_of_type((*cit).rest,add));
402 if (is_ex_exactly_of_type((*cit).rest,numeric)) {
405 GINAC_ASSERT(!is_ex_exactly_of_type((*cit).rest,numeric));
407 #endif // def DO_GINAC_ASSERT
409 if (flags & status_flags::evaluated) {
410 GINAC_ASSERT(seq.size()>0);
411 GINAC_ASSERT((seq.size()>1)||!overall_coeff.is_equal(exZERO()));
415 int seq_size=seq.size();
418 return overall_coeff;
419 } else if ((seq_size==1)&&overall_coeff.is_equal(exZERO())) {
421 return recombine_pair_to_ex(*(seq.begin()));
426 exvector add::get_indices(void) const
428 // FIXME: all terms in the sum should have the same indices (compatible
429 // tensors) however this is not checked, since there is no function yet
430 // which compares indices (idxvector can be unsorted)
434 return (seq.begin())->rest.get_indices();
437 ex add::simplify_ncmul(exvector const & v) const
440 return expairseq::simplify_ncmul(v);
442 return (*seq.begin()).rest.simplify_ncmul(v);
447 int add::compare_same_type(basic const & other) const
449 return expairseq::compare_same_type(other);
452 bool add::is_equal_same_type(basic const & other) const
454 return expairseq::is_equal_same_type(other);
457 unsigned add::return_type(void) const
460 return return_types::commutative;
462 return (*seq.begin()).rest.return_type();
465 unsigned add::return_type_tinfo(void) const
470 return (*seq.begin()).rest.return_type_tinfo();
473 ex add::thisexpairseq(epvector const & v, ex const & oc) const
475 return (new add(v,oc))->setflag(status_flags::dynallocated);
478 ex add::thisexpairseq(epvector * vp, ex const & oc) const
480 return (new add(vp,oc))->setflag(status_flags::dynallocated);
484 expair add::split_ex_to_pair(ex const & e) const
486 if (is_ex_exactly_of_type(e,mul)) {
487 mul const & mulref=ex_to_mul(e);
488 GINAC_ASSERT(mulref.seq.size()>1);
489 ex const & lastfactor_rest=(*(mulref.seq.end()-1)).rest;
490 ex const & lastfactor_coeff=(*(mulref.seq.end()-1)).coeff;
491 if (is_ex_exactly_of_type(lastfactor_rest,numeric) &&
492 ex_to_numeric(lastfactor_coeff).is_equal(numONE())) {
493 epvector s=mulref.seq;
495 //return expair((new mul(s,1))->setflag(status_flags::dynallocated),
497 mul * mulp=static_cast<mul *>(mulref.duplicate());
498 #ifdef EXPAIRSEQ_USE_HASHTAB
499 mulp->remove_hashtab_entry(mulp->seq.end()-1);
500 #endif // def EXPAIRSEQ_USE_HASHTAB
501 mulp->seq.pop_back();
502 #ifdef EXPAIRSEQ_USE_HASHTAB
503 mulp->shrink_hashtab();
504 #endif // def EXPAIRSEQ_USE_HASHTAB
505 mulp->clearflag(status_flags::evaluated);
506 mulp->clearflag(status_flags::hash_calculated);
507 return expair(mulp->setflag(status_flags::dynallocated),lastfactor_rest);
510 return expair(e,exONE());
514 expair add::split_ex_to_pair(ex const & e) const
516 if (is_ex_exactly_of_type(e,mul)) {
517 mul const & mulref=ex_to_mul(e);
518 ex numfactor=mulref.overall_coeff;
519 // mul * mulcopyp=static_cast<mul *>(mulref.duplicate());
520 mul * mulcopyp=new mul(mulref);
521 mulcopyp->overall_coeff=exONE();
522 mulcopyp->clearflag(status_flags::evaluated);
523 mulcopyp->clearflag(status_flags::hash_calculated);
524 return expair(mulcopyp->setflag(status_flags::dynallocated),numfactor);
526 return expair(e,exONE());
530 expair add::combine_ex_with_coeff_to_pair(ex const & e,
533 GINAC_ASSERT(is_ex_exactly_of_type(c,numeric));
534 if (is_ex_exactly_of_type(e,mul)) {
535 mul const & mulref=ex_to_mul(e);
536 GINAC_ASSERT(mulref.seq.size()>1);
537 ex const & lastfactor_rest=(*(mulref.seq.end()-1)).rest;
538 ex const & lastfactor_coeff=(*(mulref.seq.end()-1)).coeff;
539 if (is_ex_exactly_of_type(lastfactor_rest,numeric) &&
540 ex_to_numeric(lastfactor_coeff).is_equal(numONE())) {
541 //epvector s=mulref.seq;
543 //return expair((new mul(s,1))->setflag(status_flags::dynallocated),
544 // ex_to_numeric(lastfactor).mul_dyn(ex_to_numeric(c)));
545 mul * mulp=static_cast<mul *>(mulref.duplicate());
546 #ifdef EXPAIRSEQ_USE_HASHTAB
547 mulp->remove_hashtab_entry(mulp->seq.end()-1);
548 #endif // def EXPAIRSEQ_USE_HASHTAB
549 mulp->seq.pop_back();
550 #ifdef EXPAIRSEQ_USE_HASHTAB
551 mulp->shrink_hashtab();
552 #endif // def EXPAIRSEQ_USE_HASHTAB
553 mulp->clearflag(status_flags::evaluated);
554 mulp->clearflag(status_flags::hash_calculated);
555 if (are_ex_trivially_equal(c,exONE())) {
556 return expair(mulp->setflag(status_flags::dynallocated),lastfactor_rest);
557 } else if (are_ex_trivially_equal(lastfactor_rest,exONE())) {
558 return expair(mulp->setflag(status_flags::dynallocated),c);
560 return expair(mulp->setflag(status_flags::dynallocated),
561 ex_to_numeric(lastfactor_rest).mul_dyn(ex_to_numeric(c)));
568 expair add::combine_ex_with_coeff_to_pair(ex const & e,
571 GINAC_ASSERT(is_ex_exactly_of_type(c,numeric));
572 if (is_ex_exactly_of_type(e,mul)) {
573 mul const & mulref=ex_to_mul(e);
574 ex numfactor=mulref.overall_coeff;
575 //mul * mulcopyp=static_cast<mul *>(mulref.duplicate());
576 mul * mulcopyp=new mul(mulref);
577 mulcopyp->overall_coeff=exONE();
578 mulcopyp->clearflag(status_flags::evaluated);
579 mulcopyp->clearflag(status_flags::hash_calculated);
580 if (are_ex_trivially_equal(c,exONE())) {
581 return expair(mulcopyp->setflag(status_flags::dynallocated),numfactor);
582 } else if (are_ex_trivially_equal(numfactor,exONE())) {
583 return expair(mulcopyp->setflag(status_flags::dynallocated),c);
585 return expair(mulcopyp->setflag(status_flags::dynallocated),
586 ex_to_numeric(numfactor).mul_dyn(ex_to_numeric(c)));
587 } else if (is_ex_exactly_of_type(e,numeric)) {
588 if (are_ex_trivially_equal(c,exONE())) {
589 return expair(e,exONE());
591 return expair(ex_to_numeric(e).mul_dyn(ex_to_numeric(c)),exONE());
596 expair add::combine_pair_with_coeff_to_pair(expair const & p,
599 GINAC_ASSERT(is_ex_exactly_of_type(p.coeff,numeric));
600 GINAC_ASSERT(is_ex_exactly_of_type(c,numeric));
602 if (is_ex_exactly_of_type(p.rest,numeric)) {
603 GINAC_ASSERT(ex_to_numeric(p.coeff).is_equal(numONE())); // should be normalized
604 return expair(ex_to_numeric(p.rest).mul_dyn(ex_to_numeric(c)),exONE());
607 return expair(p.rest,ex_to_numeric(p.coeff).mul_dyn(ex_to_numeric(c)));
610 ex add::recombine_pair_to_ex(expair const & p) const
612 //if (p.coeff.compare(exONE())==0) {
613 //if (are_ex_trivially_equal(p.coeff,exONE())) {
614 if (ex_to_numeric(p.coeff).is_equal(numONE())) {
617 return p.rest*p.coeff;
621 ex add::expand(unsigned options) const
623 epvector * vp=expandchildren(options);
627 return (new add(vp,overall_coeff))->setflag(status_flags::expanded |
628 status_flags::dynallocated );
632 // new virtual functions which can be overridden by derived classes
638 // non-virtual functions in this class
644 // static member variables
649 unsigned add::precedence=40;
656 type_info const & typeid_add=typeid(some_add);
658 #ifndef NO_GINAC_NAMESPACE
660 #endif // ndef NO_GINAC_NAMESPACE