|
GiNaC
1.6.2
|
00001 00008 /* 00009 * GiNaC Copyright (C) 1999-2011 Johannes Gutenberg University Mainz, Germany 00010 * 00011 * This program is free software; you can redistribute it and/or modify 00012 * it under the terms of the GNU General Public License as published by 00013 * the Free Software Foundation; either version 2 of the License, or 00014 * (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License 00022 * along with this program; if not, write to the Free Software 00023 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00024 */ 00025 00026 #include "normal.h" 00027 #include "basic.h" 00028 #include "ex.h" 00029 #include "add.h" 00030 #include "constant.h" 00031 #include "expairseq.h" 00032 #include "fail.h" 00033 #include "inifcns.h" 00034 #include "lst.h" 00035 #include "mul.h" 00036 #include "numeric.h" 00037 #include "power.h" 00038 #include "relational.h" 00039 #include "operators.h" 00040 #include "matrix.h" 00041 #include "pseries.h" 00042 #include "symbol.h" 00043 #include "utils.h" 00044 #include "polynomial/chinrem_gcd.h" 00045 00046 #include <algorithm> 00047 #include <map> 00048 00049 namespace GiNaC { 00050 00051 // If comparing expressions (ex::compare()) is fast, you can set this to 1. 00052 // Some routines like quo(), rem() and gcd() will then return a quick answer 00053 // when they are called with two identical arguments. 00054 #define FAST_COMPARE 1 00055 00056 // Set this if you want divide_in_z() to use remembering 00057 #define USE_REMEMBER 0 00058 00059 // Set this if you want divide_in_z() to use trial division followed by 00060 // polynomial interpolation (always slower except for completely dense 00061 // polynomials) 00062 #define USE_TRIAL_DIVISION 0 00063 00064 // Set this to enable some statistical output for the GCD routines 00065 #define STATISTICS 0 00066 00067 00068 #if STATISTICS 00069 // Statistics variables 00070 static int gcd_called = 0; 00071 static int sr_gcd_called = 0; 00072 static int heur_gcd_called = 0; 00073 static int heur_gcd_failed = 0; 00074 00075 // Print statistics at end of program 00076 static struct _stat_print { 00077 _stat_print() {} 00078 ~_stat_print() { 00079 std::cout << "gcd() called " << gcd_called << " times\n"; 00080 std::cout << "sr_gcd() called " << sr_gcd_called << " times\n"; 00081 std::cout << "heur_gcd() called " << heur_gcd_called << " times\n"; 00082 std::cout << "heur_gcd() failed " << heur_gcd_failed << " times\n"; 00083 } 00084 } stat_print; 00085 #endif 00086 00087 00095 static bool get_first_symbol(const ex &e, ex &x) 00096 { 00097 if (is_a<symbol>(e)) { 00098 x = e; 00099 return true; 00100 } else if (is_exactly_a<add>(e) || is_exactly_a<mul>(e)) { 00101 for (size_t i=0; i<e.nops(); i++) 00102 if (get_first_symbol(e.op(i), x)) 00103 return true; 00104 } else if (is_exactly_a<power>(e)) { 00105 if (get_first_symbol(e.op(0), x)) 00106 return true; 00107 } 00108 return false; 00109 } 00110 00111 00112 /* 00113 * Statistical information about symbols in polynomials 00114 */ 00115 00122 struct sym_desc { 00124 ex sym; 00125 00127 int deg_a; 00128 00130 int deg_b; 00131 00133 int ldeg_a; 00134 00136 int ldeg_b; 00137 00139 int max_deg; 00140 00142 size_t max_lcnops; 00143 00145 bool operator<(const sym_desc &x) const 00146 { 00147 if (max_deg == x.max_deg) 00148 return max_lcnops < x.max_lcnops; 00149 else 00150 return max_deg < x.max_deg; 00151 } 00152 }; 00153 00154 // Vector of sym_desc structures 00155 typedef std::vector<sym_desc> sym_desc_vec; 00156 00157 // Add symbol the sym_desc_vec (used internally by get_symbol_stats()) 00158 static void add_symbol(const ex &s, sym_desc_vec &v) 00159 { 00160 sym_desc_vec::const_iterator it = v.begin(), itend = v.end(); 00161 while (it != itend) { 00162 if (it->sym.is_equal(s)) // If it's already in there, don't add it a second time 00163 return; 00164 ++it; 00165 } 00166 sym_desc d; 00167 d.sym = s; 00168 v.push_back(d); 00169 } 00170 00171 // Collect all symbols of an expression (used internally by get_symbol_stats()) 00172 static void collect_symbols(const ex &e, sym_desc_vec &v) 00173 { 00174 if (is_a<symbol>(e)) { 00175 add_symbol(e, v); 00176 } else if (is_exactly_a<add>(e) || is_exactly_a<mul>(e)) { 00177 for (size_t i=0; i<e.nops(); i++) 00178 collect_symbols(e.op(i), v); 00179 } else if (is_exactly_a<power>(e)) { 00180 collect_symbols(e.op(0), v); 00181 } 00182 } 00183 00196 static void get_symbol_stats(const ex &a, const ex &b, sym_desc_vec &v) 00197 { 00198 collect_symbols(a.eval(), v); // eval() to expand assigned symbols 00199 collect_symbols(b.eval(), v); 00200 sym_desc_vec::iterator it = v.begin(), itend = v.end(); 00201 while (it != itend) { 00202 int deg_a = a.degree(it->sym); 00203 int deg_b = b.degree(it->sym); 00204 it->deg_a = deg_a; 00205 it->deg_b = deg_b; 00206 it->max_deg = std::max(deg_a, deg_b); 00207 it->max_lcnops = std::max(a.lcoeff(it->sym).nops(), b.lcoeff(it->sym).nops()); 00208 it->ldeg_a = a.ldegree(it->sym); 00209 it->ldeg_b = b.ldegree(it->sym); 00210 ++it; 00211 } 00212 std::sort(v.begin(), v.end()); 00213 00214 #if 0 00215 std::clog << "Symbols:\n"; 00216 it = v.begin(); itend = v.end(); 00217 while (it != itend) { 00218 std::clog << " " << it->sym << ": deg_a=" << it->deg_a << ", deg_b=" << it->deg_b << ", ldeg_a=" << it->ldeg_a << ", ldeg_b=" << it->ldeg_b << ", max_deg=" << it->max_deg << ", max_lcnops=" << it->max_lcnops << endl; 00219 std::clog << " lcoeff_a=" << a.lcoeff(it->sym) << ", lcoeff_b=" << b.lcoeff(it->sym) << endl; 00220 ++it; 00221 } 00222 #endif 00223 } 00224 00225 00226 /* 00227 * Computation of LCM of denominators of coefficients of a polynomial 00228 */ 00229 00230 // Compute LCM of denominators of coefficients by going through the 00231 // expression recursively (used internally by lcm_of_coefficients_denominators()) 00232 static numeric lcmcoeff(const ex &e, const numeric &l) 00233 { 00234 if (e.info(info_flags::rational)) 00235 return lcm(ex_to<numeric>(e).denom(), l); 00236 else if (is_exactly_a<add>(e)) { 00237 numeric c = *_num1_p; 00238 for (size_t i=0; i<e.nops(); i++) 00239 c = lcmcoeff(e.op(i), c); 00240 return lcm(c, l); 00241 } else if (is_exactly_a<mul>(e)) { 00242 numeric c = *_num1_p; 00243 for (size_t i=0; i<e.nops(); i++) 00244 c *= lcmcoeff(e.op(i), *_num1_p); 00245 return lcm(c, l); 00246 } else if (is_exactly_a<power>(e)) { 00247 if (is_a<symbol>(e.op(0))) 00248 return l; 00249 else 00250 return pow(lcmcoeff(e.op(0), l), ex_to<numeric>(e.op(1))); 00251 } 00252 return l; 00253 } 00254 00262 static numeric lcm_of_coefficients_denominators(const ex &e) 00263 { 00264 return lcmcoeff(e, *_num1_p); 00265 } 00266 00272 static ex multiply_lcm(const ex &e, const numeric &lcm) 00273 { 00274 if (is_exactly_a<mul>(e)) { 00275 size_t num = e.nops(); 00276 exvector v; v.reserve(num + 1); 00277 numeric lcm_accum = *_num1_p; 00278 for (size_t i=0; i<num; i++) { 00279 numeric op_lcm = lcmcoeff(e.op(i), *_num1_p); 00280 v.push_back(multiply_lcm(e.op(i), op_lcm)); 00281 lcm_accum *= op_lcm; 00282 } 00283 v.push_back(lcm / lcm_accum); 00284 return (new mul(v))->setflag(status_flags::dynallocated); 00285 } else if (is_exactly_a<add>(e)) { 00286 size_t num = e.nops(); 00287 exvector v; v.reserve(num); 00288 for (size_t i=0; i<num; i++) 00289 v.push_back(multiply_lcm(e.op(i), lcm)); 00290 return (new add(v))->setflag(status_flags::dynallocated); 00291 } else if (is_exactly_a<power>(e)) { 00292 if (is_a<symbol>(e.op(0))) 00293 return e * lcm; 00294 else 00295 return pow(multiply_lcm(e.op(0), lcm.power(ex_to<numeric>(e.op(1)).inverse())), e.op(1)); 00296 } else 00297 return e * lcm; 00298 } 00299 00300 00307 numeric ex::integer_content() const 00308 { 00309 return bp->integer_content(); 00310 } 00311 00312 numeric basic::integer_content() const 00313 { 00314 return *_num1_p; 00315 } 00316 00317 numeric numeric::integer_content() const 00318 { 00319 return abs(*this); 00320 } 00321 00322 numeric add::integer_content() const 00323 { 00324 epvector::const_iterator it = seq.begin(); 00325 epvector::const_iterator itend = seq.end(); 00326 numeric c = *_num0_p, l = *_num1_p; 00327 while (it != itend) { 00328 GINAC_ASSERT(!is_exactly_a<numeric>(it->rest)); 00329 GINAC_ASSERT(is_exactly_a<numeric>(it->coeff)); 00330 c = gcd(ex_to<numeric>(it->coeff).numer(), c); 00331 l = lcm(ex_to<numeric>(it->coeff).denom(), l); 00332 it++; 00333 } 00334 GINAC_ASSERT(is_exactly_a<numeric>(overall_coeff)); 00335 c = gcd(ex_to<numeric>(overall_coeff).numer(), c); 00336 l = lcm(ex_to<numeric>(overall_coeff).denom(), l); 00337 return c/l; 00338 } 00339 00340 numeric mul::integer_content() const 00341 { 00342 #ifdef DO_GINAC_ASSERT 00343 epvector::const_iterator it = seq.begin(); 00344 epvector::const_iterator itend = seq.end(); 00345 while (it != itend) { 00346 GINAC_ASSERT(!is_exactly_a<numeric>(recombine_pair_to_ex(*it))); 00347 ++it; 00348 } 00349 #endif // def DO_GINAC_ASSERT 00350 GINAC_ASSERT(is_exactly_a<numeric>(overall_coeff)); 00351 return abs(ex_to<numeric>(overall_coeff)); 00352 } 00353 00354 00355 /* 00356 * Polynomial quotients and remainders 00357 */ 00358 00368 ex quo(const ex &a, const ex &b, const ex &x, bool check_args) 00369 { 00370 if (b.is_zero()) 00371 throw(std::overflow_error("quo: division by zero")); 00372 if (is_exactly_a<numeric>(a) && is_exactly_a<numeric>(b)) 00373 return a / b; 00374 #if FAST_COMPARE 00375 if (a.is_equal(b)) 00376 return _ex1; 00377 #endif 00378 if (check_args && (!a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial))) 00379 throw(std::invalid_argument("quo: arguments must be polynomials over the rationals")); 00380 00381 // Polynomial long division 00382 ex r = a.expand(); 00383 if (r.is_zero()) 00384 return r; 00385 int bdeg = b.degree(x); 00386 int rdeg = r.degree(x); 00387 ex blcoeff = b.expand().coeff(x, bdeg); 00388 bool blcoeff_is_numeric = is_exactly_a<numeric>(blcoeff); 00389 exvector v; v.reserve(std::max(rdeg - bdeg + 1, 0)); 00390 while (rdeg >= bdeg) { 00391 ex term, rcoeff = r.coeff(x, rdeg); 00392 if (blcoeff_is_numeric) 00393 term = rcoeff / blcoeff; 00394 else { 00395 if (!divide(rcoeff, blcoeff, term, false)) 00396 return (new fail())->setflag(status_flags::dynallocated); 00397 } 00398 term *= power(x, rdeg - bdeg); 00399 v.push_back(term); 00400 r -= (term * b).expand(); 00401 if (r.is_zero()) 00402 break; 00403 rdeg = r.degree(x); 00404 } 00405 return (new add(v))->setflag(status_flags::dynallocated); 00406 } 00407 00408 00418 ex rem(const ex &a, const ex &b, const ex &x, bool check_args) 00419 { 00420 if (b.is_zero()) 00421 throw(std::overflow_error("rem: division by zero")); 00422 if (is_exactly_a<numeric>(a)) { 00423 if (is_exactly_a<numeric>(b)) 00424 return _ex0; 00425 else 00426 return a; 00427 } 00428 #if FAST_COMPARE 00429 if (a.is_equal(b)) 00430 return _ex0; 00431 #endif 00432 if (check_args && (!a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial))) 00433 throw(std::invalid_argument("rem: arguments must be polynomials over the rationals")); 00434 00435 // Polynomial long division 00436 ex r = a.expand(); 00437 if (r.is_zero()) 00438 return r; 00439 int bdeg = b.degree(x); 00440 int rdeg = r.degree(x); 00441 ex blcoeff = b.expand().coeff(x, bdeg); 00442 bool blcoeff_is_numeric = is_exactly_a<numeric>(blcoeff); 00443 while (rdeg >= bdeg) { 00444 ex term, rcoeff = r.coeff(x, rdeg); 00445 if (blcoeff_is_numeric) 00446 term = rcoeff / blcoeff; 00447 else { 00448 if (!divide(rcoeff, blcoeff, term, false)) 00449 return (new fail())->setflag(status_flags::dynallocated); 00450 } 00451 term *= power(x, rdeg - bdeg); 00452 r -= (term * b).expand(); 00453 if (r.is_zero()) 00454 break; 00455 rdeg = r.degree(x); 00456 } 00457 return r; 00458 } 00459 00460 00467 ex decomp_rational(const ex &a, const ex &x) 00468 { 00469 ex nd = numer_denom(a); 00470 ex numer = nd.op(0), denom = nd.op(1); 00471 ex q = quo(numer, denom, x); 00472 if (is_exactly_a<fail>(q)) 00473 return a; 00474 else 00475 return q + rem(numer, denom, x) / denom; 00476 } 00477 00478 00487 ex prem(const ex &a, const ex &b, const ex &x, bool check_args) 00488 { 00489 if (b.is_zero()) 00490 throw(std::overflow_error("prem: division by zero")); 00491 if (is_exactly_a<numeric>(a)) { 00492 if (is_exactly_a<numeric>(b)) 00493 return _ex0; 00494 else 00495 return b; 00496 } 00497 if (check_args && (!a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial))) 00498 throw(std::invalid_argument("prem: arguments must be polynomials over the rationals")); 00499 00500 // Polynomial long division 00501 ex r = a.expand(); 00502 ex eb = b.expand(); 00503 int rdeg = r.degree(x); 00504 int bdeg = eb.degree(x); 00505 ex blcoeff; 00506 if (bdeg <= rdeg) { 00507 blcoeff = eb.coeff(x, bdeg); 00508 if (bdeg == 0) 00509 eb = _ex0; 00510 else 00511 eb -= blcoeff * power(x, bdeg); 00512 } else 00513 blcoeff = _ex1; 00514 00515 int delta = rdeg - bdeg + 1, i = 0; 00516 while (rdeg >= bdeg && !r.is_zero()) { 00517 ex rlcoeff = r.coeff(x, rdeg); 00518 ex term = (power(x, rdeg - bdeg) * eb * rlcoeff).expand(); 00519 if (rdeg == 0) 00520 r = _ex0; 00521 else 00522 r -= rlcoeff * power(x, rdeg); 00523 r = (blcoeff * r).expand() - term; 00524 rdeg = r.degree(x); 00525 i++; 00526 } 00527 return power(blcoeff, delta - i) * r; 00528 } 00529 00530 00539 ex sprem(const ex &a, const ex &b, const ex &x, bool check_args) 00540 { 00541 if (b.is_zero()) 00542 throw(std::overflow_error("prem: division by zero")); 00543 if (is_exactly_a<numeric>(a)) { 00544 if (is_exactly_a<numeric>(b)) 00545 return _ex0; 00546 else 00547 return b; 00548 } 00549 if (check_args && (!a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial))) 00550 throw(std::invalid_argument("prem: arguments must be polynomials over the rationals")); 00551 00552 // Polynomial long division 00553 ex r = a.expand(); 00554 ex eb = b.expand(); 00555 int rdeg = r.degree(x); 00556 int bdeg = eb.degree(x); 00557 ex blcoeff; 00558 if (bdeg <= rdeg) { 00559 blcoeff = eb.coeff(x, bdeg); 00560 if (bdeg == 0) 00561 eb = _ex0; 00562 else 00563 eb -= blcoeff * power(x, bdeg); 00564 } else 00565 blcoeff = _ex1; 00566 00567 while (rdeg >= bdeg && !r.is_zero()) { 00568 ex rlcoeff = r.coeff(x, rdeg); 00569 ex term = (power(x, rdeg - bdeg) * eb * rlcoeff).expand(); 00570 if (rdeg == 0) 00571 r = _ex0; 00572 else 00573 r -= rlcoeff * power(x, rdeg); 00574 r = (blcoeff * r).expand() - term; 00575 rdeg = r.degree(x); 00576 } 00577 return r; 00578 } 00579 00580 00590 bool divide(const ex &a, const ex &b, ex &q, bool check_args) 00591 { 00592 if (b.is_zero()) 00593 throw(std::overflow_error("divide: division by zero")); 00594 if (a.is_zero()) { 00595 q = _ex0; 00596 return true; 00597 } 00598 if (is_exactly_a<numeric>(b)) { 00599 q = a / b; 00600 return true; 00601 } else if (is_exactly_a<numeric>(a)) 00602 return false; 00603 #if FAST_COMPARE 00604 if (a.is_equal(b)) { 00605 q = _ex1; 00606 return true; 00607 } 00608 #endif 00609 if (check_args && (!a.info(info_flags::rational_polynomial) || 00610 !b.info(info_flags::rational_polynomial))) 00611 throw(std::invalid_argument("divide: arguments must be polynomials over the rationals")); 00612 00613 // Find first symbol 00614 ex x; 00615 if (!get_first_symbol(a, x) && !get_first_symbol(b, x)) 00616 throw(std::invalid_argument("invalid expression in divide()")); 00617 00618 // Try to avoid expanding partially factored expressions. 00619 if (is_exactly_a<mul>(b)) { 00620 // Divide sequentially by each term 00621 ex rem_new, rem_old = a; 00622 for (size_t i=0; i < b.nops(); i++) { 00623 if (! divide(rem_old, b.op(i), rem_new, false)) 00624 return false; 00625 rem_old = rem_new; 00626 } 00627 q = rem_new; 00628 return true; 00629 } else if (is_exactly_a<power>(b)) { 00630 const ex& bb(b.op(0)); 00631 int exp_b = ex_to<numeric>(b.op(1)).to_int(); 00632 ex rem_new, rem_old = a; 00633 for (int i=exp_b; i>0; i--) { 00634 if (! divide(rem_old, bb, rem_new, false)) 00635 return false; 00636 rem_old = rem_new; 00637 } 00638 q = rem_new; 00639 return true; 00640 } 00641 00642 if (is_exactly_a<mul>(a)) { 00643 // Divide sequentially each term. If some term in a is divisible 00644 // by b we are done... and if not, we can't really say anything. 00645 size_t i; 00646 ex rem_i; 00647 bool divisible_p = false; 00648 for (i=0; i < a.nops(); ++i) { 00649 if (divide(a.op(i), b, rem_i, false)) { 00650 divisible_p = true; 00651 break; 00652 } 00653 } 00654 if (divisible_p) { 00655 exvector resv; 00656 resv.reserve(a.nops()); 00657 for (size_t j=0; j < a.nops(); j++) { 00658 if (j==i) 00659 resv.push_back(rem_i); 00660 else 00661 resv.push_back(a.op(j)); 00662 } 00663 q = (new mul(resv))->setflag(status_flags::dynallocated); 00664 return true; 00665 } 00666 } else if (is_exactly_a<power>(a)) { 00667 // The base itself might be divisible by b, in that case we don't 00668 // need to expand a 00669 const ex& ab(a.op(0)); 00670 int a_exp = ex_to<numeric>(a.op(1)).to_int(); 00671 ex rem_i; 00672 if (divide(ab, b, rem_i, false)) { 00673 q = rem_i*power(ab, a_exp - 1); 00674 return true; 00675 } 00676 // code below is commented-out because it leads to a significant slowdown 00677 // for (int i=2; i < a_exp; i++) { 00678 // if (divide(power(ab, i), b, rem_i, false)) { 00679 // q = rem_i*power(ab, a_exp - i); 00680 // return true; 00681 // } 00682 // } // ... so we *really* need to expand expression. 00683 } 00684 00685 // Polynomial long division (recursive) 00686 ex r = a.expand(); 00687 if (r.is_zero()) { 00688 q = _ex0; 00689 return true; 00690 } 00691 int bdeg = b.degree(x); 00692 int rdeg = r.degree(x); 00693 ex blcoeff = b.expand().coeff(x, bdeg); 00694 bool blcoeff_is_numeric = is_exactly_a<numeric>(blcoeff); 00695 exvector v; v.reserve(std::max(rdeg - bdeg + 1, 0)); 00696 while (rdeg >= bdeg) { 00697 ex term, rcoeff = r.coeff(x, rdeg); 00698 if (blcoeff_is_numeric) 00699 term = rcoeff / blcoeff; 00700 else 00701 if (!divide(rcoeff, blcoeff, term, false)) 00702 return false; 00703 term *= power(x, rdeg - bdeg); 00704 v.push_back(term); 00705 r -= (term * b).expand(); 00706 if (r.is_zero()) { 00707 q = (new add(v))->setflag(status_flags::dynallocated); 00708 return true; 00709 } 00710 rdeg = r.degree(x); 00711 } 00712 return false; 00713 } 00714 00715 00716 #if USE_REMEMBER 00717 /* 00718 * Remembering 00719 */ 00720 00721 typedef std::pair<ex, ex> ex2; 00722 typedef std::pair<ex, bool> exbool; 00723 00724 struct ex2_less { 00725 bool operator() (const ex2 &p, const ex2 &q) const 00726 { 00727 int cmp = p.first.compare(q.first); 00728 return ((cmp<0) || (!(cmp>0) && p.second.compare(q.second)<0)); 00729 } 00730 }; 00731 00732 typedef std::map<ex2, exbool, ex2_less> ex2_exbool_remember; 00733 #endif 00734 00735 00752 static bool divide_in_z(const ex &a, const ex &b, ex &q, sym_desc_vec::const_iterator var) 00753 { 00754 q = _ex0; 00755 if (b.is_zero()) 00756 throw(std::overflow_error("divide_in_z: division by zero")); 00757 if (b.is_equal(_ex1)) { 00758 q = a; 00759 return true; 00760 } 00761 if (is_exactly_a<numeric>(a)) { 00762 if (is_exactly_a<numeric>(b)) { 00763 q = a / b; 00764 return q.info(info_flags::integer); 00765 } else 00766 return false; 00767 } 00768 #if FAST_COMPARE 00769 if (a.is_equal(b)) { 00770 q = _ex1; 00771 return true; 00772 } 00773 #endif 00774 00775 #if USE_REMEMBER 00776 // Remembering 00777 static ex2_exbool_remember dr_remember; 00778 ex2_exbool_remember::const_iterator remembered = dr_remember.find(ex2(a, b)); 00779 if (remembered != dr_remember.end()) { 00780 q = remembered->second.first; 00781 return remembered->second.second; 00782 } 00783 #endif 00784 00785 if (is_exactly_a<power>(b)) { 00786 const ex& bb(b.op(0)); 00787 ex qbar = a; 00788 int exp_b = ex_to<numeric>(b.op(1)).to_int(); 00789 for (int i=exp_b; i>0; i--) { 00790 if (!divide_in_z(qbar, bb, q, var)) 00791 return false; 00792 qbar = q; 00793 } 00794 return true; 00795 } 00796 00797 if (is_exactly_a<mul>(b)) { 00798 ex qbar = a; 00799 for (const_iterator itrb = b.begin(); itrb != b.end(); ++itrb) { 00800 sym_desc_vec sym_stats; 00801 get_symbol_stats(a, *itrb, sym_stats); 00802 if (!divide_in_z(qbar, *itrb, q, sym_stats.begin())) 00803 return false; 00804 00805 qbar = q; 00806 } 00807 return true; 00808 } 00809 00810 // Main symbol 00811 const ex &x = var->sym; 00812 00813 // Compare degrees 00814 int adeg = a.degree(x), bdeg = b.degree(x); 00815 if (bdeg > adeg) 00816 return false; 00817 00818 #if USE_TRIAL_DIVISION 00819 00820 // Trial division with polynomial interpolation 00821 int i, k; 00822 00823 // Compute values at evaluation points 0..adeg 00824 vector<numeric> alpha; alpha.reserve(adeg + 1); 00825 exvector u; u.reserve(adeg + 1); 00826 numeric point = *_num0_p; 00827 ex c; 00828 for (i=0; i<=adeg; i++) { 00829 ex bs = b.subs(x == point, subs_options::no_pattern); 00830 while (bs.is_zero()) { 00831 point += *_num1_p; 00832 bs = b.subs(x == point, subs_options::no_pattern); 00833 } 00834 if (!divide_in_z(a.subs(x == point, subs_options::no_pattern), bs, c, var+1)) 00835 return false; 00836 alpha.push_back(point); 00837 u.push_back(c); 00838 point += *_num1_p; 00839 } 00840 00841 // Compute inverses 00842 vector<numeric> rcp; rcp.reserve(adeg + 1); 00843 rcp.push_back(*_num0_p); 00844 for (k=1; k<=adeg; k++) { 00845 numeric product = alpha[k] - alpha[0]; 00846 for (i=1; i<k; i++) 00847 product *= alpha[k] - alpha[i]; 00848 rcp.push_back(product.inverse()); 00849 } 00850 00851 // Compute Newton coefficients 00852 exvector v; v.reserve(adeg + 1); 00853 v.push_back(u[0]); 00854 for (k=1; k<=adeg; k++) { 00855 ex temp = v[k - 1]; 00856 for (i=k-2; i>=0; i--) 00857 temp = temp * (alpha[k] - alpha[i]) + v[i]; 00858 v.push_back((u[k] - temp) * rcp[k]); 00859 } 00860 00861 // Convert from Newton form to standard form 00862 c = v[adeg]; 00863 for (k=adeg-1; k>=0; k--) 00864 c = c * (x - alpha[k]) + v[k]; 00865 00866 if (c.degree(x) == (adeg - bdeg)) { 00867 q = c.expand(); 00868 return true; 00869 } else 00870 return false; 00871 00872 #else 00873 00874 // Polynomial long division (recursive) 00875 ex r = a.expand(); 00876 if (r.is_zero()) 00877 return true; 00878 int rdeg = adeg; 00879 ex eb = b.expand(); 00880 ex blcoeff = eb.coeff(x, bdeg); 00881 exvector v; v.reserve(std::max(rdeg - bdeg + 1, 0)); 00882 while (rdeg >= bdeg) { 00883 ex term, rcoeff = r.coeff(x, rdeg); 00884 if (!divide_in_z(rcoeff, blcoeff, term, var+1)) 00885 break; 00886 term = (term * power(x, rdeg - bdeg)).expand(); 00887 v.push_back(term); 00888 r -= (term * eb).expand(); 00889 if (r.is_zero()) { 00890 q = (new add(v))->setflag(status_flags::dynallocated); 00891 #if USE_REMEMBER 00892 dr_remember[ex2(a, b)] = exbool(q, true); 00893 #endif 00894 return true; 00895 } 00896 rdeg = r.degree(x); 00897 } 00898 #if USE_REMEMBER 00899 dr_remember[ex2(a, b)] = exbool(q, false); 00900 #endif 00901 return false; 00902 00903 #endif 00904 } 00905 00906 00907 /* 00908 * Separation of unit part, content part and primitive part of polynomials 00909 */ 00910 00918 ex ex::unit(const ex &x) const 00919 { 00920 ex c = expand().lcoeff(x); 00921 if (is_exactly_a<numeric>(c)) 00922 return c.info(info_flags::negative) ?_ex_1 : _ex1; 00923 else { 00924 ex y; 00925 if (get_first_symbol(c, y)) 00926 return c.unit(y); 00927 else 00928 throw(std::invalid_argument("invalid expression in unit()")); 00929 } 00930 } 00931 00932 00940 ex ex::content(const ex &x) const 00941 { 00942 if (is_exactly_a<numeric>(*this)) 00943 return info(info_flags::negative) ? -*this : *this; 00944 00945 ex e = expand(); 00946 if (e.is_zero()) 00947 return _ex0; 00948 00949 // First, divide out the integer content (which we can calculate very efficiently). 00950 // If the leading coefficient of the quotient is an integer, we are done. 00951 ex c = e.integer_content(); 00952 ex r = e / c; 00953 int deg = r.degree(x); 00954 ex lcoeff = r.coeff(x, deg); 00955 if (lcoeff.info(info_flags::integer)) 00956 return c; 00957 00958 // GCD of all coefficients 00959 int ldeg = r.ldegree(x); 00960 if (deg == ldeg) 00961 return lcoeff * c / lcoeff.unit(x); 00962 ex cont = _ex0; 00963 for (int i=ldeg; i<=deg; i++) 00964 cont = gcd(r.coeff(x, i), cont, NULL, NULL, false); 00965 return cont * c; 00966 } 00967 00968 00976 ex ex::primpart(const ex &x) const 00977 { 00978 // We need to compute the unit and content anyway, so call unitcontprim() 00979 ex u, c, p; 00980 unitcontprim(x, u, c, p); 00981 return p; 00982 } 00983 00984 00992 ex ex::primpart(const ex &x, const ex &c) const 00993 { 00994 if (is_zero() || c.is_zero()) 00995 return _ex0; 00996 if (is_exactly_a<numeric>(*this)) 00997 return _ex1; 00998 00999 // Divide by unit and content to get primitive part 01000 ex u = unit(x); 01001 if (is_exactly_a<numeric>(c)) 01002 return *this / (c * u); 01003 else 01004 return quo(*this, c * u, x, false); 01005 } 01006 01007 01017 void ex::unitcontprim(const ex &x, ex &u, ex &c, ex &p) const 01018 { 01019 // Quick check for zero (avoid expanding) 01020 if (is_zero()) { 01021 u = _ex1; 01022 c = p = _ex0; 01023 return; 01024 } 01025 01026 // Special case: input is a number 01027 if (is_exactly_a<numeric>(*this)) { 01028 if (info(info_flags::negative)) { 01029 u = _ex_1; 01030 c = abs(ex_to<numeric>(*this)); 01031 } else { 01032 u = _ex1; 01033 c = *this; 01034 } 01035 p = _ex1; 01036 return; 01037 } 01038 01039 // Expand input polynomial 01040 ex e = expand(); 01041 if (e.is_zero()) { 01042 u = _ex1; 01043 c = p = _ex0; 01044 return; 01045 } 01046 01047 // Compute unit and content 01048 u = unit(x); 01049 c = content(x); 01050 01051 // Divide by unit and content to get primitive part 01052 if (c.is_zero()) { 01053 p = _ex0; 01054 return; 01055 } 01056 if (is_exactly_a<numeric>(c)) 01057 p = *this / (c * u); 01058 else 01059 p = quo(e, c * u, x, false); 01060 } 01061 01062 01063 /* 01064 * GCD of multivariate polynomials 01065 */ 01066 01076 static ex sr_gcd(const ex &a, const ex &b, sym_desc_vec::const_iterator var) 01077 { 01078 #if STATISTICS 01079 sr_gcd_called++; 01080 #endif 01081 01082 // The first symbol is our main variable 01083 const ex &x = var->sym; 01084 01085 // Sort c and d so that c has higher degree 01086 ex c, d; 01087 int adeg = a.degree(x), bdeg = b.degree(x); 01088 int cdeg, ddeg; 01089 if (adeg >= bdeg) { 01090 c = a; 01091 d = b; 01092 cdeg = adeg; 01093 ddeg = bdeg; 01094 } else { 01095 c = b; 01096 d = a; 01097 cdeg = bdeg; 01098 ddeg = adeg; 01099 } 01100 01101 // Remove content from c and d, to be attached to GCD later 01102 ex cont_c = c.content(x); 01103 ex cont_d = d.content(x); 01104 ex gamma = gcd(cont_c, cont_d, NULL, NULL, false); 01105 if (ddeg == 0) 01106 return gamma; 01107 c = c.primpart(x, cont_c); 01108 d = d.primpart(x, cont_d); 01109 01110 // First element of subresultant sequence 01111 ex r = _ex0, ri = _ex1, psi = _ex1; 01112 int delta = cdeg - ddeg; 01113 01114 for (;;) { 01115 01116 // Calculate polynomial pseudo-remainder 01117 r = prem(c, d, x, false); 01118 if (r.is_zero()) 01119 return gamma * d.primpart(x); 01120 01121 c = d; 01122 cdeg = ddeg; 01123 if (!divide_in_z(r, ri * pow(psi, delta), d, var)) 01124 throw(std::runtime_error("invalid expression in sr_gcd(), division failed")); 01125 ddeg = d.degree(x); 01126 if (ddeg == 0) { 01127 if (is_exactly_a<numeric>(r)) 01128 return gamma; 01129 else 01130 return gamma * r.primpart(x); 01131 } 01132 01133 // Next element of subresultant sequence 01134 ri = c.expand().lcoeff(x); 01135 if (delta == 1) 01136 psi = ri; 01137 else if (delta) 01138 divide_in_z(pow(ri, delta), pow(psi, delta-1), psi, var+1); 01139 delta = cdeg - ddeg; 01140 } 01141 } 01142 01143 01149 numeric ex::max_coefficient() const 01150 { 01151 return bp->max_coefficient(); 01152 } 01153 01156 numeric basic::max_coefficient() const 01157 { 01158 return *_num1_p; 01159 } 01160 01161 numeric numeric::max_coefficient() const 01162 { 01163 return abs(*this); 01164 } 01165 01166 numeric add::max_coefficient() const 01167 { 01168 epvector::const_iterator it = seq.begin(); 01169 epvector::const_iterator itend = seq.end(); 01170 GINAC_ASSERT(is_exactly_a<numeric>(overall_coeff)); 01171 numeric cur_max = abs(ex_to<numeric>(overall_coeff)); 01172 while (it != itend) { 01173 numeric a; 01174 GINAC_ASSERT(!is_exactly_a<numeric>(it->rest)); 01175 a = abs(ex_to<numeric>(it->coeff)); 01176 if (a > cur_max) 01177 cur_max = a; 01178 it++; 01179 } 01180 return cur_max; 01181 } 01182 01183 numeric mul::max_coefficient() const 01184 { 01185 #ifdef DO_GINAC_ASSERT 01186 epvector::const_iterator it = seq.begin(); 01187 epvector::const_iterator itend = seq.end(); 01188 while (it != itend) { 01189 GINAC_ASSERT(!is_exactly_a<numeric>(recombine_pair_to_ex(*it))); 01190 it++; 01191 } 01192 #endif // def DO_GINAC_ASSERT 01193 GINAC_ASSERT(is_exactly_a<numeric>(overall_coeff)); 01194 return abs(ex_to<numeric>(overall_coeff)); 01195 } 01196 01197 01204 ex basic::smod(const numeric &xi) const 01205 { 01206 return *this; 01207 } 01208 01209 ex numeric::smod(const numeric &xi) const 01210 { 01211 return GiNaC::smod(*this, xi); 01212 } 01213 01214 ex add::smod(const numeric &xi) const 01215 { 01216 epvector newseq; 01217 newseq.reserve(seq.size()+1); 01218 epvector::const_iterator it = seq.begin(); 01219 epvector::const_iterator itend = seq.end(); 01220 while (it != itend) { 01221 GINAC_ASSERT(!is_exactly_a<numeric>(it->rest)); 01222 numeric coeff = GiNaC::smod(ex_to<numeric>(it->coeff), xi); 01223 if (!coeff.is_zero()) 01224 newseq.push_back(expair(it->rest, coeff)); 01225 it++; 01226 } 01227 GINAC_ASSERT(is_exactly_a<numeric>(overall_coeff)); 01228 numeric coeff = GiNaC::smod(ex_to<numeric>(overall_coeff), xi); 01229 return (new add(newseq,coeff))->setflag(status_flags::dynallocated); 01230 } 01231 01232 ex mul::smod(const numeric &xi) const 01233 { 01234 #ifdef DO_GINAC_ASSERT 01235 epvector::const_iterator it = seq.begin(); 01236 epvector::const_iterator itend = seq.end(); 01237 while (it != itend) { 01238 GINAC_ASSERT(!is_exactly_a<numeric>(recombine_pair_to_ex(*it))); 01239 it++; 01240 } 01241 #endif // def DO_GINAC_ASSERT 01242 mul * mulcopyp = new mul(*this); 01243 GINAC_ASSERT(is_exactly_a<numeric>(overall_coeff)); 01244 mulcopyp->overall_coeff = GiNaC::smod(ex_to<numeric>(overall_coeff),xi); 01245 mulcopyp->clearflag(status_flags::evaluated); 01246 mulcopyp->clearflag(status_flags::hash_calculated); 01247 return mulcopyp->setflag(status_flags::dynallocated); 01248 } 01249 01250 01252 static ex interpolate(const ex &gamma, const numeric &xi, const ex &x, int degree_hint = 1) 01253 { 01254 exvector g; g.reserve(degree_hint); 01255 ex e = gamma; 01256 numeric rxi = xi.inverse(); 01257 for (int i=0; !e.is_zero(); i++) { 01258 ex gi = e.smod(xi); 01259 g.push_back(gi * power(x, i)); 01260 e = (e - gi) * rxi; 01261 } 01262 return (new add(g))->setflag(status_flags::dynallocated); 01263 } 01264 01266 class gcdheu_failed {}; 01267 01284 static bool heur_gcd_z(ex& res, const ex &a, const ex &b, ex *ca, ex *cb, 01285 sym_desc_vec::const_iterator var) 01286 { 01287 #if STATISTICS 01288 heur_gcd_called++; 01289 #endif 01290 01291 // Algorithm only works for non-vanishing input polynomials 01292 if (a.is_zero() || b.is_zero()) 01293 return false; 01294 01295 // GCD of two numeric values -> CLN 01296 if (is_exactly_a<numeric>(a) && is_exactly_a<numeric>(b)) { 01297 numeric g = gcd(ex_to<numeric>(a), ex_to<numeric>(b)); 01298 if (ca) 01299 *ca = ex_to<numeric>(a) / g; 01300 if (cb) 01301 *cb = ex_to<numeric>(b) / g; 01302 res = g; 01303 return true; 01304 } 01305 01306 // The first symbol is our main variable 01307 const ex &x = var->sym; 01308 01309 // Remove integer content 01310 numeric gc = gcd(a.integer_content(), b.integer_content()); 01311 numeric rgc = gc.inverse(); 01312 ex p = a * rgc; 01313 ex q = b * rgc; 01314 int maxdeg = std::max(p.degree(x), q.degree(x)); 01315 01316 // Find evaluation point 01317 numeric mp = p.max_coefficient(); 01318 numeric mq = q.max_coefficient(); 01319 numeric xi; 01320 if (mp > mq) 01321 xi = mq * (*_num2_p) + (*_num2_p); 01322 else 01323 xi = mp * (*_num2_p) + (*_num2_p); 01324 01325 // 6 tries maximum 01326 for (int t=0; t<6; t++) { 01327 if (xi.int_length() * maxdeg > 100000) { 01328 throw gcdheu_failed(); 01329 } 01330 01331 // Apply evaluation homomorphism and calculate GCD 01332 ex cp, cq; 01333 ex gamma; 01334 bool found = heur_gcd_z(gamma, 01335 p.subs(x == xi, subs_options::no_pattern), 01336 q.subs(x == xi, subs_options::no_pattern), 01337 &cp, &cq, var+1); 01338 if (found) { 01339 gamma = gamma.expand(); 01340 // Reconstruct polynomial from GCD of mapped polynomials 01341 ex g = interpolate(gamma, xi, x, maxdeg); 01342 01343 // Remove integer content 01344 g /= g.integer_content(); 01345 01346 // If the calculated polynomial divides both p and q, this is the GCD 01347 ex dummy; 01348 if (divide_in_z(p, g, ca ? *ca : dummy, var) && divide_in_z(q, g, cb ? *cb : dummy, var)) { 01349 g *= gc; 01350 res = g; 01351 return true; 01352 } 01353 } 01354 01355 // Next evaluation point 01356 xi = iquo(xi * isqrt(isqrt(xi)) * numeric(73794), numeric(27011)); 01357 } 01358 return false; 01359 } 01360 01378 static bool heur_gcd(ex& res, const ex& a, const ex& b, ex *ca, ex *cb, 01379 sym_desc_vec::const_iterator var) 01380 { 01381 if (a.info(info_flags::integer_polynomial) && 01382 b.info(info_flags::integer_polynomial)) { 01383 try { 01384 return heur_gcd_z(res, a, b, ca, cb, var); 01385 } catch (gcdheu_failed) { 01386 return false; 01387 } 01388 } 01389 01390 // convert polynomials to Z[X] 01391 const numeric a_lcm = lcm_of_coefficients_denominators(a); 01392 const numeric ab_lcm = lcmcoeff(b, a_lcm); 01393 01394 const ex ai = a*ab_lcm; 01395 const ex bi = b*ab_lcm; 01396 if (!ai.info(info_flags::integer_polynomial)) 01397 throw std::logic_error("heur_gcd: not an integer polynomial [1]"); 01398 01399 if (!bi.info(info_flags::integer_polynomial)) 01400 throw std::logic_error("heur_gcd: not an integer polynomial [2]"); 01401 01402 bool found = false; 01403 try { 01404 found = heur_gcd_z(res, ai, bi, ca, cb, var); 01405 } catch (gcdheu_failed) { 01406 return false; 01407 } 01408 01409 // GCD is not unique, it's defined up to a unit (i.e. invertible 01410 // element). If the coefficient ring is a field, every its element is 01411 // invertible, so one can multiply the polynomial GCD with any element 01412 // of the coefficient field. We use this ambiguity to make cofactors 01413 // integer polynomials. 01414 if (found) 01415 res /= ab_lcm; 01416 return found; 01417 } 01418 01419 01420 // gcd helper to handle partially factored polynomials (to avoid expanding 01421 // large expressions). At least one of the arguments should be a power. 01422 static ex gcd_pf_pow(const ex& a, const ex& b, ex* ca, ex* cb); 01423 01424 // gcd helper to handle partially factored polynomials (to avoid expanding 01425 // large expressions). At least one of the arguments should be a product. 01426 static ex gcd_pf_mul(const ex& a, const ex& b, ex* ca, ex* cb); 01427 01439 ex gcd(const ex &a, const ex &b, ex *ca, ex *cb, bool check_args, unsigned options) 01440 { 01441 #if STATISTICS 01442 gcd_called++; 01443 #endif 01444 01445 // GCD of numerics -> CLN 01446 if (is_exactly_a<numeric>(a) && is_exactly_a<numeric>(b)) { 01447 numeric g = gcd(ex_to<numeric>(a), ex_to<numeric>(b)); 01448 if (ca || cb) { 01449 if (g.is_zero()) { 01450 if (ca) 01451 *ca = _ex0; 01452 if (cb) 01453 *cb = _ex0; 01454 } else { 01455 if (ca) 01456 *ca = ex_to<numeric>(a) / g; 01457 if (cb) 01458 *cb = ex_to<numeric>(b) / g; 01459 } 01460 } 01461 return g; 01462 } 01463 01464 // Check arguments 01465 if (check_args && (!a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial))) { 01466 throw(std::invalid_argument("gcd: arguments must be polynomials over the rationals")); 01467 } 01468 01469 // Partially factored cases (to avoid expanding large expressions) 01470 if (!(options & gcd_options::no_part_factored)) { 01471 if (is_exactly_a<mul>(a) || is_exactly_a<mul>(b)) 01472 return gcd_pf_mul(a, b, ca, cb); 01473 #if FAST_COMPARE 01474 if (is_exactly_a<power>(a) || is_exactly_a<power>(b)) 01475 return gcd_pf_pow(a, b, ca, cb); 01476 #endif 01477 } 01478 01479 // Some trivial cases 01480 ex aex = a.expand(), bex = b.expand(); 01481 if (aex.is_zero()) { 01482 if (ca) 01483 *ca = _ex0; 01484 if (cb) 01485 *cb = _ex1; 01486 return b; 01487 } 01488 if (bex.is_zero()) { 01489 if (ca) 01490 *ca = _ex1; 01491 if (cb) 01492 *cb = _ex0; 01493 return a; 01494 } 01495 if (aex.is_equal(_ex1) || bex.is_equal(_ex1)) { 01496 if (ca) 01497 *ca = a; 01498 if (cb) 01499 *cb = b; 01500 return _ex1; 01501 } 01502 #if FAST_COMPARE 01503 if (a.is_equal(b)) { 01504 if (ca) 01505 *ca = _ex1; 01506 if (cb) 01507 *cb = _ex1; 01508 return a; 01509 } 01510 #endif 01511 01512 if (is_a<symbol>(aex)) { 01513 if (! bex.subs(aex==_ex0, subs_options::no_pattern).is_zero()) { 01514 if (ca) 01515 *ca = a; 01516 if (cb) 01517 *cb = b; 01518 return _ex1; 01519 } 01520 } 01521 01522 if (is_a<symbol>(bex)) { 01523 if (! aex.subs(bex==_ex0, subs_options::no_pattern).is_zero()) { 01524 if (ca) 01525 *ca = a; 01526 if (cb) 01527 *cb = b; 01528 return _ex1; 01529 } 01530 } 01531 01532 if (is_exactly_a<numeric>(aex)) { 01533 numeric bcont = bex.integer_content(); 01534 numeric g = gcd(ex_to<numeric>(aex), bcont); 01535 if (ca) 01536 *ca = ex_to<numeric>(aex)/g; 01537 if (cb) 01538 *cb = bex/g; 01539 return g; 01540 } 01541 01542 if (is_exactly_a<numeric>(bex)) { 01543 numeric acont = aex.integer_content(); 01544 numeric g = gcd(ex_to<numeric>(bex), acont); 01545 if (ca) 01546 *ca = aex/g; 01547 if (cb) 01548 *cb = ex_to<numeric>(bex)/g; 01549 return g; 01550 } 01551 01552 // Gather symbol statistics 01553 sym_desc_vec sym_stats; 01554 get_symbol_stats(a, b, sym_stats); 01555 01556 // The symbol with least degree which is contained in both polynomials 01557 // is our main variable 01558 sym_desc_vec::iterator vari = sym_stats.begin(); 01559 while ((vari != sym_stats.end()) && 01560 (((vari->ldeg_b == 0) && (vari->deg_b == 0)) || 01561 ((vari->ldeg_a == 0) && (vari->deg_a == 0)))) 01562 vari++; 01563 01564 // No common symbols at all, just return 1: 01565 if (vari == sym_stats.end()) { 01566 // N.B: keep cofactors factored 01567 if (ca) 01568 *ca = a; 01569 if (cb) 01570 *cb = b; 01571 return _ex1; 01572 } 01573 // move symbols which contained only in one of the polynomials 01574 // to the end: 01575 rotate(sym_stats.begin(), vari, sym_stats.end()); 01576 01577 sym_desc_vec::const_iterator var = sym_stats.begin(); 01578 const ex &x = var->sym; 01579 01580 // Cancel trivial common factor 01581 int ldeg_a = var->ldeg_a; 01582 int ldeg_b = var->ldeg_b; 01583 int min_ldeg = std::min(ldeg_a,ldeg_b); 01584 if (min_ldeg > 0) { 01585 ex common = power(x, min_ldeg); 01586 return gcd((aex / common).expand(), (bex / common).expand(), ca, cb, false) * common; 01587 } 01588 01589 // Try to eliminate variables 01590 if (var->deg_a == 0 && var->deg_b != 0 ) { 01591 ex bex_u, bex_c, bex_p; 01592 bex.unitcontprim(x, bex_u, bex_c, bex_p); 01593 ex g = gcd(aex, bex_c, ca, cb, false); 01594 if (cb) 01595 *cb *= bex_u * bex_p; 01596 return g; 01597 } else if (var->deg_b == 0 && var->deg_a != 0) { 01598 ex aex_u, aex_c, aex_p; 01599 aex.unitcontprim(x, aex_u, aex_c, aex_p); 01600 ex g = gcd(aex_c, bex, ca, cb, false); 01601 if (ca) 01602 *ca *= aex_u * aex_p; 01603 return g; 01604 } 01605 01606 // Try heuristic algorithm first, fall back to PRS if that failed 01607 ex g; 01608 if (!(options & gcd_options::no_heur_gcd)) { 01609 bool found = heur_gcd(g, aex, bex, ca, cb, var); 01610 if (found) { 01611 // heur_gcd have already computed cofactors... 01612 if (g.is_equal(_ex1)) { 01613 // ... but we want to keep them factored if possible. 01614 if (ca) 01615 *ca = a; 01616 if (cb) 01617 *cb = b; 01618 } 01619 return g; 01620 } 01621 #if STATISTICS 01622 else { 01623 heur_gcd_failed++; 01624 } 01625 #endif 01626 } 01627 if (options & gcd_options::use_sr_gcd) { 01628 g = sr_gcd(aex, bex, var); 01629 } else { 01630 exvector vars; 01631 for (std::size_t n = sym_stats.size(); n-- != 0; ) 01632 vars.push_back(sym_stats[n].sym); 01633 g = chinrem_gcd(aex, bex, vars); 01634 } 01635 01636 if (g.is_equal(_ex1)) { 01637 // Keep cofactors factored if possible 01638 if (ca) 01639 *ca = a; 01640 if (cb) 01641 *cb = b; 01642 } else { 01643 if (ca) 01644 divide(aex, g, *ca, false); 01645 if (cb) 01646 divide(bex, g, *cb, false); 01647 } 01648 return g; 01649 } 01650 01651 // gcd helper to handle partially factored polynomials (to avoid expanding 01652 // large expressions). Both arguments should be powers. 01653 static ex gcd_pf_pow_pow(const ex& a, const ex& b, ex* ca, ex* cb) 01654 { 01655 ex p = a.op(0); 01656 const ex& exp_a = a.op(1); 01657 ex pb = b.op(0); 01658 const ex& exp_b = b.op(1); 01659 01660 // a = p^n, b = p^m, gcd = p^min(n, m) 01661 if (p.is_equal(pb)) { 01662 if (exp_a < exp_b) { 01663 if (ca) 01664 *ca = _ex1; 01665 if (cb) 01666 *cb = power(p, exp_b - exp_a); 01667 return power(p, exp_a); 01668 } else { 01669 if (ca) 01670 *ca = power(p, exp_a - exp_b); 01671 if (cb) 01672 *cb = _ex1; 01673 return power(p, exp_b); 01674 } 01675 } 01676 01677 ex p_co, pb_co; 01678 ex p_gcd = gcd(p, pb, &p_co, &pb_co, false); 01679 // a(x) = p(x)^n, b(x) = p_b(x)^m, gcd (p, p_b) = 1 ==> gcd(a,b) = 1 01680 if (p_gcd.is_equal(_ex1)) { 01681 if (ca) 01682 *ca = a; 01683 if (cb) 01684 *cb = b; 01685 return _ex1; 01686 // XXX: do I need to check for p_gcd = -1? 01687 } 01688 01689 // there are common factors: 01690 // a(x) = g(x)^n A(x)^n, b(x) = g(x)^m B(x)^m ==> 01691 // gcd(a, b) = g(x)^n gcd(A(x)^n, g(x)^(n-m) B(x)^m 01692 if (exp_a < exp_b) { 01693 ex pg = gcd(power(p_co, exp_a), power(p_gcd, exp_b-exp_a)*power(pb_co, exp_b), ca, cb, false); 01694 return power(p_gcd, exp_a)*pg; 01695 } else { 01696 ex pg = gcd(power(p_gcd, exp_a - exp_b)*power(p_co, exp_a), power(pb_co, exp_b), ca, cb, false); 01697 return power(p_gcd, exp_b)*pg; 01698 } 01699 } 01700 01701 static ex gcd_pf_pow(const ex& a, const ex& b, ex* ca, ex* cb) 01702 { 01703 if (is_exactly_a<power>(a) && is_exactly_a<power>(b)) 01704 return gcd_pf_pow_pow(a, b, ca, cb); 01705 01706 if (is_exactly_a<power>(b) && (! is_exactly_a<power>(a))) 01707 return gcd_pf_pow(b, a, cb, ca); 01708 01709 GINAC_ASSERT(is_exactly_a<power>(a)); 01710 01711 ex p = a.op(0); 01712 const ex& exp_a = a.op(1); 01713 if (p.is_equal(b)) { 01714 // a = p^n, b = p, gcd = p 01715 if (ca) 01716 *ca = power(p, a.op(1) - 1); 01717 if (cb) 01718 *cb = _ex1; 01719 return p; 01720 } 01721 01722 ex p_co, bpart_co; 01723 ex p_gcd = gcd(p, b, &p_co, &bpart_co, false); 01724 01725 // a(x) = p(x)^n, gcd(p, b) = 1 ==> gcd(a, b) = 1 01726 if (p_gcd.is_equal(_ex1)) { 01727 if (ca) 01728 *ca = a; 01729 if (cb) 01730 *cb = b; 01731 return _ex1; 01732 } 01733 // a(x) = g(x)^n A(x)^n, b(x) = g(x) B(x) ==> gcd(a, b) = g(x) gcd(g(x)^(n-1) A(x)^n, B(x)) 01734 ex rg = gcd(power(p_gcd, exp_a-1)*power(p_co, exp_a), bpart_co, ca, cb, false); 01735 return p_gcd*rg; 01736 } 01737 01738 static ex gcd_pf_mul(const ex& a, const ex& b, ex* ca, ex* cb) 01739 { 01740 if (is_exactly_a<mul>(a) && is_exactly_a<mul>(b) 01741 && (b.nops() > a.nops())) 01742 return gcd_pf_mul(b, a, cb, ca); 01743 01744 if (is_exactly_a<mul>(b) && (!is_exactly_a<mul>(a))) 01745 return gcd_pf_mul(b, a, cb, ca); 01746 01747 GINAC_ASSERT(is_exactly_a<mul>(a)); 01748 size_t num = a.nops(); 01749 exvector g; g.reserve(num); 01750 exvector acc_ca; acc_ca.reserve(num); 01751 ex part_b = b; 01752 for (size_t i=0; i<num; i++) { 01753 ex part_ca, part_cb; 01754 g.push_back(gcd(a.op(i), part_b, &part_ca, &part_cb, false)); 01755 acc_ca.push_back(part_ca); 01756 part_b = part_cb; 01757 } 01758 if (ca) 01759 *ca = (new mul(acc_ca))->setflag(status_flags::dynallocated); 01760 if (cb) 01761 *cb = part_b; 01762 return (new mul(g))->setflag(status_flags::dynallocated); 01763 } 01764 01772 ex lcm(const ex &a, const ex &b, bool check_args) 01773 { 01774 if (is_exactly_a<numeric>(a) && is_exactly_a<numeric>(b)) 01775 return lcm(ex_to<numeric>(a), ex_to<numeric>(b)); 01776 if (check_args && (!a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial))) 01777 throw(std::invalid_argument("lcm: arguments must be polynomials over the rationals")); 01778 01779 ex ca, cb; 01780 ex g = gcd(a, b, &ca, &cb, false); 01781 return ca * cb * g; 01782 } 01783 01784 01785 /* 01786 * Square-free factorization 01787 */ 01788 01796 static exvector sqrfree_yun(const ex &a, const symbol &x) 01797 { 01798 exvector res; 01799 ex w = a; 01800 ex z = w.diff(x); 01801 ex g = gcd(w, z); 01802 if (g.is_equal(_ex1)) { 01803 res.push_back(a); 01804 return res; 01805 } 01806 ex y; 01807 do { 01808 w = quo(w, g, x); 01809 y = quo(z, g, x); 01810 z = y - w.diff(x); 01811 g = gcd(w, z); 01812 res.push_back(g); 01813 } while (!z.is_zero()); 01814 return res; 01815 } 01816 01817 01853 ex sqrfree(const ex &a, const lst &l) 01854 { 01855 if (is_exactly_a<numeric>(a) || // algorithm does not trap a==0 01856 is_a<symbol>(a)) // shortcut 01857 return a; 01858 01859 // If no lst of variables to factorize in was specified we have to 01860 // invent one now. Maybe one can optimize here by reversing the order 01861 // or so, I don't know. 01862 lst args; 01863 if (l.nops()==0) { 01864 sym_desc_vec sdv; 01865 get_symbol_stats(a, _ex0, sdv); 01866 sym_desc_vec::const_iterator it = sdv.begin(), itend = sdv.end(); 01867 while (it != itend) { 01868 args.append(it->sym); 01869 ++it; 01870 } 01871 } else { 01872 args = l; 01873 } 01874 01875 // Find the symbol to factor in at this stage 01876 if (!is_a<symbol>(args.op(0))) 01877 throw (std::runtime_error("sqrfree(): invalid factorization variable")); 01878 const symbol &x = ex_to<symbol>(args.op(0)); 01879 01880 // convert the argument from something in Q[X] to something in Z[X] 01881 const numeric lcm = lcm_of_coefficients_denominators(a); 01882 const ex tmp = multiply_lcm(a,lcm); 01883 01884 // find the factors 01885 exvector factors = sqrfree_yun(tmp, x); 01886 01887 // construct the next list of symbols with the first element popped 01888 lst newargs = args; 01889 newargs.remove_first(); 01890 01891 // recurse down the factors in remaining variables 01892 if (newargs.nops()>0) { 01893 exvector::iterator i = factors.begin(); 01894 while (i != factors.end()) { 01895 *i = sqrfree(*i, newargs); 01896 ++i; 01897 } 01898 } 01899 01900 // Done with recursion, now construct the final result 01901 ex result = _ex1; 01902 exvector::const_iterator it = factors.begin(), itend = factors.end(); 01903 for (int p = 1; it!=itend; ++it, ++p) 01904 result *= power(*it, p); 01905 01906 // Yun's algorithm does not account for constant factors. (For univariate 01907 // polynomials it works only in the monic case.) We can correct this by 01908 // inserting what has been lost back into the result. For completeness 01909 // we'll also have to recurse down that factor in the remaining variables. 01910 if (newargs.nops()>0) 01911 result *= sqrfree(quo(tmp, result, x), newargs); 01912 else 01913 result *= quo(tmp, result, x); 01914 01915 // Put in the reational overall factor again and return 01916 return result * lcm.inverse(); 01917 } 01918 01919 01927 ex sqrfree_parfrac(const ex & a, const symbol & x) 01928 { 01929 // Find numerator and denominator 01930 ex nd = numer_denom(a); 01931 ex numer = nd.op(0), denom = nd.op(1); 01932 //clog << "numer = " << numer << ", denom = " << denom << endl; 01933 01934 // Convert N(x)/D(x) -> Q(x) + R(x)/D(x), so degree(R) < degree(D) 01935 ex red_poly = quo(numer, denom, x), red_numer = rem(numer, denom, x).expand(); 01936 //clog << "red_poly = " << red_poly << ", red_numer = " << red_numer << endl; 01937 01938 // Factorize denominator and compute cofactors 01939 exvector yun = sqrfree_yun(denom, x); 01940 //clog << "yun factors: " << exprseq(yun) << endl; 01941 size_t num_yun = yun.size(); 01942 exvector factor; factor.reserve(num_yun); 01943 exvector cofac; cofac.reserve(num_yun); 01944 for (size_t i=0; i<num_yun; i++) { 01945 if (!yun[i].is_equal(_ex1)) { 01946 for (size_t j=0; j<=i; j++) { 01947 factor.push_back(pow(yun[i], j+1)); 01948 ex prod = _ex1; 01949 for (size_t k=0; k<num_yun; k++) { 01950 if (k == i) 01951 prod *= pow(yun[k], i-j); 01952 else 01953 prod *= pow(yun[k], k+1); 01954 } 01955 cofac.push_back(prod.expand()); 01956 } 01957 } 01958 } 01959 size_t num_factors = factor.size(); 01960 //clog << "factors : " << exprseq(factor) << endl; 01961 //clog << "cofactors: " << exprseq(cofac) << endl; 01962 01963 // Construct coefficient matrix for decomposition 01964 int max_denom_deg = denom.degree(x); 01965 matrix sys(max_denom_deg + 1, num_factors); 01966 matrix rhs(max_denom_deg + 1, 1); 01967 for (int i=0; i<=max_denom_deg; i++) { 01968 for (size_t j=0; j<num_factors; j++) 01969 sys(i, j) = cofac[j].coeff(x, i); 01970 rhs(i, 0) = red_numer.coeff(x, i); 01971 } 01972 //clog << "coeffs: " << sys << endl; 01973 //clog << "rhs : " << rhs << endl; 01974 01975 // Solve resulting linear system 01976 matrix vars(num_factors, 1); 01977 for (size_t i=0; i<num_factors; i++) 01978 vars(i, 0) = symbol(); 01979 matrix sol = sys.solve(vars, rhs); 01980 01981 // Sum up decomposed fractions 01982 ex sum = 0; 01983 for (size_t i=0; i<num_factors; i++) 01984 sum += sol(i, 0) / factor[i]; 01985 01986 return red_poly + sum; 01987 } 01988 01989 01990 /* 01991 * Normal form of rational functions 01992 */ 01993 01994 /* 01995 * Note: The internal normal() functions (= basic::normal() and overloaded 01996 * functions) all return lists of the form {numerator, denominator}. This 01997 * is to get around mul::eval()'s automatic expansion of numeric coefficients. 01998 * E.g. (a+b)/3 is automatically converted to a/3+b/3 but we want to keep 01999 * the information that (a+b) is the numerator and 3 is the denominator. 02000 */ 02001 02002 02007 static ex replace_with_symbol(const ex & e, exmap & repl, exmap & rev_lookup) 02008 { 02009 // Expression already replaced? Then return the assigned symbol 02010 exmap::const_iterator it = rev_lookup.find(e); 02011 if (it != rev_lookup.end()) 02012 return it->second; 02013 02014 // Otherwise create new symbol and add to list, taking care that the 02015 // replacement expression doesn't itself contain symbols from repl, 02016 // because subs() is not recursive 02017 ex es = (new symbol)->setflag(status_flags::dynallocated); 02018 ex e_replaced = e.subs(repl, subs_options::no_pattern); 02019 repl.insert(std::make_pair(es, e_replaced)); 02020 rev_lookup.insert(std::make_pair(e_replaced, es)); 02021 return es; 02022 } 02023 02029 static ex replace_with_symbol(const ex & e, exmap & repl) 02030 { 02031 // Expression already replaced? Then return the assigned symbol 02032 for (exmap::const_iterator it = repl.begin(); it != repl.end(); ++it) 02033 if (it->second.is_equal(e)) 02034 return it->first; 02035 02036 // Otherwise create new symbol and add to list, taking care that the 02037 // replacement expression doesn't itself contain symbols from repl, 02038 // because subs() is not recursive 02039 ex es = (new symbol)->setflag(status_flags::dynallocated); 02040 ex e_replaced = e.subs(repl, subs_options::no_pattern); 02041 repl.insert(std::make_pair(es, e_replaced)); 02042 return es; 02043 } 02044 02045 02047 struct normal_map_function : public map_function { 02048 int level; 02049 normal_map_function(int l) : level(l) {} 02050 ex operator()(const ex & e) { return normal(e, level); } 02051 }; 02052 02056 ex basic::normal(exmap & repl, exmap & rev_lookup, int level) const 02057 { 02058 if (nops() == 0) 02059 return (new lst(replace_with_symbol(*this, repl, rev_lookup), _ex1))->setflag(status_flags::dynallocated); 02060 else { 02061 if (level == 1) 02062 return (new lst(replace_with_symbol(*this, repl, rev_lookup), _ex1))->setflag(status_flags::dynallocated); 02063 else if (level == -max_recursion_level) 02064 throw(std::runtime_error("max recursion level reached")); 02065 else { 02066 normal_map_function map_normal(level - 1); 02067 return (new lst(replace_with_symbol(map(map_normal), repl, rev_lookup), _ex1))->setflag(status_flags::dynallocated); 02068 } 02069 } 02070 } 02071 02072 02075 ex symbol::normal(exmap & repl, exmap & rev_lookup, int level) const 02076 { 02077 return (new lst(*this, _ex1))->setflag(status_flags::dynallocated); 02078 } 02079 02080 02085 ex numeric::normal(exmap & repl, exmap & rev_lookup, int level) const 02086 { 02087 numeric num = numer(); 02088 ex numex = num; 02089 02090 if (num.is_real()) { 02091 if (!num.is_integer()) 02092 numex = replace_with_symbol(numex, repl, rev_lookup); 02093 } else { // complex 02094 numeric re = num.real(), im = num.imag(); 02095 ex re_ex = re.is_rational() ? re : replace_with_symbol(re, repl, rev_lookup); 02096 ex im_ex = im.is_rational() ? im : replace_with_symbol(im, repl, rev_lookup); 02097 numex = re_ex + im_ex * replace_with_symbol(I, repl, rev_lookup); 02098 } 02099 02100 // Denominator is always a real integer (see numeric::denom()) 02101 return (new lst(numex, denom()))->setflag(status_flags::dynallocated); 02102 } 02103 02104 02109 static ex frac_cancel(const ex &n, const ex &d) 02110 { 02111 ex num = n; 02112 ex den = d; 02113 numeric pre_factor = *_num1_p; 02114 02115 //std::clog << "frac_cancel num = " << num << ", den = " << den << std::endl; 02116 02117 // Handle trivial case where denominator is 1 02118 if (den.is_equal(_ex1)) 02119 return (new lst(num, den))->setflag(status_flags::dynallocated); 02120 02121 // Handle special cases where numerator or denominator is 0 02122 if (num.is_zero()) 02123 return (new lst(num, _ex1))->setflag(status_flags::dynallocated); 02124 if (den.expand().is_zero()) 02125 throw(std::overflow_error("frac_cancel: division by zero in frac_cancel")); 02126 02127 // Bring numerator and denominator to Z[X] by multiplying with 02128 // LCM of all coefficients' denominators 02129 numeric num_lcm = lcm_of_coefficients_denominators(num); 02130 numeric den_lcm = lcm_of_coefficients_denominators(den); 02131 num = multiply_lcm(num, num_lcm); 02132 den = multiply_lcm(den, den_lcm); 02133 pre_factor = den_lcm / num_lcm; 02134 02135 // Cancel GCD from numerator and denominator 02136 ex cnum, cden; 02137 if (gcd(num, den, &cnum, &cden, false) != _ex1) { 02138 num = cnum; 02139 den = cden; 02140 } 02141 02142 // Make denominator unit normal (i.e. coefficient of first symbol 02143 // as defined by get_first_symbol() is made positive) 02144 if (is_exactly_a<numeric>(den)) { 02145 if (ex_to<numeric>(den).is_negative()) { 02146 num *= _ex_1; 02147 den *= _ex_1; 02148 } 02149 } else { 02150 ex x; 02151 if (get_first_symbol(den, x)) { 02152 GINAC_ASSERT(is_exactly_a<numeric>(den.unit(x))); 02153 if (ex_to<numeric>(den.unit(x)).is_negative()) { 02154 num *= _ex_1; 02155 den *= _ex_1; 02156 } 02157 } 02158 } 02159 02160 // Return result as list 02161 //std::clog << " returns num = " << num << ", den = " << den << ", pre_factor = " << pre_factor << std::endl; 02162 return (new lst(num * pre_factor.numer(), den * pre_factor.denom()))->setflag(status_flags::dynallocated); 02163 } 02164 02165 02169 ex add::normal(exmap & repl, exmap & rev_lookup, int level) const 02170 { 02171 if (level == 1) 02172 return (new lst(replace_with_symbol(*this, repl, rev_lookup), _ex1))->setflag(status_flags::dynallocated); 02173 else if (level == -max_recursion_level) 02174 throw(std::runtime_error("max recursion level reached")); 02175 02176 // Normalize children and split each one into numerator and denominator 02177 exvector nums, dens; 02178 nums.reserve(seq.size()+1); 02179 dens.reserve(seq.size()+1); 02180 epvector::const_iterator it = seq.begin(), itend = seq.end(); 02181 while (it != itend) { 02182 ex n = ex_to<basic>(recombine_pair_to_ex(*it)).normal(repl, rev_lookup, level-1); 02183 nums.push_back(n.op(0)); 02184 dens.push_back(n.op(1)); 02185 it++; 02186 } 02187 ex n = ex_to<numeric>(overall_coeff).normal(repl, rev_lookup, level-1); 02188 nums.push_back(n.op(0)); 02189 dens.push_back(n.op(1)); 02190 GINAC_ASSERT(nums.size() == dens.size()); 02191 02192 // Now, nums is a vector of all numerators and dens is a vector of 02193 // all denominators 02194 //std::clog << "add::normal uses " << nums.size() << " summands:\n"; 02195 02196 // Add fractions sequentially 02197 exvector::const_iterator num_it = nums.begin(), num_itend = nums.end(); 02198 exvector::const_iterator den_it = dens.begin(), den_itend = dens.end(); 02199 //std::clog << " num = " << *num_it << ", den = " << *den_it << std::endl; 02200 ex num = *num_it++, den = *den_it++; 02201 while (num_it != num_itend) { 02202 //std::clog << " num = " << *num_it << ", den = " << *den_it << std::endl; 02203 ex next_num = *num_it++, next_den = *den_it++; 02204 02205 // Trivially add sequences of fractions with identical denominators 02206 while ((den_it != den_itend) && next_den.is_equal(*den_it)) { 02207 next_num += *num_it; 02208 num_it++; den_it++; 02209 } 02210 02211 // Additiion of two fractions, taking advantage of the fact that 02212 // the heuristic GCD algorithm computes the cofactors at no extra cost 02213 ex co_den1, co_den2; 02214 ex g = gcd(den, next_den, &co_den1, &co_den2, false); 02215 num = ((num * co_den2) + (next_num * co_den1)).expand(); 02216 den *= co_den2; // this is the lcm(den, next_den) 02217 } 02218 //std::clog << " common denominator = " << den << std::endl; 02219 02220 // Cancel common factors from num/den 02221 return frac_cancel(num, den); 02222 } 02223 02224 02228 ex mul::normal(exmap & repl, exmap & rev_lookup, int level) const 02229 { 02230 if (level == 1) 02231 return (new lst(replace_with_symbol(*this, repl, rev_lookup), _ex1))->setflag(status_flags::dynallocated); 02232 else if (level == -max_recursion_level) 02233 throw(std::runtime_error("max recursion level reached")); 02234 02235 // Normalize children, separate into numerator and denominator 02236 exvector num; num.reserve(seq.size()); 02237 exvector den; den.reserve(seq.size()); 02238 ex n; 02239 epvector::const_iterator it = seq.begin(), itend = seq.end(); 02240 while (it != itend) { 02241 n = ex_to<basic>(recombine_pair_to_ex(*it)).normal(repl, rev_lookup, level-1); 02242 num.push_back(n.op(0)); 02243 den.push_back(n.op(1)); 02244 it++; 02245 } 02246 n = ex_to<numeric>(overall_coeff).normal(repl, rev_lookup, level-1); 02247 num.push_back(n.op(0)); 02248 den.push_back(n.op(1)); 02249 02250 // Perform fraction cancellation 02251 return frac_cancel((new mul(num))->setflag(status_flags::dynallocated), 02252 (new mul(den))->setflag(status_flags::dynallocated)); 02253 } 02254 02255 02260 ex power::normal(exmap & repl, exmap & rev_lookup, int level) const 02261 { 02262 if (level == 1) 02263 return (new lst(replace_with_symbol(*this, repl, rev_lookup), _ex1))->setflag(status_flags::dynallocated); 02264 else if (level == -max_recursion_level) 02265 throw(std::runtime_error("max recursion level reached")); 02266 02267 // Normalize basis and exponent (exponent gets reassembled) 02268 ex n_basis = ex_to<basic>(basis).normal(repl, rev_lookup, level-1); 02269 ex n_exponent = ex_to<basic>(exponent).normal(repl, rev_lookup, level-1); 02270 n_exponent = n_exponent.op(0) / n_exponent.op(1); 02271 02272 if (n_exponent.info(info_flags::integer)) { 02273 02274 if (n_exponent.info(info_flags::positive)) { 02275 02276 // (a/b)^n -> {a^n, b^n} 02277 return (new lst(power(n_basis.op(0), n_exponent), power(n_basis.op(1), n_exponent)))->setflag(status_flags::dynallocated); 02278 02279 } else if (n_exponent.info(info_flags::negative)) { 02280 02281 // (a/b)^-n -> {b^n, a^n} 02282 return (new lst(power(n_basis.op(1), -n_exponent), power(n_basis.op(0), -n_exponent)))->setflag(status_flags::dynallocated); 02283 } 02284 02285 } else { 02286 02287 if (n_exponent.info(info_flags::positive)) { 02288 02289 // (a/b)^x -> {sym((a/b)^x), 1} 02290 return (new lst(replace_with_symbol(power(n_basis.op(0) / n_basis.op(1), n_exponent), repl, rev_lookup), _ex1))->setflag(status_flags::dynallocated); 02291 02292 } else if (n_exponent.info(info_flags::negative)) { 02293 02294 if (n_basis.op(1).is_equal(_ex1)) { 02295 02296 // a^-x -> {1, sym(a^x)} 02297 return (new lst(_ex1, replace_with_symbol(power(n_basis.op(0), -n_exponent), repl, rev_lookup)))->setflag(status_flags::dynallocated); 02298 02299 } else { 02300 02301 // (a/b)^-x -> {sym((b/a)^x), 1} 02302 return (new lst(replace_with_symbol(power(n_basis.op(1) / n_basis.op(0), -n_exponent), repl, rev_lookup), _ex1))->setflag(status_flags::dynallocated); 02303 } 02304 } 02305 } 02306 02307 // (a/b)^x -> {sym((a/b)^x, 1} 02308 return (new lst(replace_with_symbol(power(n_basis.op(0) / n_basis.op(1), n_exponent), repl, rev_lookup), _ex1))->setflag(status_flags::dynallocated); 02309 } 02310 02311 02315 ex pseries::normal(exmap & repl, exmap & rev_lookup, int level) const 02316 { 02317 epvector newseq; 02318 epvector::const_iterator i = seq.begin(), end = seq.end(); 02319 while (i != end) { 02320 ex restexp = i->rest.normal(); 02321 if (!restexp.is_zero()) 02322 newseq.push_back(expair(restexp, i->coeff)); 02323 ++i; 02324 } 02325 ex n = pseries(relational(var,point), newseq); 02326 return (new lst(replace_with_symbol(n, repl, rev_lookup), _ex1))->setflag(status_flags::dynallocated); 02327 } 02328 02329 02342 ex ex::normal(int level) const 02343 { 02344 exmap repl, rev_lookup; 02345 02346 ex e = bp->normal(repl, rev_lookup, level); 02347 GINAC_ASSERT(is_a<lst>(e)); 02348 02349 // Re-insert replaced symbols 02350 if (!repl.empty()) 02351 e = e.subs(repl, subs_options::no_pattern); 02352 02353 // Convert {numerator, denominator} form back to fraction 02354 return e.op(0) / e.op(1); 02355 } 02356 02363 ex ex::numer() const 02364 { 02365 exmap repl, rev_lookup; 02366 02367 ex e = bp->normal(repl, rev_lookup, 0); 02368 GINAC_ASSERT(is_a<lst>(e)); 02369 02370 // Re-insert replaced symbols 02371 if (repl.empty()) 02372 return e.op(0); 02373 else 02374 return e.op(0).subs(repl, subs_options::no_pattern); 02375 } 02376 02383 ex ex::denom() const 02384 { 02385 exmap repl, rev_lookup; 02386 02387 ex e = bp->normal(repl, rev_lookup, 0); 02388 GINAC_ASSERT(is_a<lst>(e)); 02389 02390 // Re-insert replaced symbols 02391 if (repl.empty()) 02392 return e.op(1); 02393 else 02394 return e.op(1).subs(repl, subs_options::no_pattern); 02395 } 02396 02403 ex ex::numer_denom() const 02404 { 02405 exmap repl, rev_lookup; 02406 02407 ex e = bp->normal(repl, rev_lookup, 0); 02408 GINAC_ASSERT(is_a<lst>(e)); 02409 02410 // Re-insert replaced symbols 02411 if (repl.empty()) 02412 return e; 02413 else 02414 return e.subs(repl, subs_options::no_pattern); 02415 } 02416 02417 02431 ex ex::to_rational(exmap & repl) const 02432 { 02433 return bp->to_rational(repl); 02434 } 02435 02436 // GiNaC 1.1 compatibility function 02437 ex ex::to_rational(lst & repl_lst) const 02438 { 02439 // Convert lst to exmap 02440 exmap m; 02441 for (lst::const_iterator it = repl_lst.begin(); it != repl_lst.end(); ++it) 02442 m.insert(std::make_pair(it->op(0), it->op(1))); 02443 02444 ex ret = bp->to_rational(m); 02445 02446 // Convert exmap back to lst 02447 repl_lst.remove_all(); 02448 for (exmap::const_iterator it = m.begin(); it != m.end(); ++it) 02449 repl_lst.append(it->first == it->second); 02450 02451 return ret; 02452 } 02453 02454 ex ex::to_polynomial(exmap & repl) const 02455 { 02456 return bp->to_polynomial(repl); 02457 } 02458 02459 // GiNaC 1.1 compatibility function 02460 ex ex::to_polynomial(lst & repl_lst) const 02461 { 02462 // Convert lst to exmap 02463 exmap m; 02464 for (lst::const_iterator it = repl_lst.begin(); it != repl_lst.end(); ++it) 02465 m.insert(std::make_pair(it->op(0), it->op(1))); 02466 02467 ex ret = bp->to_polynomial(m); 02468 02469 // Convert exmap back to lst 02470 repl_lst.remove_all(); 02471 for (exmap::const_iterator it = m.begin(); it != m.end(); ++it) 02472 repl_lst.append(it->first == it->second); 02473 02474 return ret; 02475 } 02476 02479 ex basic::to_rational(exmap & repl) const 02480 { 02481 return replace_with_symbol(*this, repl); 02482 } 02483 02484 ex basic::to_polynomial(exmap & repl) const 02485 { 02486 return replace_with_symbol(*this, repl); 02487 } 02488 02489 02492 ex symbol::to_rational(exmap & repl) const 02493 { 02494 return *this; 02495 } 02496 02499 ex symbol::to_polynomial(exmap & repl) const 02500 { 02501 return *this; 02502 } 02503 02504 02508 ex numeric::to_rational(exmap & repl) const 02509 { 02510 if (is_real()) { 02511 if (!is_rational()) 02512 return replace_with_symbol(*this, repl); 02513 } else { // complex 02514 numeric re = real(); 02515 numeric im = imag(); 02516 ex re_ex = re.is_rational() ? re : replace_with_symbol(re, repl); 02517 ex im_ex = im.is_rational() ? im : replace_with_symbol(im, repl); 02518 return re_ex + im_ex * replace_with_symbol(I, repl); 02519 } 02520 return *this; 02521 } 02522 02526 ex numeric::to_polynomial(exmap & repl) const 02527 { 02528 if (is_real()) { 02529 if (!is_integer()) 02530 return replace_with_symbol(*this, repl); 02531 } else { // complex 02532 numeric re = real(); 02533 numeric im = imag(); 02534 ex re_ex = re.is_integer() ? re : replace_with_symbol(re, repl); 02535 ex im_ex = im.is_integer() ? im : replace_with_symbol(im, repl); 02536 return re_ex + im_ex * replace_with_symbol(I, repl); 02537 } 02538 return *this; 02539 } 02540 02541 02544 ex power::to_rational(exmap & repl) const 02545 { 02546 if (exponent.info(info_flags::integer)) 02547 return power(basis.to_rational(repl), exponent); 02548 else 02549 return replace_with_symbol(*this, repl); 02550 } 02551 02554 ex power::to_polynomial(exmap & repl) const 02555 { 02556 if (exponent.info(info_flags::posint)) 02557 return power(basis.to_rational(repl), exponent); 02558 else if (exponent.info(info_flags::negint)) 02559 { 02560 ex basis_pref = collect_common_factors(basis); 02561 if (is_exactly_a<mul>(basis_pref) || is_exactly_a<power>(basis_pref)) { 02562 // (A*B)^n will be automagically transformed to A^n*B^n 02563 ex t = power(basis_pref, exponent); 02564 return t.to_polynomial(repl); 02565 } 02566 else 02567 return power(replace_with_symbol(power(basis, _ex_1), repl), -exponent); 02568 } 02569 else 02570 return replace_with_symbol(*this, repl); 02571 } 02572 02573 02575 ex expairseq::to_rational(exmap & repl) const 02576 { 02577 epvector s; 02578 s.reserve(seq.size()); 02579 epvector::const_iterator i = seq.begin(), end = seq.end(); 02580 while (i != end) { 02581 s.push_back(split_ex_to_pair(recombine_pair_to_ex(*i).to_rational(repl))); 02582 ++i; 02583 } 02584 ex oc = overall_coeff.to_rational(repl); 02585 if (oc.info(info_flags::numeric)) 02586 return thisexpairseq(s, overall_coeff); 02587 else 02588 s.push_back(combine_ex_with_coeff_to_pair(oc, _ex1)); 02589 return thisexpairseq(s, default_overall_coeff()); 02590 } 02591 02593 ex expairseq::to_polynomial(exmap & repl) const 02594 { 02595 epvector s; 02596 s.reserve(seq.size()); 02597 epvector::const_iterator i = seq.begin(), end = seq.end(); 02598 while (i != end) { 02599 s.push_back(split_ex_to_pair(recombine_pair_to_ex(*i).to_polynomial(repl))); 02600 ++i; 02601 } 02602 ex oc = overall_coeff.to_polynomial(repl); 02603 if (oc.info(info_flags::numeric)) 02604 return thisexpairseq(s, overall_coeff); 02605 else 02606 s.push_back(combine_ex_with_coeff_to_pair(oc, _ex1)); 02607 return thisexpairseq(s, default_overall_coeff()); 02608 } 02609 02610 02614 static ex find_common_factor(const ex & e, ex & factor, exmap & repl) 02615 { 02616 if (is_exactly_a<add>(e)) { 02617 02618 size_t num = e.nops(); 02619 exvector terms; terms.reserve(num); 02620 ex gc; 02621 02622 // Find the common GCD 02623 for (size_t i=0; i<num; i++) { 02624 ex x = e.op(i).to_polynomial(repl); 02625 02626 if (is_exactly_a<add>(x) || is_exactly_a<mul>(x) || is_a<power>(x)) { 02627 ex f = 1; 02628 x = find_common_factor(x, f, repl); 02629 x *= f; 02630 } 02631 02632 if (i == 0) 02633 gc = x; 02634 else 02635 gc = gcd(gc, x); 02636 02637 terms.push_back(x); 02638 } 02639 02640 if (gc.is_equal(_ex1)) 02641 return e; 02642 02643 // The GCD is the factor we pull out 02644 factor *= gc; 02645 02646 // Now divide all terms by the GCD 02647 for (size_t i=0; i<num; i++) { 02648 ex x; 02649 02650 // Try to avoid divide() because it expands the polynomial 02651 ex &t = terms[i]; 02652 if (is_exactly_a<mul>(t)) { 02653 for (size_t j=0; j<t.nops(); j++) { 02654 if (t.op(j).is_equal(gc)) { 02655 exvector v; v.reserve(t.nops()); 02656 for (size_t k=0; k<t.nops(); k++) { 02657 if (k == j) 02658 v.push_back(_ex1); 02659 else 02660 v.push_back(t.op(k)); 02661 } 02662 t = (new mul(v))->setflag(status_flags::dynallocated); 02663 goto term_done; 02664 } 02665 } 02666 } 02667 02668 divide(t, gc, x); 02669 t = x; 02670 term_done: ; 02671 } 02672 return (new add(terms))->setflag(status_flags::dynallocated); 02673 02674 } else if (is_exactly_a<mul>(e)) { 02675 02676 size_t num = e.nops(); 02677 exvector v; v.reserve(num); 02678 02679 for (size_t i=0; i<num; i++) 02680 v.push_back(find_common_factor(e.op(i), factor, repl)); 02681 02682 return (new mul(v))->setflag(status_flags::dynallocated); 02683 02684 } else if (is_exactly_a<power>(e)) { 02685 const ex e_exp(e.op(1)); 02686 if (e_exp.info(info_flags::integer)) { 02687 ex eb = e.op(0).to_polynomial(repl); 02688 ex factor_local(_ex1); 02689 ex pre_res = find_common_factor(eb, factor_local, repl); 02690 factor *= power(factor_local, e_exp); 02691 return power(pre_res, e_exp); 02692 02693 } else 02694 return e.to_polynomial(repl); 02695 02696 } else 02697 return e; 02698 } 02699 02700 02703 ex collect_common_factors(const ex & e) 02704 { 02705 if (is_exactly_a<add>(e) || is_exactly_a<mul>(e) || is_exactly_a<power>(e)) { 02706 02707 exmap repl; 02708 ex factor = 1; 02709 ex r = find_common_factor(e, factor, repl); 02710 return factor.subs(repl, subs_options::no_pattern) * r.subs(repl, subs_options::no_pattern); 02711 02712 } else 02713 return e; 02714 } 02715 02716 02719 ex resultant(const ex & e1, const ex & e2, const ex & s) 02720 { 02721 const ex ee1 = e1.expand(); 02722 const ex ee2 = e2.expand(); 02723 if (!ee1.info(info_flags::polynomial) || 02724 !ee2.info(info_flags::polynomial)) 02725 throw(std::runtime_error("resultant(): arguments must be polynomials")); 02726 02727 const int h1 = ee1.degree(s); 02728 const int l1 = ee1.ldegree(s); 02729 const int h2 = ee2.degree(s); 02730 const int l2 = ee2.ldegree(s); 02731 02732 const int msize = h1 + h2; 02733 matrix m(msize, msize); 02734 02735 for (int l = h1; l >= l1; --l) { 02736 const ex e = ee1.coeff(s, l); 02737 for (int k = 0; k < h2; ++k) 02738 m(k, k+h1-l) = e; 02739 } 02740 for (int l = h2; l >= l2; --l) { 02741 const ex e = ee2.coeff(s, l); 02742 for (int k = 0; k < h1; ++k) 02743 m(k+h2, k+h2-l) = e; 02744 } 02745 02746 return m.determinant(); 02747 } 02748 02749 02750 } // namespace GiNaC