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