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 #ifndef NO_GINAC_NAMESPACE
33 #endif // ndef NO_GINAC_NAMESPACE
36 // default constructor, destructor, copy constructor assignment operator and helpers
43 debugmsg("mul default constructor",LOGLEVEL_CONSTRUCT);
44 tinfo_key = TINFO_mul;
49 debugmsg("mul destructor",LOGLEVEL_DESTRUCT);
53 mul::mul(mul const & other)
55 debugmsg("mul copy constructor",LOGLEVEL_CONSTRUCT);
59 mul const & mul::operator=(mul const & other)
61 debugmsg("mul operator=",LOGLEVEL_ASSIGNMENT);
71 void mul::copy(mul const & other)
73 expairseq::copy(other);
76 void mul::destroy(bool call_parent)
78 if (call_parent) expairseq::destroy(call_parent);
87 mul::mul(ex const & lh, ex const & rh)
89 debugmsg("mul constructor from ex,ex",LOGLEVEL_CONSTRUCT);
90 tinfo_key = TINFO_mul;
91 overall_coeff=exONE();
92 construct_from_2_ex(lh,rh);
93 GINAC_ASSERT(is_canonical());
96 mul::mul(exvector const & v)
98 debugmsg("mul constructor from exvector",LOGLEVEL_CONSTRUCT);
99 tinfo_key = TINFO_mul;
100 overall_coeff=exONE();
101 construct_from_exvector(v);
102 GINAC_ASSERT(is_canonical());
106 mul::mul(epvector const & v, bool do_not_canonicalize)
108 debugmsg("mul constructor from epvector,bool",LOGLEVEL_CONSTRUCT);
109 tinfo_key = TINFO_mul;
110 if (do_not_canonicalize) {
112 #ifdef EXPAIRSEQ_USE_HASHTAB
113 combine_same_terms(); // to build hashtab
114 #endif // def EXPAIRSEQ_USE_HASHTAB
116 construct_from_epvector(v);
118 GINAC_ASSERT(is_canonical());
122 mul::mul(epvector const & v)
124 debugmsg("mul constructor from epvector",LOGLEVEL_CONSTRUCT);
125 tinfo_key = TINFO_mul;
126 overall_coeff=exONE();
127 construct_from_epvector(v);
128 GINAC_ASSERT(is_canonical());
131 mul::mul(epvector const & v, ex const & oc)
133 debugmsg("mul constructor from epvector,ex",LOGLEVEL_CONSTRUCT);
134 tinfo_key = TINFO_mul;
136 construct_from_epvector(v);
137 GINAC_ASSERT(is_canonical());
140 mul::mul(epvector * vp, ex const & oc)
142 debugmsg("mul constructor from epvector *,ex",LOGLEVEL_CONSTRUCT);
143 tinfo_key = TINFO_mul;
146 construct_from_epvector(*vp);
148 GINAC_ASSERT(is_canonical());
151 mul::mul(ex const & lh, ex const & mh, ex const & rh)
153 debugmsg("mul constructor from ex,ex,ex",LOGLEVEL_CONSTRUCT);
154 tinfo_key = TINFO_mul;
157 factors.push_back(lh);
158 factors.push_back(mh);
159 factors.push_back(rh);
160 overall_coeff=exONE();
161 construct_from_exvector(factors);
162 GINAC_ASSERT(is_canonical());
166 // functions overriding virtual functions from bases classes
171 basic * mul::duplicate() const
173 debugmsg("mul duplicate",LOGLEVEL_ASSIGNMENT);
174 return new mul(*this);
177 void mul::print(ostream & os, unsigned upper_precedence) const
179 debugmsg("mul print",LOGLEVEL_PRINT);
180 if (precedence<=upper_precedence) os << "(";
182 // first print the overall numeric coefficient:
183 if (ex_to_numeric(overall_coeff).csgn()==-1) os << '-';
184 if (!overall_coeff.is_equal(exONE()) &&
185 !overall_coeff.is_equal(exMINUSONE())) {
186 if (ex_to_numeric(overall_coeff).csgn()==-1)
187 (numMINUSONE()*overall_coeff).print(os, precedence);
189 overall_coeff.print(os, precedence);
192 // then proceed with the remaining factors:
193 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
199 recombine_pair_to_ex(*cit).print(os,precedence);
201 if (precedence<=upper_precedence) os << ")";
204 void mul::printraw(ostream & os) const
206 debugmsg("mul printraw",LOGLEVEL_PRINT);
209 for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
211 (*it).rest.bp->printraw(os);
213 (*it).coeff.bp->printraw(os);
216 os << ",hash=" << hashvalue << ",flags=" << flags;
220 void mul::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
222 debugmsg("mul print csrc", LOGLEVEL_PRINT);
223 if (precedence <= upper_precedence)
226 if (!overall_coeff.is_equal(exONE())) {
227 overall_coeff.bp->printcsrc(os,type,precedence);
231 // Print arguments, separated by "*" or "/"
232 epvector::const_iterator it = seq.begin();
233 epvector::const_iterator itend = seq.end();
234 while (it != itend) {
236 // If the first argument is a negative integer power, it gets printed as "1.0/<expr>"
237 if (it == seq.begin() && ex_to_numeric(it->coeff).is_integer() && it->coeff.compare(numZERO()) < 0) {
238 if (type == csrc_types::ctype_cl_N)
244 // If the exponent is 1 or -1, it is left out
245 if (it->coeff.compare(exONE()) == 0 || it->coeff.compare(numMINUSONE()) == 0)
246 it->rest.bp->printcsrc(os, type, precedence);
248 // outer parens around ex needed for broken gcc-2.95 parser:
249 (ex(power(it->rest, abs(ex_to_numeric(it->coeff))))).bp->printcsrc(os, type, upper_precedence);
251 // Separator is "/" for negative integer powers, "*" otherwise
254 if (ex_to_numeric(it->coeff).is_integer() && it->coeff.compare(numZERO()) < 0)
260 if (precedence <= upper_precedence)
264 bool mul::info(unsigned inf) const
267 if (inf==info_flags::polynomial ||
268 inf==info_flags::integer_polynomial ||
269 inf==info_flags::cinteger_polynomial ||
270 inf==info_flags::rational_polynomial ||
271 inf==info_flags::crational_polynomial ||
272 inf==info_flags::rational_function) {
273 for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
274 if (!(recombine_pair_to_ex(*it).info(inf)))
277 return overall_coeff.info(inf);
279 return expairseq::info(inf);
283 typedef vector<int> intvector;
285 int mul::degree(symbol const & s) const
288 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
289 deg_sum+=(*cit).rest.degree(s) * ex_to_numeric((*cit).coeff).to_int();
294 int mul::ldegree(symbol const & s) const
297 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
298 deg_sum+=(*cit).rest.ldegree(s) * ex_to_numeric((*cit).coeff).to_int();
303 ex mul::coeff(symbol const & s, int const n) const
306 coeffseq.reserve(seq.size()+1);
309 // product of individual coeffs
310 // if a non-zero power of s is found, the resulting product will be 0
311 epvector::const_iterator it=seq.begin();
312 while (it!=seq.end()) {
313 coeffseq.push_back(recombine_pair_to_ex(*it).coeff(s,n));
316 coeffseq.push_back(overall_coeff);
317 return (new mul(coeffseq))->setflag(status_flags::dynallocated);
320 epvector::const_iterator it=seq.begin();
322 while (it!=seq.end()) {
323 ex t=recombine_pair_to_ex(*it);
326 coeffseq.push_back(c);
329 coeffseq.push_back(t);
334 coeffseq.push_back(overall_coeff);
335 return (new mul(coeffseq))->setflag(status_flags::dynallocated);
341 ex mul::eval(int level) const
343 // simplifications *(...,x;0) -> 0
344 // *(+(x,y,...);c) -> *(+(*(x,c),*(y,c),...)) (c numeric())
348 debugmsg("mul eval",LOGLEVEL_MEMBER_FUNCTION);
350 epvector * evaled_seqp=evalchildren(level);
351 if (evaled_seqp!=0) {
352 // do more evaluation later
353 return (new mul(evaled_seqp,overall_coeff))->
354 setflag(status_flags::dynallocated);
357 #ifdef DO_GINAC_ASSERT
358 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
359 GINAC_ASSERT((!is_ex_exactly_of_type((*cit).rest,mul))||
360 (!(ex_to_numeric((*cit).coeff).is_integer())));
361 GINAC_ASSERT(!((*cit).is_numeric_with_coeff_1()));
362 if (is_ex_exactly_of_type(recombine_pair_to_ex(*cit),numeric)) {
365 GINAC_ASSERT(!is_ex_exactly_of_type(recombine_pair_to_ex(*cit),numeric));
367 expair p=split_ex_to_pair(recombine_pair_to_ex(*cit));
368 GINAC_ASSERT(p.rest.is_equal((*cit).rest));
369 GINAC_ASSERT(p.coeff.is_equal((*cit).coeff));
372 #endif // def DO_GINAC_ASSERT
374 if (flags & status_flags::evaluated) {
375 GINAC_ASSERT(seq.size()>0);
376 GINAC_ASSERT((seq.size()>1)||!overall_coeff.is_equal(exONE()));
380 int seq_size=seq.size();
381 if (overall_coeff.is_equal(exZERO())) {
384 } else if (seq_size==0) {
386 return overall_coeff;
387 } else if ((seq_size==1)&&overall_coeff.is_equal(exONE())) {
389 return recombine_pair_to_ex(*(seq.begin()));
390 } else if ((seq_size==1) &&
391 is_ex_exactly_of_type((*seq.begin()).rest,add) &&
392 ex_to_numeric((*seq.begin()).coeff).is_equal(numONE())) {
393 // *(+(x,y,...);c) -> +(*(x,c),*(y,c),...) (c numeric(), no powers of +())
394 add const & addref=ex_to_add((*seq.begin()).rest);
396 distrseq.reserve(addref.seq.size());
397 for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
398 distrseq.push_back(addref.combine_pair_with_coeff_to_pair(*cit,
401 return (new add(distrseq,
402 ex_to_numeric(addref.overall_coeff).
403 mul_dyn(ex_to_numeric(overall_coeff))))
404 ->setflag(status_flags::dynallocated |
405 status_flags::evaluated );
410 exvector mul::get_indices(void) const
412 // return union of indices of factors
414 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
415 exvector subiv=(*cit).rest.get_indices();
416 iv.reserve(iv.size()+subiv.size());
417 for (exvector::const_iterator cit2=subiv.begin(); cit2!=subiv.end(); ++cit2) {
424 ex mul::simplify_ncmul(exvector const & v) const
426 throw(std::logic_error("mul::simplify_ncmul() should never have been called!"));
431 int mul::compare_same_type(basic const & other) const
433 return expairseq::compare_same_type(other);
436 bool mul::is_equal_same_type(basic const & other) const
438 return expairseq::is_equal_same_type(other);
441 unsigned mul::return_type(void) const
444 // mul without factors: should not happen, but commutes
445 return return_types::commutative;
448 bool all_commutative=1;
450 epvector::const_iterator cit_noncommutative_element; // point to first found nc element
452 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
453 rt=(*cit).rest.return_type();
454 if (rt==return_types::noncommutative_composite) return rt; // one ncc -> mul also ncc
455 if ((rt==return_types::noncommutative)&&(all_commutative)) {
456 // first nc element found, remember position
457 cit_noncommutative_element=cit;
460 if ((rt==return_types::noncommutative)&&(!all_commutative)) {
461 // another nc element found, compare type_infos
462 if ((*cit_noncommutative_element).rest.return_type_tinfo()!=(*cit).rest.return_type_tinfo()) {
463 // diffent types -> mul is ncc
464 return return_types::noncommutative_composite;
468 // all factors checked
469 return all_commutative ? return_types::commutative : return_types::noncommutative;
472 unsigned mul::return_type_tinfo(void) const
475 // mul without factors: should not happen
478 // return type_info of first noncommutative element
479 for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
480 if ((*cit).rest.return_type()==return_types::noncommutative) {
481 return (*cit).rest.return_type_tinfo();
484 // no noncommutative element found, should not happen
488 ex mul::thisexpairseq(epvector const & v, ex const & oc) const
490 return (new mul(v,oc))->setflag(status_flags::dynallocated);
493 ex mul::thisexpairseq(epvector * vp, ex const & oc) const
495 return (new mul(vp,oc))->setflag(status_flags::dynallocated);
498 expair mul::split_ex_to_pair(ex const & e) const
500 if (is_ex_exactly_of_type(e,power)) {
501 power const & powerref=ex_to_power(e);
502 if (is_ex_exactly_of_type(powerref.exponent,numeric)) {
503 return expair(powerref.basis,powerref.exponent);
506 return expair(e,exONE());
509 expair mul::combine_ex_with_coeff_to_pair(ex const & e,
512 // to avoid duplication of power simplification rules,
513 // we create a temporary power object
514 // otherwise it would be hard to correctly simplify
515 // expression like (4^(1/3))^(3/2)
516 if (are_ex_trivially_equal(c,exONE())) {
517 return split_ex_to_pair(e);
519 return split_ex_to_pair(power(e,c));
522 expair mul::combine_pair_with_coeff_to_pair(expair const & p,
525 // to avoid duplication of power simplification rules,
526 // we create a temporary power object
527 // otherwise it would be hard to correctly simplify
528 // expression like (4^(1/3))^(3/2)
529 if (are_ex_trivially_equal(c,exONE())) {
532 return split_ex_to_pair(power(recombine_pair_to_ex(p),c));
535 ex mul::recombine_pair_to_ex(expair const & p) const
537 // if (p.coeff.compare(exONE())==0) {
538 // if (are_ex_trivially_equal(p.coeff,exONE())) {
539 if (ex_to_numeric(p.coeff).is_equal(numONE())) {
542 return power(p.rest,p.coeff);
546 bool mul::expair_needs_further_processing(epp it)
548 if (is_ex_exactly_of_type((*it).rest,mul) &&
549 ex_to_numeric((*it).coeff).is_integer()) {
550 // combined pair is product with integer power -> expand it
551 *it=split_ex_to_pair(recombine_pair_to_ex(*it));
554 if (is_ex_exactly_of_type((*it).rest,numeric)) {
555 expair ep=split_ex_to_pair(recombine_pair_to_ex(*it));
556 if (!ep.is_equal(*it)) {
557 // combined pair is a numeric power which can be simplified
561 if (ex_to_numeric((*it).coeff).is_equal(numONE())) {
562 // combined pair has coeff 1 and must be moved to the end
569 ex mul::default_overall_coeff(void) const
574 void mul::combine_overall_coeff(ex const & c)
576 GINAC_ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
577 GINAC_ASSERT(is_ex_exactly_of_type(c,numeric));
578 overall_coeff = ex_to_numeric(overall_coeff).mul_dyn(ex_to_numeric(c));
581 void mul::combine_overall_coeff(ex const & c1, ex const & c2)
583 GINAC_ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
584 GINAC_ASSERT(is_ex_exactly_of_type(c1,numeric));
585 GINAC_ASSERT(is_ex_exactly_of_type(c2,numeric));
586 overall_coeff = ex_to_numeric(overall_coeff).
587 mul_dyn(ex_to_numeric(c1).power(ex_to_numeric(c2)));
590 bool mul::can_make_flat(expair const & p) const
592 GINAC_ASSERT(is_ex_exactly_of_type(p.coeff,numeric));
593 // this assertion will probably fail somewhere
594 // it would require a more careful make_flat, obeying the power laws
595 // probably should return true only if p.coeff is integer
596 return ex_to_numeric(p.coeff).is_equal(numONE());
599 ex mul::expand(unsigned options) const
601 exvector sub_expanded_seq;
602 intvector positions_of_adds;
603 intvector number_of_add_operands;
605 epvector * expanded_seqp=expandchildren(options);
607 epvector const & expanded_seq = expanded_seqp==0 ? seq : *expanded_seqp;
609 positions_of_adds.resize(expanded_seq.size());
610 number_of_add_operands.resize(expanded_seq.size());
612 int number_of_adds=0;
613 int number_of_expanded_terms=1;
615 unsigned current_position=0;
616 epvector::const_iterator last=expanded_seq.end();
617 for (epvector::const_iterator cit=expanded_seq.begin(); cit!=last; ++cit) {
618 if (is_ex_exactly_of_type((*cit).rest,add)&&
619 (ex_to_numeric((*cit).coeff).is_equal(numONE()))) {
620 positions_of_adds[number_of_adds]=current_position;
621 add const & expanded_addref=ex_to_add((*cit).rest);
622 int addref_nops=expanded_addref.nops();
623 number_of_add_operands[number_of_adds]=addref_nops;
624 number_of_expanded_terms *= addref_nops;
630 if (number_of_adds==0) {
631 if (expanded_seqp==0) {
632 return this->setflag(status_flags::expanded);
634 return (new mul(expanded_seqp,overall_coeff))->
635 setflag(status_flags::dynallocated ||
636 status_flags::expanded);
640 distrseq.reserve(number_of_expanded_terms);
643 k.resize(number_of_adds);
646 for (l=0; l<number_of_adds; l++) {
653 for (l=0; l<number_of_adds; l++) {
654 add const & addref=ex_to_add(expanded_seq[positions_of_adds[l]].rest);
655 GINAC_ASSERT(term[positions_of_adds[l]].coeff.compare(exONE())==0);
656 term[positions_of_adds[l]]=split_ex_to_pair(addref.op(k[l]));
659 cout << "mul::expand() term begin" << endl;
660 for (epvector::const_iterator cit=term.begin(); cit!=term.end(); ++cit) {
661 cout << "rest" << endl;
662 (*cit).rest.printtree(cout);
663 cout << "coeff" << endl;
664 (*cit).coeff.printtree(cout);
666 cout << "mul::expand() term end" << endl;
668 distrseq.push_back((new mul(term,overall_coeff))->
669 setflag(status_flags::dynallocated |
670 status_flags::expanded));
674 while ((l>=0)&&((++k[l])>=number_of_add_operands[l])) {
681 if (expanded_seqp!=0) {
682 delete expanded_seqp;
685 cout << "mul::expand() distrseq begin" << endl;
686 for (exvector::const_iterator cit=distrseq.begin(); cit!=distrseq.end(); ++cit) {
687 (*cit).printtree(cout);
689 cout << "mul::expand() distrseq end" << endl;
692 return (new add(distrseq))->setflag(status_flags::dynallocated |
693 status_flags::expanded);
697 // new virtual functions which can be overridden by derived classes
703 // non-virtual functions in this class
706 epvector * mul::expandchildren(unsigned options) const
708 epvector::const_iterator last=seq.end();
709 epvector::const_iterator cit=seq.begin();
711 ex const & factor=recombine_pair_to_ex(*cit);
712 ex const & expanded_factor=factor.expand(options);
713 if (!are_ex_trivially_equal(factor,expanded_factor)) {
715 // something changed, copy seq, eval and return it
716 epvector *s=new epvector;
717 s->reserve(seq.size());
719 // copy parts of seq which are known not to have changed
720 epvector::const_iterator cit2=seq.begin();
725 // copy first changed element
726 s->push_back(split_ex_to_pair(expanded_factor));
730 s->push_back(split_ex_to_pair(recombine_pair_to_ex(*cit2).expand(options)));
738 return 0; // nothing has changed
742 // static member variables
747 unsigned mul::precedence=50;
755 type_info const & typeid_mul=typeid(some_mul);
757 #ifndef NO_GINAC_NAMESPACE
759 #endif // ndef NO_GINAC_NAMESPACE