X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=blobdiff_plain;f=ginac%2Fnormal.cpp;h=610c48d6a2653bd9945ce35862b5e59e7f2f66da;hp=f123be2060c4fc4451c42f759648768141a7cbf6;hb=b3f0d2416a7a0195446e410ebba10ec2c51cbd37;hpb=27d6204effdef95a00af461fff98024e290dbaa7 diff --git a/ginac/normal.cpp b/ginac/normal.cpp index f123be20..610c48d6 100644 --- a/ginac/normal.cpp +++ b/ginac/normal.cpp @@ -6,7 +6,7 @@ * computation, square-free factorization and rational function normalization. */ /* - * GiNaC Copyright (C) 1999-2001 Johannes Gutenberg University Mainz, Germany + * GiNaC Copyright (C) 1999-2002 Johannes Gutenberg University Mainz, Germany * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -74,10 +74,10 @@ static int heur_gcd_failed = 0; static struct _stat_print { _stat_print() {} ~_stat_print() { - cout << "gcd() called " << gcd_called << " times\n"; - cout << "sr_gcd() called " << sr_gcd_called << " times\n"; - cout << "heur_gcd() called " << heur_gcd_called << " times\n"; - cout << "heur_gcd() failed " << heur_gcd_failed << " times\n"; + std::cout << "gcd() called " << gcd_called << " times\n"; + std::cout << "sr_gcd() called " << sr_gcd_called << " times\n"; + std::cout << "heur_gcd() called " << heur_gcd_called << " times\n"; + std::cout << "heur_gcd() failed " << heur_gcd_failed << " times\n"; } } stat_print; #endif @@ -381,7 +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); + exvector v; v.reserve(std::max(rdeg - bdeg + 1, 0)); while (rdeg >= bdeg) { ex term, rcoeff = r.coeff(x, rdeg); if (blcoeff_is_numeric) @@ -581,14 +581,15 @@ ex sprem(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 "true" when exact division succeeds (quotient returned in q), - * "false" otherwise */ + * "false" otherwise (q left untouched) */ bool divide(const ex &a, const ex &b, ex &q, bool check_args) { - q = _ex0; if (b.is_zero()) throw(std::overflow_error("divide: division by zero")); - if (a.is_zero()) + if (a.is_zero()) { + q = _ex0; return true; + } if (is_ex_exactly_of_type(b, numeric)) { q = a / b; return true; @@ -611,13 +612,15 @@ bool divide(const ex &a, const ex &b, ex &q, bool check_args) // Polynomial long division (recursive) ex r = a.expand(); - if (r.is_zero()) + if (r.is_zero()) { + q = _ex0; return true; + } int bdeg = b.degree(*x); 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); + exvector v; v.reserve(std::max(rdeg - bdeg + 1, 0)); while (rdeg >= bdeg) { ex term, rcoeff = r.coeff(*x, rdeg); if (blcoeff_is_numeric) @@ -778,7 +781,7 @@ 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); + exvector v; v.reserve(std::max(rdeg - bdeg + 1, 0)); while (rdeg >= bdeg) { ex term, rcoeff = r.coeff(*x, rdeg); if (!divide_in_z(rcoeff, blcoeff, term, var+1)) @@ -1738,15 +1741,45 @@ static exvector sqrfree_yun(const ex &a, const symbol &x) return res; } -/** Compute square-free factorization of multivariate polynomial in Q[X]. +/** Compute a square-free factorization of a multivariate polynomial in Q[X]. * * @param a multivariate polynomial over Q[X] * @param x lst of variables to factor in, may be left empty for autodetection - * @return polynomail a in square-free factored form. */ + * @return a square-free factorization of \p a. + * + * \note + * A polynomial \f$p(X) \in C[X]\f$ is said square-free + * if, whenever any two polynomials \f$q(X)\f$ and \f$r(X)\f$ + * are such that + * \f[ + * p(X) = q(X)^2 r(X), + * \f] + * we have \f$q(X) \in C\f$. + * This means that \f$p(X)\f$ has no repeated factors, apart + * eventually from constants. + * Given a polynomial \f$p(X) \in C[X]\f$, we say that the + * decomposition + * \f[ + * p(X) = b \cdot p_1(X)^{a_1} \cdot p_2(X)^{a_2} \cdots p_r(X)^{a_r} + * \f] + * is a square-free factorization of \f$p(X)\f$ if the + * following conditions hold: + * -# \f$b \in C\f$ and \f$b \neq 0\f$; + * -# \f$a_i\f$ is a positive integer for \f$i = 1, \ldots, r\f$; + * -# the degree of the polynomial \f$p_i\f$ is strictly positive + * for \f$i = 1, \ldots, r\f$; + * -# the polynomial \f$\Pi_{i=1}^r p_i(X)\f$ is square-free. + * + * Square-free factorizations need not be unique. For example, if + * \f$a_i\f$ is even, we could change the polynomial \f$p_i(X)\f$ + * into \f$-p_i(X)\f$. + * Observe also that the factors \f$p_i(X)\f$ need not be irreducible + * polynomials. + */ 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 + if (is_a(a) || // algorithm does not trap a==0 + is_a(a)) // shortcut return a; // If no lst of variables to factorize in was specified we have to @@ -1768,11 +1801,11 @@ 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(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); + const numeric lcm = lcm_of_coefficients_denominators(a); + const ex tmp = multiply_lcm(a,lcm); // find the factors exvector factors = sqrfree_yun(tmp,x); @@ -1781,10 +1814,10 @@ ex sqrfree(const ex &a, const lst &l) lst newargs = args; newargs.remove_first(); - // recurse down the factors in remaining vars + // recurse down the factors in remaining variables if (newargs.nops()>0) { - exvector::iterator i = factors.begin(), end = factors.end(); - while (i != end) { + exvector::iterator i = factors.begin(); + while (i != factors.end()) { *i = sqrfree(*i, newargs); ++i; } @@ -1796,10 +1829,16 @@ ex sqrfree(const ex &a, const lst &l) 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: - result = result * quo(tmp, result, x); + // 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. For completeness + // we'll also have to recurse down that factor in the remaining variables. + if (newargs.nops()>0) + result *= sqrfree(quo(tmp, result, x), newargs); + else + result *= quo(tmp, result, x); + + // Put in the reational overall factor again and return return result * lcm.inverse(); }