-ex power::expand_add(const add & a, int n) const
-{
- // expand a^n where a is an add and n is an integer
-
- if (n==2) {
- return expand_add_2(a);
- }
-
- int m=a.nops();
- exvector sum;
- sum.reserve((n+1)*(m-1));
- intvector k(m-1);
- intvector k_cum(m-1); // k_cum[l]:=sum(i=0,l,k[l]);
- intvector upper_limit(m-1);
- int l;
-
- for (int l=0; l<m-1; l++) {
- k[l]=0;
- k_cum[l]=0;
- upper_limit[l]=n;
- }
-
- while (1) {
- exvector term;
- term.reserve(m+1);
- for (l=0; l<m-1; l++) {
- const ex & b=a.op(l);
- GINAC_ASSERT(!is_ex_exactly_of_type(b,add));
- GINAC_ASSERT(!is_ex_exactly_of_type(b,power)||
- !is_ex_exactly_of_type(ex_to_power(b).exponent,numeric)||
- !ex_to_numeric(ex_to_power(b).exponent).is_pos_integer());
- if (is_ex_exactly_of_type(b,mul)) {
- term.push_back(expand_mul(ex_to_mul(b),numeric(k[l])));
- } else {
- term.push_back(power(b,k[l]));
- }
- }
-
- const ex & b=a.op(l);
- GINAC_ASSERT(!is_ex_exactly_of_type(b,add));
- GINAC_ASSERT(!is_ex_exactly_of_type(b,power)||
- !is_ex_exactly_of_type(ex_to_power(b).exponent,numeric)||
- !ex_to_numeric(ex_to_power(b).exponent).is_pos_integer());
- if (is_ex_exactly_of_type(b,mul)) {
- term.push_back(expand_mul(ex_to_mul(b),numeric(n-k_cum[m-2])));
- } else {
- term.push_back(power(b,n-k_cum[m-2]));
- }
-
- numeric f=binomial(numeric(n),numeric(k[0]));
- for (l=1; l<m-1; l++) {
- f=f*binomial(numeric(n-k_cum[l-1]),numeric(k[l]));
- }
- term.push_back(f);
-
- /*
- cout << "begin term" << endl;
- for (int i=0; i<m-1; i++) {
- cout << "k[" << i << "]=" << k[i] << endl;
- cout << "k_cum[" << i << "]=" << k_cum[i] << endl;
- cout << "upper_limit[" << i << "]=" << upper_limit[i] << endl;
- }
- for (exvector::const_iterator cit=term.begin(); cit!=term.end(); ++cit) {
- cout << *cit << endl;
- }
- cout << "end term" << endl;
- */
-
- // TODO: optimize this
- sum.push_back((new mul(term))->setflag(status_flags::dynallocated));
-
- // increment k[]
- l=m-2;
- while ((l>=0)&&((++k[l])>upper_limit[l])) {
- k[l]=0;
- l--;
- }
- if (l<0) break;
-
- // recalc k_cum[] and upper_limit[]
- if (l==0) {
- k_cum[0]=k[0];
- } else {
- k_cum[l]=k_cum[l-1]+k[l];
- }
- for (int i=l+1; i<m-1; i++) {
- k_cum[i]=k_cum[i-1]+k[i];
- }
-
- for (int i=l+1; i<m-1; i++) {
- upper_limit[i]=n-k_cum[i-1];
- }
- }
- return (new add(sum))->setflag(status_flags::dynallocated);
-}
-
-ex power::expand_add_2(const add & a) const
-{
- // special case: expand a^2 where a is an add
-
- epvector sum;
- unsigned a_nops=a.nops();
- sum.reserve((a_nops*(a_nops+1))/2);
- epvector::const_iterator last=a.seq.end();
-
- // power(+(x,...,z;c),2)=power(+(x,...,z;0),2)+2*c*+(x,...,z;0)+c*c
- // first part: ignore overall_coeff and expand other terms
- for (epvector::const_iterator cit0=a.seq.begin(); cit0!=last; ++cit0) {
- const ex & r=(*cit0).rest;
- const ex & c=(*cit0).coeff;
-
- GINAC_ASSERT(!is_ex_exactly_of_type(r,add));
- GINAC_ASSERT(!is_ex_exactly_of_type(r,power)||
- !is_ex_exactly_of_type(ex_to_power(r).exponent,numeric)||
- !ex_to_numeric(ex_to_power(r).exponent).is_pos_integer()||
- !is_ex_exactly_of_type(ex_to_power(r).basis,add)||
- !is_ex_exactly_of_type(ex_to_power(r).basis,mul)||
- !is_ex_exactly_of_type(ex_to_power(r).basis,power));
-
- if (are_ex_trivially_equal(c,_ex1())) {
- if (is_ex_exactly_of_type(r,mul)) {
- sum.push_back(expair(expand_mul(ex_to_mul(r),_num2()),_ex1()));
- } else {
- sum.push_back(expair((new power(r,_ex2()))->setflag(status_flags::dynallocated),
- _ex1()));
- }
- } else {
- if (is_ex_exactly_of_type(r,mul)) {
- sum.push_back(expair(expand_mul(ex_to_mul(r),_num2()),
- ex_to_numeric(c).power_dyn(_num2())));
- } else {
- sum.push_back(expair((new power(r,_ex2()))->setflag(status_flags::dynallocated),
- ex_to_numeric(c).power_dyn(_num2())));
- }
- }
-
- for (epvector::const_iterator cit1=cit0+1; cit1!=last; ++cit1) {
- const ex & r1=(*cit1).rest;
- const ex & c1=(*cit1).coeff;
- sum.push_back(a.combine_ex_with_coeff_to_pair((new mul(r,r1))->setflag(status_flags::dynallocated),
- _num2().mul(ex_to_numeric(c)).mul_dyn(ex_to_numeric(c1))));
- }
- }
-
- GINAC_ASSERT(sum.size()==(a.seq.size()*(a.seq.size()+1))/2);
-
- // second part: add terms coming from overall_factor (if != 0)
- if (!a.overall_coeff.is_equal(_ex0())) {
- for (epvector::const_iterator cit=a.seq.begin(); cit!=a.seq.end(); ++cit) {
- sum.push_back(a.combine_pair_with_coeff_to_pair(*cit,ex_to_numeric(a.overall_coeff).mul_dyn(_num2())));
- }
- sum.push_back(expair(ex_to_numeric(a.overall_coeff).power_dyn(_num2()),_ex1()));
- }
-
- GINAC_ASSERT(sum.size()==(a_nops*(a_nops+1))/2);
-
- return (new add(sum))->setflag(status_flags::dynallocated);
-}
-
-ex power::expand_mul(const mul & m, const numeric & n) const
-{
- // expand m^n where m is a mul and n is and integer
-
- if (n.is_equal(_num0())) {
- return _ex1();
- }
-
- epvector distrseq;
- distrseq.reserve(m.seq.size());
- epvector::const_iterator last=m.seq.end();
- epvector::const_iterator cit=m.seq.begin();
- while (cit!=last) {
- if (is_ex_exactly_of_type((*cit).rest,numeric)) {
- distrseq.push_back(m.combine_pair_with_coeff_to_pair(*cit,n));
- } else {
- // it is safe not to call mul::combine_pair_with_coeff_to_pair()
- // since n is an integer
- distrseq.push_back(expair((*cit).rest,
- ex_to_numeric((*cit).coeff).mul(n)));
- }
- ++cit;
- }
- return (new mul(distrseq,ex_to_numeric(m.overall_coeff).power_dyn(n)))
- ->setflag(status_flags::dynallocated);
-}
-
-/*
-ex power::expand_commutative_3(const ex & basis, const numeric & exponent,
- unsigned options) const
-{
- // obsolete
-
- exvector distrseq;
- epvector splitseq;
-
- const add & addref=static_cast<const add &>(*basis.bp);
-
- splitseq=addref.seq;
- splitseq.pop_back();
- ex first_operands=add(splitseq);
- ex last_operand=addref.recombine_pair_to_ex(*(addref.seq.end()-1));
-
- int n=exponent.to_int();
- for (int k=0; k<=n; k++) {
- distrseq.push_back(binomial(n,k)*power(first_operands,numeric(k))*
- power(last_operand,numeric(n-k)));
- }
- return ex((new add(distrseq))->setflag(status_flags::sub_expanded |
- status_flags::expanded |
- status_flags::dynallocated )).
- expand(options);
-}
-*/
-
-/*
-ex power::expand_noncommutative(const ex & basis, const numeric & exponent,
- unsigned options) const
-{
- ex rest_power=ex(power(basis,exponent.add(_num_1()))).
- expand(options | expand_options::internal_do_not_expand_power_operands);
-
- return ex(mul(rest_power,basis),0).
- expand(options | expand_options::internal_do_not_expand_mul_operands);
-}
-*/
-
-//////////
-// static member variables
-//////////
-
-// protected
-
-unsigned power::precedence=60;
-
-//////////
-// global constants
-//////////
-
-const power some_power;
-const type_info & typeid_power=typeid(some_power);
-
-// helper function
-
-ex sqrt(const ex & a)
-{
- return power(a,_ex1_2());
+/** expand a^n where a is an add and n is a positive integer.
+ * @see power::expand */
+ex power::expand_add(const add & a, int n, unsigned options) const
+{
+ if (n==2)
+ return expand_add_2(a, options);
+
+ const size_t m = a.nops();
+ exvector result;
+ // The number of terms will be the number of combinatorial compositions,
+ // i.e. the number of unordered arrangement of m nonnegative integers
+ // which sum up to n. It is frequently written as C_n(m) and directly
+ // related with binomial coefficients:
+ result.reserve(binomial(numeric(n+m-1), numeric(m-1)).to_int());
+ intvector k(m-1);
+ intvector k_cum(m-1); // k_cum[l]:=sum(i=0,l,k[l]);
+ intvector upper_limit(m-1);
+ int l;
+
+ for (size_t l=0; l<m-1; ++l) {
+ k[l] = 0;
+ k_cum[l] = 0;
+ upper_limit[l] = n;
+ }
+
+ while (true) {
+ exvector term;
+ term.reserve(m+1);
+ for (l=0; l<m-1; ++l) {
+ const ex & b = a.op(l);
+ GINAC_ASSERT(!is_exactly_a<add>(b));
+ GINAC_ASSERT(!is_exactly_a<power>(b) ||
+ !is_exactly_a<numeric>(ex_to<power>(b).exponent) ||
+ !ex_to<numeric>(ex_to<power>(b).exponent).is_pos_integer() ||
+ !is_exactly_a<add>(ex_to<power>(b).basis) ||
+ !is_exactly_a<mul>(ex_to<power>(b).basis) ||
+ !is_exactly_a<power>(ex_to<power>(b).basis));
+ if (is_exactly_a<mul>(b))
+ term.push_back(expand_mul(ex_to<mul>(b), numeric(k[l]), options, true));
+ else
+ term.push_back(power(b,k[l]));
+ }
+
+ const ex & b = a.op(l);
+ GINAC_ASSERT(!is_exactly_a<add>(b));
+ GINAC_ASSERT(!is_exactly_a<power>(b) ||
+ !is_exactly_a<numeric>(ex_to<power>(b).exponent) ||
+ !ex_to<numeric>(ex_to<power>(b).exponent).is_pos_integer() ||
+ !is_exactly_a<add>(ex_to<power>(b).basis) ||
+ !is_exactly_a<mul>(ex_to<power>(b).basis) ||
+ !is_exactly_a<power>(ex_to<power>(b).basis));
+ if (is_exactly_a<mul>(b))
+ term.push_back(expand_mul(ex_to<mul>(b), numeric(n-k_cum[m-2]), options, true));
+ else
+ term.push_back(power(b,n-k_cum[m-2]));
+
+ numeric f = binomial(numeric(n),numeric(k[0]));
+ for (l=1; l<m-1; ++l)
+ f *= binomial(numeric(n-k_cum[l-1]),numeric(k[l]));
+
+ term.push_back(f);
+
+ result.push_back(ex((new mul(term))->setflag(status_flags::dynallocated)).expand(options));
+
+ // increment k[]
+ l = m-2;
+ while ((l>=0) && ((++k[l])>upper_limit[l])) {
+ k[l] = 0;
+ --l;
+ }
+ if (l<0) break;
+
+ // recalc k_cum[] and upper_limit[]
+ k_cum[l] = (l==0 ? k[0] : k_cum[l-1]+k[l]);
+
+ for (size_t i=l+1; i<m-1; ++i)
+ k_cum[i] = k_cum[i-1]+k[i];
+
+ for (size_t i=l+1; i<m-1; ++i)
+ upper_limit[i] = n-k_cum[i-1];
+ }
+
+ return (new add(result))->setflag(status_flags::dynallocated |
+ status_flags::expanded);
+}
+
+
+/** Special case of power::expand_add. Expands a^2 where a is an add.
+ * @see power::expand_add */
+ex power::expand_add_2(const add & a, unsigned options) const
+{
+ epvector sum;
+ size_t a_nops = a.nops();
+ sum.reserve((a_nops*(a_nops+1))/2);
+ epvector::const_iterator last = a.seq.end();
+
+ // power(+(x,...,z;c),2)=power(+(x,...,z;0),2)+2*c*+(x,...,z;0)+c*c
+ // first part: ignore overall_coeff and expand other terms
+ for (epvector::const_iterator cit0=a.seq.begin(); cit0!=last; ++cit0) {
+ const ex & r = cit0->rest;
+ const ex & c = cit0->coeff;
+
+ GINAC_ASSERT(!is_exactly_a<add>(r));
+ GINAC_ASSERT(!is_exactly_a<power>(r) ||
+ !is_exactly_a<numeric>(ex_to<power>(r).exponent) ||
+ !ex_to<numeric>(ex_to<power>(r).exponent).is_pos_integer() ||
+ !is_exactly_a<add>(ex_to<power>(r).basis) ||
+ !is_exactly_a<mul>(ex_to<power>(r).basis) ||
+ !is_exactly_a<power>(ex_to<power>(r).basis));
+
+ if (c.is_equal(_ex1)) {
+ if (is_exactly_a<mul>(r)) {
+ sum.push_back(expair(expand_mul(ex_to<mul>(r), _num2, options, true),
+ _ex1));
+ } else {
+ sum.push_back(expair((new power(r,_ex2))->setflag(status_flags::dynallocated),
+ _ex1));
+ }
+ } else {
+ if (is_exactly_a<mul>(r)) {
+ sum.push_back(a.combine_ex_with_coeff_to_pair(expand_mul(ex_to<mul>(r), _num2, options, true),
+ ex_to<numeric>(c).power_dyn(_num2)));
+ } else {
+ sum.push_back(a.combine_ex_with_coeff_to_pair((new power(r,_ex2))->setflag(status_flags::dynallocated),
+ ex_to<numeric>(c).power_dyn(_num2)));
+ }
+ }
+
+ for (epvector::const_iterator cit1=cit0+1; cit1!=last; ++cit1) {
+ const ex & r1 = cit1->rest;
+ const ex & c1 = cit1->coeff;
+ sum.push_back(a.combine_ex_with_coeff_to_pair((new mul(r,r1))->setflag(status_flags::dynallocated),
+ _num2.mul(ex_to<numeric>(c)).mul_dyn(ex_to<numeric>(c1))));
+ }
+ }
+
+ GINAC_ASSERT(sum.size()==(a.seq.size()*(a.seq.size()+1))/2);
+
+ // second part: add terms coming from overall_factor (if != 0)
+ if (!a.overall_coeff.is_zero()) {
+ epvector::const_iterator i = a.seq.begin(), end = a.seq.end();
+ while (i != end) {
+ sum.push_back(a.combine_pair_with_coeff_to_pair(*i, ex_to<numeric>(a.overall_coeff).mul_dyn(_num2)));
+ ++i;
+ }
+ sum.push_back(expair(ex_to<numeric>(a.overall_coeff).power_dyn(_num2),_ex1));
+ }
+
+ GINAC_ASSERT(sum.size()==(a_nops*(a_nops+1))/2);
+
+ return (new add(sum))->setflag(status_flags::dynallocated | status_flags::expanded);
+}
+
+/** Expand factors of m in m^n where m is a mul and n is and integer.
+ * @see power::expand */
+ex power::expand_mul(const mul & m, const numeric & n, unsigned options, bool from_expand) const
+{
+ GINAC_ASSERT(n.is_integer());
+
+ if (n.is_zero())
+ return _ex1;
+
+ epvector distrseq;
+ distrseq.reserve(m.seq.size());
+ bool need_reexpand = false;
+
+ epvector::const_iterator last = m.seq.end();
+ epvector::const_iterator cit = m.seq.begin();
+ while (cit!=last) {
+ if (is_exactly_a<numeric>(cit->rest)) {
+ distrseq.push_back(m.combine_pair_with_coeff_to_pair(*cit, n));
+ } else {
+ // it is safe not to call mul::combine_pair_with_coeff_to_pair()
+ // since n is an integer
+ numeric new_coeff = ex_to<numeric>(cit->coeff).mul(n);
+ if (from_expand && is_exactly_a<add>(cit->rest) && new_coeff.is_pos_integer()) {
+ // this happens when e.g. (a+b)^(1/2) gets squared and
+ // the resulting product needs to be reexpanded
+ need_reexpand = true;
+ }
+ distrseq.push_back(expair(cit->rest, new_coeff));
+ }
+ ++cit;
+ }
+
+ const mul & result = static_cast<const mul &>((new mul(distrseq, ex_to<numeric>(m.overall_coeff).power_dyn(n)))->setflag(status_flags::dynallocated));
+ if (need_reexpand)
+ return ex(result).expand(options);
+ if (from_expand)
+ return result.setflag(status_flags::expanded);
+ return result;