* Implementation of GiNaC's symbolic exponentiation (basis^exponent). */
/*
- * GiNaC Copyright (C) 1999-2010 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2015 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
return (flags & status_flags::expanded);
case info_flags::positive:
return basis.info(info_flags::positive) && exponent.info(info_flags::real);
+ case info_flags::nonnegative:
+ return (basis.info(info_flags::positive) && exponent.info(info_flags::real)) ||
+ (basis.info(info_flags::real) && exponent.info(info_flags::integer) && exponent.info(info_flags::even));
case info_flags::has_indices: {
if (flags & status_flags::has_indices)
return true;
bool power::is_polynomial(const ex & var) const
{
- if (exponent.has(var))
- return false;
- if (!exponent.info(info_flags::nonnegint))
- return false;
- return basis.is_polynomial(var);
+ if (basis.is_polynomial(var)) {
+ if (basis.has(var))
+ // basis is non-constant polynomial in var
+ return exponent.info(info_flags::nonnegint);
+ else
+ // basis is constant in var
+ return !exponent.has(var);
+ }
+ // basis is a non-polynomial function of var
+ return false;
}
int power::degree(const ex & s) const
* - ^(1,x) -> 1
* - ^(c1,c2) -> *(c1^n,c1^(c2-n)) (so that 0<(c2-n)<1, try to evaluate roots, possibly in numerator and denominator of c1)
* - ^(^(x,c1),c2) -> ^(x,c1*c2) if x is positive and c1 is real.
- * - ^(^(x,c1),c2) -> ^(x,c1*c2) (c2 integer or -1 < c1 <= 1, case c1=1 should not happen, see below!)
+ * - ^(^(x,c1),c2) -> ^(x,c1*c2) (c2 integer or -1 < c1 <= 1 or (c1=-1 and c2>0), case c1=1 should not happen, see below!)
* - ^(*(x,y,z),c) -> *(x^c,y^c,z^c) (if c integer)
* - ^(*(x,c1),c2) -> ^(x,c2)*c1^c2 (c1>0)
* - ^(*(x,c1),c2) -> ^(-x,c2)*c1^c2 (c1<0)
}
// ^(^(x,c1),c2) -> ^(x,c1*c2)
- // (c1, c2 numeric(), c2 integer or -1 < c1 <= 1,
+ // (c1, c2 numeric(), c2 integer or -1 < c1 <= 1 or (c1=-1 and c2>0),
// case c1==1 should not happen, see below!)
if (is_exactly_a<power>(ebasis)) {
const power & sub_power = ex_to<power>(ebasis);
if (is_exactly_a<numeric>(sub_exponent)) {
const numeric & num_sub_exponent = ex_to<numeric>(sub_exponent);
GINAC_ASSERT(num_sub_exponent!=numeric(1));
- if (num_exponent->is_integer() || (abs(num_sub_exponent) - (*_num1_p)).is_negative()) {
+ if (num_exponent->is_integer() || (abs(num_sub_exponent) - (*_num1_p)).is_negative()
+ || (num_sub_exponent == *_num_1_p && num_exponent->is_positive())) {
return power(sub_basis,num_sub_exponent.mul(*num_exponent));
}
}
if (num_coeff.is_positive()) {
mul *mulp = new mul(mulref);
mulp->overall_coeff = _ex1;
+ mulp->setflag(status_flags::dynallocated);
mulp->clearflag(status_flags::evaluated);
mulp->clearflag(status_flags::hash_calculated);
return (new mul(power(*mulp,exponent),
if (!num_coeff.is_equal(*_num_1_p)) {
mul *mulp = new mul(mulref);
mulp->overall_coeff = _ex_1;
+ mulp->setflag(status_flags::dynallocated);
mulp->clearflag(status_flags::evaluated);
mulp->clearflag(status_flags::hash_calculated);
return (new mul(power(*mulp,exponent),
ex power::conjugate() const
{
- ex newbasis = basis.conjugate();
- ex newexponent = exponent.conjugate();
- if (are_ex_trivially_equal(basis, newbasis) && are_ex_trivially_equal(exponent, newexponent)) {
- return *this;
+ // conjugate(pow(x,y))==pow(conjugate(x),conjugate(y)) unless on the
+ // branch cut which runs along the negative real axis.
+ if (basis.info(info_flags::positive)) {
+ ex newexponent = exponent.conjugate();
+ if (are_ex_trivially_equal(exponent, newexponent)) {
+ return *this;
+ }
+ return (new power(basis, newexponent))->setflag(status_flags::dynallocated);
}
- return (new power(newbasis, newexponent))->setflag(status_flags::dynallocated);
+ if (exponent.info(info_flags::integer)) {
+ ex newbasis = basis.conjugate();
+ if (are_ex_trivially_equal(basis, newbasis)) {
+ return *this;
+ }
+ return (new power(newbasis, exponent))->setflag(status_flags::dynallocated);
+ }
+ return conjugate_function(*this).hold();
}
ex power::real_part() const
ex b=basis.imag_part();
ex c=exponent.real_part();
ex d=exponent.imag_part();
- return
- power(abs(basis),c)*exp(-d*atan2(b,a))*sin(c*atan2(b,a)+d*log(abs(basis)));
+ return power(abs(basis),c)*exp(-d*atan2(b,a))*sin(c*atan2(b,a)+d*log(abs(basis)));
}
// protected
return *this;
}
+ // (x*p)^c -> x^c * p^c, if p>0
+ // makes sense before expanding the basis
+ if (is_exactly_a<mul>(basis) && !basis.info(info_flags::indefinite)) {
+ const mul &m = ex_to<mul>(basis);
+ exvector prodseq;
+ epvector powseq;
+ prodseq.reserve(m.seq.size() + 1);
+ powseq.reserve(m.seq.size() + 1);
+ epvector::const_iterator last = m.seq.end();
+ epvector::const_iterator cit = m.seq.begin();
+ bool possign = true;
+
+ // search for positive/negative factors
+ while (cit!=last) {
+ ex e=m.recombine_pair_to_ex(*cit);
+ if (e.info(info_flags::positive))
+ prodseq.push_back(pow(e, exponent).expand(options));
+ else if (e.info(info_flags::negative)) {
+ prodseq.push_back(pow(-e, exponent).expand(options));
+ possign = !possign;
+ } else
+ powseq.push_back(*cit);
+ ++cit;
+ }
+
+ // take care on the numeric coefficient
+ ex coeff=(possign? _ex1 : _ex_1);
+ if (m.overall_coeff.info(info_flags::positive) && m.overall_coeff != _ex1)
+ prodseq.push_back(power(m.overall_coeff, exponent));
+ else if (m.overall_coeff.info(info_flags::negative) && m.overall_coeff != _ex_1)
+ prodseq.push_back(power(-m.overall_coeff, exponent));
+ else
+ coeff *= m.overall_coeff;
+
+ // If positive/negative factors are found, then extract them.
+ // In either case we set a flag to avoid the second run on a part
+ // which does not have positive/negative terms.
+ if (prodseq.size() > 0) {
+ ex newbasis = coeff*mul(powseq);
+ ex_to<basic>(newbasis).setflag(status_flags::purely_indefinite);
+ return ((new mul(prodseq))->setflag(status_flags::dynallocated)*(new power(newbasis, exponent))->setflag(status_flags::dynallocated).expand(options)).expand(options);
+ } else
+ ex_to<basic>(basis).setflag(status_flags::purely_indefinite);
+ }
+
const ex expanded_basis = basis.expand(options);
const ex expanded_exponent = exponent.expand(options);
if (c.is_equal(_ex1)) {
if (is_exactly_a<mul>(r)) {
- sum.push_back(expair(expand_mul(ex_to<mul>(r), *_num2_p, options, true),
- _ex1));
+ sum.push_back(a.combine_ex_with_coeff_to_pair(expand_mul(ex_to<mul>(r), *_num2_p, options, true),
+ _ex1));
} else {
- sum.push_back(expair((new power(r,_ex2))->setflag(status_flags::dynallocated),
- _ex1));
+ sum.push_back(a.combine_ex_with_coeff_to_pair((new power(r,_ex2))->setflag(status_flags::dynallocated),
+ _ex1));
}
} else {
if (is_exactly_a<mul>(r)) {