X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=blobdiff_plain;f=ginac%2Fnormal.cpp;h=7a52c71d2914d331a0be314dd100a9e46dc155e6;hp=9c9082acc3c87251a4d66edb05245509d66382c3;hb=1566be23d91ed1311bee2071bdae9ef93d0b7cf6;hpb=d19df5c2498b59e53200bcb92f1d91ff0b77fd12 diff --git a/ginac/normal.cpp b/ginac/normal.cpp index 9c9082ac..7a52c71d 100644 --- a/ginac/normal.cpp +++ b/ginac/normal.cpp @@ -36,10 +36,10 @@ #include "inifcns.h" #include "lst.h" #include "mul.h" -#include "ncmul.h" #include "numeric.h" #include "power.h" #include "relational.h" +#include "matrix.h" #include "pseries.h" #include "symbol.h" #include "utils.h" @@ -155,11 +155,11 @@ typedef std::vector sym_desc_vec; // Add symbol the sym_desc_vec (used internally by get_symbol_stats()) static void add_symbol(const symbol *s, sym_desc_vec &v) { - sym_desc_vec::iterator it = v.begin(), itend = v.end(); + sym_desc_vec::const_iterator it = v.begin(), itend = v.end(); while (it != itend) { if (it->sym->compare(*s) == 0) // If it's already in there, don't add it a second time return; - it++; + ++it; } sym_desc d; d.sym = s; @@ -205,16 +205,16 @@ static void get_symbol_stats(const ex &a, const ex &b, sym_desc_vec &v) it->max_lcnops = std::max(a.lcoeff(*(it->sym)).nops(), b.lcoeff(*(it->sym)).nops()); it->ldeg_a = a.ldegree(*(it->sym)); it->ldeg_b = b.ldegree(*(it->sym)); - it++; + ++it; } - sort(v.begin(), v.end()); + std::sort(v.begin(), v.end()); #if 0 std::clog << "Symbols:\n"; it = v.begin(); itend = v.end(); while (it != itend) { 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; std::clog << " lcoeff_a=" << a.lcoeff(*(it->sym)) << ", lcoeff_b=" << b.lcoeff(*(it->sym)) << endl; - it++; + ++it; } #endif } @@ -229,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; } @@ -269,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; } @@ -322,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; } @@ -341,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)); } @@ -372,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; @@ -380,22 +381,23 @@ 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) term = rcoeff / blcoeff; else { if (!divide(rcoeff, blcoeff, term, false)) - return *new ex(fail()); + 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); } @@ -416,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)) @@ -439,7 +441,7 @@ ex rem(const ex &a, const ex &b, const symbol &x, bool check_args) term = rcoeff / blcoeff; else { if (!divide(rcoeff, blcoeff, term, false)) - return *new ex(fail()); + return (new fail())->setflag(status_flags::dynallocated); } term *= power(x, rdeg - bdeg); r -= (term * b).expand(); @@ -451,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) @@ -511,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()) @@ -598,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) @@ -606,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; @@ -756,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 @@ -1205,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++; @@ -1228,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)); } @@ -1263,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); } @@ -1283,9 +1307,9 @@ ex mul::smod(const numeric &xi) const it++; } #endif // def DO_GINAC_ASSERT - mul * mulcopyp=new mul(*this); + 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); @@ -1293,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. */ @@ -1331,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 ex(fail()); + 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; } @@ -1353,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(); @@ -1367,7 +1391,7 @@ static ex heur_gcd(const ex &a, const ex &b, ex *ca, ex *cb, sym_desc_vec::const // 6 tries maximum for (int t=0; t<6; t++) { if (xi.int_length() * maxdeg > 100000) { -//std::clog << "giving up heur_gcd, xi.int_length = " << xi.int_length() << ", maxdeg = " << maxdeg << endl; +//std::clog << "giving up heur_gcd, xi.int_length = " << xi.int_length() << ", maxdeg = " << maxdeg << std::endl; throw gcdheu_failed(); } @@ -1377,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(); @@ -1387,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; @@ -1400,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; @@ -1413,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; @@ -1425,7 +1449,7 @@ static ex heur_gcd(const ex &a, const ex &b, ex *ca, ex *cb, sym_desc_vec::const // Next evaluation point xi = iquo(xi * isqrt(isqrt(xi)) * numeric(73794), numeric(27011)); } - return *new ex(fail()); + return (new fail())->setflag(status_flags::dynallocated); } @@ -1446,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) @@ -1455,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; @@ -1473,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 @@ -1599,20 +1625,20 @@ factored_b: int min_ldeg = std::min(ldeg_a,ldeg_b); if (min_ldeg > 0) { ex common = power(x, min_ldeg); -//std::clog << "trivial common factor " << common << endl; +//std::clog << "trivial common factor " << common << std::endl; return gcd((aex / common).expand(), (bex / common).expand(), ca, cb, false) * common; } // Try to eliminate variables if (var->deg_a == 0) { -//std::clog << "eliminating variable " << x << " from b" << endl; +//std::clog << "eliminating variable " << x << " from b" << std::endl; ex c = bex.content(x); ex g = gcd(aex, c, ca, cb, false); if (cb) *cb *= bex.unit(x) * bex.primpart(x, c); return g; } else if (var->deg_b == 0) { -//std::clog << "eliminating variable " << x << " from a" << endl; +//std::clog << "eliminating variable " << x << " from a" << std::endl; ex c = aex.content(x); ex g = gcd(c, bex, ca, cb, false); if (ca) @@ -1626,10 +1652,10 @@ factored_b: try { g = heur_gcd(aex, bex, ca, cb, var); } catch (gcdheu_failed) { - g = *new ex(fail()); + g = fail(); } if (is_ex_exactly_of_type(g, fail)) { -//std::clog << "heuristics failed" << endl; +//std::clog << "heuristics failed" << std::endl; #if STATISTICS heur_gcd_failed++; #endif @@ -1677,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")); @@ -1718,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] @@ -1728,6 +1755,7 @@ ex sqrfree(const ex &a, const lst &l) if (is_ex_of_type(a,numeric) || // algorithm does not trap a==0 is_ex_of_type(a,symbol)) // shortcut return a; + // If no lst of variables to factorize in was specified we have to // invent one now. Maybe one can optimize here by reversing the order // or so, I don't know. @@ -1735,34 +1763,46 @@ ex sqrfree(const ex &a, const lst &l) if (l.nops()==0) { sym_desc_vec sdv; get_symbol_stats(a, _ex0(), sdv); - for (sym_desc_vec::iterator it=sdv.begin(); it!=sdv.end(); ++it) + sym_desc_vec::const_iterator it = sdv.begin(), itend = sdv.end(); + while (it != itend) { args.append(*it->sym); + ++it; + } } else { args = 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); + // find the factors exvector factors = sqrfree_yun(tmp,x); + // construct the next list of symbols with the first element popped - lst newargs; - for (int i=1; i0) { - for (exvector::iterator i=factors.begin(); i!=factors.end(); ++i) + exvector::iterator i = factors.begin(), end = factors.end(); + while (i != end) { *i = sqrfree(*i, newargs); + ++i; + } } + // Done with recursion, now construct the final result ex result = _ex1(); - exvector::iterator it = factors.begin(); - for (int p = 1; it!=factors.end(); ++it, ++p) + exvector::const_iterator it = factors.begin(), itend = factors.end(); + for (int p = 1; it!=itend; ++it, ++p) result *= power(*it, p); + // Yun's algorithm does not account for constant factors. (For // univariate polynomials it works only in the monic case.) We can // correct this by inserting what has been lost back into the result: @@ -1770,6 +1810,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; + unsigned 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); + } + } } @@ -1877,7 +2006,7 @@ static ex frac_cancel(const ex &n, const ex &d) ex den = d; numeric pre_factor = _num1(); -//std::clog << "frac_cancel num = " << num << ", den = " << den << endl; +//std::clog << "frac_cancel num = " << num << ", den = " << den << std::endl; // Handle trivial case where denominator is 1 if (den.is_equal(_ex1())) @@ -1909,14 +2038,14 @@ 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(); } } // Return result as list -//std::clog << " returns num = " << num << ", den = " << den << ", pre_factor = " << pre_factor << endl; +//std::clog << " returns num = " << num << ", den = " << den << ", pre_factor = " << pre_factor << std::endl; return (new lst(num * pre_factor.numer(), den * pre_factor.denom()))->setflag(status_flags::dynallocated); } @@ -1954,10 +2083,10 @@ ex add::normal(lst &sym_lst, lst &repl_lst, int level) const // Add fractions sequentially exvector::const_iterator num_it = nums.begin(), num_itend = nums.end(); exvector::const_iterator den_it = dens.begin(), den_itend = dens.end(); -//std::clog << " num = " << *num_it << ", den = " << *den_it << endl; +//std::clog << " num = " << *num_it << ", den = " << *den_it << std::endl; ex num = *num_it++, den = *den_it++; while (num_it != num_itend) { -//std::clog << " num = " << *num_it << ", den = " << *den_it << endl; +//std::clog << " num = " << *num_it << ", den = " << *den_it << std::endl; ex next_num = *num_it++, next_den = *den_it++; // Trivially add sequences of fractions with identical denominators @@ -1973,7 +2102,7 @@ ex add::normal(lst &sym_lst, lst &repl_lst, int level) const num = ((num * co_den2) + (next_num * co_den1)).expand(); den *= co_den2; // this is the lcm(den, next_den) } -//std::clog << " common denominator = " << den << endl; +//std::clog << " common denominator = " << den << std::endl; // Cancel common factors from num/den return frac_cancel(num, den); @@ -1991,22 +2120,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)); } @@ -2074,24 +2204,18 @@ ex power::normal(lst &sym_lst, lst &repl_lst, int level) const ex pseries::normal(lst &sym_lst, lst &repl_lst, int level) const { epvector newseq; - for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) { + epvector::const_iterator i = seq.begin(), end = seq.end(); + while (i != end) { ex restexp = i->rest.normal(); if (!restexp.is_zero()) newseq.push_back(expair(restexp, i->coeff)); + ++i; } ex n = pseries(relational(var,point), newseq); return (new lst(replace_with_symbol(n, sym_lst, repl_lst), _ex1()))->setflag(status_flags::dynallocated); } -/** 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 @@ -2119,9 +2243,9 @@ ex ex::normal(int level) const return e.op(0) / e.op(1); } -/** Numerator of an expression. If the expression is not of the normal form - * "numerator/denominator", it is first converted to this form and then the - * numerator is returned. +/** Get numerator of an expression. If the expression is not of the normal + * form "numerator/denominator", it is first converted to this form and + * then the numerator is returned. * * @see ex::normal * @return numerator */ @@ -2139,9 +2263,9 @@ ex ex::numer(void) const return e.op(0); } -/** Denominator of an expression. If the expression is not of the normal form - * "numerator/denominator", it is first converted to this form and then the - * denominator is returned. +/** Get denominator of an expression. If the expression is not of the normal + * form "numerator/denominator", it is first converted to this form and + * then the denominator is returned. * * @see ex::normal * @return denominator */ @@ -2159,6 +2283,26 @@ ex ex::denom(void) const return e.op(1); } +/** Get numerator and denominator of an expression. If the expresison is not + * of the normal form "numerator/denominator", it is first converted to this + * form and then a list [numerator, denominator] is returned. + * + * @see ex::normal + * @return a list [numerator, denominator] */ +ex ex::numer_denom(void) const +{ + lst sym_lst, repl_lst; + + ex e = bp->normal(sym_lst, repl_lst, 0); + GINAC_ASSERT(is_ex_of_type(e, lst)); + + // Re-insert replaced symbols + if (sym_lst.nops() > 0) + return e.subs(sym_lst, repl_lst); + else + return e; +} + /** Default implementation of ex::to_rational(). It replaces the object with a * temporary symbol. @@ -2216,14 +2360,16 @@ ex expairseq::to_rational(lst &repl_lst) const { epvector s; s.reserve(seq.size()); - for (epvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) { - s.push_back(split_ex_to_pair(recombine_pair_to_ex(*it).to_rational(repl_lst))); - // s.push_back(combine_ex_with_coeff_to_pair((*it).rest.to_rational(repl_lst), + epvector::const_iterator i = seq.begin(), end = seq.end(); + while (i != end) { + s.push_back(split_ex_to_pair(recombine_pair_to_ex(*i).to_rational(repl_lst))); + ++i; } ex oc = overall_coeff.to_rational(repl_lst); if (oc.info(info_flags::numeric)) return thisexpairseq(s, overall_coeff); - else s.push_back(combine_ex_with_coeff_to_pair(oc,_ex1())); + else + s.push_back(combine_ex_with_coeff_to_pair(oc, _ex1())); return thisexpairseq(s, default_overall_coeff()); }