X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=blobdiff_plain;f=ginac%2Fnormal.cpp;h=a016a76bce4fb345dfea3bcd3aeccddd5fc8e68f;hp=f985573a5f6da669dba179ba91049f6b242c6cac;hb=b29bf684f84590c436c768a646b5c905ea530071;hpb=9961dfdd7a383f09b1040e195a8817a85d945e58 diff --git a/ginac/normal.cpp b/ginac/normal.cpp index f985573a..a016a76b 100644 --- a/ginac/normal.cpp +++ b/ginac/normal.cpp @@ -39,6 +39,7 @@ #include "numeric.h" #include "power.h" #include "relational.h" +#include "matrix.h" #include "pseries.h" #include "symbol.h" #include "utils.h" @@ -228,7 +229,7 @@ static void get_symbol_stats(const ex &a, const ex &b, sym_desc_vec &v) static numeric lcmcoeff(const ex &e, const numeric &l) { if (e.info(info_flags::rational)) - return lcm(ex_to_numeric(e).denom(), l); + return lcm(ex_to(e).denom(), l); else if (is_ex_exactly_of_type(e, add)) { numeric c = _num1(); for (unsigned i=0; i(e.op(1))); } return l; } @@ -268,25 +269,27 @@ static numeric lcm_of_coefficients_denominators(const ex &e) static ex multiply_lcm(const ex &e, const numeric &lcm) { if (is_ex_exactly_of_type(e, mul)) { - ex c = _ex1(); + unsigned num = e.nops(); + exvector v; v.reserve(num + 1); numeric lcm_accum = _num1(); for (unsigned i=0; isetflag(status_flags::dynallocated); } else if (is_ex_exactly_of_type(e, add)) { - ex c = _ex0(); - for (unsigned i=0; isetflag(status_flags::dynallocated); } else if (is_ex_exactly_of_type(e, power)) { if (is_ex_exactly_of_type(e.op(0), symbol)) return e * lcm; else - return pow(multiply_lcm(e.op(0), lcm.power(ex_to_numeric(e.op(1)).inverse())), e.op(1)); + return pow(multiply_lcm(e.op(0), lcm.power(ex_to(e.op(1)).inverse())), e.op(1)); } else return e * lcm; } @@ -321,11 +324,11 @@ numeric add::integer_content(void) const while (it != itend) { GINAC_ASSERT(!is_ex_exactly_of_type(it->rest,numeric)); GINAC_ASSERT(is_ex_exactly_of_type(it->coeff,numeric)); - c = gcd(ex_to_numeric(it->coeff), c); + c = gcd(ex_to(it->coeff), c); it++; } GINAC_ASSERT(is_ex_exactly_of_type(overall_coeff,numeric)); - c = gcd(ex_to_numeric(overall_coeff),c); + c = gcd(ex_to(overall_coeff),c); return c; } @@ -340,7 +343,7 @@ numeric mul::integer_content(void) const } #endif // def DO_GINAC_ASSERT GINAC_ASSERT(is_ex_exactly_of_type(overall_coeff,numeric)); - return abs(ex_to_numeric(overall_coeff)); + return abs(ex_to(overall_coeff)); } @@ -371,7 +374,6 @@ ex quo(const ex &a, const ex &b, const symbol &x, bool check_args) throw(std::invalid_argument("quo: arguments must be polynomials over the rationals")); // Polynomial long division - ex q = _ex0(); ex r = a.expand(); if (r.is_zero()) return r; @@ -379,6 +381,7 @@ ex quo(const ex &a, const ex &b, const symbol &x, bool check_args) int rdeg = r.degree(x); ex blcoeff = b.expand().coeff(x, bdeg); bool blcoeff_is_numeric = is_ex_exactly_of_type(blcoeff, numeric); + exvector v; v.reserve(rdeg - bdeg + 1); while (rdeg >= bdeg) { ex term, rcoeff = r.coeff(x, rdeg); if (blcoeff_is_numeric) @@ -388,13 +391,13 @@ ex quo(const ex &a, const ex &b, const symbol &x, bool check_args) return (new fail())->setflag(status_flags::dynallocated); } term *= power(x, rdeg - bdeg); - q += term; + v.push_back(term); r -= (term * b).expand(); if (r.is_zero()) break; rdeg = r.degree(x); } - return q; + return (new add(v))->setflag(status_flags::dynallocated); } @@ -415,7 +418,7 @@ ex rem(const ex &a, const ex &b, const symbol &x, bool check_args) if (is_ex_exactly_of_type(b, numeric)) return _ex0(); else - return b; + return a; } #if FAST_COMPARE if (a.is_equal(b)) @@ -450,6 +453,24 @@ ex rem(const ex &a, const ex &b, const symbol &x, bool check_args) } +/** Decompose rational function a(x)=N(x)/D(x) into P(x)+n(x)/D(x) + * with degree(n, x) < degree(D, x). + * + * @param a rational function in x + * @param x a is a function of x + * @return decomposed function. */ +ex decomp_rational(const ex &a, const symbol &x) +{ + ex nd = numer_denom(a); + ex numer = nd.op(0), denom = nd.op(1); + ex q = quo(numer, denom, x); + if (is_ex_exactly_of_type(q, fail)) + return a; + else + return q + rem(numer, denom, x) / denom; +} + + /** Pseudo-remainder of polynomials a(x) and b(x) in Z[x]. * * @param a first polynomial in x (dividend) @@ -510,7 +531,6 @@ ex prem(const ex &a, const ex &b, const symbol &x, bool check_args) * @param check_args check whether a and b are polynomials with rational * coefficients (defaults to "true") * @return sparse pseudo-remainder of a(x) and b(x) in Z[x] */ - ex sprem(const ex &a, const ex &b, const symbol &x, bool check_args) { if (b.is_zero()) @@ -597,6 +617,7 @@ bool divide(const ex &a, const ex &b, ex &q, bool check_args) int rdeg = r.degree(*x); ex blcoeff = b.expand().coeff(*x, bdeg); bool blcoeff_is_numeric = is_ex_exactly_of_type(blcoeff, numeric); + exvector v; v.reserve(rdeg - bdeg + 1); while (rdeg >= bdeg) { ex term, rcoeff = r.coeff(*x, rdeg); if (blcoeff_is_numeric) @@ -605,10 +626,12 @@ bool divide(const ex &a, const ex &b, ex &q, bool check_args) if (!divide(rcoeff, blcoeff, term, false)) return false; term *= power(*x, rdeg - bdeg); - q += term; + v.push_back(term); r -= (term * b).expand(); - if (r.is_zero()) + if (r.is_zero()) { + q = (new add(v))->setflag(status_flags::dynallocated); return true; + } rdeg = r.degree(*x); } return false; @@ -755,14 +778,16 @@ static bool divide_in_z(const ex &a, const ex &b, ex &q, sym_desc_vec::const_ite int rdeg = adeg; ex eb = b.expand(); ex blcoeff = eb.coeff(*x, bdeg); + exvector v; v.reserve(rdeg - bdeg + 1); while (rdeg >= bdeg) { ex term, rcoeff = r.coeff(*x, rdeg); if (!divide_in_z(rcoeff, blcoeff, term, var+1)) break; term = (term * power(*x, rdeg - bdeg)).expand(); - q += term; + v.push_back(term); r -= (term * eb).expand(); if (r.is_zero()) { + q = (new add(v))->setflag(status_flags::dynallocated); #if USE_REMEMBER dr_remember[ex2(a, b)] = exbool(q, true); #endif @@ -1204,11 +1229,11 @@ numeric add::max_coefficient(void) const epvector::const_iterator it = seq.begin(); epvector::const_iterator itend = seq.end(); GINAC_ASSERT(is_ex_exactly_of_type(overall_coeff,numeric)); - numeric cur_max = abs(ex_to_numeric(overall_coeff)); + numeric cur_max = abs(ex_to(overall_coeff)); while (it != itend) { numeric a; GINAC_ASSERT(!is_ex_exactly_of_type(it->rest,numeric)); - a = abs(ex_to_numeric(it->coeff)); + a = abs(ex_to(it->coeff)); if (a > cur_max) cur_max = a; it++; @@ -1227,7 +1252,7 @@ numeric mul::max_coefficient(void) const } #endif // def DO_GINAC_ASSERT GINAC_ASSERT(is_ex_exactly_of_type(overall_coeff,numeric)); - return abs(ex_to_numeric(overall_coeff)); + return abs(ex_to(overall_coeff)); } @@ -1262,13 +1287,13 @@ ex add::smod(const numeric &xi) const epvector::const_iterator itend = seq.end(); while (it != itend) { GINAC_ASSERT(!is_ex_exactly_of_type(it->rest,numeric)); - numeric coeff = GiNaC::smod(ex_to_numeric(it->coeff), xi); + numeric coeff = GiNaC::smod(ex_to(it->coeff), xi); if (!coeff.is_zero()) newseq.push_back(expair(it->rest, coeff)); it++; } GINAC_ASSERT(is_ex_exactly_of_type(overall_coeff,numeric)); - numeric coeff = GiNaC::smod(ex_to_numeric(overall_coeff), xi); + numeric coeff = GiNaC::smod(ex_to(overall_coeff), xi); return (new add(newseq,coeff))->setflag(status_flags::dynallocated); } @@ -1284,7 +1309,7 @@ ex mul::smod(const numeric &xi) const #endif // def DO_GINAC_ASSERT mul * mulcopyp = new mul(*this); GINAC_ASSERT(is_ex_exactly_of_type(overall_coeff,numeric)); - mulcopyp->overall_coeff = GiNaC::smod(ex_to_numeric(overall_coeff),xi); + mulcopyp->overall_coeff = GiNaC::smod(ex_to(overall_coeff),xi); mulcopyp->clearflag(status_flags::evaluated); mulcopyp->clearflag(status_flags::hash_calculated); return mulcopyp->setflag(status_flags::dynallocated); @@ -1292,17 +1317,17 @@ ex mul::smod(const numeric &xi) const /** xi-adic polynomial interpolation */ -static ex interpolate(const ex &gamma, const numeric &xi, const symbol &x) +static ex interpolate(const ex &gamma, const numeric &xi, const symbol &x, int degree_hint = 1) { - ex g = _ex0(); + exvector g; g.reserve(degree_hint); ex e = gamma; numeric rxi = xi.inverse(); for (int i=0; !e.is_zero(); i++) { ex gi = e.smod(xi); - g += gi * power(x, i); + g.push_back(gi * power(x, i)); e = (e - gi) * rxi; } - return g; + return (new add(g))->setflag(status_flags::dynallocated); } /** Exception thrown by heur_gcd() to signal failure. */ @@ -1330,17 +1355,17 @@ static ex heur_gcd(const ex &a, const ex &b, ex *ca, ex *cb, sym_desc_vec::const heur_gcd_called++; #endif - // Algorithms only works for non-vanishing input polynomials + // Algorithm only works for non-vanishing input polynomials if (a.is_zero() || b.is_zero()) return (new fail())->setflag(status_flags::dynallocated); // GCD of two numeric values -> CLN if (is_ex_exactly_of_type(a, numeric) && is_ex_exactly_of_type(b, numeric)) { - numeric g = gcd(ex_to_numeric(a), ex_to_numeric(b)); + numeric g = gcd(ex_to(a), ex_to(b)); if (ca) - *ca = ex_to_numeric(a) / g; + *ca = ex_to(a) / g; if (cb) - *cb = ex_to_numeric(b) / g; + *cb = ex_to(b) / g; return g; } @@ -1352,7 +1377,7 @@ static ex heur_gcd(const ex &a, const ex &b, ex *ca, ex *cb, sym_desc_vec::const numeric rgc = gc.inverse(); ex p = a * rgc; ex q = b * rgc; - int maxdeg = std::max(p.degree(x),q.degree(x)); + int maxdeg = std::max(p.degree(x), q.degree(x)); // Find evaluation point numeric mp = p.max_coefficient(); @@ -1376,7 +1401,7 @@ static ex heur_gcd(const ex &a, const ex &b, ex *ca, ex *cb, sym_desc_vec::const if (!is_ex_exactly_of_type(gamma, fail)) { // Reconstruct polynomial from GCD of mapped polynomials - ex g = interpolate(gamma, xi, x); + ex g = interpolate(gamma, xi, x, maxdeg); // Remove integer content g /= g.integer_content(); @@ -1386,7 +1411,7 @@ static ex heur_gcd(const ex &a, const ex &b, ex *ca, ex *cb, sym_desc_vec::const if (divide_in_z(p, g, ca ? *ca : dummy, var) && divide_in_z(q, g, cb ? *cb : dummy, var)) { g *= gc; ex lc = g.lcoeff(x); - if (is_ex_exactly_of_type(lc, numeric) && ex_to_numeric(lc).is_negative()) + if (is_ex_exactly_of_type(lc, numeric) && ex_to(lc).is_negative()) return -g; else return g; @@ -1399,7 +1424,7 @@ static ex heur_gcd(const ex &a, const ex &b, ex *ca, ex *cb, sym_desc_vec::const if (ca) *ca = cp; ex lc = g.lcoeff(x); - if (is_ex_exactly_of_type(lc, numeric) && ex_to_numeric(lc).is_negative()) + if (is_ex_exactly_of_type(lc, numeric) && ex_to(lc).is_negative()) return -g; else return g; @@ -1412,7 +1437,7 @@ static ex heur_gcd(const ex &a, const ex &b, ex *ca, ex *cb, sym_desc_vec::const if (cb) *cb = cq; ex lc = g.lcoeff(x); - if (is_ex_exactly_of_type(lc, numeric) && ex_to_numeric(lc).is_negative()) + if (is_ex_exactly_of_type(lc, numeric) && ex_to(lc).is_negative()) return -g; else return g; @@ -1445,7 +1470,7 @@ ex gcd(const ex &a, const ex &b, ex *ca, ex *cb, bool check_args) // GCD of numerics -> CLN if (is_ex_exactly_of_type(a, numeric) && is_ex_exactly_of_type(b, numeric)) { - numeric g = gcd(ex_to_numeric(a), ex_to_numeric(b)); + numeric g = gcd(ex_to(a), ex_to(b)); if (ca || cb) { if (g.is_zero()) { if (ca) @@ -1454,9 +1479,9 @@ ex gcd(const ex &a, const ex &b, ex *ca, ex *cb, bool check_args) *cb = _ex0(); } else { if (ca) - *ca = ex_to_numeric(a) / g; + *ca = ex_to(a) / g; if (cb) - *cb = ex_to_numeric(b) / g; + *cb = ex_to(b) / g; } } return g; @@ -1472,38 +1497,40 @@ ex gcd(const ex &a, const ex &b, ex *ca, ex *cb, bool check_args) if (is_ex_exactly_of_type(b, mul) && b.nops() > a.nops()) goto factored_b; factored_a: - ex g = _ex1(); - ex acc_ca = _ex1(); + unsigned num = a.nops(); + exvector g; g.reserve(num); + exvector acc_ca; acc_ca.reserve(num); ex part_b = b; - for (unsigned i=0; isetflag(status_flags::dynallocated); if (cb) *cb = part_b; - return g; + return (new mul(g))->setflag(status_flags::dynallocated); } else if (is_ex_exactly_of_type(b, mul)) { if (is_ex_exactly_of_type(a, mul) && a.nops() > b.nops()) goto factored_a; factored_b: - ex g = _ex1(); - ex acc_cb = _ex1(); + unsigned num = b.nops(); + exvector g; g.reserve(num); + exvector acc_cb; acc_cb.reserve(num); ex part_a = a; - for (unsigned i=0; isetflag(status_flags::dynallocated); + return (new mul(g))->setflag(status_flags::dynallocated); } #if FAST_COMPARE @@ -1676,7 +1703,7 @@ factored_b: ex lcm(const ex &a, const ex &b, bool check_args) { if (is_ex_exactly_of_type(a, numeric) && is_ex_exactly_of_type(b, numeric)) - return lcm(ex_to_numeric(a), ex_to_numeric(b)); + return lcm(ex_to(a), ex_to(b)); if (check_args && (!a.info(info_flags::rational_polynomial) || !b.info(info_flags::rational_polynomial))) throw(std::invalid_argument("lcm: arguments must be polynomials over the rationals")); @@ -1717,6 +1744,7 @@ static exvector sqrfree_yun(const ex &a, const symbol &x) } while (!z.is_zero()); return res; } + /** Compute square-free factorization of multivariate polynomial in Q[X]. * * @param a multivariate polynomial over Q[X] @@ -1742,7 +1770,7 @@ ex sqrfree(const ex &a, const lst &l) // Find the symbol to factor in at this stage if (!is_ex_of_type(args.op(0), symbol)) throw (std::runtime_error("sqrfree(): invalid factorization variable")); - const symbol x = ex_to_symbol(args.op(0)); + const symbol x = ex_to(args.op(0)); // convert the argument from something in Q[X] to something in Z[X] numeric lcm = lcm_of_coefficients_denominators(a); ex tmp = multiply_lcm(a,lcm); @@ -1769,6 +1797,75 @@ ex sqrfree(const ex &a, const lst &l) return result * lcm.inverse(); } +/** Compute square-free partial fraction decomposition of rational function + * a(x). + * + * @param a rational function over Z[x], treated as univariate polynomial + * in x + * @param x variable to factor in + * @return decomposed rational function */ +ex sqrfree_parfrac(const ex & a, const symbol & x) +{ + // Find numerator and denominator + ex nd = numer_denom(a); + ex numer = nd.op(0), denom = nd.op(1); +//clog << "numer = " << numer << ", denom = " << denom << endl; + + // Convert N(x)/D(x) -> Q(x) + R(x)/D(x), so degree(R) < degree(D) + ex red_poly = quo(numer, denom, x), red_numer = rem(numer, denom, x).expand(); +//clog << "red_poly = " << red_poly << ", red_numer = " << red_numer << endl; + + // Factorize denominator and compute cofactors + exvector yun = sqrfree_yun(denom, x); +//clog << "yun factors: " << exprseq(yun) << endl; + int num_yun = yun.size(); + exvector factor; factor.reserve(num_yun); + exvector cofac; cofac.reserve(num_yun); + for (unsigned i=0; isetflag(status_flags::dynallocated); + if (nops() == 0) + return (new lst(replace_with_symbol(*this, sym_lst, repl_lst), _ex1()))->setflag(status_flags::dynallocated); + else { + if (level == 1) + return (new lst(replace_with_symbol(*this, sym_lst, repl_lst), _ex1()))->setflag(status_flags::dynallocated); + else if (level == -max_recursion_level) + throw(std::runtime_error("max recursion level reached")); + else { + normal_map_function map_normal(level - 1); + return (new lst(replace_with_symbol(map(map_normal), sym_lst, repl_lst), _ex1()))->setflag(status_flags::dynallocated); + } + } } @@ -1908,7 +2025,7 @@ static ex frac_cancel(const ex &n, const ex &d) const symbol *x; if (get_first_symbol(den, x)) { GINAC_ASSERT(is_ex_exactly_of_type(den.unit(*x),numeric)); - if (ex_to_numeric(den.unit(*x)).is_negative()) { + if (ex_to(den.unit(*x)).is_negative()) { num *= _ex_1(); den *= _ex_1(); } @@ -1990,22 +2107,23 @@ ex mul::normal(lst &sym_lst, lst &repl_lst, int level) const throw(std::runtime_error("max recursion level reached")); // Normalize children, separate into numerator and denominator - ex num = _ex1(); - ex den = _ex1(); + exvector num; num.reserve(seq.size()); + exvector den; den.reserve(seq.size()); ex n; epvector::const_iterator it = seq.begin(), itend = seq.end(); while (it != itend) { n = recombine_pair_to_ex(*it).bp->normal(sym_lst, repl_lst, level-1); - num *= n.op(0); - den *= n.op(1); + num.push_back(n.op(0)); + den.push_back(n.op(1)); it++; } n = overall_coeff.bp->normal(sym_lst, repl_lst, level-1); - num *= n.op(0); - den *= n.op(1); + num.push_back(n.op(0)); + den.push_back(n.op(1)); // Perform fraction cancellation - return frac_cancel(num, den); + return frac_cancel((new mul(num))->setflag(status_flags::dynallocated), + (new mul(den))->setflag(status_flags::dynallocated)); } @@ -2083,14 +2201,6 @@ ex pseries::normal(lst &sym_lst, lst &repl_lst, int level) const } -/** Implementation of ex::normal() for relationals. It normalizes both sides. - * @see ex::normal */ -ex relational::normal(lst &sym_lst, lst &repl_lst, int level) const -{ - return (new lst(relational(lh.normal(), rh.normal(), o), _ex1()))->setflag(status_flags::dynallocated); -} - - /** Normalization of rational functions. * This function converts an expression to its normal form * "numerator/denominator", where numerator and denominator are (relatively