]> www.ginac.de Git - ginac.git/blob - ginac/mul.cpp
- Banned exZERO(), exONE(), exMINUSHALF() and all this from the interface.
[ginac.git] / ginac / mul.cpp
1 /** @file mul.cpp
2  *
3  *  Implementation of GiNaC's products of expressions. */
4
5 /*
6  *  GiNaC Copyright (C) 1999 Johannes Gutenberg University Mainz, Germany
7  *
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.
12  *
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.
17  *
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
21  */
22
23 #include <vector>
24 #include <stdexcept>
25
26 #include "mul.h"
27 #include "add.h"
28 #include "power.h"
29 #include "debugmsg.h"
30 #include "utils.h"
31
32 #ifndef NO_GINAC_NAMESPACE
33 namespace GiNaC {
34 #endif // ndef NO_GINAC_NAMESPACE
35
36 //////////
37 // default constructor, destructor, copy constructor assignment operator and helpers
38 //////////
39
40 // public
41
42 mul::mul()
43 {
44     debugmsg("mul default constructor",LOGLEVEL_CONSTRUCT);
45     tinfo_key = TINFO_mul;
46 }
47
48 mul::~mul()
49 {
50     debugmsg("mul destructor",LOGLEVEL_DESTRUCT);
51     destroy(0);
52 }
53
54 mul::mul(mul const & other)
55 {
56     debugmsg("mul copy constructor",LOGLEVEL_CONSTRUCT);
57     copy(other);
58 }
59
60 mul const & mul::operator=(mul const & other)
61 {
62     debugmsg("mul operator=",LOGLEVEL_ASSIGNMENT);
63     if (this != &other) {
64         destroy(1);
65         copy(other);
66     }
67     return *this;
68 }
69
70 // protected
71
72 void mul::copy(mul const & other)
73 {
74     expairseq::copy(other);
75 }
76
77 void mul::destroy(bool call_parent)
78 {
79     if (call_parent) expairseq::destroy(call_parent);
80 }
81
82 //////////
83 // other constructors
84 //////////
85
86 // public
87
88 mul::mul(ex const & lh, ex const & rh)
89 {
90     debugmsg("mul constructor from ex,ex",LOGLEVEL_CONSTRUCT);
91     tinfo_key = TINFO_mul;
92     overall_coeff=_ex1();
93     construct_from_2_ex(lh,rh);
94     GINAC_ASSERT(is_canonical());
95 }
96
97 mul::mul(exvector const & v)
98 {
99     debugmsg("mul constructor from exvector",LOGLEVEL_CONSTRUCT);
100     tinfo_key = TINFO_mul;
101     overall_coeff=_ex1();
102     construct_from_exvector(v);
103     GINAC_ASSERT(is_canonical());
104 }
105
106 /*
107 mul::mul(epvector const & v, bool do_not_canonicalize)
108 {
109     debugmsg("mul constructor from epvector,bool",LOGLEVEL_CONSTRUCT);
110     tinfo_key = TINFO_mul;
111     if (do_not_canonicalize) {
112         seq=v;
113 #ifdef EXPAIRSEQ_USE_HASHTAB
114         combine_same_terms(); // to build hashtab
115 #endif // def EXPAIRSEQ_USE_HASHTAB
116     } else {
117         construct_from_epvector(v);
118     }
119     GINAC_ASSERT(is_canonical());
120 }
121 */
122
123 mul::mul(epvector const & v)
124 {
125     debugmsg("mul constructor from epvector",LOGLEVEL_CONSTRUCT);
126     tinfo_key = TINFO_mul;
127     overall_coeff=_ex1();
128     construct_from_epvector(v);
129     GINAC_ASSERT(is_canonical());
130 }
131
132 mul::mul(epvector const & v, ex const & oc)
133 {
134     debugmsg("mul constructor from epvector,ex",LOGLEVEL_CONSTRUCT);
135     tinfo_key = TINFO_mul;
136     overall_coeff=oc;
137     construct_from_epvector(v);
138     GINAC_ASSERT(is_canonical());
139 }
140
141 mul::mul(epvector * vp, ex const & oc)
142 {
143     debugmsg("mul constructor from epvector *,ex",LOGLEVEL_CONSTRUCT);
144     tinfo_key = TINFO_mul;
145     GINAC_ASSERT(vp!=0);
146     overall_coeff=oc;
147     construct_from_epvector(*vp);
148     delete vp;
149     GINAC_ASSERT(is_canonical());
150 }
151
152 mul::mul(ex const & lh, ex const & mh, ex const & rh)
153 {
154     debugmsg("mul constructor from ex,ex,ex",LOGLEVEL_CONSTRUCT);
155     tinfo_key = TINFO_mul;
156     exvector factors;
157     factors.reserve(3);
158     factors.push_back(lh);
159     factors.push_back(mh);
160     factors.push_back(rh);
161     overall_coeff=_ex1();
162     construct_from_exvector(factors);
163     GINAC_ASSERT(is_canonical());
164 }
165
166 //////////
167 // functions overriding virtual functions from bases classes
168 //////////
169
170 // public
171
172 basic * mul::duplicate() const
173 {
174     debugmsg("mul duplicate",LOGLEVEL_ASSIGNMENT);
175     return new mul(*this);
176 }
177
178 void mul::print(ostream & os, unsigned upper_precedence) const
179 {
180     debugmsg("mul print",LOGLEVEL_PRINT);
181     if (precedence<=upper_precedence) os << "(";
182     bool first=true;
183     // first print the overall numeric coefficient:
184     if (ex_to_numeric(overall_coeff).csgn()==-1) os << '-';
185     if (!overall_coeff.is_equal(_ex1()) &&
186         !overall_coeff.is_equal(_ex_1())) {
187         if (ex_to_numeric(overall_coeff).csgn()==-1)
188             (_num_1()*overall_coeff).print(os, precedence);
189         else
190             overall_coeff.print(os, precedence);
191         os << '*';
192     }
193     // then proceed with the remaining factors:
194     for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
195         if (!first) {
196             os << '*';
197         } else {
198             first=false;
199         }
200         recombine_pair_to_ex(*cit).print(os,precedence);
201     }
202     if (precedence<=upper_precedence) os << ")";
203 }
204
205 void mul::printraw(ostream & os) const
206 {
207     debugmsg("mul printraw",LOGLEVEL_PRINT);
208
209     os << "*(";
210     for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
211         os << "(";
212         (*it).rest.bp->printraw(os);
213         os << ",";
214         (*it).coeff.bp->printraw(os);
215         os << "),";
216     }
217     os << ",hash=" << hashvalue << ",flags=" << flags;
218     os << ")";
219 }
220
221 void mul::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
222 {
223     debugmsg("mul print csrc", LOGLEVEL_PRINT);
224     if (precedence <= upper_precedence)
225         os << "(";
226
227     if (!overall_coeff.is_equal(_ex1())) {
228         overall_coeff.bp->printcsrc(os,type,precedence);
229         os << "*";
230     }
231     
232     // Print arguments, separated by "*" or "/"
233     epvector::const_iterator it = seq.begin();
234     epvector::const_iterator itend = seq.end();
235     while (it != itend) {
236
237         // If the first argument is a negative integer power, it gets printed as "1.0/<expr>"
238         if (it == seq.begin() && ex_to_numeric(it->coeff).is_integer() && it->coeff.compare(_num0()) < 0) {
239             if (type == csrc_types::ctype_cl_N)
240                 os << "recip(";
241             else
242                 os << "1.0/";
243         }
244
245         // If the exponent is 1 or -1, it is left out
246         if (it->coeff.compare(_ex1()) == 0 || it->coeff.compare(_num_1()) == 0)
247             it->rest.bp->printcsrc(os, type, precedence);
248         else
249             // outer parens around ex needed for broken gcc-2.95 parser:
250             (ex(power(it->rest, abs(ex_to_numeric(it->coeff))))).bp->printcsrc(os, type, upper_precedence);
251
252         // Separator is "/" for negative integer powers, "*" otherwise
253         it++;
254         if (it != itend) {
255             if (ex_to_numeric(it->coeff).is_integer() && it->coeff.compare(_num0()) < 0)
256                 os << "/";
257             else
258                 os << "*";
259         }
260     }
261     if (precedence <= upper_precedence)
262         os << ")";
263 }
264
265 bool mul::info(unsigned inf) const
266 {
267     // TODO: optimize
268     if (inf==info_flags::polynomial ||
269         inf==info_flags::integer_polynomial ||
270         inf==info_flags::cinteger_polynomial ||
271         inf==info_flags::rational_polynomial ||
272         inf==info_flags::crational_polynomial ||
273         inf==info_flags::rational_function) {
274         for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
275             if (!(recombine_pair_to_ex(*it).info(inf)))
276                 return false;
277         }
278         return overall_coeff.info(inf);
279     } else {
280         return expairseq::info(inf);
281     }
282 }
283
284 typedef vector<int> intvector;
285
286 int mul::degree(symbol const & s) const
287 {
288     int deg_sum=0;
289     for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
290         deg_sum+=(*cit).rest.degree(s) * ex_to_numeric((*cit).coeff).to_int();
291     }
292     return deg_sum;
293 }
294
295 int mul::ldegree(symbol const & s) const
296 {
297     int deg_sum=0;
298     for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
299         deg_sum+=(*cit).rest.ldegree(s) * ex_to_numeric((*cit).coeff).to_int();
300     }
301     return deg_sum;
302 }
303
304 ex mul::coeff(symbol const & s, int const n) const
305 {
306     exvector coeffseq;
307     coeffseq.reserve(seq.size()+1);
308     
309     if (n==0) {
310         // product of individual coeffs
311         // if a non-zero power of s is found, the resulting product will be 0
312         epvector::const_iterator it=seq.begin();
313         while (it!=seq.end()) {
314             coeffseq.push_back(recombine_pair_to_ex(*it).coeff(s,n));
315             ++it;
316         }
317         coeffseq.push_back(overall_coeff);
318         return (new mul(coeffseq))->setflag(status_flags::dynallocated);
319     }
320          
321     epvector::const_iterator it=seq.begin();
322     bool coeff_found=0;
323     while (it!=seq.end()) {
324         ex t=recombine_pair_to_ex(*it);
325         ex c=t.coeff(s,n);
326         if (!c.is_zero()) {
327             coeffseq.push_back(c);
328             coeff_found=1;
329         } else {
330             coeffseq.push_back(t);
331         }
332         ++it;
333     }
334     if (coeff_found) {
335         coeffseq.push_back(overall_coeff);
336         return (new mul(coeffseq))->setflag(status_flags::dynallocated);
337     }
338     
339     return _ex0();
340 }
341
342 ex mul::eval(int level) const
343 {
344     // simplifications  *(...,x;0) -> 0
345     //                  *(+(x,y,...);c) -> *(+(*(x,c),*(y,c),...)) (c numeric())
346     //                  *(x;1) -> x
347     //                  *(;c) -> c
348
349     debugmsg("mul eval",LOGLEVEL_MEMBER_FUNCTION);
350
351     epvector * evaled_seqp=evalchildren(level);
352     if (evaled_seqp!=0) {
353         // do more evaluation later
354         return (new mul(evaled_seqp,overall_coeff))->
355                    setflag(status_flags::dynallocated);
356     }
357
358 #ifdef DO_GINAC_ASSERT
359     for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
360         GINAC_ASSERT((!is_ex_exactly_of_type((*cit).rest,mul))||
361                (!(ex_to_numeric((*cit).coeff).is_integer())));
362         GINAC_ASSERT(!((*cit).is_numeric_with_coeff_1()));
363         if (is_ex_exactly_of_type(recombine_pair_to_ex(*cit),numeric)) {
364             printtree(cerr,0);
365         }
366         GINAC_ASSERT(!is_ex_exactly_of_type(recombine_pair_to_ex(*cit),numeric));
367         /* for paranoia */
368         expair p=split_ex_to_pair(recombine_pair_to_ex(*cit));
369         GINAC_ASSERT(p.rest.is_equal((*cit).rest));
370         GINAC_ASSERT(p.coeff.is_equal((*cit).coeff));
371         /* end paranoia */
372     }
373 #endif // def DO_GINAC_ASSERT
374
375     if (flags & status_flags::evaluated) {
376         GINAC_ASSERT(seq.size()>0);
377         GINAC_ASSERT((seq.size()>1)||!overall_coeff.is_equal(_ex1()));
378         return *this;
379     }
380
381     int seq_size=seq.size();
382     if (overall_coeff.is_equal(_ex0())) {
383         // *(...,x;0) -> 0
384         return _ex0();
385     } else if (seq_size==0) {
386         // *(;c) -> c
387         return overall_coeff;
388     } else if ((seq_size==1)&&overall_coeff.is_equal(_ex1())) {
389         // *(x;1) -> x
390         return recombine_pair_to_ex(*(seq.begin()));
391     } else if ((seq_size==1) &&
392                is_ex_exactly_of_type((*seq.begin()).rest,add) &&
393                ex_to_numeric((*seq.begin()).coeff).is_equal(_num1())) {
394         // *(+(x,y,...);c) -> +(*(x,c),*(y,c),...) (c numeric(), no powers of +())
395         add const & addref=ex_to_add((*seq.begin()).rest);
396         epvector distrseq;
397         distrseq.reserve(addref.seq.size());
398         for (epvector::const_iterator cit=addref.seq.begin(); cit!=addref.seq.end(); ++cit) {
399             distrseq.push_back(addref.combine_pair_with_coeff_to_pair(*cit,
400                                    overall_coeff));
401         }
402         return (new add(distrseq,
403                         ex_to_numeric(addref.overall_coeff).
404                         mul_dyn(ex_to_numeric(overall_coeff))))
405             ->setflag(status_flags::dynallocated  |
406                       status_flags::evaluated );
407     }
408     return this->hold();
409 }
410
411 exvector mul::get_indices(void) const
412 {
413     // return union of indices of factors
414     exvector iv;
415     for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
416         exvector subiv=(*cit).rest.get_indices();
417         iv.reserve(iv.size()+subiv.size());
418         for (exvector::const_iterator cit2=subiv.begin(); cit2!=subiv.end(); ++cit2) {
419             iv.push_back(*cit2);
420         }
421     }
422     return iv;
423 }
424
425 ex mul::simplify_ncmul(exvector const & v) const
426 {
427     throw(std::logic_error("mul::simplify_ncmul() should never have been called!"));
428 }
429
430 // protected
431
432 int mul::compare_same_type(basic const & other) const
433 {
434     return expairseq::compare_same_type(other);
435 }
436
437 bool mul::is_equal_same_type(basic const & other) const
438 {
439     return expairseq::is_equal_same_type(other);
440 }
441
442 unsigned mul::return_type(void) const
443 {
444     if (seq.size()==0) {
445         // mul without factors: should not happen, but commutes
446         return return_types::commutative;
447     }
448
449     bool all_commutative=1;
450     unsigned rt;
451     epvector::const_iterator cit_noncommutative_element; // point to first found nc element
452
453     for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
454         rt=(*cit).rest.return_type();
455         if (rt==return_types::noncommutative_composite) return rt; // one ncc -> mul also ncc
456         if ((rt==return_types::noncommutative)&&(all_commutative)) {
457             // first nc element found, remember position
458             cit_noncommutative_element=cit;
459             all_commutative=0;
460         }
461         if ((rt==return_types::noncommutative)&&(!all_commutative)) {
462             // another nc element found, compare type_infos
463             if ((*cit_noncommutative_element).rest.return_type_tinfo()!=(*cit).rest.return_type_tinfo()) {
464                 // diffent types -> mul is ncc
465                 return return_types::noncommutative_composite;
466             }
467         }
468     }
469     // all factors checked
470     return all_commutative ? return_types::commutative : return_types::noncommutative;
471 }
472    
473 unsigned mul::return_type_tinfo(void) const
474 {
475     if (seq.size()==0) {
476         // mul without factors: should not happen
477         return tinfo_key;
478     }
479     // return type_info of first noncommutative element
480     for (epvector::const_iterator cit=seq.begin(); cit!=seq.end(); ++cit) {
481         if ((*cit).rest.return_type()==return_types::noncommutative) {
482             return (*cit).rest.return_type_tinfo();
483         }
484     }
485     // no noncommutative element found, should not happen
486     return tinfo_key;
487 }
488
489 ex mul::thisexpairseq(epvector const & v, ex const & oc) const
490 {
491     return (new mul(v,oc))->setflag(status_flags::dynallocated);
492 }
493
494 ex mul::thisexpairseq(epvector * vp, ex const & oc) const
495 {
496     return (new mul(vp,oc))->setflag(status_flags::dynallocated);
497 }
498
499 expair mul::split_ex_to_pair(ex const & e) const
500 {
501     if (is_ex_exactly_of_type(e,power)) {
502         power const & powerref=ex_to_power(e);
503         if (is_ex_exactly_of_type(powerref.exponent,numeric)) {
504             return expair(powerref.basis,powerref.exponent);
505         }
506     }
507     return expair(e,_ex1());
508 }
509     
510 expair mul::combine_ex_with_coeff_to_pair(ex const & e,
511                                           ex const & c) const
512 {
513     // to avoid duplication of power simplification rules,
514     // we create a temporary power object
515     // otherwise it would be hard to correctly simplify
516     // expression like (4^(1/3))^(3/2)
517     if (are_ex_trivially_equal(c,_ex1())) {
518         return split_ex_to_pair(e);
519     }
520     return split_ex_to_pair(power(e,c));
521 }
522     
523 expair mul::combine_pair_with_coeff_to_pair(expair const & p,
524                                             ex const & c) const
525 {
526     // to avoid duplication of power simplification rules,
527     // we create a temporary power object
528     // otherwise it would be hard to correctly simplify
529     // expression like (4^(1/3))^(3/2)
530     if (are_ex_trivially_equal(c,_ex1())) {
531         return p;
532     }
533     return split_ex_to_pair(power(recombine_pair_to_ex(p),c));
534 }
535     
536 ex mul::recombine_pair_to_ex(expair const & p) const
537 {
538     // if (p.coeff.compare(_ex1())==0) {
539     // if (are_ex_trivially_equal(p.coeff,_ex1())) {
540     if (ex_to_numeric(p.coeff).is_equal(_num1())) {
541         return p.rest;
542     } else {
543         return power(p.rest,p.coeff);
544     }
545 }
546
547 bool mul::expair_needs_further_processing(epp it)
548 {
549     if (is_ex_exactly_of_type((*it).rest,mul) &&
550         ex_to_numeric((*it).coeff).is_integer()) {
551         // combined pair is product with integer power -> expand it
552         *it=split_ex_to_pair(recombine_pair_to_ex(*it));
553         return true;
554     }
555     if (is_ex_exactly_of_type((*it).rest,numeric)) {
556         expair ep=split_ex_to_pair(recombine_pair_to_ex(*it));
557         if (!ep.is_equal(*it)) {
558             // combined pair is a numeric power which can be simplified
559             *it=ep;
560             return true;
561         }
562         if (ex_to_numeric((*it).coeff).is_equal(_num1())) {
563             // combined pair has coeff 1 and must be moved to the end
564             return true;
565         }
566     }
567     return false;
568 }       
569
570 ex mul::default_overall_coeff(void) const
571 {
572     return _ex1();
573 }
574
575 void mul::combine_overall_coeff(ex const & c)
576 {
577     GINAC_ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
578     GINAC_ASSERT(is_ex_exactly_of_type(c,numeric));
579     overall_coeff = ex_to_numeric(overall_coeff).mul_dyn(ex_to_numeric(c));
580 }
581
582 void mul::combine_overall_coeff(ex const & c1, ex const & c2)
583 {
584     GINAC_ASSERT(is_ex_exactly_of_type(overall_coeff,numeric));
585     GINAC_ASSERT(is_ex_exactly_of_type(c1,numeric));
586     GINAC_ASSERT(is_ex_exactly_of_type(c2,numeric));
587     overall_coeff = ex_to_numeric(overall_coeff).
588                         mul_dyn(ex_to_numeric(c1).power(ex_to_numeric(c2)));
589 }
590
591 bool mul::can_make_flat(expair const & p) const
592 {
593     GINAC_ASSERT(is_ex_exactly_of_type(p.coeff,numeric));
594     // this assertion will probably fail somewhere
595     // it would require a more careful make_flat, obeying the power laws
596     // probably should return true only if p.coeff is integer
597     return ex_to_numeric(p.coeff).is_equal(_num1());
598 }
599
600 ex mul::expand(unsigned options) const
601 {
602     exvector sub_expanded_seq;
603     intvector positions_of_adds;
604     intvector number_of_add_operands;
605
606     epvector * expanded_seqp=expandchildren(options);
607
608     epvector const & expanded_seq = expanded_seqp==0 ? seq : *expanded_seqp;
609
610     positions_of_adds.resize(expanded_seq.size());
611     number_of_add_operands.resize(expanded_seq.size());
612
613     int number_of_adds=0;
614     int number_of_expanded_terms=1;
615
616     unsigned current_position=0;
617     epvector::const_iterator last=expanded_seq.end();
618     for (epvector::const_iterator cit=expanded_seq.begin(); cit!=last; ++cit) {
619         if (is_ex_exactly_of_type((*cit).rest,add)&&
620             (ex_to_numeric((*cit).coeff).is_equal(_num1()))) {
621             positions_of_adds[number_of_adds]=current_position;
622             add const & expanded_addref=ex_to_add((*cit).rest);
623             int addref_nops=expanded_addref.nops();
624             number_of_add_operands[number_of_adds]=addref_nops;
625             number_of_expanded_terms *= addref_nops;
626             number_of_adds++;
627         }
628         current_position++;
629     }
630
631     if (number_of_adds==0) {
632         if (expanded_seqp==0) {
633             return this->setflag(status_flags::expanded);
634         }
635         return (new mul(expanded_seqp,overall_coeff))->
636                      setflag(status_flags::dynallocated ||
637                              status_flags::expanded);
638     }
639
640     exvector distrseq;
641     distrseq.reserve(number_of_expanded_terms);
642
643     intvector k;
644     k.resize(number_of_adds);
645     
646     int l;
647     for (l=0; l<number_of_adds; l++) {
648         k[l]=0;
649     }
650
651     while (1) {
652         epvector term;
653         term=expanded_seq;
654         for (l=0; l<number_of_adds; l++) {
655             add const & addref=ex_to_add(expanded_seq[positions_of_adds[l]].rest);
656             GINAC_ASSERT(term[positions_of_adds[l]].coeff.compare(_ex1())==0);
657             term[positions_of_adds[l]]=split_ex_to_pair(addref.op(k[l]));
658         }
659         /*
660         cout << "mul::expand() term begin" << endl;
661         for (epvector::const_iterator cit=term.begin(); cit!=term.end(); ++cit) {
662             cout << "rest" << endl;
663             (*cit).rest.printtree(cout);
664             cout << "coeff" << endl;
665             (*cit).coeff.printtree(cout);
666         }
667         cout << "mul::expand() term end" << endl;
668         */
669         distrseq.push_back((new mul(term,overall_coeff))->
670                                 setflag(status_flags::dynallocated |
671                                         status_flags::expanded));
672
673         // increment k[]
674         l=number_of_adds-1;
675         while ((l>=0)&&((++k[l])>=number_of_add_operands[l])) {
676             k[l]=0;    
677             l--;
678         }
679         if (l<0) break;
680     }
681
682     if (expanded_seqp!=0) {
683         delete expanded_seqp;
684     }
685     /*
686     cout << "mul::expand() distrseq begin" << endl;
687     for (exvector::const_iterator cit=distrseq.begin(); cit!=distrseq.end(); ++cit) {
688         (*cit).printtree(cout);
689     }
690     cout << "mul::expand() distrseq end" << endl;
691     */
692
693     return (new add(distrseq))->setflag(status_flags::dynallocated |
694                                         status_flags::expanded);
695 }
696
697 //////////
698 // new virtual functions which can be overridden by derived classes
699 //////////
700
701 // none
702
703 //////////
704 // non-virtual functions in this class
705 //////////
706
707 epvector * mul::expandchildren(unsigned options) const
708 {
709     epvector::const_iterator last=seq.end();
710     epvector::const_iterator cit=seq.begin();
711     while (cit!=last) {
712         ex const & factor=recombine_pair_to_ex(*cit);
713         ex const & expanded_factor=factor.expand(options);
714         if (!are_ex_trivially_equal(factor,expanded_factor)) {
715
716             // something changed, copy seq, eval and return it
717             epvector *s=new epvector;
718             s->reserve(seq.size());
719
720             // copy parts of seq which are known not to have changed
721             epvector::const_iterator cit2=seq.begin();
722             while (cit2!=cit) {
723                 s->push_back(*cit2);
724                 ++cit2;
725             }
726             // copy first changed element
727             s->push_back(split_ex_to_pair(expanded_factor));
728             ++cit2;
729             // copy rest
730             while (cit2!=last) {
731                 s->push_back(split_ex_to_pair(recombine_pair_to_ex(*cit2).expand(options)));
732                 ++cit2;
733             }
734             return s;
735         }
736         ++cit;
737     }
738     
739     return 0; // nothing has changed
740 }
741    
742 //////////
743 // static member variables
744 //////////
745
746 // protected
747
748 unsigned mul::precedence=50;
749
750
751 //////////
752 // global constants
753 //////////
754
755 const mul some_mul;
756 type_info const & typeid_mul=typeid(some_mul);
757
758 #ifndef NO_GINAC_NAMESPACE
759 } // namespace GiNaC
760 #endif // ndef NO_GINAC_NAMESPACE