3 * Implementation of GiNaC's products 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
31 // default constructor, destructor, copy constructor assignment operator and helpers
38 debugmsg("mul default constructor",LOGLEVEL_CONSTRUCT);
39 tinfo_key = TINFO_mul;
44 debugmsg("mul destructor",LOGLEVEL_DESTRUCT);
48 mul::mul(mul const & other)
50 debugmsg("mul copy constructor",LOGLEVEL_CONSTRUCT);
54 mul const & mul::operator=(mul const & other)
56 debugmsg("mul operator=",LOGLEVEL_ASSIGNMENT);
66 void mul::copy(mul const & other)
68 expairseq::copy(other);
71 void mul::destroy(bool call_parent)
73 if (call_parent) expairseq::destroy(call_parent);
82 mul::mul(ex const & lh, ex const & rh)
84 debugmsg("mul constructor from ex,ex",LOGLEVEL_CONSTRUCT);
85 tinfo_key = TINFO_mul;
86 overall_coeff=exONE();
87 construct_from_2_ex(lh,rh);
88 ASSERT(is_canonical());
91 mul::mul(exvector const & v)
93 debugmsg("mul constructor from exvector",LOGLEVEL_CONSTRUCT);
94 tinfo_key = TINFO_mul;
95 overall_coeff=exONE();
96 construct_from_exvector(v);
97 ASSERT(is_canonical());
101 mul::mul(epvector const & v, bool do_not_canonicalize)
103 debugmsg("mul constructor from epvector,bool",LOGLEVEL_CONSTRUCT);
104 tinfo_key = TINFO_mul;
105 if (do_not_canonicalize) {
107 #ifdef EXPAIRSEQ_USE_HASHTAB
108 combine_same_terms(); // to build hashtab
109 #endif // def EXPAIRSEQ_USE_HASHTAB
111 construct_from_epvector(v);
113 ASSERT(is_canonical());
117 mul::mul(epvector const & v)
119 debugmsg("mul constructor from epvector",LOGLEVEL_CONSTRUCT);
120 tinfo_key = TINFO_mul;
121 overall_coeff=exONE();
122 construct_from_epvector(v);
123 ASSERT(is_canonical());
126 mul::mul(epvector const & v, ex const & oc)
128 debugmsg("mul constructor from epvector,ex",LOGLEVEL_CONSTRUCT);
129 tinfo_key = TINFO_mul;
131 construct_from_epvector(v);
132 ASSERT(is_canonical());
135 mul::mul(epvector * vp, ex const & oc)
137 debugmsg("mul constructor from epvector *,ex",LOGLEVEL_CONSTRUCT);
138 tinfo_key = TINFO_mul;
141 construct_from_epvector(*vp);
143 ASSERT(is_canonical());
146 mul::mul(ex const & lh, ex const & mh, ex const & rh)
148 debugmsg("mul constructor from ex,ex,ex",LOGLEVEL_CONSTRUCT);
149 tinfo_key = TINFO_mul;
152 factors.push_back(lh);
153 factors.push_back(mh);
154 factors.push_back(rh);
155 overall_coeff=exONE();
156 construct_from_exvector(factors);
157 ASSERT(is_canonical());
161 // functions overriding virtual functions from bases classes
166 basic * mul::duplicate() const
168 debugmsg("mul duplicate",LOGLEVEL_ASSIGNMENT);
169 return new mul(*this);
172 bool mul::info(unsigned inf) const
175 if (inf==info_flags::polynomial || inf==info_flags::integer_polynomial || inf==info_flags::rational_polynomial || inf==info_flags::rational_function) {
176 for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
177 if (!(recombine_pair_to_ex(*it).info(inf)))
182 return expairseq::info(inf);
186 typedef vector<int> intvector;
188 int mul::degree(symbol const & s) const
191 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
192 deg_sum+=(*cit).rest.degree(s) * ex_to_numeric((*cit).coeff).to_int();
197 int mul::ldegree(symbol const & s) const
200 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
201 deg_sum+=(*cit).rest.ldegree(s) * ex_to_numeric((*cit).coeff).to_int();
206 ex mul::coeff(symbol const & s, int const n) const
209 coeffseq.reserve(seq.size()+1);
212 // product of individual coeffs
213 // if a non-zero power of s is found, the resulting product will be 0
214 epvector::const_iterator it=seq.begin();
215 while (it!=seq.end()) {
216 coeffseq.push_back(recombine_pair_to_ex(*it).coeff(s,n));
219 coeffseq.push_back(overall_coeff);
220 return (new mul(coeffseq))->setflag(status_flags::dynallocated);
223 epvector::const_iterator it=seq.begin();
225 while (it!=seq.end()) {
226 ex t=recombine_pair_to_ex(*it);
229 coeffseq.push_back(c);
232 coeffseq.push_back(t);
237 coeffseq.push_back(overall_coeff);
238 return (new mul(coeffseq))->setflag(status_flags::dynallocated);
245 ex mul::eval(int level) const
247 // simplifications: *(...,x,(c1,1),(c2,1)) -> *(...,x,(c1*c2,1)) (c1, c2 numeric(), move pairs to end first)
248 // *(...,x,1) -> *(...,x)
250 // *(+(x,y,...),(c,1)) -> *(+(*(x,c),*(y,c),...)) (c numeric())
254 debugmsg("mul 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,mul))||
260 (!(ex_to_numeric((*cit).coeff).is_integer())));
263 // test if all numerics were moved to the end and
264 // all numerics with coeff 1 to the very end
266 epvector::const_iterator cit=seq.end();
267 bool all_coeff_1=true;
268 bool all_numeric=true;
271 if (is_ex_exactly_of_type((*cit).rest,numeric)) {
273 if ((*cit).coeff.is_equal(exONE())) {
281 } while (cit!=seq.begin());
283 #endif // def DOASSERT
288 epvector::iterator it1,it2;
289 bool seq_copied=false;
291 epvector * evaled_seqp=evalchildren(level);
292 if (evaled_seqp!=0) {
293 // do more evaluation later
294 return (new mul(evaled_seqp))->setflag(status_flags::dynallocated);
297 // combine pairs with coeff 1 (all numerics should be at end, assert below)
299 // count number of pairs with coeff 1
300 unsigned num_coeff_1=0;
301 bool still_numeric=true;
302 epvector::const_iterator cit=seq.end();
307 if (is_ex_exactly_of_type((*cit).rest,numeric)) {
308 if ((*cit).coeff.is_equal(exONE())) {
314 } while ((cit!=seq.begin())&&still_numeric);
322 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
323 ASSERT((!is_ex_exactly_of_type((*cit).rest,mul))||
324 (!(ex_to_numeric((*cit).coeff).is_integer())));
327 // test if all numerics were moved to the end and
328 // all numerics with coeff 1 to the very end
330 epvector::const_iterator cit=seq.end();
331 bool all_coeff_1=true;
332 bool all_numeric=true;
335 if (is_ex_exactly_of_type((*cit).rest,numeric)) {
337 if ((*cit).coeff.is_equal(exONE())) {
345 } while (cit!=seq.begin());
347 #endif // def DOASSERT
349 if (flags & status_flags::evaluated) {
353 expair const & last_expair=*(seq.end()-1);
354 expair const & next_to_last_expair=*(seq.end()-2);
355 int seq_size = seq.size();
357 // *(...,x,(c1,1),(c2,1)) -> *(...,x,(c1*c2,1)) (c1, c2 numeric())
358 if ((!seq_copied) && (seq_size>=2) &&
359 is_ex_exactly_of_type(last_expair.rest,numeric) &&
360 ex_to_numeric(last_expair.coeff).is_equal(numONE()) &&
361 is_ex_exactly_of_type(next_to_last_expair.rest,numeric) &&
362 ex_to_numeric(next_to_last_expair.coeff).is_equal(numONE()) ) {
368 while (seq_copied && (newseq.size()>=2) &&
369 is_ex_exactly_of_type((*it1).rest,numeric) &&
370 ex_to_numeric((*it1).coeff).is_equal(numONE()) &&
371 is_ex_exactly_of_type((*it2).rest,numeric) &&
372 ex_to_numeric((*it2).coeff).is_equal(numONE()) ) {
373 *it1=expair(ex_to_numeric((*it1).rest).mul_dyn(ex_to_numeric((*it2).rest)),exONE());
379 // *(...,x,1) -> *(...,x)
380 if ((!seq_copied) && (seq_size>=1) &&
381 (is_ex_exactly_of_type(last_expair.rest,numeric)) &&
382 (ex_to_numeric(last_expair.rest).compare(numONE())==0)) {
387 if (seq_copied && (newseq.size()>=1) &&
388 (is_ex_exactly_of_type((*it2).rest,numeric)) &&
389 (ex_to_numeric((*it2).rest).compare(numONE())==0)) {
395 if ((!seq_copied) && (seq_size>=1) &&
396 (is_ex_exactly_of_type(last_expair.rest,numeric)) &&
397 (ex_to_numeric(last_expair.rest).is_zero())) {
400 if (seq_copied && (newseq.size()>=1) &&
401 (is_ex_exactly_of_type((*it2).rest,numeric)) &&
402 (ex_to_numeric((*it2).rest).is_zero())) {
406 // *(+(x,y,...),c) -> +(*(x,c),*(y,c),...) (c numeric(), no powers of +())
407 if ((!seq_copied) && (seq_size==2) &&
408 is_ex_exactly_of_type(next_to_last_expair.rest,add) &&
409 is_ex_exactly_of_type(last_expair.rest,numeric) &&
410 ex_to_numeric(last_expair.coeff).is_equal(numONE()) &&
411 (ex_to_numeric(next_to_last_expair.coeff).compare(numONE())==0)) {
412 add const & addref=ex_to_add(next_to_last_expair.rest);
414 distrseq.reserve(addref.seq.size());
415 for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
416 distrseq.push_back(addref.combine_pair_with_coeff_to_pair(*cit,
419 // special treatment for the last element if it is numeric (to
420 // avoid terms like (2/3)*(3/2)) is no longer necessary, this
421 // is handled in add::combine_pair_with_coeff_to_pair()
422 return (new add(distrseq,1))->setflag(status_flags::dynallocated |
423 status_flags::evaluated );
425 if (seq_copied && (newseq.size()==2) &&
426 is_ex_exactly_of_type(newseq[0].rest,add) &&
427 is_ex_exactly_of_type(newseq[1].rest,numeric) &&
428 ex_to_numeric(newseq[1].coeff).is_equal(numONE()) &&
429 (ex_to_numeric(newseq[0].coeff).compare(numONE())==0)) {
430 add const & addref=ex_to_add(newseq[0].rest);
432 distrseq.reserve(addref.seq.size());
433 for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
434 distrseq.push_back(addref.combine_pair_with_coeff_to_pair(*cit,
437 // special treatment for the last element if it is numeric (to
438 // avoid terms like (2/3)*(3/2)) is no longer necessary, this
439 // is handled in add::combine_pair_with_coeff_to_pair()
440 return (new add(distrseq,1))->setflag(status_flags::dynallocated |
441 status_flags::evaluated );
445 if ((!seq_copied) && (seq_size==0)) {
447 } else if (seq_copied && (newseq.size()==0)) {
452 if ((!seq_copied) && (seq_size==1)) {
453 return recombine_pair_to_ex(*(seq.begin()));
454 } else if (seq_copied && (newseq.size()==1)) {
455 return recombine_pair_to_ex(*(newseq.begin()));
458 if (!seq_copied) return this->hold();
460 return (new mul(newseq,1))->setflag(status_flags::dynallocated |
461 status_flags::evaluated );
465 ex mul::eval(int level) const
467 // simplifications *(...,x;0) -> 0
468 // *(+(x,y,...);c) -> *(+(*(x,c),*(y,c),...)) (c numeric())
472 debugmsg("mul eval",LOGLEVEL_MEMBER_FUNCTION);
474 epvector * evaled_seqp=evalchildren(level);
475 if (evaled_seqp!=0) {
476 // do more evaluation later
477 return (new mul(evaled_seqp,overall_coeff))->
478 setflag(status_flags::dynallocated);
482 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
483 ASSERT((!is_ex_exactly_of_type((*cit).rest,mul))||
484 (!(ex_to_numeric((*cit).coeff).is_integer())));
485 ASSERT(!((*cit).is_numeric_with_coeff_1()));
486 if (is_ex_exactly_of_type(recombine_pair_to_ex(*cit),numeric)) {
489 ASSERT(!is_ex_exactly_of_type(recombine_pair_to_ex(*cit),numeric));
491 expair p=split_ex_to_pair(recombine_pair_to_ex(*cit));
492 ASSERT(p.rest.is_equal((*cit).rest));
493 ASSERT(p.coeff.is_equal((*cit).coeff));
496 #endif // def DOASSERT
498 if (flags & status_flags::evaluated) {
499 ASSERT(seq.size()>0);
500 ASSERT((seq.size()>1)||!overall_coeff.is_equal(exONE()));
504 int seq_size=seq.size();
505 if (overall_coeff.is_equal(exZERO())) {
508 } else if (seq_size==0) {
510 return overall_coeff;
511 } else if ((seq_size==1)&&overall_coeff.is_equal(exONE())) {
513 return recombine_pair_to_ex(*(seq.begin()));
514 } else if ((seq_size==1) &&
515 is_ex_exactly_of_type((*seq.begin()).rest,add) &&
516 ex_to_numeric((*seq.begin()).coeff).is_equal(numONE())) {
517 // *(+(x,y,...);c) -> +(*(x,c),*(y,c),...) (c numeric(), no powers of +())
518 add const & addref=ex_to_add((*seq.begin()).rest);
520 distrseq.reserve(addref.seq.size());
521 for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
522 distrseq.push_back(addref.combine_pair_with_coeff_to_pair(*cit,
525 return (new add(distrseq,
526 ex_to_numeric(addref.overall_coeff).
527 mul_dyn(ex_to_numeric(overall_coeff))))
528 ->setflag(status_flags::dynallocated |
529 status_flags::evaluated );
535 ex mul::eval(int level) const
537 // simplifications: *(...,x,c1,c2) -> *(...,x,c1*c2) (c1, c2 numeric())
538 // *(...,(c1,c2)) -> (...,(c1^c2,1)) (normalize)
539 // *(...,x,1) -> +(...,x)
541 // *(+(x,y,...),c) -> *(+(*(x,c),*(y,c),...)) (c numeric())
545 debugmsg("mul eval",LOGLEVEL_MEMBER_FUNCTION);
548 epvector::iterator it1,it2;
550 // *(...,x,c1,c2) -> *(...,x,c1*c2) (c1, c2 numeric())
553 while ((newseq.size()>=2)&&is_exactly_of_type(*(*it1).rest.bp,numeric)&&
554 is_exactly_of_type(*(*it2).rest.bp,numeric)) {
555 *it1=expair(ex_to_numeric((*it1).rest).power(ex_to_numeric((*it1).coeff))
556 .mul(ex_to_numeric((*it2).rest).power(ex_to_numeric((*it2).coeff))),exONE());
562 if ((newseq.size()>=1)&&is_exactly_of_type(*(*it2).rest.bp,numeric)) {
563 // *(...,(c1,c2)) -> (...,(c1^c2,1)) (normalize)
564 *it2=expair(ex_to_numeric((*it2).rest).power(ex_to_numeric((*it2).coeff)),exONE());
565 // *(...,x,1) -> *(...,x)
566 if (static_cast<numeric &>(*(*it2).rest.bp).compare(numONE())==0) {
573 if ((newseq.size()>=1)&&is_exactly_of_type(*(*it2).rest.bp,numeric)) {
574 if (static_cast<numeric &>(*(*it2).rest.bp).is_zero()==0) {
579 // *(+(x,y,...),c) -> +(*(x,c),*(y,c),...) (c numeric(), no powers of +())
580 if ((newseq.size()==2)&&is_ex_exactly_of_type(newseq[0].rest,add)&&
581 is_ex_exactly_of_type(newseq[1].rest,numeric)&&
582 (ex_to_numeric(newseq[0].coeff).compare(numONE())==0)) {
583 add const & addref=ex_to_add(newseq[0].rest);
584 numeric const & numref=ex_to_numeric(newseq[1].rest);
586 distrseq.reserve(addref.seq.size());
587 for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
588 distrseq.push_back(expair((*cit).rest,ex_to_numeric((*cit).coeff).mul(numref)));
590 return (new add(distrseq,1))->setflag(status_flags::dynallocated |
591 status_flags::evaluated );
594 if (newseq.size()==0) {
597 } else if (newseq.size()==1) {
599 return recombine_pair_to_ex(*newseq.begin());
602 return (new mul(newseq,1))->setflag(status_flags::dynallocated |
603 status_flags::evaluated );
607 exvector mul::get_indices(void) const
609 // return union of indices of factors
611 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
612 exvector subiv=(*cit).rest.get_indices();
613 iv.reserve(iv.size()+subiv.size());
614 for (exvector::const_iterator cit2=subiv.begin(); cit2!=subiv.end(); ++cit2) {
621 ex mul::simplify_ncmul(exvector const & v) const
623 throw(std::logic_error("mul::simplify_ncmul() should never have been called!"));
628 int mul::compare_same_type(basic const & other) const
630 return expairseq::compare_same_type(other);
633 bool mul::is_equal_same_type(basic const & other) const
635 return expairseq::is_equal_same_type(other);
638 unsigned mul::return_type(void) const
641 // mul without factors: should not happen, but commutes
642 return return_types::commutative;
645 bool all_commutative=1;
647 epvector::const_iterator cit_noncommutative_element; // point to first found nc element
649 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
650 rt=(*cit).rest.return_type();
651 if (rt==return_types::noncommutative_composite) return rt; // one ncc -> mul also ncc
652 if ((rt==return_types::noncommutative)&&(all_commutative)) {
653 // first nc element found, remember position
654 cit_noncommutative_element=cit;
657 if ((rt==return_types::noncommutative)&&(!all_commutative)) {
658 // another nc element found, compare type_infos
659 if ((*cit_noncommutative_element).rest.return_type_tinfo()!=(*cit).rest.return_type_tinfo()) {
660 // diffent types -> mul is ncc
661 return return_types::noncommutative_composite;
665 // all factors checked
666 return all_commutative ? return_types::commutative : return_types::noncommutative;
669 unsigned mul::return_type_tinfo(void) const
672 // mul without factors: should not happen
675 // return type_info of first noncommutative element
676 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
677 if ((*cit).rest.return_type()==return_types::noncommutative) {
678 return (*cit).rest.return_type_tinfo();
681 // no noncommutative element found, should not happen
685 ex mul::thisexpairseq(epvector const & v, ex const & oc) const
687 return (new mul(v,oc))->setflag(status_flags::dynallocated);
690 ex mul::thisexpairseq(epvector * vp, ex const & oc) const
692 return (new mul(vp,oc))->setflag(status_flags::dynallocated);
695 expair mul::split_ex_to_pair(ex const & e) const
697 if (is_ex_exactly_of_type(e,power)) {
698 power const & powerref=ex_to_power(e);
699 if (is_ex_exactly_of_type(powerref.exponent,numeric)) {
700 return expair(powerref.basis,powerref.exponent);
703 return expair(e,exONE());
706 expair mul::combine_ex_with_coeff_to_pair(ex const & e,
709 // to avoid duplication of power simplification rules,
710 // we create a temporary power object
711 // otherwise it would be hard to correctly simplify
712 // expression like (4^(1/3))^(3/2)
713 if (are_ex_trivially_equal(c,exONE())) {
714 return split_ex_to_pair(e);
716 return split_ex_to_pair(power(e,c));
719 expair mul::combine_pair_with_coeff_to_pair(expair const & p,
722 // to avoid duplication of power simplification rules,
723 // we create a temporary power object
724 // otherwise it would be hard to correctly simplify
725 // expression like (4^(1/3))^(3/2)
726 if (are_ex_trivially_equal(c,exONE())) {
729 return split_ex_to_pair(power(recombine_pair_to_ex(p),c));
732 ex mul::recombine_pair_to_ex(expair const & p) const
734 // if (p.coeff.compare(exONE())==0) {
735 // if (are_ex_trivially_equal(p.coeff,exONE())) {
736 if (ex_to_numeric(p.coeff).is_equal(numONE())) {
739 return power(p.rest,p.coeff);
743 bool mul::expair_needs_further_processing(epp it)
745 if (is_ex_exactly_of_type((*it).rest,mul) &&
746 ex_to_numeric((*it).coeff).is_integer()) {
747 // combined pair is product with integer power -> expand it
748 *it=split_ex_to_pair(recombine_pair_to_ex(*it));
751 if (is_ex_exactly_of_type((*it).rest,numeric)) {
752 expair ep=split_ex_to_pair(recombine_pair_to_ex(*it));
753 if (!ep.is_equal(*it)) {
754 // combined pair is a numeric power which can be simplified
758 if (ex_to_numeric((*it).coeff).is_equal(numONE())) {
759 // combined pair has coeff 1 and must be moved to the end
766 ex mul::default_overall_coeff(void) const
771 void mul::combine_overall_coeff(ex const & c)
773 ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
774 ASSERT(is_ex_exactly_of_type(c,numeric));
775 overall_coeff = ex_to_numeric(overall_coeff).mul_dyn(ex_to_numeric(c));
778 void mul::combine_overall_coeff(ex const & c1, ex const & c2)
780 ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
781 ASSERT(is_ex_exactly_of_type(c1,numeric));
782 ASSERT(is_ex_exactly_of_type(c2,numeric));
783 overall_coeff = ex_to_numeric(overall_coeff).
784 mul_dyn(ex_to_numeric(c1).power(ex_to_numeric(c2)));
787 bool mul::can_make_flat(expair const & p) const
789 ASSERT(is_ex_exactly_of_type(p.coeff,numeric));
790 // this assertion will probably fail somewhere
791 // it would require a more careful make_flat, obeying the power laws
792 // probably should return true only if p.coeff is integer
793 return ex_to_numeric(p.coeff).is_equal(numONE());
796 ex mul::expand(unsigned options) const
798 exvector sub_expanded_seq;
799 intvector positions_of_adds;
800 intvector number_of_add_operands;
802 epvector * expanded_seqp=expandchildren(options);
804 epvector const & expanded_seq = expanded_seqp==0 ? seq : *expanded_seqp;
806 positions_of_adds.resize(expanded_seq.size());
807 number_of_add_operands.resize(expanded_seq.size());
809 int number_of_adds=0;
810 int number_of_expanded_terms=1;
812 unsigned current_position=0;
813 epvector::const_iterator last=expanded_seq.end();
814 for (epvector::const_iterator cit=expanded_seq.begin(); cit!=last; ++cit) {
815 if (is_ex_exactly_of_type((*cit).rest,add)&&
816 (ex_to_numeric((*cit).coeff).is_equal(numONE()))) {
817 positions_of_adds[number_of_adds]=current_position;
818 add const & expanded_addref=ex_to_add((*cit).rest);
819 int addref_nops=expanded_addref.nops();
820 number_of_add_operands[number_of_adds]=addref_nops;
821 number_of_expanded_terms *= addref_nops;
827 if (number_of_adds==0) {
828 if (expanded_seqp==0) {
829 return this->setflag(status_flags::expanded);
831 return (new mul(expanded_seqp,overall_coeff))->
832 setflag(status_flags::dynallocated ||
833 status_flags::expanded);
837 distrseq.reserve(number_of_expanded_terms);
840 k.resize(number_of_adds);
843 for (l=0; l<number_of_adds; l++) {
850 for (l=0; l<number_of_adds; l++) {
851 add const & addref=ex_to_add(expanded_seq[positions_of_adds[l]].rest);
852 ASSERT(term[positions_of_adds[l]].coeff.compare(exONE())==0);
853 term[positions_of_adds[l]]=split_ex_to_pair(addref.op(k[l]));
856 cout << "mul::expand() term begin" << endl;
857 for (epvector::const_iterator cit=term.begin(); cit!=term.end(); ++cit) {
858 cout << "rest" << endl;
859 (*cit).rest.printtree(cout);
860 cout << "coeff" << endl;
861 (*cit).coeff.printtree(cout);
863 cout << "mul::expand() term end" << endl;
865 distrseq.push_back((new mul(term,overall_coeff))->
866 setflag(status_flags::dynallocated |
867 status_flags::expanded));
871 while ((l>=0)&&((++k[l])>=number_of_add_operands[l])) {
878 if (expanded_seqp!=0) {
879 delete expanded_seqp;
882 cout << "mul::expand() distrseq begin" << endl;
883 for (exvector::const_iterator cit=distrseq.begin(); cit!=distrseq.end(); ++cit) {
884 (*cit).printtree(cout);
886 cout << "mul::expand() distrseq end" << endl;
889 return (new add(distrseq))->setflag(status_flags::dynallocated |
890 status_flags::expanded);
894 ex mul::expand(unsigned options) const
896 exvector sub_expanded_seq;
897 intvector positions_of_adds;
898 intvector number_of_add_operands;
900 sub_expanded_seq.resize(seq.size());
901 positions_of_adds.resize(seq.size());
902 number_of_add_operands.reserve(seq.size());
904 int number_of_adds=0;
905 int number_of_expanded_terms=1;
906 for (unsigned current_position=0; current_position<seq.size(); current_position++) {
907 ex const & expanded_ex=recombine_pair_to_ex(seq[current_position]).expand(options);
908 if (is_ex_exactly_of_type(expanded_ex,add)) {
909 positions_of_adds[number_of_adds]=current_position;
910 add const & expanded_addref=ex_to_add(expanded_ex);
911 number_of_add_operands[number_of_adds]=expanded_addref.seq.size();
912 number_of_expanded_terms *= expanded_addref.seq.size();
915 sub_expanded_seq.push_back(expanded_ex);
919 distrseq.reserve(number_of_expanded_terms);
922 k.resize(number_of_adds);
925 for (l=0; l<number_of_adds; l++) {
931 term=sub_expanded_seq;
932 for (l=0; l<number_of_adds; l++) {
933 add const & addref=ex_to_add(sub_expanded_seq[positions_of_adds[l]]);
934 term[positions_of_adds[l]]=addref.recombine_pair_to_ex(addref.seq[k[l]]);
936 distrseq.push_back((new mul(term))->setflag(status_flags::dynallocated |
937 status_flags::expanded));
941 while ((l>=0)&&((++k[l])>=number_of_add_operands[l])) {
948 return (new add(distrseq))->setflag(status_flags::dynallocated |
949 status_flags::expanded);
954 // new virtual functions which can be overridden by derived classes
960 // non-virtual functions in this class
963 epvector * mul::expandchildren(unsigned options) const
965 epvector::const_iterator last=seq.end();
966 epvector::const_iterator cit=seq.begin();
968 ex const & factor=recombine_pair_to_ex(*cit);
969 ex const & expanded_factor=factor.expand(options);
970 if (!are_ex_trivially_equal(factor,expanded_factor)) {
972 // something changed, copy seq, eval and return it
973 epvector *s=new epvector;
974 s->reserve(seq.size());
976 // copy parts of seq which are known not to have changed
977 epvector::const_iterator cit2=seq.begin();
982 // copy first changed element
983 s->push_back(split_ex_to_pair(expanded_factor));
987 s->push_back(split_ex_to_pair(recombine_pair_to_ex(*cit2).expand(options)));
995 return 0; // nothing has changed
999 // static member variables
1004 unsigned mul::precedence=50;
1012 type_info const & typeid_mul=typeid(some_mul);