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