|
GiNaC
1.6.2
|
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