GiNaC  1.6.2
mul.cpp
Go to the documentation of this file.
00001 
00005 /*
00006  *  GiNaC Copyright (C) 1999-2011 Johannes Gutenberg University Mainz, Germany
00007  *
00008  *  This program is free software; you can redistribute it and/or modify
00009  *  it under the terms of the GNU General Public License as published by
00010  *  the Free Software Foundation; either version 2 of the License, or
00011  *  (at your option) any later version.
00012  *
00013  *  This program is distributed in the hope that it will be useful,
00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *  GNU General Public License for more details.
00017  *
00018  *  You should have received a copy of the GNU General Public License
00019  *  along with this program; if not, write to the Free Software
00020  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00021  */
00022 
00023 #include "mul.h"
00024 #include "add.h"
00025 #include "power.h"
00026 #include "operators.h"
00027 #include "matrix.h"
00028 #include "indexed.h"
00029 #include "lst.h"
00030 #include "archive.h"
00031 #include "utils.h"
00032 #include "symbol.h"
00033 #include "compiler.h"
00034 
00035 #include <iostream>
00036 #include <limits>
00037 #include <stdexcept>
00038 #include <vector>
00039 
00040 namespace GiNaC {
00041 
00042 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(mul, expairseq,
00043   print_func<print_context>(&mul::do_print).
00044   print_func<print_latex>(&mul::do_print_latex).
00045   print_func<print_csrc>(&mul::do_print_csrc).
00046   print_func<print_tree>(&mul::do_print_tree).
00047   print_func<print_python_repr>(&mul::do_print_python_repr))
00048 
00049 
00050 
00051 // default constructor
00053 
00054 mul::mul()
00055 {
00056 }
00057 
00059 // other constructors
00061 
00062 // public
00063 
00064 mul::mul(const ex & lh, const ex & rh)
00065 {
00066     overall_coeff = _ex1;
00067     construct_from_2_ex(lh,rh);
00068     GINAC_ASSERT(is_canonical());
00069 }
00070 
00071 mul::mul(const exvector & v)
00072 {
00073     overall_coeff = _ex1;
00074     construct_from_exvector(v);
00075     GINAC_ASSERT(is_canonical());
00076 }
00077 
00078 mul::mul(const epvector & v)
00079 {
00080     overall_coeff = _ex1;
00081     construct_from_epvector(v);
00082     GINAC_ASSERT(is_canonical());
00083 }
00084 
00085 mul::mul(const epvector & v, const ex & oc, bool do_index_renaming)
00086 {
00087     overall_coeff = oc;
00088     construct_from_epvector(v, do_index_renaming);
00089     GINAC_ASSERT(is_canonical());
00090 }
00091 
00092 mul::mul(std::auto_ptr<epvector> vp, const ex & oc, bool do_index_renaming)
00093 {
00094     GINAC_ASSERT(vp.get()!=0);
00095     overall_coeff = oc;
00096     construct_from_epvector(*vp, do_index_renaming);
00097     GINAC_ASSERT(is_canonical());
00098 }
00099 
00100 mul::mul(const ex & lh, const ex & mh, const ex & rh)
00101 {
00102     exvector factors;
00103     factors.reserve(3);
00104     factors.push_back(lh);
00105     factors.push_back(mh);
00106     factors.push_back(rh);
00107     overall_coeff = _ex1;
00108     construct_from_exvector(factors);
00109     GINAC_ASSERT(is_canonical());
00110 }
00111 
00113 // archiving
00115 
00117 // functions overriding virtual functions from base classes
00119 
00120 void mul::print_overall_coeff(const print_context & c, const char *mul_sym) const
00121 {
00122     const numeric &coeff = ex_to<numeric>(overall_coeff);
00123     if (coeff.csgn() == -1)
00124         c.s << '-';
00125     if (!coeff.is_equal(*_num1_p) &&
00126         !coeff.is_equal(*_num_1_p)) {
00127         if (coeff.is_rational()) {
00128             if (coeff.is_negative())
00129                 (-coeff).print(c);
00130             else
00131                 coeff.print(c);
00132         } else {
00133             if (coeff.csgn() == -1)
00134                 (-coeff).print(c, precedence());
00135             else
00136                 coeff.print(c, precedence());
00137         }
00138         c.s << mul_sym;
00139     }
00140 }
00141 
00142 void mul::do_print(const print_context & c, unsigned level) const
00143 {
00144     if (precedence() <= level)
00145         c.s << '(';
00146 
00147     print_overall_coeff(c, "*");
00148 
00149     epvector::const_iterator it = seq.begin(), itend = seq.end();
00150     bool first = true;
00151     while (it != itend) {
00152         if (!first)
00153             c.s << '*';
00154         else
00155             first = false;
00156         recombine_pair_to_ex(*it).print(c, precedence());
00157         ++it;
00158     }
00159 
00160     if (precedence() <= level)
00161         c.s << ')';
00162 }
00163 
00164 void mul::do_print_latex(const print_latex & c, unsigned level) const
00165 {
00166     if (precedence() <= level)
00167         c.s << "{(";
00168 
00169     print_overall_coeff(c, " ");
00170 
00171     // Separate factors into those with negative numeric exponent
00172     // and all others
00173     epvector::const_iterator it = seq.begin(), itend = seq.end();
00174     exvector neg_powers, others;
00175     while (it != itend) {
00176         GINAC_ASSERT(is_exactly_a<numeric>(it->coeff));
00177         if (ex_to<numeric>(it->coeff).is_negative())
00178             neg_powers.push_back(recombine_pair_to_ex(expair(it->rest, -(it->coeff))));
00179         else
00180             others.push_back(recombine_pair_to_ex(*it));
00181         ++it;
00182     }
00183 
00184     if (!neg_powers.empty()) {
00185 
00186         // Factors with negative exponent are printed as a fraction
00187         c.s << "\\frac{";
00188         mul(others).eval().print(c);
00189         c.s << "}{";
00190         mul(neg_powers).eval().print(c);
00191         c.s << "}";
00192 
00193     } else {
00194 
00195         // All other factors are printed in the ordinary way
00196         exvector::const_iterator vit = others.begin(), vitend = others.end();
00197         while (vit != vitend) {
00198             c.s << ' ';
00199             vit->print(c, precedence());
00200             ++vit;
00201         }
00202     }
00203 
00204     if (precedence() <= level)
00205         c.s << ")}";
00206 }
00207 
00208 void mul::do_print_csrc(const print_csrc & c, unsigned level) const
00209 {
00210     if (precedence() <= level)
00211         c.s << "(";
00212 
00213     if (!overall_coeff.is_equal(_ex1)) {
00214         if (overall_coeff.is_equal(_ex_1))
00215             c.s << "-";
00216         else {
00217             overall_coeff.print(c, precedence());
00218             c.s << "*";
00219         }
00220     }
00221 
00222     // Print arguments, separated by "*" or "/"
00223     epvector::const_iterator it = seq.begin(), itend = seq.end();
00224     while (it != itend) {
00225 
00226         // If the first argument is a negative integer power, it gets printed as "1.0/<expr>"
00227         bool needclosingparenthesis = false;
00228         if (it == seq.begin() && it->coeff.info(info_flags::negint)) {
00229             if (is_a<print_csrc_cl_N>(c)) {
00230                 c.s << "recip(";
00231                 needclosingparenthesis = true;
00232             } else
00233                 c.s << "1.0/";
00234         }
00235 
00236         // If the exponent is 1 or -1, it is left out
00237         if (it->coeff.is_equal(_ex1) || it->coeff.is_equal(_ex_1))
00238             it->rest.print(c, precedence());
00239         else if (it->coeff.info(info_flags::negint))
00240             // Outer parens around ex needed for broken GCC parser:
00241             (ex(power(it->rest, -ex_to<numeric>(it->coeff)))).print(c, level);
00242         else
00243             // Outer parens around ex needed for broken GCC parser:
00244             (ex(power(it->rest, ex_to<numeric>(it->coeff)))).print(c, level);
00245 
00246         if (needclosingparenthesis)
00247             c.s << ")";
00248 
00249         // Separator is "/" for negative integer powers, "*" otherwise
00250         ++it;
00251         if (it != itend) {
00252             if (it->coeff.info(info_flags::negint))
00253                 c.s << "/";
00254             else
00255                 c.s << "*";
00256         }
00257     }
00258 
00259     if (precedence() <= level)
00260         c.s << ")";
00261 }
00262 
00263 void mul::do_print_python_repr(const print_python_repr & c, unsigned level) const
00264 {
00265     c.s << class_name() << '(';
00266     op(0).print(c);
00267     for (size_t i=1; i<nops(); ++i) {
00268         c.s << ',';
00269         op(i).print(c);
00270     }
00271     c.s << ')';
00272 }
00273 
00274 bool mul::info(unsigned inf) const
00275 {
00276     switch (inf) {
00277         case info_flags::polynomial:
00278         case info_flags::integer_polynomial:
00279         case info_flags::cinteger_polynomial:
00280         case info_flags::rational_polynomial:
00281         case info_flags::real:
00282         case info_flags::rational:
00283         case info_flags::integer:
00284         case info_flags::crational:
00285         case info_flags::cinteger:
00286         case info_flags::positive:
00287         case info_flags::nonnegative:
00288         case info_flags::posint:
00289         case info_flags::nonnegint:
00290         case info_flags::even:
00291         case info_flags::crational_polynomial:
00292         case info_flags::rational_function: {
00293             epvector::const_iterator i = seq.begin(), end = seq.end();
00294             while (i != end) {
00295                 if (!(recombine_pair_to_ex(*i).info(inf)))
00296                     return false;
00297                 ++i;
00298             }
00299             if (overall_coeff.is_equal(*_num1_p) && inf == info_flags::even)
00300                 return true;
00301             return overall_coeff.info(inf);
00302         }
00303         case info_flags::algebraic: {
00304             epvector::const_iterator i = seq.begin(), end = seq.end();
00305             while (i != end) {
00306                 if ((recombine_pair_to_ex(*i).info(inf)))
00307                     return true;
00308                 ++i;
00309             }
00310             return false;
00311         }
00312         case info_flags::negative: {
00313             bool neg = false;
00314             epvector::const_iterator i = seq.begin(), end = seq.end();
00315             while (i != end) {
00316                 const ex& factor = recombine_pair_to_ex(*i++);
00317                 if (factor.info(info_flags::positive))
00318                     continue;
00319                 else if (factor.info(info_flags::negative))
00320                     neg = !neg;
00321                 else
00322                     return false;
00323             }
00324             if (overall_coeff.info(info_flags::negative))
00325                 neg = !neg;
00326             return neg;
00327         }
00328         case info_flags::negint: {
00329             bool neg = false;
00330             epvector::const_iterator i = seq.begin(), end = seq.end();
00331             while (i != end) {
00332                 const ex& factor = recombine_pair_to_ex(*i++);
00333                 if (factor.info(info_flags::posint))
00334                     continue;
00335                 else if (factor.info(info_flags::negint))
00336                     neg = !neg;
00337                 else
00338                     return false;
00339             }
00340             if (overall_coeff.info(info_flags::negint))
00341                 neg = !neg;
00342             else if (!overall_coeff.info(info_flags::posint))
00343                 return false;
00344             return neg;
00345         }
00346     }
00347     return inherited::info(inf);
00348 }
00349 
00350 bool mul::is_polynomial(const ex & var) const
00351 {
00352     for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
00353         if (!i->rest.is_polynomial(var) ||
00354             (i->rest.has(var) && !i->coeff.info(info_flags::integer))) {
00355             return false;
00356         }
00357     }
00358     return true;
00359 }
00360 
00361 int mul::degree(const ex & s) const
00362 {
00363     // Sum up degrees of factors
00364     int deg_sum = 0;
00365     epvector::const_iterator i = seq.begin(), end = seq.end();
00366     while (i != end) {
00367         if (ex_to<numeric>(i->coeff).is_integer())
00368             deg_sum += recombine_pair_to_ex(*i).degree(s);
00369         else {
00370             if (i->rest.has(s))
00371                 throw std::runtime_error("mul::degree() undefined degree because of non-integer exponent");
00372         }
00373         ++i;
00374     }
00375     return deg_sum;
00376 }
00377 
00378 int mul::ldegree(const ex & s) const
00379 {
00380     // Sum up degrees of factors
00381     int deg_sum = 0;
00382     epvector::const_iterator i = seq.begin(), end = seq.end();
00383     while (i != end) {
00384         if (ex_to<numeric>(i->coeff).is_integer())
00385             deg_sum += recombine_pair_to_ex(*i).ldegree(s);
00386         else {
00387             if (i->rest.has(s))
00388                 throw std::runtime_error("mul::ldegree() undefined degree because of non-integer exponent");
00389         }
00390         ++i;
00391     }
00392     return deg_sum;
00393 }
00394 
00395 ex mul::coeff(const ex & s, int n) const
00396 {
00397     exvector coeffseq;
00398     coeffseq.reserve(seq.size()+1);
00399     
00400     if (n==0) {
00401         // product of individual coeffs
00402         // if a non-zero power of s is found, the resulting product will be 0
00403         epvector::const_iterator i = seq.begin(), end = seq.end();
00404         while (i != end) {
00405             coeffseq.push_back(recombine_pair_to_ex(*i).coeff(s,n));
00406             ++i;
00407         }
00408         coeffseq.push_back(overall_coeff);
00409         return (new mul(coeffseq))->setflag(status_flags::dynallocated);
00410     }
00411     
00412     epvector::const_iterator i = seq.begin(), end = seq.end();
00413     bool coeff_found = false;
00414     while (i != end) {
00415         ex t = recombine_pair_to_ex(*i);
00416         ex c = t.coeff(s, n);
00417         if (!c.is_zero()) {
00418             coeffseq.push_back(c);
00419             coeff_found = 1;
00420         } else {
00421             coeffseq.push_back(t);
00422         }
00423         ++i;
00424     }
00425     if (coeff_found) {
00426         coeffseq.push_back(overall_coeff);
00427         return (new mul(coeffseq))->setflag(status_flags::dynallocated);
00428     }
00429     
00430     return _ex0;
00431 }
00432 
00442 ex mul::eval(int level) const
00443 {
00444     std::auto_ptr<epvector> evaled_seqp = evalchildren(level);
00445     if (evaled_seqp.get()) {
00446         // do more evaluation later
00447         return (new mul(evaled_seqp, overall_coeff))->
00448                    setflag(status_flags::dynallocated);
00449     }
00450     
00451     if (flags & status_flags::evaluated) {
00452         GINAC_ASSERT(seq.size()>0);
00453         GINAC_ASSERT(seq.size()>1 || !overall_coeff.is_equal(_ex1));
00454         return *this;
00455     }
00456     
00457     size_t seq_size = seq.size();
00458     if (overall_coeff.is_zero()) {
00459         // *(...,x;0) -> 0
00460         return _ex0;
00461     } else if (seq_size==0) {
00462         // *(;c) -> c
00463         return overall_coeff;
00464     } else if (seq_size==1 && overall_coeff.is_equal(_ex1)) {
00465         // *(x;1) -> x
00466         return recombine_pair_to_ex(*(seq.begin()));
00467     } else if ((seq_size==1) &&
00468                is_exactly_a<add>((*seq.begin()).rest) &&
00469                ex_to<numeric>((*seq.begin()).coeff).is_equal(*_num1_p)) {
00470         // *(+(x,y,...);c) -> +(*(x,c),*(y,c),...) (c numeric(), no powers of +())
00471         const add & addref = ex_to<add>((*seq.begin()).rest);
00472         std::auto_ptr<epvector> distrseq(new epvector);
00473         distrseq->reserve(addref.seq.size());
00474         epvector::const_iterator i = addref.seq.begin(), end = addref.seq.end();
00475         while (i != end) {
00476             distrseq->push_back(addref.combine_pair_with_coeff_to_pair(*i, overall_coeff));
00477             ++i;
00478         }
00479         return (new add(distrseq,
00480                         ex_to<numeric>(addref.overall_coeff).
00481                         mul_dyn(ex_to<numeric>(overall_coeff)))
00482                )->setflag(status_flags::dynallocated | status_flags::evaluated);
00483     } else if ((seq_size >= 2) && (! (flags & status_flags::expanded))) {
00484         // Strip the content and the unit part from each term. Thus
00485         // things like (-x+a)*(3*x-3*a) automagically turn into - 3*(x-a)^2
00486 
00487         epvector::const_iterator last = seq.end();
00488         epvector::const_iterator i = seq.begin();
00489         epvector::const_iterator j = seq.begin();
00490         std::auto_ptr<epvector> s(new epvector);
00491         numeric oc = *_num1_p;
00492         bool something_changed = false;
00493         while (i!=last) {
00494             if (likely(! (is_a<add>(i->rest) && i->coeff.is_equal(_ex1)))) {
00495                 // power::eval has such a rule, no need to handle powers here
00496                 ++i;
00497                 continue;
00498             }
00499 
00500             // XXX: What is the best way to check if the polynomial is a primitive? 
00501             numeric c = i->rest.integer_content();
00502             const numeric lead_coeff =
00503                 ex_to<numeric>(ex_to<add>(i->rest).seq.begin()->coeff).div(c);
00504             const bool canonicalizable = lead_coeff.is_integer();
00505 
00506             // XXX: The main variable is chosen in a random way, so this code 
00507             // does NOT transform the term into the canonical form (thus, in some
00508             // very unlucky event it can even loop forever). Hopefully the main
00509             // variable will be the same for all terms in *this
00510             const bool unit_normal = lead_coeff.is_pos_integer();
00511             if (likely((c == *_num1_p) && ((! canonicalizable) || unit_normal))) {
00512                 ++i;
00513                 continue;
00514             }
00515 
00516             if (! something_changed) {
00517                 s->reserve(seq_size);
00518                 something_changed = true;
00519             }
00520 
00521             while ((j!=i) && (j!=last)) {
00522                 s->push_back(*j);
00523                 ++j;
00524             }
00525 
00526             if (! unit_normal)
00527                 c = c.mul(*_num_1_p);
00528 
00529             oc = oc.mul(c);
00530 
00531             // divide add by the number in place to save at least 2 .eval() calls
00532             const add& addref = ex_to<add>(i->rest);
00533             add* primitive = new add(addref);
00534             primitive->setflag(status_flags::dynallocated);
00535             primitive->clearflag(status_flags::hash_calculated);
00536             primitive->overall_coeff = ex_to<numeric>(primitive->overall_coeff).div_dyn(c);
00537             for (epvector::iterator ai = primitive->seq.begin(); ai != primitive->seq.end(); ++ai)
00538                 ai->coeff = ex_to<numeric>(ai->coeff).div_dyn(c);
00539             
00540             s->push_back(expair(*primitive, _ex1));
00541 
00542             ++i;
00543             ++j;
00544         }
00545         if (something_changed) {
00546             while (j!=last) {
00547                 s->push_back(*j);
00548                 ++j;
00549             }
00550             return (new mul(s, ex_to<numeric>(overall_coeff).mul_dyn(oc))
00551                    )->setflag(status_flags::dynallocated);
00552         }
00553     }
00554 
00555     return this->hold();
00556 }
00557 
00558 ex mul::evalf(int level) const
00559 {
00560     if (level==1)
00561         return mul(seq,overall_coeff);
00562     
00563     if (level==-max_recursion_level)
00564         throw(std::runtime_error("max recursion level reached"));
00565     
00566     std::auto_ptr<epvector> s(new epvector);
00567     s->reserve(seq.size());
00568 
00569     --level;
00570     epvector::const_iterator i = seq.begin(), end = seq.end();
00571     while (i != end) {
00572         s->push_back(combine_ex_with_coeff_to_pair(i->rest.evalf(level),
00573                                                    i->coeff));
00574         ++i;
00575     }
00576     return mul(s, overall_coeff.evalf(level));
00577 }
00578 
00579 void mul::find_real_imag(ex & rp, ex & ip) const
00580 {
00581     rp = overall_coeff.real_part();
00582     ip = overall_coeff.imag_part();
00583     for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
00584         ex factor = recombine_pair_to_ex(*i);
00585         ex new_rp = factor.real_part();
00586         ex new_ip = factor.imag_part();
00587         if(new_ip.is_zero()) {
00588             rp *= new_rp;
00589             ip *= new_rp;
00590         } else {
00591             ex temp = rp*new_rp - ip*new_ip;
00592             ip = ip*new_rp + rp*new_ip;
00593             rp = temp;
00594         }
00595     }
00596     rp = rp.expand();
00597     ip = ip.expand();
00598 }
00599 
00600 ex mul::real_part() const
00601 {
00602     ex rp, ip;
00603     find_real_imag(rp, ip);
00604     return rp;
00605 }
00606 
00607 ex mul::imag_part() const
00608 {
00609     ex rp, ip;
00610     find_real_imag(rp, ip);
00611     return ip;
00612 }
00613 
00614 ex mul::evalm() const
00615 {
00616     // numeric*matrix
00617     if (seq.size() == 1 && seq[0].coeff.is_equal(_ex1)
00618      && is_a<matrix>(seq[0].rest))
00619         return ex_to<matrix>(seq[0].rest).mul(ex_to<numeric>(overall_coeff));
00620 
00621     // Evaluate children first, look whether there are any matrices at all
00622     // (there can be either no matrices or one matrix; if there were more
00623     // than one matrix, it would be a non-commutative product)
00624     std::auto_ptr<epvector> s(new epvector);
00625     s->reserve(seq.size());
00626 
00627     bool have_matrix = false;
00628     epvector::iterator the_matrix;
00629 
00630     epvector::const_iterator i = seq.begin(), end = seq.end();
00631     while (i != end) {
00632         const ex &m = recombine_pair_to_ex(*i).evalm();
00633         s->push_back(split_ex_to_pair(m));
00634         if (is_a<matrix>(m)) {
00635             have_matrix = true;
00636             the_matrix = s->end() - 1;
00637         }
00638         ++i;
00639     }
00640 
00641     if (have_matrix) {
00642 
00643         // The product contained a matrix. We will multiply all other factors
00644         // into that matrix.
00645         matrix m = ex_to<matrix>(the_matrix->rest);
00646         s->erase(the_matrix);
00647         ex scalar = (new mul(s, overall_coeff))->setflag(status_flags::dynallocated);
00648         return m.mul_scalar(scalar);
00649 
00650     } else
00651         return (new mul(s, overall_coeff))->setflag(status_flags::dynallocated);
00652 }
00653 
00654 ex mul::eval_ncmul(const exvector & v) const
00655 {
00656     if (seq.empty())
00657         return inherited::eval_ncmul(v);
00658 
00659     // Find first noncommutative element and call its eval_ncmul()
00660     epvector::const_iterator i = seq.begin(), end = seq.end();
00661     while (i != end) {
00662         if (i->rest.return_type() == return_types::noncommutative)
00663             return i->rest.eval_ncmul(v);
00664         ++i;
00665     }
00666     return inherited::eval_ncmul(v);
00667 }
00668 
00669 bool tryfactsubs(const ex & origfactor, const ex & patternfactor, int & nummatches, exmap& repls)
00670 {   
00671     ex origbase;
00672     int origexponent;
00673     int origexpsign;
00674 
00675     if (is_exactly_a<power>(origfactor) && origfactor.op(1).info(info_flags::integer)) {
00676         origbase = origfactor.op(0);
00677         int expon = ex_to<numeric>(origfactor.op(1)).to_int();
00678         origexponent = expon > 0 ? expon : -expon;
00679         origexpsign = expon > 0 ? 1 : -1;
00680     } else {
00681         origbase = origfactor;
00682         origexponent = 1;
00683         origexpsign = 1;
00684     }
00685 
00686     ex patternbase;
00687     int patternexponent;
00688     int patternexpsign;
00689 
00690     if (is_exactly_a<power>(patternfactor) && patternfactor.op(1).info(info_flags::integer)) {
00691         patternbase = patternfactor.op(0);
00692         int expon = ex_to<numeric>(patternfactor.op(1)).to_int();
00693         patternexponent = expon > 0 ? expon : -expon;
00694         patternexpsign = expon > 0 ? 1 : -1;
00695     } else {
00696         patternbase = patternfactor;
00697         patternexponent = 1;
00698         patternexpsign = 1;
00699     }
00700 
00701     exmap saverepls = repls;
00702     if (origexponent < patternexponent || origexpsign != patternexpsign || !origbase.match(patternbase,saverepls))
00703         return false;
00704     repls = saverepls;
00705 
00706     int newnummatches = origexponent / patternexponent;
00707     if (newnummatches < nummatches)
00708         nummatches = newnummatches;
00709     return true;
00710 }
00711 
00720 bool algebraic_match_mul_with_mul(const mul &e, const ex &pat, exmap& repls,
00721                                   int factor, int &nummatches, const std::vector<bool> &subsed,
00722                                   std::vector<bool> &matched)
00723 {
00724     GINAC_ASSERT(subsed.size() == e.nops());
00725     GINAC_ASSERT(matched.size() == e.nops());
00726 
00727     if (factor == (int)pat.nops())
00728         return true;
00729 
00730     for (size_t i=0; i<e.nops(); ++i) {
00731         if(subsed[i] || matched[i])
00732             continue;
00733         exmap newrepls = repls;
00734         int newnummatches = nummatches;
00735         if (tryfactsubs(e.op(i), pat.op(factor), newnummatches, newrepls)) {
00736             matched[i] = true;
00737             if (algebraic_match_mul_with_mul(e, pat, newrepls, factor+1,
00738                     newnummatches, subsed, matched)) {
00739                 repls = newrepls;
00740                 nummatches = newnummatches;
00741                 return true;
00742             }
00743             else
00744                 matched[i] = false;
00745         }
00746     }
00747 
00748     return false;
00749 }
00750 
00751 bool mul::has(const ex & pattern, unsigned options) const
00752 {
00753     if(!(options&has_options::algebraic))
00754         return basic::has(pattern,options);
00755     if(is_a<mul>(pattern)) {
00756         exmap repls;
00757         int nummatches = std::numeric_limits<int>::max();
00758         std::vector<bool> subsed(nops(), false);
00759         std::vector<bool> matched(nops(), false);
00760         if(algebraic_match_mul_with_mul(*this, pattern, repls, 0, nummatches,
00761                 subsed, matched))
00762             return true;
00763     }
00764     return basic::has(pattern, options);
00765 }
00766 
00767 ex mul::algebraic_subs_mul(const exmap & m, unsigned options) const
00768 {   
00769     std::vector<bool> subsed(nops(), false);
00770     ex divide_by = 1;
00771     ex multiply_by = 1;
00772 
00773     for (exmap::const_iterator it = m.begin(); it != m.end(); ++it) {
00774 
00775         if (is_exactly_a<mul>(it->first)) {
00776 retry1:
00777             int nummatches = std::numeric_limits<int>::max();
00778             std::vector<bool> currsubsed(nops(), false);
00779             exmap repls;
00780             
00781             if(!algebraic_match_mul_with_mul(*this, it->first, repls, 0, nummatches, subsed, currsubsed))
00782                 continue;
00783 
00784             for (size_t j=0; j<subsed.size(); j++)
00785                 if (currsubsed[j])
00786                     subsed[j] = true;
00787             ex subsed_pattern
00788                 = it->first.subs(repls, subs_options::no_pattern);
00789             divide_by *= power(subsed_pattern, nummatches);
00790             ex subsed_result
00791                 = it->second.subs(repls, subs_options::no_pattern);
00792             multiply_by *= power(subsed_result, nummatches);
00793             goto retry1;
00794 
00795         } else {
00796 
00797             for (size_t j=0; j<this->nops(); j++) {
00798                 int nummatches = std::numeric_limits<int>::max();
00799                 exmap repls;
00800                 if (!subsed[j] && tryfactsubs(op(j), it->first, nummatches, repls)){
00801                     subsed[j] = true;
00802                     ex subsed_pattern
00803                         = it->first.subs(repls, subs_options::no_pattern);
00804                     divide_by *= power(subsed_pattern, nummatches);
00805                     ex subsed_result
00806                         = it->second.subs(repls, subs_options::no_pattern);
00807                     multiply_by *= power(subsed_result, nummatches);
00808                 }
00809             }
00810         }
00811     }
00812 
00813     bool subsfound = false;
00814     for (size_t i=0; i<subsed.size(); i++) {
00815         if (subsed[i]) {
00816             subsfound = true;
00817             break;
00818         }
00819     }
00820     if (!subsfound)
00821         return subs_one_level(m, options | subs_options::algebraic);
00822 
00823     return ((*this)/divide_by)*multiply_by;
00824 }
00825 
00826 ex mul::conjugate() const
00827 {
00828     // The base class' method is wrong here because we have to be careful at
00829     // branch cuts. power::conjugate takes care of that already, so use it.
00830     epvector *newepv = 0;
00831     for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
00832         if (newepv) {
00833             newepv->push_back(split_ex_to_pair(recombine_pair_to_ex(*i).conjugate()));
00834             continue;
00835         }
00836         ex x = recombine_pair_to_ex(*i);
00837         ex c = x.conjugate();
00838         if (c.is_equal(x)) {
00839             continue;
00840         }
00841         newepv = new epvector;
00842         newepv->reserve(seq.size());
00843         for (epvector::const_iterator j=seq.begin(); j!=i; ++j) {
00844             newepv->push_back(*j);
00845         }
00846         newepv->push_back(split_ex_to_pair(c));
00847     }
00848     ex x = overall_coeff.conjugate();
00849     if (!newepv && are_ex_trivially_equal(x, overall_coeff)) {
00850         return *this;
00851     }
00852     ex result = thisexpairseq(newepv ? *newepv : seq, x);
00853     delete newepv;
00854     return result;
00855 }
00856 
00857 
00858 // protected
00859 
00862 ex mul::derivative(const symbol & s) const
00863 {
00864     size_t num = seq.size();
00865     exvector addseq;
00866     addseq.reserve(num);
00867     
00868     // D(a*b*c) = D(a)*b*c + a*D(b)*c + a*b*D(c)
00869     epvector mulseq = seq;
00870     epvector::const_iterator i = seq.begin(), end = seq.end();
00871     epvector::iterator i2 = mulseq.begin();
00872     while (i != end) {
00873         expair ep = split_ex_to_pair(power(i->rest, i->coeff - _ex1) *
00874                                      i->rest.diff(s));
00875         ep.swap(*i2);
00876         addseq.push_back((new mul(mulseq, overall_coeff * i->coeff))->setflag(status_flags::dynallocated));
00877         ep.swap(*i2);
00878         ++i; ++i2;
00879     }
00880     return (new add(addseq))->setflag(status_flags::dynallocated);
00881 }
00882 
00883 int mul::compare_same_type(const basic & other) const
00884 {
00885     return inherited::compare_same_type(other);
00886 }
00887 
00888 unsigned mul::return_type() const
00889 {
00890     if (seq.empty()) {
00891         // mul without factors: should not happen, but commutates
00892         return return_types::commutative;
00893     }
00894     
00895     bool all_commutative = true;
00896     epvector::const_iterator noncommutative_element; // point to first found nc element
00897     
00898     epvector::const_iterator i = seq.begin(), end = seq.end();
00899     while (i != end) {
00900         unsigned rt = i->rest.return_type();
00901         if (rt == return_types::noncommutative_composite)
00902             return rt; // one ncc -> mul also ncc
00903         if ((rt == return_types::noncommutative) && (all_commutative)) {
00904             // first nc element found, remember position
00905             noncommutative_element = i;
00906             all_commutative = false;
00907         }
00908         if ((rt == return_types::noncommutative) && (!all_commutative)) {
00909             // another nc element found, compare type_infos
00910             if (noncommutative_element->rest.return_type_tinfo() != i->rest.return_type_tinfo()) {
00911                     // different types -> mul is ncc
00912                     return return_types::noncommutative_composite;
00913             }
00914         }
00915         ++i;
00916     }
00917     // all factors checked
00918     return all_commutative ? return_types::commutative : return_types::noncommutative;
00919 }
00920 
00921 return_type_t mul::return_type_tinfo() const
00922 {
00923     if (seq.empty())
00924         return make_return_type_t<mul>(); // mul without factors: should not happen
00925     
00926     // return type_info of first noncommutative element
00927     epvector::const_iterator i = seq.begin(), end = seq.end();
00928     while (i != end) {
00929         if (i->rest.return_type() == return_types::noncommutative)
00930             return i->rest.return_type_tinfo();
00931         ++i;
00932     }
00933     // no noncommutative element found, should not happen
00934     return make_return_type_t<mul>();
00935 }
00936 
00937 ex mul::thisexpairseq(const epvector & v, const ex & oc, bool do_index_renaming) const
00938 {
00939     return (new mul(v, oc, do_index_renaming))->setflag(status_flags::dynallocated);
00940 }
00941 
00942 ex mul::thisexpairseq(std::auto_ptr<epvector> vp, const ex & oc, bool do_index_renaming) const
00943 {
00944     return (new mul(vp, oc, do_index_renaming))->setflag(status_flags::dynallocated);
00945 }
00946 
00947 expair mul::split_ex_to_pair(const ex & e) const
00948 {
00949     if (is_exactly_a<power>(e)) {
00950         const power & powerref = ex_to<power>(e);
00951         if (is_exactly_a<numeric>(powerref.exponent))
00952             return expair(powerref.basis,powerref.exponent);
00953     }
00954     return expair(e,_ex1);
00955 }
00956 
00957 expair mul::combine_ex_with_coeff_to_pair(const ex & e,
00958                                           const ex & c) const
00959 {
00960     // to avoid duplication of power simplification rules,
00961     // we create a temporary power object
00962     // otherwise it would be hard to correctly evaluate
00963     // expression like (4^(1/3))^(3/2)
00964     if (c.is_equal(_ex1))
00965         return split_ex_to_pair(e);
00966 
00967     return split_ex_to_pair(power(e,c));
00968 }
00969 
00970 expair mul::combine_pair_with_coeff_to_pair(const expair & p,
00971                                             const ex & c) const
00972 {
00973     // to avoid duplication of power simplification rules,
00974     // we create a temporary power object
00975     // otherwise it would be hard to correctly evaluate
00976     // expression like (4^(1/3))^(3/2)
00977     if (c.is_equal(_ex1))
00978         return p;
00979 
00980     return split_ex_to_pair(power(recombine_pair_to_ex(p),c));
00981 }
00982 
00983 ex mul::recombine_pair_to_ex(const expair & p) const
00984 {
00985     if (ex_to<numeric>(p.coeff).is_equal(*_num1_p)) 
00986         return p.rest;
00987     else
00988         return (new power(p.rest,p.coeff))->setflag(status_flags::dynallocated);
00989 }
00990 
00991 bool mul::expair_needs_further_processing(epp it)
00992 {
00993     if (is_exactly_a<mul>(it->rest) &&
00994         ex_to<numeric>(it->coeff).is_integer()) {
00995         // combined pair is product with integer power -> expand it
00996         *it = split_ex_to_pair(recombine_pair_to_ex(*it));
00997         return true;
00998     }
00999     if (is_exactly_a<numeric>(it->rest)) {
01000         if (it->coeff.is_equal(_ex1)) {
01001             // pair has coeff 1 and must be moved to the end
01002             return true;
01003         }
01004         expair ep = split_ex_to_pair(recombine_pair_to_ex(*it));
01005         if (!ep.is_equal(*it)) {
01006             // combined pair is a numeric power which can be simplified
01007             *it = ep;
01008             return true;
01009         }
01010     }
01011     return false;
01012 }       
01013 
01014 ex mul::default_overall_coeff() const
01015 {
01016     return _ex1;
01017 }
01018 
01019 void mul::combine_overall_coeff(const ex & c)
01020 {
01021     GINAC_ASSERT(is_exactly_a<numeric>(overall_coeff));
01022     GINAC_ASSERT(is_exactly_a<numeric>(c));
01023     overall_coeff = ex_to<numeric>(overall_coeff).mul_dyn(ex_to<numeric>(c));
01024 }
01025 
01026 void mul::combine_overall_coeff(const ex & c1, const ex & c2)
01027 {
01028     GINAC_ASSERT(is_exactly_a<numeric>(overall_coeff));
01029     GINAC_ASSERT(is_exactly_a<numeric>(c1));
01030     GINAC_ASSERT(is_exactly_a<numeric>(c2));
01031     overall_coeff = ex_to<numeric>(overall_coeff).mul_dyn(ex_to<numeric>(c1).power(ex_to<numeric>(c2)));
01032 }
01033 
01034 bool mul::can_make_flat(const expair & p) const
01035 {
01036     GINAC_ASSERT(is_exactly_a<numeric>(p.coeff));
01037     // this assertion will probably fail somewhere
01038     // it would require a more careful make_flat, obeying the power laws
01039     // probably should return true only if p.coeff is integer
01040     return ex_to<numeric>(p.coeff).is_equal(*_num1_p);
01041 }
01042 
01043 bool mul::can_be_further_expanded(const ex & e)
01044 {
01045     if (is_exactly_a<mul>(e)) {
01046         for (epvector::const_iterator cit = ex_to<mul>(e).seq.begin(); cit != ex_to<mul>(e).seq.end(); ++cit) {
01047             if (is_exactly_a<add>(cit->rest) && cit->coeff.info(info_flags::posint))
01048                 return true;
01049         }
01050     } else if (is_exactly_a<power>(e)) {
01051         if (is_exactly_a<add>(e.op(0)) && e.op(1).info(info_flags::posint))
01052             return true;
01053     }
01054     return false;
01055 }
01056 
01057 ex mul::expand(unsigned options) const
01058 {
01059     {
01060     // trivial case: expanding the monomial (~ 30% of all calls)
01061         epvector::const_iterator i = seq.begin(), seq_end = seq.end();
01062         while ((i != seq.end()) &&  is_a<symbol>(i->rest) && i->coeff.info(info_flags::integer))
01063             ++i;
01064         if (i == seq_end) {
01065             setflag(status_flags::expanded);
01066             return *this;
01067         }
01068     }
01069 
01070     // do not rename indices if the object has no indices at all
01071     if ((!(options & expand_options::expand_rename_idx)) && 
01072             this->info(info_flags::has_indices))
01073         options |= expand_options::expand_rename_idx;
01074 
01075     const bool skip_idx_rename = !(options & expand_options::expand_rename_idx);
01076 
01077     // First, expand the children
01078     std::auto_ptr<epvector> expanded_seqp = expandchildren(options);
01079     const epvector & expanded_seq = (expanded_seqp.get() ? *expanded_seqp : seq);
01080 
01081     // Now, look for all the factors that are sums and multiply each one out
01082     // with the next one that is found while collecting the factors which are
01083     // not sums
01084     ex last_expanded = _ex1;
01085 
01086     epvector non_adds;
01087     non_adds.reserve(expanded_seq.size());
01088 
01089     for (epvector::const_iterator cit = expanded_seq.begin(); cit != expanded_seq.end(); ++cit) {
01090         if (is_exactly_a<add>(cit->rest) &&
01091             (cit->coeff.is_equal(_ex1))) {
01092             if (is_exactly_a<add>(last_expanded)) {
01093 
01094                 // Expand a product of two sums, aggressive version.
01095                 // Caring for the overall coefficients in separate loops can
01096                 // sometimes give a performance gain of up to 15%!
01097 
01098                 const int sizedifference = ex_to<add>(last_expanded).seq.size()-ex_to<add>(cit->rest).seq.size();
01099                 // add2 is for the inner loop and should be the bigger of the two sums
01100                 // in the presence of asymptotically good sorting:
01101                 const add& add1 = (sizedifference<0 ? ex_to<add>(last_expanded) : ex_to<add>(cit->rest));
01102                 const add& add2 = (sizedifference<0 ? ex_to<add>(cit->rest) : ex_to<add>(last_expanded));
01103                 const epvector::const_iterator add1begin = add1.seq.begin();
01104                 const epvector::const_iterator add1end   = add1.seq.end();
01105                 const epvector::const_iterator add2begin = add2.seq.begin();
01106                 const epvector::const_iterator add2end   = add2.seq.end();
01107                 epvector distrseq;
01108                 distrseq.reserve(add1.seq.size()+add2.seq.size());
01109 
01110                 // Multiply add2 with the overall coefficient of add1 and append it to distrseq:
01111                 if (!add1.overall_coeff.is_zero()) {
01112                     if (add1.overall_coeff.is_equal(_ex1))
01113                         distrseq.insert(distrseq.end(),add2begin,add2end);
01114                     else
01115                         for (epvector::const_iterator i=add2begin; i!=add2end; ++i)
01116                             distrseq.push_back(expair(i->rest, ex_to<numeric>(i->coeff).mul_dyn(ex_to<numeric>(add1.overall_coeff))));
01117                 }
01118 
01119                 // Multiply add1 with the overall coefficient of add2 and append it to distrseq:
01120                 if (!add2.overall_coeff.is_zero()) {
01121                     if (add2.overall_coeff.is_equal(_ex1))
01122                         distrseq.insert(distrseq.end(),add1begin,add1end);
01123                     else
01124                         for (epvector::const_iterator i=add1begin; i!=add1end; ++i)
01125                             distrseq.push_back(expair(i->rest, ex_to<numeric>(i->coeff).mul_dyn(ex_to<numeric>(add2.overall_coeff))));
01126                 }
01127 
01128                 // Compute the new overall coefficient and put it together:
01129                 ex tmp_accu = (new add(distrseq, add1.overall_coeff*add2.overall_coeff))->setflag(status_flags::dynallocated);
01130 
01131                 exvector add1_dummy_indices, add2_dummy_indices, add_indices;
01132                 lst dummy_subs;
01133 
01134                 if (!skip_idx_rename) {
01135                     for (epvector::const_iterator i=add1begin; i!=add1end; ++i) {
01136                         add_indices = get_all_dummy_indices_safely(i->rest);
01137                         add1_dummy_indices.insert(add1_dummy_indices.end(), add_indices.begin(), add_indices.end());
01138                     }
01139                     for (epvector::const_iterator i=add2begin; i!=add2end; ++i) {
01140                         add_indices = get_all_dummy_indices_safely(i->rest);
01141                         add2_dummy_indices.insert(add2_dummy_indices.end(), add_indices.begin(), add_indices.end());
01142                     }
01143 
01144                     sort(add1_dummy_indices.begin(), add1_dummy_indices.end(), ex_is_less());
01145                     sort(add2_dummy_indices.begin(), add2_dummy_indices.end(), ex_is_less());
01146                     dummy_subs = rename_dummy_indices_uniquely(add1_dummy_indices, add2_dummy_indices);
01147                 }
01148 
01149                 // Multiply explicitly all non-numeric terms of add1 and add2:
01150                 for (epvector::const_iterator i2=add2begin; i2!=add2end; ++i2) {
01151                     // We really have to combine terms here in order to compactify
01152                     // the result.  Otherwise it would become waayy tooo bigg.
01153                     numeric oc(*_num0_p);
01154                     epvector distrseq2;
01155                     distrseq2.reserve(add1.seq.size());
01156                     const ex i2_new = (skip_idx_rename || (dummy_subs.op(0).nops() == 0) ?
01157                             i2->rest :
01158                             i2->rest.subs(ex_to<lst>(dummy_subs.op(0)), 
01159                                 ex_to<lst>(dummy_subs.op(1)), subs_options::no_pattern));
01160                     for (epvector::const_iterator i1=add1begin; i1!=add1end; ++i1) {
01161                         // Don't push_back expairs which might have a rest that evaluates to a numeric,
01162                         // since that would violate an invariant of expairseq:
01163                         const ex rest = (new mul(i1->rest, i2_new))->setflag(status_flags::dynallocated);
01164                         if (is_exactly_a<numeric>(rest)) {
01165                             oc += ex_to<numeric>(rest).mul(ex_to<numeric>(i1->coeff).mul(ex_to<numeric>(i2->coeff)));
01166                         } else {
01167                             distrseq2.push_back(expair(rest, ex_to<numeric>(i1->coeff).mul_dyn(ex_to<numeric>(i2->coeff))));
01168                         }
01169                     }
01170                     tmp_accu += (new add(distrseq2, oc))->setflag(status_flags::dynallocated);
01171                 } 
01172                 last_expanded = tmp_accu;
01173             } else {
01174                 if (!last_expanded.is_equal(_ex1))
01175                     non_adds.push_back(split_ex_to_pair(last_expanded));
01176                 last_expanded = cit->rest;
01177             }
01178 
01179         } else {
01180             non_adds.push_back(*cit);
01181         }
01182     }
01183 
01184     // Now the only remaining thing to do is to multiply the factors which
01185     // were not sums into the "last_expanded" sum
01186     if (is_exactly_a<add>(last_expanded)) {
01187         size_t n = last_expanded.nops();
01188         exvector distrseq;
01189         distrseq.reserve(n);
01190         exvector va;
01191         if (! skip_idx_rename) {
01192             va = get_all_dummy_indices_safely(mul(non_adds));
01193             sort(va.begin(), va.end(), ex_is_less());
01194         }
01195 
01196         for (size_t i=0; i<n; ++i) {
01197             epvector factors = non_adds;
01198             if (skip_idx_rename)
01199                 factors.push_back(split_ex_to_pair(last_expanded.op(i)));
01200             else
01201                 factors.push_back(split_ex_to_pair(rename_dummy_indices_uniquely(va, last_expanded.op(i))));
01202             ex term = (new mul(factors, overall_coeff))->setflag(status_flags::dynallocated);
01203             if (can_be_further_expanded(term)) {
01204                 distrseq.push_back(term.expand());
01205             } else {
01206                 if (options == 0)
01207                     ex_to<basic>(term).setflag(status_flags::expanded);
01208                 distrseq.push_back(term);
01209             }
01210         }
01211 
01212         return ((new add(distrseq))->
01213                 setflag(status_flags::dynallocated | (options == 0 ? status_flags::expanded : 0)));
01214     }
01215 
01216     non_adds.push_back(split_ex_to_pair(last_expanded));
01217     ex result = (new mul(non_adds, overall_coeff))->setflag(status_flags::dynallocated);
01218     if (can_be_further_expanded(result)) {
01219         return result.expand();
01220     } else {
01221         if (options == 0)
01222             ex_to<basic>(result).setflag(status_flags::expanded);
01223         return result;
01224     }
01225 }
01226 
01227   
01229 // new virtual functions which can be overridden by derived classes
01231 
01232 // none
01233 
01235 // non-virtual functions in this class
01237 
01238 
01246 std::auto_ptr<epvector> mul::expandchildren(unsigned options) const
01247 {
01248     const epvector::const_iterator last = seq.end();
01249     epvector::const_iterator cit = seq.begin();
01250     while (cit!=last) {
01251         const ex & factor = recombine_pair_to_ex(*cit);
01252         const ex & expanded_factor = factor.expand(options);
01253         if (!are_ex_trivially_equal(factor,expanded_factor)) {
01254             
01255             // something changed, copy seq, eval and return it
01256             std::auto_ptr<epvector> s(new epvector);
01257             s->reserve(seq.size());
01258             
01259             // copy parts of seq which are known not to have changed
01260             epvector::const_iterator cit2 = seq.begin();
01261             while (cit2!=cit) {
01262                 s->push_back(*cit2);
01263                 ++cit2;
01264             }
01265 
01266             // copy first changed element
01267             s->push_back(split_ex_to_pair(expanded_factor));
01268             ++cit2;
01269 
01270             // copy rest
01271             while (cit2!=last) {
01272                 s->push_back(split_ex_to_pair(recombine_pair_to_ex(*cit2).expand(options)));
01273                 ++cit2;
01274             }
01275             return s;
01276         }
01277         ++cit;
01278     }
01279     
01280     return std::auto_ptr<epvector>(0); // nothing has changed
01281 }
01282 
01283 GINAC_BIND_UNARCHIVER(mul);
01284 
01285 } // namespace GiNaC

This page is part of the GiNaC developer's reference. It was generated automatically by doxygen. For an introduction, see the tutorial.