- switched to automake build environment
[ginac.git] / ginac / mul.cpp
1 /** @file mul.cpp
2  *
3  *  Implementation of GiNaC's products of expressions. */
4
5 #include <vector>
6 #include <stdexcept>
7
8 #include "ginac.h"
9
10 //////////
11 // default constructor, destructor, copy constructor assignment operator and helpers
12 //////////
13
14 // public
15
16 mul::mul()
17 {
18     debugmsg("mul default constructor",LOGLEVEL_CONSTRUCT);
19     tinfo_key = TINFO_MUL;
20 }
21
22 mul::~mul()
23 {
24     debugmsg("mul destructor",LOGLEVEL_DESTRUCT);
25     destroy(0);
26 }
27
28 mul::mul(mul const & other)
29 {
30     debugmsg("mul copy constructor",LOGLEVEL_CONSTRUCT);
31     copy(other);
32 }
33
34 mul const & mul::operator=(mul const & other)
35 {
36     debugmsg("mul operator=",LOGLEVEL_ASSIGNMENT);
37     if (this != &other) {
38         destroy(1);
39         copy(other);
40     }
41     return *this;
42 }
43
44 // protected
45
46 void mul::copy(mul const & other)
47 {
48     expairseq::copy(other);
49 }
50
51 void mul::destroy(bool call_parent)
52 {
53     if (call_parent) expairseq::destroy(call_parent);
54 }
55
56 //////////
57 // other constructors
58 //////////
59
60 // public
61
62 mul::mul(ex const & lh, ex const & rh)
63 {
64     debugmsg("mul constructor from ex,ex",LOGLEVEL_CONSTRUCT);
65     tinfo_key = TINFO_MUL;
66     overall_coeff=exONE();
67     construct_from_2_ex(lh,rh);
68     ASSERT(is_canonical());
69 }
70
71 mul::mul(exvector const & v)
72 {
73     debugmsg("mul constructor from exvector",LOGLEVEL_CONSTRUCT);
74     tinfo_key = TINFO_MUL;
75     overall_coeff=exONE();
76     construct_from_exvector(v);
77     ASSERT(is_canonical());
78 }
79
80 /*
81 mul::mul(epvector const & v, bool do_not_canonicalize)
82 {
83     debugmsg("mul constructor from epvector,bool",LOGLEVEL_CONSTRUCT);
84     tinfo_key = TINFO_MUL;
85     if (do_not_canonicalize) {
86         seq=v;
87 #ifdef EXPAIRSEQ_USE_HASHTAB
88         combine_same_terms(); // to build hashtab
89 #endif // def EXPAIRSEQ_USE_HASHTAB
90     } else {
91         construct_from_epvector(v);
92     }
93     ASSERT(is_canonical());
94 }
95 */
96
97 mul::mul(epvector const & v)
98 {
99     debugmsg("mul constructor from epvector",LOGLEVEL_CONSTRUCT);
100     tinfo_key = TINFO_MUL;
101     overall_coeff=exONE();
102     construct_from_epvector(v);
103     ASSERT(is_canonical());
104 }
105
106 mul::mul(epvector const & v, ex const & oc)
107 {
108     debugmsg("mul constructor from epvector,ex",LOGLEVEL_CONSTRUCT);
109     tinfo_key = TINFO_MUL;
110     overall_coeff=oc;
111     construct_from_epvector(v);
112     ASSERT(is_canonical());
113 }
114
115 mul::mul(epvector * vp, ex const & oc)
116 {
117     debugmsg("mul constructor from epvector *,ex",LOGLEVEL_CONSTRUCT);
118     tinfo_key = TINFO_MUL;
119     ASSERT(vp!=0);
120     overall_coeff=oc;
121     construct_from_epvector(*vp);
122     delete vp;
123     ASSERT(is_canonical());
124 }
125
126 mul::mul(ex const & lh, ex const & mh, ex const & rh)
127 {
128     debugmsg("mul constructor from ex,ex,ex",LOGLEVEL_CONSTRUCT);
129     tinfo_key = TINFO_MUL;
130     exvector factors;
131     factors.reserve(3);
132     factors.push_back(lh);
133     factors.push_back(mh);
134     factors.push_back(rh);
135     overall_coeff=exONE();
136     construct_from_exvector(factors);
137     ASSERT(is_canonical());
138 }
139
140 //////////
141 // functions overriding virtual functions from bases classes
142 //////////
143
144 // public
145
146 basic * mul::duplicate() const
147 {
148     debugmsg("mul duplicate",LOGLEVEL_ASSIGNMENT);
149     return new mul(*this);
150 }
151
152 bool mul::info(unsigned inf) const
153 {
154     // TODO: optimize
155     if (inf==info_flags::polynomial || inf==info_flags::integer_polynomial || inf==info_flags::rational_polynomial || inf==info_flags::rational_function) {
156         for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
157             if (!(recombine_pair_to_ex(*it).info(inf)))
158                 return false;
159         }
160         return true;
161     } else {
162         return expairseq::info(inf);
163     }
164 }
165
166 typedef vector<int> intvector;
167
168 int mul::degree(symbol const & s) const
169 {
170     int deg_sum=0;
171     for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
172         deg_sum+=(*cit).rest.degree(s) * ex_to_numeric((*cit).coeff).to_int();
173     }
174     return deg_sum;
175 }
176
177 int mul::ldegree(symbol const & s) const
178 {
179     int deg_sum=0;
180     for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
181         deg_sum+=(*cit).rest.ldegree(s) * ex_to_numeric((*cit).coeff).to_int();
182     }
183     return deg_sum;
184 }
185
186 ex mul::coeff(symbol const & s, int const n) const
187 {
188     exvector coeffseq;
189     coeffseq.reserve(seq.size()+1);
190     
191     if (n==0) {
192         // product of individual coeffs
193         // if a non-zero power of s is found, the resulting product will be 0
194         epvector::const_iterator it=seq.begin();
195         while (it!=seq.end()) {
196             coeffseq.push_back(recombine_pair_to_ex(*it).coeff(s,n));
197             ++it;
198         }
199         coeffseq.push_back(overall_coeff);
200         return (new mul(coeffseq))->setflag(status_flags::dynallocated);
201     }
202          
203     epvector::const_iterator it=seq.begin();
204     bool coeff_found=0;
205     while (it!=seq.end()) {
206         ex t=recombine_pair_to_ex(*it);
207         ex c=t.coeff(s,n);
208         if (!c.is_zero()) {
209             coeffseq.push_back(c);
210             coeff_found=1;
211         } else {
212             coeffseq.push_back(t);
213         }
214         ++it;
215     }
216     if (coeff_found) {
217         coeffseq.push_back(overall_coeff);
218         return (new mul(coeffseq))->setflag(status_flags::dynallocated);
219     }
220     
221     return exZERO();
222 }
223
224 /*
225 ex mul::eval(int level) const
226 {
227     // simplifications: *(...,x,(c1,1),(c2,1)) -> *(...,x,(c1*c2,1)) (c1, c2 numeric(), move pairs to end first)
228     //                  *(...,x,1) -> *(...,x)
229     //                  *(...,x,0) -> 0
230     //                  *(+(x,y,...),(c,1)) -> *(+(*(x,c),*(y,c),...)) (c numeric())
231     //                  *(x) -> x
232     //                  *() -> 1
233
234     debugmsg("mul eval",LOGLEVEL_MEMBER_FUNCTION);
235
236     if ((level==1)&&(flags & status_flags::evaluated)) {
237 #ifdef DOASSERT
238         for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
239             ASSERT((!is_ex_exactly_of_type((*cit).rest,mul))||
240                    (!(ex_to_numeric((*cit).coeff).is_integer())));
241         }
242
243         // test if all numerics were moved to the end and
244         // all numerics with coeff 1 to the very end
245         if (seq.size()!=0) {
246             epvector::const_iterator cit=seq.end();
247             bool all_coeff_1=true;
248             bool all_numeric=true;
249             do {
250                 cit--;
251                 if (is_ex_exactly_of_type((*cit).rest,numeric)) {
252                     ASSERT(all_numeric);
253                     if ((*cit).coeff.is_equal(exONE())) {
254                         ASSERT(all_coeff_1);
255                     } else {
256                         all_coeff_1=false;
257                     }
258                 } else {
259                     all_numeric=false;
260                 }
261             } while (cit!=seq.begin());
262         }
263 #endif // def DOASSERT    
264         return *this;
265     }
266
267     epvector newseq;
268     epvector::iterator it1,it2;
269     bool seq_copied=false;
270
271     epvector * evaled_seqp=evalchildren(level);
272     if (evaled_seqp!=0) {
273         // do more evaluation later
274         return (new mul(evaled_seqp))->setflag(status_flags::dynallocated);
275     }
276
277     // combine pairs with coeff 1 (all numerics should be at end, assert below)
278     if (seq.size()>1) {
279         // count number of pairs with coeff 1
280         unsigned num_coeff_1=0;
281         bool still_numeric=true;
282         epvector::const_iterator cit=seq.end();
283         unsigned first_pos;
284         unsigned second_pos;
285         do {
286             cit--;
287             if (is_ex_exactly_of_type((*cit).rest,numeric)) {
288                 if ((*cit).coeff.is_equal(exONE())) {
289                     num_coeff_1++;
290                 }
291             } else {
292                 still_numeric=false;
293             }
294         } while ((cit!=seq.begin())&&still_numeric);
295         if (num_coeff_1>1) {
296             newseq=seq;
297             
298     }
299     
300     
301 #ifdef DOASSERT
302     for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
303         ASSERT((!is_ex_exactly_of_type((*cit).rest,mul))||
304                (!(ex_to_numeric((*cit).coeff).is_integer())));
305     }
306
307     // test if all numerics were moved to the end and
308     // all numerics with coeff 1 to the very end
309     if (seq.size()!=0) {
310         epvector::const_iterator cit=seq.end();
311         bool all_coeff_1=true;
312         bool all_numeric=true;
313         do {
314             cit--;
315             if (is_ex_exactly_of_type((*cit).rest,numeric)) {
316                 ASSERT(all_numeric);
317                 if ((*cit).coeff.is_equal(exONE())) {
318                     ASSERT(all_coeff_1);
319                 } else {
320                     all_coeff_1=false;
321                 }
322             } else {
323                 all_numeric=false;
324             }
325         } while (cit!=seq.begin());
326     }
327 #endif // def DOASSERT
328     
329     if (flags & status_flags::evaluated) {
330         return *this;
331     }
332     
333     expair const & last_expair=*(seq.end()-1);
334     expair const & next_to_last_expair=*(seq.end()-2);
335     int seq_size = seq.size();
336
337     // *(...,x,(c1,1),(c2,1)) -> *(...,x,(c1*c2,1)) (c1, c2 numeric())
338     if ((!seq_copied) && (seq_size>=2) &&
339         is_ex_exactly_of_type(last_expair.rest,numeric) &&
340         ex_to_numeric(last_expair.coeff).is_equal(numONE()) &&
341         is_ex_exactly_of_type(next_to_last_expair.rest,numeric) &&
342         ex_to_numeric(next_to_last_expair.coeff).is_equal(numONE()) ) {
343         newseq=seq;
344         seq_copied=true;
345         it2=newseq.end()-1;
346         it1=it2-1;
347     }
348     while (seq_copied && (newseq.size()>=2) &&
349            is_ex_exactly_of_type((*it1).rest,numeric) &&
350            ex_to_numeric((*it1).coeff).is_equal(numONE()) &&
351            is_ex_exactly_of_type((*it2).rest,numeric) &&
352            ex_to_numeric((*it2).coeff).is_equal(numONE()) ) {
353         *it1=expair(ex_to_numeric((*it1).rest).mul_dyn(ex_to_numeric((*it2).rest)),exONE());
354         newseq.pop_back();
355         it2=newseq.end()-1;
356         it1=it2-1;
357     }
358
359     // *(...,x,1) -> *(...,x)
360     if ((!seq_copied) && (seq_size>=1) &&
361         (is_ex_exactly_of_type(last_expair.rest,numeric)) &&
362         (ex_to_numeric(last_expair.rest).compare(numONE())==0)) {
363         newseq=seq;
364         seq_copied=true;
365         it2=newseq.end()-1;
366     }
367     if (seq_copied && (newseq.size()>=1) &&
368         (is_ex_exactly_of_type((*it2).rest,numeric)) &&
369         (ex_to_numeric((*it2).rest).compare(numONE())==0)) {
370         newseq.pop_back();
371         it2=newseq.end()-1;
372     }
373
374     // *(...,x,0) -> 0
375     if ((!seq_copied) && (seq_size>=1) &&
376         (is_ex_exactly_of_type(last_expair.rest,numeric)) &&
377         (ex_to_numeric(last_expair.rest).is_zero())) {
378         return exZERO();
379     }
380     if (seq_copied && (newseq.size()>=1) &&
381         (is_ex_exactly_of_type((*it2).rest,numeric)) &&
382         (ex_to_numeric((*it2).rest).is_zero())) {
383         return exZERO();
384     }
385
386     // *(+(x,y,...),c) -> +(*(x,c),*(y,c),...) (c numeric(), no powers of +())
387     if ((!seq_copied) && (seq_size==2) &&
388         is_ex_exactly_of_type(next_to_last_expair.rest,add) &&
389         is_ex_exactly_of_type(last_expair.rest,numeric) &&
390         ex_to_numeric(last_expair.coeff).is_equal(numONE()) &&
391         (ex_to_numeric(next_to_last_expair.coeff).compare(numONE())==0)) {
392         add const & addref=ex_to_add(next_to_last_expair.rest);
393         epvector distrseq;
394         distrseq.reserve(addref.seq.size());
395         for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
396             distrseq.push_back(addref.combine_pair_with_coeff_to_pair(*cit,
397                                    last_expair.rest));
398         }
399         // special treatment for the last element if it is numeric (to
400         // avoid terms like (2/3)*(3/2)) is no longer necessary, this
401         // is handled in add::combine_pair_with_coeff_to_pair()
402         return (new add(distrseq,1))->setflag(status_flags::dynallocated  |
403                                               status_flags::evaluated );
404     }
405     if (seq_copied && (newseq.size()==2) &&
406         is_ex_exactly_of_type(newseq[0].rest,add) &&
407         is_ex_exactly_of_type(newseq[1].rest,numeric) &&
408         ex_to_numeric(newseq[1].coeff).is_equal(numONE()) &&
409         (ex_to_numeric(newseq[0].coeff).compare(numONE())==0)) {
410         add const & addref=ex_to_add(newseq[0].rest);
411         epvector distrseq;
412         distrseq.reserve(addref.seq.size());
413         for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
414             distrseq.push_back(addref.combine_pair_with_coeff_to_pair(*cit,
415                                    newseq[1].rest));
416         }
417         // special treatment for the last element if it is numeric (to
418         // avoid terms like (2/3)*(3/2)) is no longer necessary, this
419         // is handled in add::combine_pair_with_coeff_to_pair()
420         return (new add(distrseq,1))->setflag(status_flags::dynallocated  |
421                                               status_flags::evaluated );
422     }
423     
424     // *() -> 1
425     if ((!seq_copied) && (seq_size==0)) {
426         return exONE();
427     } else if (seq_copied && (newseq.size()==0)) {
428         return exONE();
429     }
430
431     // *(x) -> x
432     if ((!seq_copied) && (seq_size==1)) {
433         return recombine_pair_to_ex(*(seq.begin()));
434     } else if (seq_copied && (newseq.size()==1)) {
435         return recombine_pair_to_ex(*(newseq.begin()));
436     }
437
438     if (!seq_copied) return this->hold();
439
440     return (new mul(newseq,1))->setflag(status_flags::dynallocated  |
441                                         status_flags::evaluated );
442 }
443 */
444
445 ex mul::eval(int level) const
446 {
447     // simplifications  *(...,x;0) -> 0
448     //                  *(+(x,y,...);c) -> *(+(*(x,c),*(y,c),...)) (c numeric())
449     //                  *(x;1) -> x
450     //                  *(;c) -> c
451
452     debugmsg("mul eval",LOGLEVEL_MEMBER_FUNCTION);
453
454     epvector * evaled_seqp=evalchildren(level);
455     if (evaled_seqp!=0) {
456         // do more evaluation later
457         return (new mul(evaled_seqp,overall_coeff))->
458                    setflag(status_flags::dynallocated);
459     }
460
461 #ifdef DOASSERT
462     for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
463         ASSERT((!is_ex_exactly_of_type((*cit).rest,mul))||
464                (!(ex_to_numeric((*cit).coeff).is_integer())));
465         ASSERT(!((*cit).is_numeric_with_coeff_1()));
466         if (is_ex_exactly_of_type(recombine_pair_to_ex(*cit),numeric)) {
467             printtree(cerr,0);
468         }
469         ASSERT(!is_ex_exactly_of_type(recombine_pair_to_ex(*cit),numeric));
470         /* for paranoia */
471         expair p=split_ex_to_pair(recombine_pair_to_ex(*cit));
472         ASSERT(p.rest.is_equal((*cit).rest));
473         ASSERT(p.coeff.is_equal((*cit).coeff));
474         /* end paranoia */
475     }
476 #endif // def DOASSERT
477
478     if (flags & status_flags::evaluated) {
479         ASSERT(seq.size()>0);
480         ASSERT((seq.size()>1)||!overall_coeff.is_equal(exONE()));
481         return *this;
482     }
483
484     int seq_size=seq.size();
485     if (overall_coeff.is_equal(exZERO())) {
486         // *(...,x;0) -> 0
487         return exZERO();
488     } else if (seq_size==0) {
489         // *(;c) -> c
490         return overall_coeff;
491     } else if ((seq_size==1)&&overall_coeff.is_equal(exONE())) {
492         // *(x;1) -> x
493         return recombine_pair_to_ex(*(seq.begin()));
494     } else if ((seq_size==1) &&
495                is_ex_exactly_of_type((*seq.begin()).rest,add) &&
496                ex_to_numeric((*seq.begin()).coeff).is_equal(numONE())) {
497         // *(+(x,y,...);c) -> +(*(x,c),*(y,c),...) (c numeric(), no powers of +())
498         add const & addref=ex_to_add((*seq.begin()).rest);
499         epvector distrseq;
500         distrseq.reserve(addref.seq.size());
501         for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
502             distrseq.push_back(addref.combine_pair_with_coeff_to_pair(*cit,
503                                    overall_coeff));
504         }
505         return (new add(distrseq,
506                         ex_to_numeric(addref.overall_coeff).
507                         mul_dyn(ex_to_numeric(overall_coeff))))
508             ->setflag(status_flags::dynallocated  |
509                       status_flags::evaluated );
510     }
511     return this->hold();
512 }
513
514 /*
515 ex mul::eval(int level) const
516 {
517     // simplifications: *(...,x,c1,c2) -> *(...,x,c1*c2) (c1, c2 numeric())
518     //                  *(...,(c1,c2)) -> (...,(c1^c2,1)) (normalize)
519     //                  *(...,x,1) -> +(...,x)
520     //                  *(...,x,0) -> 0
521     //                  *(+(x,y,...),c) -> *(+(*(x,c),*(y,c),...)) (c numeric())
522     //                  *(x) -> x
523     //                  *() -> 1
524
525     debugmsg("mul eval",LOGLEVEL_MEMBER_FUNCTION);
526
527     epvector newseq=seq;
528     epvector::iterator it1,it2;
529     
530     // *(...,x,c1,c2) -> *(...,x,c1*c2) (c1, c2 numeric())
531     it2=newseq.end()-1;
532     it1=it2-1;
533     while ((newseq.size()>=2)&&is_exactly_of_type(*(*it1).rest.bp,numeric)&&
534                                is_exactly_of_type(*(*it2).rest.bp,numeric)) {
535         *it1=expair(ex_to_numeric((*it1).rest).power(ex_to_numeric((*it1).coeff))
536                     .mul(ex_to_numeric((*it2).rest).power(ex_to_numeric((*it2).coeff))),exONE());
537         newseq.pop_back();
538         it2=newseq.end()-1;
539         it1=it2-1;
540     }
541
542     if ((newseq.size()>=1)&&is_exactly_of_type(*(*it2).rest.bp,numeric)) {
543         // *(...,(c1,c2)) -> (...,(c1^c2,1)) (normalize)
544         *it2=expair(ex_to_numeric((*it2).rest).power(ex_to_numeric((*it2).coeff)),exONE());
545         // *(...,x,1) -> *(...,x)
546         if (static_cast<numeric &>(*(*it2).rest.bp).compare(numONE())==0) {
547             newseq.pop_back();
548             it2=newseq.end()-1;
549         }
550     }
551
552     // *(...,x,0) -> 0
553     if ((newseq.size()>=1)&&is_exactly_of_type(*(*it2).rest.bp,numeric)) {
554         if (static_cast<numeric &>(*(*it2).rest.bp).is_zero()==0) {
555             return exZERO();
556         }
557     }
558
559     // *(+(x,y,...),c) -> +(*(x,c),*(y,c),...) (c numeric(), no powers of +())
560     if ((newseq.size()==2)&&is_ex_exactly_of_type(newseq[0].rest,add)&&
561         is_ex_exactly_of_type(newseq[1].rest,numeric)&&
562         (ex_to_numeric(newseq[0].coeff).compare(numONE())==0)) {
563         add const & addref=ex_to_add(newseq[0].rest);
564         numeric const & numref=ex_to_numeric(newseq[1].rest);
565         epvector distrseq;
566         distrseq.reserve(addref.seq.size());
567         for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
568             distrseq.push_back(expair((*cit).rest,ex_to_numeric((*cit).coeff).mul(numref)));
569         }
570         return (new add(distrseq,1))->setflag(status_flags::dynallocated  |
571                                               status_flags::evaluated );
572     }
573     
574     if (newseq.size()==0) {
575         // *() -> 1
576         return exONE();
577     } else if (newseq.size()==1) {
578         // *(x) -> x
579         return recombine_pair_to_ex(*newseq.begin());
580     }
581
582     return (new mul(newseq,1))->setflag(status_flags::dynallocated  |
583                                         status_flags::evaluated );
584 }
585 */
586
587 exvector mul::get_indices(void) const
588 {
589     // return union of indices of factors
590     exvector iv;
591     for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
592         exvector subiv=(*cit).rest.get_indices();
593         iv.reserve(iv.size()+subiv.size());
594         for (exvector::const_iterator cit2=subiv.begin(); cit2!=subiv.end(); ++cit2) {
595             iv.push_back(*cit2);
596         }
597     }
598     return iv;
599 }
600
601 ex mul::simplify_ncmul(exvector const & v) const
602 {
603     throw(std::logic_error("mul::simplify_ncmul() should never have been called!"));
604 }
605
606 // protected
607
608 int mul::compare_same_type(basic const & other) const
609 {
610     return expairseq::compare_same_type(other);
611 }
612
613 bool mul::is_equal_same_type(basic const & other) const
614 {
615     return expairseq::is_equal_same_type(other);
616 }
617
618 unsigned mul::return_type(void) const
619 {
620     if (seq.size()==0) {
621         // mul without factors: should not happen, but commutes
622         return return_types::commutative;
623     }
624
625     bool all_commutative=1;
626     unsigned rt;
627     epvector::const_iterator cit_noncommutative_element; // point to first found nc element
628
629     for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
630         rt=(*cit).rest.return_type();
631         if (rt==return_types::noncommutative_composite) return rt; // one ncc -> mul also ncc
632         if ((rt==return_types::noncommutative)&&(all_commutative)) {
633             // first nc element found, remember position
634             cit_noncommutative_element=cit;
635             all_commutative=0;
636         }
637         if ((rt==return_types::noncommutative)&&(!all_commutative)) {
638                 // another nc element found, compare type_infos
639             if ((*cit_noncommutative_element).rest.return_type_tinfo()!=(*cit).rest.return_type_tinfo()) {
640                 // diffent types -> mul is ncc
641                 return return_types::noncommutative_composite;
642             }
643         }
644     }
645     // all factors checked
646     return all_commutative ? return_types::commutative : return_types::noncommutative;
647 }
648    
649 unsigned mul::return_type_tinfo(void) const
650 {
651     if (seq.size()==0) {
652         // mul without factors: should not happen
653         return tinfo_key;
654     }
655     // return type_info of first noncommutative element
656     for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
657         if ((*cit).rest.return_type()==return_types::noncommutative) {
658             return (*cit).rest.return_type_tinfo();
659         }
660     }
661     // no noncommutative element found, should not happen
662     return tinfo_key;
663 }
664
665 ex mul::thisexpairseq(epvector const & v, ex const & oc) const
666 {
667     return (new mul(v,oc))->setflag(status_flags::dynallocated);
668 }
669
670 ex mul::thisexpairseq(epvector * vp, ex const & oc) const
671 {
672     return (new mul(vp,oc))->setflag(status_flags::dynallocated);
673 }
674
675 expair mul::split_ex_to_pair(ex const & e) const
676 {
677     if (is_ex_exactly_of_type(e,power)) {
678         power const & powerref=ex_to_power(e);
679         if (is_ex_exactly_of_type(powerref.exponent,numeric)) {
680             return expair(powerref.basis,powerref.exponent);
681         }
682     }
683     return expair(e,exONE());
684 }
685     
686 expair mul::combine_ex_with_coeff_to_pair(ex const & e,
687                                           ex const & c) const
688 {
689     // to avoid duplication of power simplification rules,
690     // we create a temporary power object
691     // otherwise it would be hard to correctly simplify
692     // expression like (4^(1/3))^(3/2)
693     if (are_ex_trivially_equal(c,exONE())) {
694         return split_ex_to_pair(e);
695     }
696     return split_ex_to_pair(power(e,c));
697 }
698     
699 expair mul::combine_pair_with_coeff_to_pair(expair const & p,
700                                             ex const & c) const
701 {
702     // to avoid duplication of power simplification rules,
703     // we create a temporary power object
704     // otherwise it would be hard to correctly simplify
705     // expression like (4^(1/3))^(3/2)
706     if (are_ex_trivially_equal(c,exONE())) {
707         return p;
708     }
709     return split_ex_to_pair(power(recombine_pair_to_ex(p),c));
710 }
711     
712 ex mul::recombine_pair_to_ex(expair const & p) const
713 {
714     // if (p.coeff.compare(exONE())==0) {
715     // if (are_ex_trivially_equal(p.coeff,exONE())) {
716     if (ex_to_numeric(p.coeff).is_equal(numONE())) {
717         return p.rest;
718     } else {
719         return power(p.rest,p.coeff);
720     }
721 }
722
723 bool mul::expair_needs_further_processing(epp it)
724 {
725     if (is_ex_exactly_of_type((*it).rest,mul) &&
726         ex_to_numeric((*it).coeff).is_integer()) {
727         // combined pair is product with integer power -> expand it
728         *it=split_ex_to_pair(recombine_pair_to_ex(*it));
729         return true;
730     }
731     if (is_ex_exactly_of_type((*it).rest,numeric)) {
732         expair ep=split_ex_to_pair(recombine_pair_to_ex(*it));
733         if (!ep.is_equal(*it)) {
734             // combined pair is a numeric power which can be simplified
735             *it=ep;
736             return true;
737         }
738         if (ex_to_numeric((*it).coeff).is_equal(numONE())) {
739             // combined pair has coeff 1 and must be moved to the end
740             return true;
741         }
742     }
743     return false;
744 }       
745
746 ex mul::default_overall_coeff(void) const
747 {
748     return exONE();
749 }
750
751 void mul::combine_overall_coeff(ex const & c)
752 {
753     ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
754     ASSERT(is_ex_exactly_of_type(c,numeric));
755     overall_coeff = ex_to_numeric(overall_coeff).mul_dyn(ex_to_numeric(c));
756 }
757
758 void mul::combine_overall_coeff(ex const & c1, ex const & c2)
759 {
760     ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
761     ASSERT(is_ex_exactly_of_type(c1,numeric));
762     ASSERT(is_ex_exactly_of_type(c2,numeric));
763     overall_coeff = ex_to_numeric(overall_coeff).
764                         mul_dyn(ex_to_numeric(c1).power(ex_to_numeric(c2)));
765 }
766
767 bool mul::can_make_flat(expair const & p) const
768 {
769     ASSERT(is_ex_exactly_of_type(p.coeff,numeric));
770     // this assertion will probably fail somewhere
771     // it would require a more careful make_flat, obeying the power laws
772     // probably should return true only if p.coeff is integer
773     return ex_to_numeric(p.coeff).is_equal(numONE());
774 }
775
776 ex mul::expand(unsigned options) const
777 {
778     exvector sub_expanded_seq;
779     intvector positions_of_adds;
780     intvector number_of_add_operands;
781
782     epvector * expanded_seqp=expandchildren(options);
783
784     epvector const & expanded_seq = expanded_seqp==0 ? seq : *expanded_seqp;
785
786     positions_of_adds.resize(expanded_seq.size());
787     number_of_add_operands.resize(expanded_seq.size());
788
789     int number_of_adds=0;
790     int number_of_expanded_terms=1;
791
792     unsigned current_position=0;
793     epvector::const_iterator last=expanded_seq.end();
794     for (epvector::const_iterator cit=expanded_seq.begin(); cit!=last; ++cit) {
795         if (is_ex_exactly_of_type((*cit).rest,add)&&
796             (ex_to_numeric((*cit).coeff).is_equal(numONE()))) {
797             positions_of_adds[number_of_adds]=current_position;
798             add const & expanded_addref=ex_to_add((*cit).rest);
799             int addref_nops=expanded_addref.nops();
800             number_of_add_operands[number_of_adds]=addref_nops;
801             number_of_expanded_terms *= addref_nops;
802             number_of_adds++;
803         }
804         current_position++;
805     }
806
807     if (number_of_adds==0) {
808         if (expanded_seqp==0) {
809             return this->setflag(status_flags::expanded);
810         }
811         return (new mul(expanded_seqp,overall_coeff))->
812                      setflag(status_flags::dynallocated ||
813                              status_flags::expanded);
814     }
815
816     exvector distrseq;
817     distrseq.reserve(number_of_expanded_terms);
818
819     intvector k;
820     k.resize(number_of_adds);
821     
822     int l;
823     for (l=0; l<number_of_adds; l++) {
824         k[l]=0;
825     }
826
827     while (1) {
828         epvector term;
829         term=expanded_seq;
830         for (l=0; l<number_of_adds; l++) {
831             add const & addref=ex_to_add(expanded_seq[positions_of_adds[l]].rest);
832             ASSERT(term[positions_of_adds[l]].coeff.compare(exONE())==0);
833             term[positions_of_adds[l]]=split_ex_to_pair(addref.op(k[l]));
834         }
835         /*
836         cout << "mul::expand() term begin" << endl;
837         for (epvector::const_iterator cit=term.begin(); cit!=term.end(); ++cit) {
838             cout << "rest" << endl;
839             (*cit).rest.printtree(cout);
840             cout << "coeff" << endl;
841             (*cit).coeff.printtree(cout);
842         }
843         cout << "mul::expand() term end" << endl;
844         */
845         distrseq.push_back((new mul(term,overall_coeff))->
846                                 setflag(status_flags::dynallocated |
847                                         status_flags::expanded));
848
849         // increment k[]
850         l=number_of_adds-1;
851         while ((l>=0)&&((++k[l])>=number_of_add_operands[l])) {
852             k[l]=0;    
853             l--;
854         }
855         if (l<0) break;
856     }
857
858     if (expanded_seqp!=0) {
859         delete expanded_seqp;
860     }
861     /*
862     cout << "mul::expand() distrseq begin" << endl;
863     for (exvector::const_iterator cit=distrseq.begin(); cit!=distrseq.end(); ++cit) {
864         (*cit).printtree(cout);
865     }
866     cout << "mul::expand() distrseq end" << endl;
867     */
868
869     return (new add(distrseq))->setflag(status_flags::dynallocated |
870                                         status_flags::expanded);
871 }
872
873 /*
874 ex mul::expand(unsigned options) const
875 {
876     exvector sub_expanded_seq;
877     intvector positions_of_adds;
878     intvector number_of_add_operands;
879
880     sub_expanded_seq.resize(seq.size());
881     positions_of_adds.resize(seq.size());
882     number_of_add_operands.reserve(seq.size());
883
884     int number_of_adds=0;
885     int number_of_expanded_terms=1;
886     for (unsigned current_position=0; current_position<seq.size(); current_position++) {
887         ex const & expanded_ex=recombine_pair_to_ex(seq[current_position]).expand(options);
888         if (is_ex_exactly_of_type(expanded_ex,add)) {
889             positions_of_adds[number_of_adds]=current_position;
890             add const & expanded_addref=ex_to_add(expanded_ex);
891             number_of_add_operands[number_of_adds]=expanded_addref.seq.size();
892             number_of_expanded_terms *= expanded_addref.seq.size();
893             number_of_adds++;
894         }
895         sub_expanded_seq.push_back(expanded_ex);
896     }
897
898     exvector distrseq;
899     distrseq.reserve(number_of_expanded_terms);
900
901     intvector k;
902     k.resize(number_of_adds);
903     
904     int l;
905     for (l=0; l<number_of_adds; l++) {
906         k[l]=0;
907     }
908
909     while (1) {
910         exvector term;
911         term=sub_expanded_seq;
912         for (l=0; l<number_of_adds; l++) {
913             add const & addref=ex_to_add(sub_expanded_seq[positions_of_adds[l]]);
914             term[positions_of_adds[l]]=addref.recombine_pair_to_ex(addref.seq[k[l]]);
915         }
916         distrseq.push_back((new mul(term))->setflag(status_flags::dynallocated |
917                                                     status_flags::expanded));
918
919         // increment k[]
920         l=number_of_adds-1;
921         while ((l>=0)&&((++k[l])>=number_of_add_operands[l])) {
922             k[l]=0;    
923             l--;
924         }
925         if (l<0) break;
926     }
927
928     return (new add(distrseq))->setflag(status_flags::dynallocated |
929                                         status_flags::expanded);
930 }
931 */
932
933 //////////
934 // new virtual functions which can be overridden by derived classes
935 //////////
936
937 // none
938
939 //////////
940 // non-virtual functions in this class
941 //////////
942
943 epvector * mul::expandchildren(unsigned options) const
944 {
945     epvector::const_iterator last=seq.end();
946     epvector::const_iterator cit=seq.begin();
947     while (cit!=last) {
948         ex const & factor=recombine_pair_to_ex(*cit);
949         ex const & expanded_factor=factor.expand(options);
950         if (!are_ex_trivially_equal(factor,expanded_factor)) {
951
952             // something changed, copy seq, eval and return it
953             epvector *s=new epvector;
954             s->reserve(seq.size());
955
956             // copy parts of seq which are known not to have changed
957             epvector::const_iterator cit2=seq.begin();
958             while (cit2!=cit) {
959                 s->push_back(*cit2);
960                 ++cit2;
961             }
962             // copy first changed element
963             s->push_back(split_ex_to_pair(expanded_factor));
964             ++cit2;
965             // copy rest
966             while (cit2!=last) {
967                 s->push_back(split_ex_to_pair(recombine_pair_to_ex(*cit2).expand(options)));
968                 ++cit2;
969             }
970             return s;
971         }
972         ++cit;
973     }
974     
975     return 0; // nothing has changed
976 }
977    
978 //////////
979 // static member variables
980 //////////
981
982 // protected
983
984 unsigned mul::precedence=50;
985
986
987 //////////
988 // global constants
989 //////////
990
991 const mul some_mul;
992 type_info const & typeid_mul=typeid(some_mul);
993
994