* @param lcm LCM to multiply in */
static ex multiply_lcm(const ex &e, const numeric &lcm)
{
+ if (lcm.is_equal(*_num1_p))
+ // e * 1 -> e;
+ return e;
+
if (is_exactly_a<mul>(e)) {
+ // (a*b*...)*lcm -> (a*lcma)*(b*lcmb)*...*(lcm/(lcma*lcmb*...))
size_t num = e.nops();
- exvector v; v.reserve(num + 1);
+ exvector v;
+ v.reserve(num + 1);
numeric lcm_accum = *_num1_p;
for (size_t i=0; i<num; i++) {
numeric op_lcm = lcmcoeff(e.op(i), *_num1_p);
v.push_back(lcm / lcm_accum);
return dynallocate<mul>(v);
} else if (is_exactly_a<add>(e)) {
+ // (a+b+...)*lcm -> a*lcm+b*lcm+...
size_t num = e.nops();
- exvector v; v.reserve(num);
+ exvector v;
+ v.reserve(num);
for (size_t i=0; i<num; i++)
v.push_back(multiply_lcm(e.op(i), lcm));
return dynallocate<add>(v);
} else if (is_exactly_a<power>(e)) {
- if (is_a<symbol>(e.op(0)))
- return e * lcm;
- else
- return pow(multiply_lcm(e.op(0), lcm.power(ex_to<numeric>(e.op(1)).inverse())), e.op(1));
- } else
- return e * lcm;
+ if (!is_a<symbol>(e.op(0))) {
+ // (b^e)*lcm -> (b*lcm^(1/e))^e if lcm^(1/e) ∈ ℝ (i.e. not a float)
+ // but not for symbolic b, as evaluation would undo this again
+ numeric root_of_lcm = lcm.power(ex_to<numeric>(e.op(1)).inverse());
+ if (root_of_lcm.is_rational())
+ return pow(multiply_lcm(e.op(0), root_of_lcm), e.op(1));
+ }
+ }
+ // can't recurse down into e
+ return dynallocate<mul>(e, lcm);
}
* Yun's algorithm. Used internally by sqrfree().
*
* @param a multivariate polynomial over Z[X], treated here as univariate
- * polynomial in x.
+ * polynomial in x (needs not be expanded).
* @param x variable to factor in
* @return vector of factors sorted in ascending degree */
static exvector sqrfree_yun(const ex &a, const symbol &x)
ex w = a;
ex z = w.diff(x);
ex g = gcd(w, z);
+ if (g.is_zero()) {
+ return res;
+ }
if (g.is_equal(_ex1)) {
res.push_back(a);
return res;
ex y;
do {
w = quo(w, g, x);
+ if (w.is_zero()) {
+ return res;
+ }
y = quo(z, g, x);
z = y - w.diff(x);
g = gcd(w, z);
/** Compute a square-free factorization of a multivariate polynomial in Q[X].
*
- * @param a multivariate polynomial over Q[X]
+ * @param a multivariate polynomial over Q[X] (needs not be expanded)
* @param l lst of variables to factor in, may be left empty for autodetection
* @return a square-free factorization of \p a.
*
*/
ex sqrfree(const ex &a, const lst &l)
{
- if (is_exactly_a<numeric>(a) || // algorithm does not trap a==0
- is_a<symbol>(a)) // shortcut
+ if (is_exactly_a<numeric>(a) ||
+ is_a<symbol>(a)) // shortcuts
return a;
// If no lst of variables to factorize in was specified we have to