3 * Implementation of GiNaC's products 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
30 // default constructor, destructor, copy constructor assignment operator and helpers
37 debugmsg("mul default constructor",LOGLEVEL_CONSTRUCT);
38 tinfo_key = TINFO_mul;
43 debugmsg("mul destructor",LOGLEVEL_DESTRUCT);
47 mul::mul(mul const & other)
49 debugmsg("mul copy constructor",LOGLEVEL_CONSTRUCT);
53 mul const & mul::operator=(mul const & other)
55 debugmsg("mul operator=",LOGLEVEL_ASSIGNMENT);
65 void mul::copy(mul const & other)
67 expairseq::copy(other);
70 void mul::destroy(bool call_parent)
72 if (call_parent) expairseq::destroy(call_parent);
81 mul::mul(ex const & lh, ex const & rh)
83 debugmsg("mul constructor from ex,ex",LOGLEVEL_CONSTRUCT);
84 tinfo_key = TINFO_mul;
85 overall_coeff=exONE();
86 construct_from_2_ex(lh,rh);
87 ASSERT(is_canonical());
90 mul::mul(exvector const & v)
92 debugmsg("mul constructor from exvector",LOGLEVEL_CONSTRUCT);
93 tinfo_key = TINFO_mul;
94 overall_coeff=exONE();
95 construct_from_exvector(v);
96 ASSERT(is_canonical());
100 mul::mul(epvector const & v, bool do_not_canonicalize)
102 debugmsg("mul constructor from epvector,bool",LOGLEVEL_CONSTRUCT);
103 tinfo_key = TINFO_mul;
104 if (do_not_canonicalize) {
106 #ifdef EXPAIRSEQ_USE_HASHTAB
107 combine_same_terms(); // to build hashtab
108 #endif // def EXPAIRSEQ_USE_HASHTAB
110 construct_from_epvector(v);
112 ASSERT(is_canonical());
116 mul::mul(epvector const & v)
118 debugmsg("mul constructor from epvector",LOGLEVEL_CONSTRUCT);
119 tinfo_key = TINFO_mul;
120 overall_coeff=exONE();
121 construct_from_epvector(v);
122 ASSERT(is_canonical());
125 mul::mul(epvector const & v, ex const & oc)
127 debugmsg("mul constructor from epvector,ex",LOGLEVEL_CONSTRUCT);
128 tinfo_key = TINFO_mul;
130 construct_from_epvector(v);
131 ASSERT(is_canonical());
134 mul::mul(epvector * vp, ex const & oc)
136 debugmsg("mul constructor from epvector *,ex",LOGLEVEL_CONSTRUCT);
137 tinfo_key = TINFO_mul;
140 construct_from_epvector(*vp);
142 ASSERT(is_canonical());
145 mul::mul(ex const & lh, ex const & mh, ex const & rh)
147 debugmsg("mul constructor from ex,ex,ex",LOGLEVEL_CONSTRUCT);
148 tinfo_key = TINFO_mul;
151 factors.push_back(lh);
152 factors.push_back(mh);
153 factors.push_back(rh);
154 overall_coeff=exONE();
155 construct_from_exvector(factors);
156 ASSERT(is_canonical());
160 // functions overriding virtual functions from bases classes
165 basic * mul::duplicate() const
167 debugmsg("mul duplicate",LOGLEVEL_ASSIGNMENT);
168 return new mul(*this);
171 bool mul::info(unsigned inf) const
174 if (inf==info_flags::polynomial || inf==info_flags::integer_polynomial || inf==info_flags::rational_polynomial || inf==info_flags::rational_function) {
175 for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
176 if (!(recombine_pair_to_ex(*it).info(inf)))
181 return expairseq::info(inf);
185 typedef vector<int> intvector;
187 int mul::degree(symbol const & s) const
190 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
191 deg_sum+=(*cit).rest.degree(s) * ex_to_numeric((*cit).coeff).to_int();
196 int mul::ldegree(symbol const & s) const
199 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
200 deg_sum+=(*cit).rest.ldegree(s) * ex_to_numeric((*cit).coeff).to_int();
205 ex mul::coeff(symbol const & s, int const n) const
208 coeffseq.reserve(seq.size()+1);
211 // product of individual coeffs
212 // if a non-zero power of s is found, the resulting product will be 0
213 epvector::const_iterator it=seq.begin();
214 while (it!=seq.end()) {
215 coeffseq.push_back(recombine_pair_to_ex(*it).coeff(s,n));
218 coeffseq.push_back(overall_coeff);
219 return (new mul(coeffseq))->setflag(status_flags::dynallocated);
222 epvector::const_iterator it=seq.begin();
224 while (it!=seq.end()) {
225 ex t=recombine_pair_to_ex(*it);
228 coeffseq.push_back(c);
231 coeffseq.push_back(t);
236 coeffseq.push_back(overall_coeff);
237 return (new mul(coeffseq))->setflag(status_flags::dynallocated);
244 ex mul::eval(int level) const
246 // simplifications: *(...,x,(c1,1),(c2,1)) -> *(...,x,(c1*c2,1)) (c1, c2 numeric(), move pairs to end first)
247 // *(...,x,1) -> *(...,x)
249 // *(+(x,y,...),(c,1)) -> *(+(*(x,c),*(y,c),...)) (c numeric())
253 debugmsg("mul eval",LOGLEVEL_MEMBER_FUNCTION);
255 if ((level==1)&&(flags & status_flags::evaluated)) {
257 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
258 ASSERT((!is_ex_exactly_of_type((*cit).rest,mul))||
259 (!(ex_to_numeric((*cit).coeff).is_integer())));
262 // test if all numerics were moved to the end and
263 // all numerics with coeff 1 to the very end
265 epvector::const_iterator cit=seq.end();
266 bool all_coeff_1=true;
267 bool all_numeric=true;
270 if (is_ex_exactly_of_type((*cit).rest,numeric)) {
272 if ((*cit).coeff.is_equal(exONE())) {
280 } while (cit!=seq.begin());
282 #endif // def DOASSERT
287 epvector::iterator it1,it2;
288 bool seq_copied=false;
290 epvector * evaled_seqp=evalchildren(level);
291 if (evaled_seqp!=0) {
292 // do more evaluation later
293 return (new mul(evaled_seqp))->setflag(status_flags::dynallocated);
296 // combine pairs with coeff 1 (all numerics should be at end, assert below)
298 // count number of pairs with coeff 1
299 unsigned num_coeff_1=0;
300 bool still_numeric=true;
301 epvector::const_iterator cit=seq.end();
306 if (is_ex_exactly_of_type((*cit).rest,numeric)) {
307 if ((*cit).coeff.is_equal(exONE())) {
313 } while ((cit!=seq.begin())&&still_numeric);
321 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
322 ASSERT((!is_ex_exactly_of_type((*cit).rest,mul))||
323 (!(ex_to_numeric((*cit).coeff).is_integer())));
326 // test if all numerics were moved to the end and
327 // all numerics with coeff 1 to the very end
329 epvector::const_iterator cit=seq.end();
330 bool all_coeff_1=true;
331 bool all_numeric=true;
334 if (is_ex_exactly_of_type((*cit).rest,numeric)) {
336 if ((*cit).coeff.is_equal(exONE())) {
344 } while (cit!=seq.begin());
346 #endif // def DOASSERT
348 if (flags & status_flags::evaluated) {
352 expair const & last_expair=*(seq.end()-1);
353 expair const & next_to_last_expair=*(seq.end()-2);
354 int seq_size = seq.size();
356 // *(...,x,(c1,1),(c2,1)) -> *(...,x,(c1*c2,1)) (c1, c2 numeric())
357 if ((!seq_copied) && (seq_size>=2) &&
358 is_ex_exactly_of_type(last_expair.rest,numeric) &&
359 ex_to_numeric(last_expair.coeff).is_equal(numONE()) &&
360 is_ex_exactly_of_type(next_to_last_expair.rest,numeric) &&
361 ex_to_numeric(next_to_last_expair.coeff).is_equal(numONE()) ) {
367 while (seq_copied && (newseq.size()>=2) &&
368 is_ex_exactly_of_type((*it1).rest,numeric) &&
369 ex_to_numeric((*it1).coeff).is_equal(numONE()) &&
370 is_ex_exactly_of_type((*it2).rest,numeric) &&
371 ex_to_numeric((*it2).coeff).is_equal(numONE()) ) {
372 *it1=expair(ex_to_numeric((*it1).rest).mul_dyn(ex_to_numeric((*it2).rest)),exONE());
378 // *(...,x,1) -> *(...,x)
379 if ((!seq_copied) && (seq_size>=1) &&
380 (is_ex_exactly_of_type(last_expair.rest,numeric)) &&
381 (ex_to_numeric(last_expair.rest).compare(numONE())==0)) {
386 if (seq_copied && (newseq.size()>=1) &&
387 (is_ex_exactly_of_type((*it2).rest,numeric)) &&
388 (ex_to_numeric((*it2).rest).compare(numONE())==0)) {
394 if ((!seq_copied) && (seq_size>=1) &&
395 (is_ex_exactly_of_type(last_expair.rest,numeric)) &&
396 (ex_to_numeric(last_expair.rest).is_zero())) {
399 if (seq_copied && (newseq.size()>=1) &&
400 (is_ex_exactly_of_type((*it2).rest,numeric)) &&
401 (ex_to_numeric((*it2).rest).is_zero())) {
405 // *(+(x,y,...),c) -> +(*(x,c),*(y,c),...) (c numeric(), no powers of +())
406 if ((!seq_copied) && (seq_size==2) &&
407 is_ex_exactly_of_type(next_to_last_expair.rest,add) &&
408 is_ex_exactly_of_type(last_expair.rest,numeric) &&
409 ex_to_numeric(last_expair.coeff).is_equal(numONE()) &&
410 (ex_to_numeric(next_to_last_expair.coeff).compare(numONE())==0)) {
411 add const & addref=ex_to_add(next_to_last_expair.rest);
413 distrseq.reserve(addref.seq.size());
414 for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
415 distrseq.push_back(addref.combine_pair_with_coeff_to_pair(*cit,
418 // special treatment for the last element if it is numeric (to
419 // avoid terms like (2/3)*(3/2)) is no longer necessary, this
420 // is handled in add::combine_pair_with_coeff_to_pair()
421 return (new add(distrseq,1))->setflag(status_flags::dynallocated |
422 status_flags::evaluated );
424 if (seq_copied && (newseq.size()==2) &&
425 is_ex_exactly_of_type(newseq[0].rest,add) &&
426 is_ex_exactly_of_type(newseq[1].rest,numeric) &&
427 ex_to_numeric(newseq[1].coeff).is_equal(numONE()) &&
428 (ex_to_numeric(newseq[0].coeff).compare(numONE())==0)) {
429 add const & addref=ex_to_add(newseq[0].rest);
431 distrseq.reserve(addref.seq.size());
432 for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
433 distrseq.push_back(addref.combine_pair_with_coeff_to_pair(*cit,
436 // special treatment for the last element if it is numeric (to
437 // avoid terms like (2/3)*(3/2)) is no longer necessary, this
438 // is handled in add::combine_pair_with_coeff_to_pair()
439 return (new add(distrseq,1))->setflag(status_flags::dynallocated |
440 status_flags::evaluated );
444 if ((!seq_copied) && (seq_size==0)) {
446 } else if (seq_copied && (newseq.size()==0)) {
451 if ((!seq_copied) && (seq_size==1)) {
452 return recombine_pair_to_ex(*(seq.begin()));
453 } else if (seq_copied && (newseq.size()==1)) {
454 return recombine_pair_to_ex(*(newseq.begin()));
457 if (!seq_copied) return this->hold();
459 return (new mul(newseq,1))->setflag(status_flags::dynallocated |
460 status_flags::evaluated );
464 ex mul::eval(int level) const
466 // simplifications *(...,x;0) -> 0
467 // *(+(x,y,...);c) -> *(+(*(x,c),*(y,c),...)) (c numeric())
471 debugmsg("mul eval",LOGLEVEL_MEMBER_FUNCTION);
473 epvector * evaled_seqp=evalchildren(level);
474 if (evaled_seqp!=0) {
475 // do more evaluation later
476 return (new mul(evaled_seqp,overall_coeff))->
477 setflag(status_flags::dynallocated);
481 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
482 ASSERT((!is_ex_exactly_of_type((*cit).rest,mul))||
483 (!(ex_to_numeric((*cit).coeff).is_integer())));
484 ASSERT(!((*cit).is_numeric_with_coeff_1()));
485 if (is_ex_exactly_of_type(recombine_pair_to_ex(*cit),numeric)) {
488 ASSERT(!is_ex_exactly_of_type(recombine_pair_to_ex(*cit),numeric));
490 expair p=split_ex_to_pair(recombine_pair_to_ex(*cit));
491 ASSERT(p.rest.is_equal((*cit).rest));
492 ASSERT(p.coeff.is_equal((*cit).coeff));
495 #endif // def DOASSERT
497 if (flags & status_flags::evaluated) {
498 ASSERT(seq.size()>0);
499 ASSERT((seq.size()>1)||!overall_coeff.is_equal(exONE()));
503 int seq_size=seq.size();
504 if (overall_coeff.is_equal(exZERO())) {
507 } else if (seq_size==0) {
509 return overall_coeff;
510 } else if ((seq_size==1)&&overall_coeff.is_equal(exONE())) {
512 return recombine_pair_to_ex(*(seq.begin()));
513 } else if ((seq_size==1) &&
514 is_ex_exactly_of_type((*seq.begin()).rest,add) &&
515 ex_to_numeric((*seq.begin()).coeff).is_equal(numONE())) {
516 // *(+(x,y,...);c) -> +(*(x,c),*(y,c),...) (c numeric(), no powers of +())
517 add const & addref=ex_to_add((*seq.begin()).rest);
519 distrseq.reserve(addref.seq.size());
520 for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
521 distrseq.push_back(addref.combine_pair_with_coeff_to_pair(*cit,
524 return (new add(distrseq,
525 ex_to_numeric(addref.overall_coeff).
526 mul_dyn(ex_to_numeric(overall_coeff))))
527 ->setflag(status_flags::dynallocated |
528 status_flags::evaluated );
534 ex mul::eval(int level) const
536 // simplifications: *(...,x,c1,c2) -> *(...,x,c1*c2) (c1, c2 numeric())
537 // *(...,(c1,c2)) -> (...,(c1^c2,1)) (normalize)
538 // *(...,x,1) -> +(...,x)
540 // *(+(x,y,...),c) -> *(+(*(x,c),*(y,c),...)) (c numeric())
544 debugmsg("mul eval",LOGLEVEL_MEMBER_FUNCTION);
547 epvector::iterator it1,it2;
549 // *(...,x,c1,c2) -> *(...,x,c1*c2) (c1, c2 numeric())
552 while ((newseq.size()>=2)&&is_exactly_of_type(*(*it1).rest.bp,numeric)&&
553 is_exactly_of_type(*(*it2).rest.bp,numeric)) {
554 *it1=expair(ex_to_numeric((*it1).rest).power(ex_to_numeric((*it1).coeff))
555 .mul(ex_to_numeric((*it2).rest).power(ex_to_numeric((*it2).coeff))),exONE());
561 if ((newseq.size()>=1)&&is_exactly_of_type(*(*it2).rest.bp,numeric)) {
562 // *(...,(c1,c2)) -> (...,(c1^c2,1)) (normalize)
563 *it2=expair(ex_to_numeric((*it2).rest).power(ex_to_numeric((*it2).coeff)),exONE());
564 // *(...,x,1) -> *(...,x)
565 if (static_cast<numeric &>(*(*it2).rest.bp).compare(numONE())==0) {
572 if ((newseq.size()>=1)&&is_exactly_of_type(*(*it2).rest.bp,numeric)) {
573 if (static_cast<numeric &>(*(*it2).rest.bp).is_zero()==0) {
578 // *(+(x,y,...),c) -> +(*(x,c),*(y,c),...) (c numeric(), no powers of +())
579 if ((newseq.size()==2)&&is_ex_exactly_of_type(newseq[0].rest,add)&&
580 is_ex_exactly_of_type(newseq[1].rest,numeric)&&
581 (ex_to_numeric(newseq[0].coeff).compare(numONE())==0)) {
582 add const & addref=ex_to_add(newseq[0].rest);
583 numeric const & numref=ex_to_numeric(newseq[1].rest);
585 distrseq.reserve(addref.seq.size());
586 for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
587 distrseq.push_back(expair((*cit).rest,ex_to_numeric((*cit).coeff).mul(numref)));
589 return (new add(distrseq,1))->setflag(status_flags::dynallocated |
590 status_flags::evaluated );
593 if (newseq.size()==0) {
596 } else if (newseq.size()==1) {
598 return recombine_pair_to_ex(*newseq.begin());
601 return (new mul(newseq,1))->setflag(status_flags::dynallocated |
602 status_flags::evaluated );
606 exvector mul::get_indices(void) const
608 // return union of indices of factors
610 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
611 exvector subiv=(*cit).rest.get_indices();
612 iv.reserve(iv.size()+subiv.size());
613 for (exvector::const_iterator cit2=subiv.begin(); cit2!=subiv.end(); ++cit2) {
620 ex mul::simplify_ncmul(exvector const & v) const
622 throw(std::logic_error("mul::simplify_ncmul() should never have been called!"));
627 int mul::compare_same_type(basic const & other) const
629 return expairseq::compare_same_type(other);
632 bool mul::is_equal_same_type(basic const & other) const
634 return expairseq::is_equal_same_type(other);
637 unsigned mul::return_type(void) const
640 // mul without factors: should not happen, but commutes
641 return return_types::commutative;
644 bool all_commutative=1;
646 epvector::const_iterator cit_noncommutative_element; // point to first found nc element
648 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
649 rt=(*cit).rest.return_type();
650 if (rt==return_types::noncommutative_composite) return rt; // one ncc -> mul also ncc
651 if ((rt==return_types::noncommutative)&&(all_commutative)) {
652 // first nc element found, remember position
653 cit_noncommutative_element=cit;
656 if ((rt==return_types::noncommutative)&&(!all_commutative)) {
657 // another nc element found, compare type_infos
658 if ((*cit_noncommutative_element).rest.return_type_tinfo()!=(*cit).rest.return_type_tinfo()) {
659 // diffent types -> mul is ncc
660 return return_types::noncommutative_composite;
664 // all factors checked
665 return all_commutative ? return_types::commutative : return_types::noncommutative;
668 unsigned mul::return_type_tinfo(void) const
671 // mul without factors: should not happen
674 // return type_info of first noncommutative element
675 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
676 if ((*cit).rest.return_type()==return_types::noncommutative) {
677 return (*cit).rest.return_type_tinfo();
680 // no noncommutative element found, should not happen
684 ex mul::thisexpairseq(epvector const & v, ex const & oc) const
686 return (new mul(v,oc))->setflag(status_flags::dynallocated);
689 ex mul::thisexpairseq(epvector * vp, ex const & oc) const
691 return (new mul(vp,oc))->setflag(status_flags::dynallocated);
694 expair mul::split_ex_to_pair(ex const & e) const
696 if (is_ex_exactly_of_type(e,power)) {
697 power const & powerref=ex_to_power(e);
698 if (is_ex_exactly_of_type(powerref.exponent,numeric)) {
699 return expair(powerref.basis,powerref.exponent);
702 return expair(e,exONE());
705 expair mul::combine_ex_with_coeff_to_pair(ex const & e,
708 // to avoid duplication of power simplification rules,
709 // we create a temporary power object
710 // otherwise it would be hard to correctly simplify
711 // expression like (4^(1/3))^(3/2)
712 if (are_ex_trivially_equal(c,exONE())) {
713 return split_ex_to_pair(e);
715 return split_ex_to_pair(power(e,c));
718 expair mul::combine_pair_with_coeff_to_pair(expair const & p,
721 // to avoid duplication of power simplification rules,
722 // we create a temporary power object
723 // otherwise it would be hard to correctly simplify
724 // expression like (4^(1/3))^(3/2)
725 if (are_ex_trivially_equal(c,exONE())) {
728 return split_ex_to_pair(power(recombine_pair_to_ex(p),c));
731 ex mul::recombine_pair_to_ex(expair const & p) const
733 // if (p.coeff.compare(exONE())==0) {
734 // if (are_ex_trivially_equal(p.coeff,exONE())) {
735 if (ex_to_numeric(p.coeff).is_equal(numONE())) {
738 return power(p.rest,p.coeff);
742 bool mul::expair_needs_further_processing(epp it)
744 if (is_ex_exactly_of_type((*it).rest,mul) &&
745 ex_to_numeric((*it).coeff).is_integer()) {
746 // combined pair is product with integer power -> expand it
747 *it=split_ex_to_pair(recombine_pair_to_ex(*it));
750 if (is_ex_exactly_of_type((*it).rest,numeric)) {
751 expair ep=split_ex_to_pair(recombine_pair_to_ex(*it));
752 if (!ep.is_equal(*it)) {
753 // combined pair is a numeric power which can be simplified
757 if (ex_to_numeric((*it).coeff).is_equal(numONE())) {
758 // combined pair has coeff 1 and must be moved to the end
765 ex mul::default_overall_coeff(void) const
770 void mul::combine_overall_coeff(ex const & c)
772 ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
773 ASSERT(is_ex_exactly_of_type(c,numeric));
774 overall_coeff = ex_to_numeric(overall_coeff).mul_dyn(ex_to_numeric(c));
777 void mul::combine_overall_coeff(ex const & c1, ex const & c2)
779 ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
780 ASSERT(is_ex_exactly_of_type(c1,numeric));
781 ASSERT(is_ex_exactly_of_type(c2,numeric));
782 overall_coeff = ex_to_numeric(overall_coeff).
783 mul_dyn(ex_to_numeric(c1).power(ex_to_numeric(c2)));
786 bool mul::can_make_flat(expair const & p) const
788 ASSERT(is_ex_exactly_of_type(p.coeff,numeric));
789 // this assertion will probably fail somewhere
790 // it would require a more careful make_flat, obeying the power laws
791 // probably should return true only if p.coeff is integer
792 return ex_to_numeric(p.coeff).is_equal(numONE());
795 ex mul::expand(unsigned options) const
797 exvector sub_expanded_seq;
798 intvector positions_of_adds;
799 intvector number_of_add_operands;
801 epvector * expanded_seqp=expandchildren(options);
803 epvector const & expanded_seq = expanded_seqp==0 ? seq : *expanded_seqp;
805 positions_of_adds.resize(expanded_seq.size());
806 number_of_add_operands.resize(expanded_seq.size());
808 int number_of_adds=0;
809 int number_of_expanded_terms=1;
811 unsigned current_position=0;
812 epvector::const_iterator last=expanded_seq.end();
813 for (epvector::const_iterator cit=expanded_seq.begin(); cit!=last; ++cit) {
814 if (is_ex_exactly_of_type((*cit).rest,add)&&
815 (ex_to_numeric((*cit).coeff).is_equal(numONE()))) {
816 positions_of_adds[number_of_adds]=current_position;
817 add const & expanded_addref=ex_to_add((*cit).rest);
818 int addref_nops=expanded_addref.nops();
819 number_of_add_operands[number_of_adds]=addref_nops;
820 number_of_expanded_terms *= addref_nops;
826 if (number_of_adds==0) {
827 if (expanded_seqp==0) {
828 return this->setflag(status_flags::expanded);
830 return (new mul(expanded_seqp,overall_coeff))->
831 setflag(status_flags::dynallocated ||
832 status_flags::expanded);
836 distrseq.reserve(number_of_expanded_terms);
839 k.resize(number_of_adds);
842 for (l=0; l<number_of_adds; l++) {
849 for (l=0; l<number_of_adds; l++) {
850 add const & addref=ex_to_add(expanded_seq[positions_of_adds[l]].rest);
851 ASSERT(term[positions_of_adds[l]].coeff.compare(exONE())==0);
852 term[positions_of_adds[l]]=split_ex_to_pair(addref.op(k[l]));
855 cout << "mul::expand() term begin" << endl;
856 for (epvector::const_iterator cit=term.begin(); cit!=term.end(); ++cit) {
857 cout << "rest" << endl;
858 (*cit).rest.printtree(cout);
859 cout << "coeff" << endl;
860 (*cit).coeff.printtree(cout);
862 cout << "mul::expand() term end" << endl;
864 distrseq.push_back((new mul(term,overall_coeff))->
865 setflag(status_flags::dynallocated |
866 status_flags::expanded));
870 while ((l>=0)&&((++k[l])>=number_of_add_operands[l])) {
877 if (expanded_seqp!=0) {
878 delete expanded_seqp;
881 cout << "mul::expand() distrseq begin" << endl;
882 for (exvector::const_iterator cit=distrseq.begin(); cit!=distrseq.end(); ++cit) {
883 (*cit).printtree(cout);
885 cout << "mul::expand() distrseq end" << endl;
888 return (new add(distrseq))->setflag(status_flags::dynallocated |
889 status_flags::expanded);
893 ex mul::expand(unsigned options) const
895 exvector sub_expanded_seq;
896 intvector positions_of_adds;
897 intvector number_of_add_operands;
899 sub_expanded_seq.resize(seq.size());
900 positions_of_adds.resize(seq.size());
901 number_of_add_operands.reserve(seq.size());
903 int number_of_adds=0;
904 int number_of_expanded_terms=1;
905 for (unsigned current_position=0; current_position<seq.size(); current_position++) {
906 ex const & expanded_ex=recombine_pair_to_ex(seq[current_position]).expand(options);
907 if (is_ex_exactly_of_type(expanded_ex,add)) {
908 positions_of_adds[number_of_adds]=current_position;
909 add const & expanded_addref=ex_to_add(expanded_ex);
910 number_of_add_operands[number_of_adds]=expanded_addref.seq.size();
911 number_of_expanded_terms *= expanded_addref.seq.size();
914 sub_expanded_seq.push_back(expanded_ex);
918 distrseq.reserve(number_of_expanded_terms);
921 k.resize(number_of_adds);
924 for (l=0; l<number_of_adds; l++) {
930 term=sub_expanded_seq;
931 for (l=0; l<number_of_adds; l++) {
932 add const & addref=ex_to_add(sub_expanded_seq[positions_of_adds[l]]);
933 term[positions_of_adds[l]]=addref.recombine_pair_to_ex(addref.seq[k[l]]);
935 distrseq.push_back((new mul(term))->setflag(status_flags::dynallocated |
936 status_flags::expanded));
940 while ((l>=0)&&((++k[l])>=number_of_add_operands[l])) {
947 return (new add(distrseq))->setflag(status_flags::dynallocated |
948 status_flags::expanded);
953 // new virtual functions which can be overridden by derived classes
959 // non-virtual functions in this class
962 epvector * mul::expandchildren(unsigned options) const
964 epvector::const_iterator last=seq.end();
965 epvector::const_iterator cit=seq.begin();
967 ex const & factor=recombine_pair_to_ex(*cit);
968 ex const & expanded_factor=factor.expand(options);
969 if (!are_ex_trivially_equal(factor,expanded_factor)) {
971 // something changed, copy seq, eval and return it
972 epvector *s=new epvector;
973 s->reserve(seq.size());
975 // copy parts of seq which are known not to have changed
976 epvector::const_iterator cit2=seq.begin();
981 // copy first changed element
982 s->push_back(split_ex_to_pair(expanded_factor));
986 s->push_back(split_ex_to_pair(recombine_pair_to_ex(*cit2).expand(options)));
994 return 0; // nothing has changed
998 // static member variables
1003 unsigned mul::precedence=50;
1011 type_info const & typeid_mul=typeid(some_mul);