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
28 // default constructor, destructor, copy constructor assignment operator and helpers
35 debugmsg("mul default constructor",LOGLEVEL_CONSTRUCT);
36 tinfo_key = TINFO_MUL;
41 debugmsg("mul destructor",LOGLEVEL_DESTRUCT);
45 mul::mul(mul const & other)
47 debugmsg("mul copy constructor",LOGLEVEL_CONSTRUCT);
51 mul const & mul::operator=(mul const & other)
53 debugmsg("mul operator=",LOGLEVEL_ASSIGNMENT);
63 void mul::copy(mul const & other)
65 expairseq::copy(other);
68 void mul::destroy(bool call_parent)
70 if (call_parent) expairseq::destroy(call_parent);
79 mul::mul(ex const & lh, ex const & rh)
81 debugmsg("mul constructor from ex,ex",LOGLEVEL_CONSTRUCT);
82 tinfo_key = TINFO_MUL;
83 overall_coeff=exONE();
84 construct_from_2_ex(lh,rh);
85 ASSERT(is_canonical());
88 mul::mul(exvector const & v)
90 debugmsg("mul constructor from exvector",LOGLEVEL_CONSTRUCT);
91 tinfo_key = TINFO_MUL;
92 overall_coeff=exONE();
93 construct_from_exvector(v);
94 ASSERT(is_canonical());
98 mul::mul(epvector const & v, bool do_not_canonicalize)
100 debugmsg("mul constructor from epvector,bool",LOGLEVEL_CONSTRUCT);
101 tinfo_key = TINFO_MUL;
102 if (do_not_canonicalize) {
104 #ifdef EXPAIRSEQ_USE_HASHTAB
105 combine_same_terms(); // to build hashtab
106 #endif // def EXPAIRSEQ_USE_HASHTAB
108 construct_from_epvector(v);
110 ASSERT(is_canonical());
114 mul::mul(epvector const & v)
116 debugmsg("mul constructor from epvector",LOGLEVEL_CONSTRUCT);
117 tinfo_key = TINFO_MUL;
118 overall_coeff=exONE();
119 construct_from_epvector(v);
120 ASSERT(is_canonical());
123 mul::mul(epvector const & v, ex const & oc)
125 debugmsg("mul constructor from epvector,ex",LOGLEVEL_CONSTRUCT);
126 tinfo_key = TINFO_MUL;
128 construct_from_epvector(v);
129 ASSERT(is_canonical());
132 mul::mul(epvector * vp, ex const & oc)
134 debugmsg("mul constructor from epvector *,ex",LOGLEVEL_CONSTRUCT);
135 tinfo_key = TINFO_MUL;
138 construct_from_epvector(*vp);
140 ASSERT(is_canonical());
143 mul::mul(ex const & lh, ex const & mh, ex const & rh)
145 debugmsg("mul constructor from ex,ex,ex",LOGLEVEL_CONSTRUCT);
146 tinfo_key = TINFO_MUL;
149 factors.push_back(lh);
150 factors.push_back(mh);
151 factors.push_back(rh);
152 overall_coeff=exONE();
153 construct_from_exvector(factors);
154 ASSERT(is_canonical());
158 // functions overriding virtual functions from bases classes
163 basic * mul::duplicate() const
165 debugmsg("mul duplicate",LOGLEVEL_ASSIGNMENT);
166 return new mul(*this);
169 bool mul::info(unsigned inf) const
172 if (inf==info_flags::polynomial || inf==info_flags::integer_polynomial || inf==info_flags::rational_polynomial || inf==info_flags::rational_function) {
173 for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
174 if (!(recombine_pair_to_ex(*it).info(inf)))
179 return expairseq::info(inf);
183 typedef vector<int> intvector;
185 int mul::degree(symbol const & s) const
188 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
189 deg_sum+=(*cit).rest.degree(s) * ex_to_numeric((*cit).coeff).to_int();
194 int mul::ldegree(symbol const & s) const
197 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
198 deg_sum+=(*cit).rest.ldegree(s) * ex_to_numeric((*cit).coeff).to_int();
203 ex mul::coeff(symbol const & s, int const n) const
206 coeffseq.reserve(seq.size()+1);
209 // product of individual coeffs
210 // if a non-zero power of s is found, the resulting product will be 0
211 epvector::const_iterator it=seq.begin();
212 while (it!=seq.end()) {
213 coeffseq.push_back(recombine_pair_to_ex(*it).coeff(s,n));
216 coeffseq.push_back(overall_coeff);
217 return (new mul(coeffseq))->setflag(status_flags::dynallocated);
220 epvector::const_iterator it=seq.begin();
222 while (it!=seq.end()) {
223 ex t=recombine_pair_to_ex(*it);
226 coeffseq.push_back(c);
229 coeffseq.push_back(t);
234 coeffseq.push_back(overall_coeff);
235 return (new mul(coeffseq))->setflag(status_flags::dynallocated);
242 ex mul::eval(int level) const
244 // simplifications: *(...,x,(c1,1),(c2,1)) -> *(...,x,(c1*c2,1)) (c1, c2 numeric(), move pairs to end first)
245 // *(...,x,1) -> *(...,x)
247 // *(+(x,y,...),(c,1)) -> *(+(*(x,c),*(y,c),...)) (c numeric())
251 debugmsg("mul eval",LOGLEVEL_MEMBER_FUNCTION);
253 if ((level==1)&&(flags & status_flags::evaluated)) {
255 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
256 ASSERT((!is_ex_exactly_of_type((*cit).rest,mul))||
257 (!(ex_to_numeric((*cit).coeff).is_integer())));
260 // test if all numerics were moved to the end and
261 // all numerics with coeff 1 to the very end
263 epvector::const_iterator cit=seq.end();
264 bool all_coeff_1=true;
265 bool all_numeric=true;
268 if (is_ex_exactly_of_type((*cit).rest,numeric)) {
270 if ((*cit).coeff.is_equal(exONE())) {
278 } while (cit!=seq.begin());
280 #endif // def DOASSERT
285 epvector::iterator it1,it2;
286 bool seq_copied=false;
288 epvector * evaled_seqp=evalchildren(level);
289 if (evaled_seqp!=0) {
290 // do more evaluation later
291 return (new mul(evaled_seqp))->setflag(status_flags::dynallocated);
294 // combine pairs with coeff 1 (all numerics should be at end, assert below)
296 // count number of pairs with coeff 1
297 unsigned num_coeff_1=0;
298 bool still_numeric=true;
299 epvector::const_iterator cit=seq.end();
304 if (is_ex_exactly_of_type((*cit).rest,numeric)) {
305 if ((*cit).coeff.is_equal(exONE())) {
311 } while ((cit!=seq.begin())&&still_numeric);
319 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
320 ASSERT((!is_ex_exactly_of_type((*cit).rest,mul))||
321 (!(ex_to_numeric((*cit).coeff).is_integer())));
324 // test if all numerics were moved to the end and
325 // all numerics with coeff 1 to the very end
327 epvector::const_iterator cit=seq.end();
328 bool all_coeff_1=true;
329 bool all_numeric=true;
332 if (is_ex_exactly_of_type((*cit).rest,numeric)) {
334 if ((*cit).coeff.is_equal(exONE())) {
342 } while (cit!=seq.begin());
344 #endif // def DOASSERT
346 if (flags & status_flags::evaluated) {
350 expair const & last_expair=*(seq.end()-1);
351 expair const & next_to_last_expair=*(seq.end()-2);
352 int seq_size = seq.size();
354 // *(...,x,(c1,1),(c2,1)) -> *(...,x,(c1*c2,1)) (c1, c2 numeric())
355 if ((!seq_copied) && (seq_size>=2) &&
356 is_ex_exactly_of_type(last_expair.rest,numeric) &&
357 ex_to_numeric(last_expair.coeff).is_equal(numONE()) &&
358 is_ex_exactly_of_type(next_to_last_expair.rest,numeric) &&
359 ex_to_numeric(next_to_last_expair.coeff).is_equal(numONE()) ) {
365 while (seq_copied && (newseq.size()>=2) &&
366 is_ex_exactly_of_type((*it1).rest,numeric) &&
367 ex_to_numeric((*it1).coeff).is_equal(numONE()) &&
368 is_ex_exactly_of_type((*it2).rest,numeric) &&
369 ex_to_numeric((*it2).coeff).is_equal(numONE()) ) {
370 *it1=expair(ex_to_numeric((*it1).rest).mul_dyn(ex_to_numeric((*it2).rest)),exONE());
376 // *(...,x,1) -> *(...,x)
377 if ((!seq_copied) && (seq_size>=1) &&
378 (is_ex_exactly_of_type(last_expair.rest,numeric)) &&
379 (ex_to_numeric(last_expair.rest).compare(numONE())==0)) {
384 if (seq_copied && (newseq.size()>=1) &&
385 (is_ex_exactly_of_type((*it2).rest,numeric)) &&
386 (ex_to_numeric((*it2).rest).compare(numONE())==0)) {
392 if ((!seq_copied) && (seq_size>=1) &&
393 (is_ex_exactly_of_type(last_expair.rest,numeric)) &&
394 (ex_to_numeric(last_expair.rest).is_zero())) {
397 if (seq_copied && (newseq.size()>=1) &&
398 (is_ex_exactly_of_type((*it2).rest,numeric)) &&
399 (ex_to_numeric((*it2).rest).is_zero())) {
403 // *(+(x,y,...),c) -> +(*(x,c),*(y,c),...) (c numeric(), no powers of +())
404 if ((!seq_copied) && (seq_size==2) &&
405 is_ex_exactly_of_type(next_to_last_expair.rest,add) &&
406 is_ex_exactly_of_type(last_expair.rest,numeric) &&
407 ex_to_numeric(last_expair.coeff).is_equal(numONE()) &&
408 (ex_to_numeric(next_to_last_expair.coeff).compare(numONE())==0)) {
409 add const & addref=ex_to_add(next_to_last_expair.rest);
411 distrseq.reserve(addref.seq.size());
412 for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
413 distrseq.push_back(addref.combine_pair_with_coeff_to_pair(*cit,
416 // special treatment for the last element if it is numeric (to
417 // avoid terms like (2/3)*(3/2)) is no longer necessary, this
418 // is handled in add::combine_pair_with_coeff_to_pair()
419 return (new add(distrseq,1))->setflag(status_flags::dynallocated |
420 status_flags::evaluated );
422 if (seq_copied && (newseq.size()==2) &&
423 is_ex_exactly_of_type(newseq[0].rest,add) &&
424 is_ex_exactly_of_type(newseq[1].rest,numeric) &&
425 ex_to_numeric(newseq[1].coeff).is_equal(numONE()) &&
426 (ex_to_numeric(newseq[0].coeff).compare(numONE())==0)) {
427 add const & addref=ex_to_add(newseq[0].rest);
429 distrseq.reserve(addref.seq.size());
430 for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
431 distrseq.push_back(addref.combine_pair_with_coeff_to_pair(*cit,
434 // special treatment for the last element if it is numeric (to
435 // avoid terms like (2/3)*(3/2)) is no longer necessary, this
436 // is handled in add::combine_pair_with_coeff_to_pair()
437 return (new add(distrseq,1))->setflag(status_flags::dynallocated |
438 status_flags::evaluated );
442 if ((!seq_copied) && (seq_size==0)) {
444 } else if (seq_copied && (newseq.size()==0)) {
449 if ((!seq_copied) && (seq_size==1)) {
450 return recombine_pair_to_ex(*(seq.begin()));
451 } else if (seq_copied && (newseq.size()==1)) {
452 return recombine_pair_to_ex(*(newseq.begin()));
455 if (!seq_copied) return this->hold();
457 return (new mul(newseq,1))->setflag(status_flags::dynallocated |
458 status_flags::evaluated );
462 ex mul::eval(int level) const
464 // simplifications *(...,x;0) -> 0
465 // *(+(x,y,...);c) -> *(+(*(x,c),*(y,c),...)) (c numeric())
469 debugmsg("mul eval",LOGLEVEL_MEMBER_FUNCTION);
471 epvector * evaled_seqp=evalchildren(level);
472 if (evaled_seqp!=0) {
473 // do more evaluation later
474 return (new mul(evaled_seqp,overall_coeff))->
475 setflag(status_flags::dynallocated);
479 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
480 ASSERT((!is_ex_exactly_of_type((*cit).rest,mul))||
481 (!(ex_to_numeric((*cit).coeff).is_integer())));
482 ASSERT(!((*cit).is_numeric_with_coeff_1()));
483 if (is_ex_exactly_of_type(recombine_pair_to_ex(*cit),numeric)) {
486 ASSERT(!is_ex_exactly_of_type(recombine_pair_to_ex(*cit),numeric));
488 expair p=split_ex_to_pair(recombine_pair_to_ex(*cit));
489 ASSERT(p.rest.is_equal((*cit).rest));
490 ASSERT(p.coeff.is_equal((*cit).coeff));
493 #endif // def DOASSERT
495 if (flags & status_flags::evaluated) {
496 ASSERT(seq.size()>0);
497 ASSERT((seq.size()>1)||!overall_coeff.is_equal(exONE()));
501 int seq_size=seq.size();
502 if (overall_coeff.is_equal(exZERO())) {
505 } else if (seq_size==0) {
507 return overall_coeff;
508 } else if ((seq_size==1)&&overall_coeff.is_equal(exONE())) {
510 return recombine_pair_to_ex(*(seq.begin()));
511 } else if ((seq_size==1) &&
512 is_ex_exactly_of_type((*seq.begin()).rest,add) &&
513 ex_to_numeric((*seq.begin()).coeff).is_equal(numONE())) {
514 // *(+(x,y,...);c) -> +(*(x,c),*(y,c),...) (c numeric(), no powers of +())
515 add const & addref=ex_to_add((*seq.begin()).rest);
517 distrseq.reserve(addref.seq.size());
518 for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
519 distrseq.push_back(addref.combine_pair_with_coeff_to_pair(*cit,
522 return (new add(distrseq,
523 ex_to_numeric(addref.overall_coeff).
524 mul_dyn(ex_to_numeric(overall_coeff))))
525 ->setflag(status_flags::dynallocated |
526 status_flags::evaluated );
532 ex mul::eval(int level) const
534 // simplifications: *(...,x,c1,c2) -> *(...,x,c1*c2) (c1, c2 numeric())
535 // *(...,(c1,c2)) -> (...,(c1^c2,1)) (normalize)
536 // *(...,x,1) -> +(...,x)
538 // *(+(x,y,...),c) -> *(+(*(x,c),*(y,c),...)) (c numeric())
542 debugmsg("mul eval",LOGLEVEL_MEMBER_FUNCTION);
545 epvector::iterator it1,it2;
547 // *(...,x,c1,c2) -> *(...,x,c1*c2) (c1, c2 numeric())
550 while ((newseq.size()>=2)&&is_exactly_of_type(*(*it1).rest.bp,numeric)&&
551 is_exactly_of_type(*(*it2).rest.bp,numeric)) {
552 *it1=expair(ex_to_numeric((*it1).rest).power(ex_to_numeric((*it1).coeff))
553 .mul(ex_to_numeric((*it2).rest).power(ex_to_numeric((*it2).coeff))),exONE());
559 if ((newseq.size()>=1)&&is_exactly_of_type(*(*it2).rest.bp,numeric)) {
560 // *(...,(c1,c2)) -> (...,(c1^c2,1)) (normalize)
561 *it2=expair(ex_to_numeric((*it2).rest).power(ex_to_numeric((*it2).coeff)),exONE());
562 // *(...,x,1) -> *(...,x)
563 if (static_cast<numeric &>(*(*it2).rest.bp).compare(numONE())==0) {
570 if ((newseq.size()>=1)&&is_exactly_of_type(*(*it2).rest.bp,numeric)) {
571 if (static_cast<numeric &>(*(*it2).rest.bp).is_zero()==0) {
576 // *(+(x,y,...),c) -> +(*(x,c),*(y,c),...) (c numeric(), no powers of +())
577 if ((newseq.size()==2)&&is_ex_exactly_of_type(newseq[0].rest,add)&&
578 is_ex_exactly_of_type(newseq[1].rest,numeric)&&
579 (ex_to_numeric(newseq[0].coeff).compare(numONE())==0)) {
580 add const & addref=ex_to_add(newseq[0].rest);
581 numeric const & numref=ex_to_numeric(newseq[1].rest);
583 distrseq.reserve(addref.seq.size());
584 for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
585 distrseq.push_back(expair((*cit).rest,ex_to_numeric((*cit).coeff).mul(numref)));
587 return (new add(distrseq,1))->setflag(status_flags::dynallocated |
588 status_flags::evaluated );
591 if (newseq.size()==0) {
594 } else if (newseq.size()==1) {
596 return recombine_pair_to_ex(*newseq.begin());
599 return (new mul(newseq,1))->setflag(status_flags::dynallocated |
600 status_flags::evaluated );
604 exvector mul::get_indices(void) const
606 // return union of indices of factors
608 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
609 exvector subiv=(*cit).rest.get_indices();
610 iv.reserve(iv.size()+subiv.size());
611 for (exvector::const_iterator cit2=subiv.begin(); cit2!=subiv.end(); ++cit2) {
618 ex mul::simplify_ncmul(exvector const & v) const
620 throw(std::logic_error("mul::simplify_ncmul() should never have been called!"));
625 int mul::compare_same_type(basic const & other) const
627 return expairseq::compare_same_type(other);
630 bool mul::is_equal_same_type(basic const & other) const
632 return expairseq::is_equal_same_type(other);
635 unsigned mul::return_type(void) const
638 // mul without factors: should not happen, but commutes
639 return return_types::commutative;
642 bool all_commutative=1;
644 epvector::const_iterator cit_noncommutative_element; // point to first found nc element
646 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
647 rt=(*cit).rest.return_type();
648 if (rt==return_types::noncommutative_composite) return rt; // one ncc -> mul also ncc
649 if ((rt==return_types::noncommutative)&&(all_commutative)) {
650 // first nc element found, remember position
651 cit_noncommutative_element=cit;
654 if ((rt==return_types::noncommutative)&&(!all_commutative)) {
655 // another nc element found, compare type_infos
656 if ((*cit_noncommutative_element).rest.return_type_tinfo()!=(*cit).rest.return_type_tinfo()) {
657 // diffent types -> mul is ncc
658 return return_types::noncommutative_composite;
662 // all factors checked
663 return all_commutative ? return_types::commutative : return_types::noncommutative;
666 unsigned mul::return_type_tinfo(void) const
669 // mul without factors: should not happen
672 // return type_info of first noncommutative element
673 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
674 if ((*cit).rest.return_type()==return_types::noncommutative) {
675 return (*cit).rest.return_type_tinfo();
678 // no noncommutative element found, should not happen
682 ex mul::thisexpairseq(epvector const & v, ex const & oc) const
684 return (new mul(v,oc))->setflag(status_flags::dynallocated);
687 ex mul::thisexpairseq(epvector * vp, ex const & oc) const
689 return (new mul(vp,oc))->setflag(status_flags::dynallocated);
692 expair mul::split_ex_to_pair(ex const & e) const
694 if (is_ex_exactly_of_type(e,power)) {
695 power const & powerref=ex_to_power(e);
696 if (is_ex_exactly_of_type(powerref.exponent,numeric)) {
697 return expair(powerref.basis,powerref.exponent);
700 return expair(e,exONE());
703 expair mul::combine_ex_with_coeff_to_pair(ex const & e,
706 // to avoid duplication of power simplification rules,
707 // we create a temporary power object
708 // otherwise it would be hard to correctly simplify
709 // expression like (4^(1/3))^(3/2)
710 if (are_ex_trivially_equal(c,exONE())) {
711 return split_ex_to_pair(e);
713 return split_ex_to_pair(power(e,c));
716 expair mul::combine_pair_with_coeff_to_pair(expair const & p,
719 // to avoid duplication of power simplification rules,
720 // we create a temporary power object
721 // otherwise it would be hard to correctly simplify
722 // expression like (4^(1/3))^(3/2)
723 if (are_ex_trivially_equal(c,exONE())) {
726 return split_ex_to_pair(power(recombine_pair_to_ex(p),c));
729 ex mul::recombine_pair_to_ex(expair const & p) const
731 // if (p.coeff.compare(exONE())==0) {
732 // if (are_ex_trivially_equal(p.coeff,exONE())) {
733 if (ex_to_numeric(p.coeff).is_equal(numONE())) {
736 return power(p.rest,p.coeff);
740 bool mul::expair_needs_further_processing(epp it)
742 if (is_ex_exactly_of_type((*it).rest,mul) &&
743 ex_to_numeric((*it).coeff).is_integer()) {
744 // combined pair is product with integer power -> expand it
745 *it=split_ex_to_pair(recombine_pair_to_ex(*it));
748 if (is_ex_exactly_of_type((*it).rest,numeric)) {
749 expair ep=split_ex_to_pair(recombine_pair_to_ex(*it));
750 if (!ep.is_equal(*it)) {
751 // combined pair is a numeric power which can be simplified
755 if (ex_to_numeric((*it).coeff).is_equal(numONE())) {
756 // combined pair has coeff 1 and must be moved to the end
763 ex mul::default_overall_coeff(void) const
768 void mul::combine_overall_coeff(ex const & c)
770 ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
771 ASSERT(is_ex_exactly_of_type(c,numeric));
772 overall_coeff = ex_to_numeric(overall_coeff).mul_dyn(ex_to_numeric(c));
775 void mul::combine_overall_coeff(ex const & c1, ex const & c2)
777 ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
778 ASSERT(is_ex_exactly_of_type(c1,numeric));
779 ASSERT(is_ex_exactly_of_type(c2,numeric));
780 overall_coeff = ex_to_numeric(overall_coeff).
781 mul_dyn(ex_to_numeric(c1).power(ex_to_numeric(c2)));
784 bool mul::can_make_flat(expair const & p) const
786 ASSERT(is_ex_exactly_of_type(p.coeff,numeric));
787 // this assertion will probably fail somewhere
788 // it would require a more careful make_flat, obeying the power laws
789 // probably should return true only if p.coeff is integer
790 return ex_to_numeric(p.coeff).is_equal(numONE());
793 ex mul::expand(unsigned options) const
795 exvector sub_expanded_seq;
796 intvector positions_of_adds;
797 intvector number_of_add_operands;
799 epvector * expanded_seqp=expandchildren(options);
801 epvector const & expanded_seq = expanded_seqp==0 ? seq : *expanded_seqp;
803 positions_of_adds.resize(expanded_seq.size());
804 number_of_add_operands.resize(expanded_seq.size());
806 int number_of_adds=0;
807 int number_of_expanded_terms=1;
809 unsigned current_position=0;
810 epvector::const_iterator last=expanded_seq.end();
811 for (epvector::const_iterator cit=expanded_seq.begin(); cit!=last; ++cit) {
812 if (is_ex_exactly_of_type((*cit).rest,add)&&
813 (ex_to_numeric((*cit).coeff).is_equal(numONE()))) {
814 positions_of_adds[number_of_adds]=current_position;
815 add const & expanded_addref=ex_to_add((*cit).rest);
816 int addref_nops=expanded_addref.nops();
817 number_of_add_operands[number_of_adds]=addref_nops;
818 number_of_expanded_terms *= addref_nops;
824 if (number_of_adds==0) {
825 if (expanded_seqp==0) {
826 return this->setflag(status_flags::expanded);
828 return (new mul(expanded_seqp,overall_coeff))->
829 setflag(status_flags::dynallocated ||
830 status_flags::expanded);
834 distrseq.reserve(number_of_expanded_terms);
837 k.resize(number_of_adds);
840 for (l=0; l<number_of_adds; l++) {
847 for (l=0; l<number_of_adds; l++) {
848 add const & addref=ex_to_add(expanded_seq[positions_of_adds[l]].rest);
849 ASSERT(term[positions_of_adds[l]].coeff.compare(exONE())==0);
850 term[positions_of_adds[l]]=split_ex_to_pair(addref.op(k[l]));
853 cout << "mul::expand() term begin" << endl;
854 for (epvector::const_iterator cit=term.begin(); cit!=term.end(); ++cit) {
855 cout << "rest" << endl;
856 (*cit).rest.printtree(cout);
857 cout << "coeff" << endl;
858 (*cit).coeff.printtree(cout);
860 cout << "mul::expand() term end" << endl;
862 distrseq.push_back((new mul(term,overall_coeff))->
863 setflag(status_flags::dynallocated |
864 status_flags::expanded));
868 while ((l>=0)&&((++k[l])>=number_of_add_operands[l])) {
875 if (expanded_seqp!=0) {
876 delete expanded_seqp;
879 cout << "mul::expand() distrseq begin" << endl;
880 for (exvector::const_iterator cit=distrseq.begin(); cit!=distrseq.end(); ++cit) {
881 (*cit).printtree(cout);
883 cout << "mul::expand() distrseq end" << endl;
886 return (new add(distrseq))->setflag(status_flags::dynallocated |
887 status_flags::expanded);
891 ex mul::expand(unsigned options) const
893 exvector sub_expanded_seq;
894 intvector positions_of_adds;
895 intvector number_of_add_operands;
897 sub_expanded_seq.resize(seq.size());
898 positions_of_adds.resize(seq.size());
899 number_of_add_operands.reserve(seq.size());
901 int number_of_adds=0;
902 int number_of_expanded_terms=1;
903 for (unsigned current_position=0; current_position<seq.size(); current_position++) {
904 ex const & expanded_ex=recombine_pair_to_ex(seq[current_position]).expand(options);
905 if (is_ex_exactly_of_type(expanded_ex,add)) {
906 positions_of_adds[number_of_adds]=current_position;
907 add const & expanded_addref=ex_to_add(expanded_ex);
908 number_of_add_operands[number_of_adds]=expanded_addref.seq.size();
909 number_of_expanded_terms *= expanded_addref.seq.size();
912 sub_expanded_seq.push_back(expanded_ex);
916 distrseq.reserve(number_of_expanded_terms);
919 k.resize(number_of_adds);
922 for (l=0; l<number_of_adds; l++) {
928 term=sub_expanded_seq;
929 for (l=0; l<number_of_adds; l++) {
930 add const & addref=ex_to_add(sub_expanded_seq[positions_of_adds[l]]);
931 term[positions_of_adds[l]]=addref.recombine_pair_to_ex(addref.seq[k[l]]);
933 distrseq.push_back((new mul(term))->setflag(status_flags::dynallocated |
934 status_flags::expanded));
938 while ((l>=0)&&((++k[l])>=number_of_add_operands[l])) {
945 return (new add(distrseq))->setflag(status_flags::dynallocated |
946 status_flags::expanded);
951 // new virtual functions which can be overridden by derived classes
957 // non-virtual functions in this class
960 epvector * mul::expandchildren(unsigned options) const
962 epvector::const_iterator last=seq.end();
963 epvector::const_iterator cit=seq.begin();
965 ex const & factor=recombine_pair_to_ex(*cit);
966 ex const & expanded_factor=factor.expand(options);
967 if (!are_ex_trivially_equal(factor,expanded_factor)) {
969 // something changed, copy seq, eval and return it
970 epvector *s=new epvector;
971 s->reserve(seq.size());
973 // copy parts of seq which are known not to have changed
974 epvector::const_iterator cit2=seq.begin();
979 // copy first changed element
980 s->push_back(split_ex_to_pair(expanded_factor));
984 s->push_back(split_ex_to_pair(recombine_pair_to_ex(*cit2).expand(options)));
992 return 0; // nothing has changed
996 // static member variables
1001 unsigned mul::precedence=50;
1009 type_info const & typeid_mul=typeid(some_mul);