GiNaC  1.6.2
normal.cpp
Go to the documentation of this file.
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

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