* Implementation of GiNaC's products of expressions. */
/*
- * GiNaC Copyright (C) 1999-2006 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2007 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
GINAC_ASSERT(is_canonical());
}
-mul::mul(const epvector & v, const ex & oc)
+mul::mul(const epvector & v, const ex & oc, bool do_index_renaming)
{
tinfo_key = &mul::tinfo_static;
overall_coeff = oc;
- construct_from_epvector(v);
+ construct_from_epvector(v, do_index_renaming);
GINAC_ASSERT(is_canonical());
}
-mul::mul(std::auto_ptr<epvector> vp, const ex & oc)
+mul::mul(std::auto_ptr<epvector> vp, const ex & oc, bool do_index_renaming)
{
tinfo_key = &mul::tinfo_static;
GINAC_ASSERT(vp.get()!=0);
overall_coeff = oc;
- construct_from_epvector(*vp);
+ construct_from_epvector(*vp, do_index_renaming);
GINAC_ASSERT(is_canonical());
}
c.s << "(";
if (!overall_coeff.is_equal(_ex1)) {
- overall_coeff.print(c, precedence());
- c.s << "*";
+ if (overall_coeff.is_equal(_ex_1))
+ c.s << "-";
+ else {
+ overall_coeff.print(c, precedence());
+ c.s << "*";
+ }
}
// Print arguments, separated by "*" or "/"
epvector::const_iterator i = seq.begin(), end = seq.end();
while (i != end) {
if (ex_to<numeric>(i->coeff).is_integer())
- deg_sum += i->rest.degree(s) * ex_to<numeric>(i->coeff).to_int();
+ deg_sum += recombine_pair_to_ex(*i).degree(s);
+ else {
+ if (i->rest.has(s))
+ throw std::runtime_error("mul::degree() undefined degree because of non-integer exponent");
+ }
++i;
}
return deg_sum;
epvector::const_iterator i = seq.begin(), end = seq.end();
while (i != end) {
if (ex_to<numeric>(i->coeff).is_integer())
- deg_sum += i->rest.ldegree(s) * ex_to<numeric>(i->coeff).to_int();
+ deg_sum += recombine_pair_to_ex(*i).ldegree(s);
+ else {
+ if (i->rest.has(s))
+ throw std::runtime_error("mul::ldegree() undefined degree because of non-integer exponent");
+ }
++i;
}
return deg_sum;
}
return (new add(distrseq,
ex_to<numeric>(addref.overall_coeff).
- mul_dyn(ex_to<numeric>(overall_coeff))))
- ->setflag(status_flags::dynallocated | status_flags::evaluated);
+ mul_dyn(ex_to<numeric>(overall_coeff)))
+ )->setflag(status_flags::dynallocated | status_flags::evaluated);
+ } else if (seq_size >= 2) {
+ // Strip the content and the unit part from each term. Thus
+ // things like (-x+a)*(3*x-3*a) automagically turn into - 3*(x-a)2
+
+ epvector::const_iterator last = seq.end();
+ epvector::const_iterator i = seq.begin();
+ while (i!=last) {
+ if (! (is_a<add>(i->rest) && i->coeff.is_equal(_ex1))) {
+ // power::eval has such a rule, no need to handle powers here
+ ++i;
+ continue;
+ }
+
+ // XXX: What is the best way to check if the polynomial is a primitive?
+ numeric c = i->rest.integer_content();
+ const numeric& lead_coeff =
+ ex_to<numeric>(ex_to<add>(i->rest).seq.begin()->coeff).div_dyn(c);
+ const bool canonicalizable = lead_coeff.is_integer();
+
+ // XXX: The main variable is chosen in a random way, so this code
+ // does NOT transform the term into the canonical form (thus, in some
+ // very unlucky event it can even loop forever). Hopefully the main
+ // variable will be the same for all terms in *this
+ const bool unit_normal = lead_coeff.is_pos_integer();
+ if ((c == *_num1_p) && ((! canonicalizable) || unit_normal)) {
+ ++i;
+ continue;
+ }
+
+ std::auto_ptr<epvector> s(new epvector);
+ s->reserve(seq.size());
+
+ epvector::const_iterator j=seq.begin();
+ while (j!=i) {
+ s->push_back(*j);
+ ++j;
+ }
+
+ if (! unit_normal) {
+ c = c.mul(*_num_1_p);
+ }
+ const ex primitive = (i->rest)/c;
+ s->push_back(expair(primitive, _ex1));
+ ++j;
+
+ while (j!=last) {
+ s->push_back(*j);
+ ++j;
+ }
+ return (new mul(s, ex_to<numeric>(overall_coeff).mul_dyn(c))
+ )->setflag(status_flags::dynallocated);
+ }
}
+
return this->hold();
}
return mul(s, overall_coeff.evalf(level));
}
+void mul::find_real_imag(ex & rp, ex & ip) const
+{
+ rp = overall_coeff.real_part();
+ ip = overall_coeff.imag_part();
+ for (epvector::const_iterator i=seq.begin(); i!=seq.end(); ++i) {
+ ex factor = recombine_pair_to_ex(*i);
+ ex new_rp = factor.real_part();
+ ex new_ip = factor.imag_part();
+ if(new_ip.is_zero()) {
+ rp *= new_rp;
+ ip *= new_rp;
+ } else {
+ ex temp = rp*new_rp - ip*new_ip;
+ ip = ip*new_rp + rp*new_ip;
+ rp = temp;
+ }
+ }
+ rp = rp.expand();
+ ip = ip.expand();
+}
+
+ex mul::real_part() const
+{
+ ex rp, ip;
+ find_real_imag(rp, ip);
+ return rp;
+}
+
+ex mul::imag_part() const
+{
+ ex rp, ip;
+ find_real_imag(rp, ip);
+ return ip;
+}
+
ex mul::evalm() const
{
// numeric*matrix
return true;
}
-/** Checks wheter e matches to the pattern pat and the (possibly to be updated
+/** Checks wheter e matches to the pattern pat and the (possibly to be updated)
* list of replacements repls. This matching is in the sense of algebraic
* substitutions. Matching starts with pat.op(factor) of the pattern because
* the factors before this one have already been matched. The (possibly
{
std::vector<bool> subsed(seq.size(), false);
exvector subsresult(seq.size());
+ ex divide_by = 1;
+ ex multiply_by = 1;
for (exmap::const_iterator it = m.begin(); it != m.end(); ++it) {
retry1:
int nummatches = std::numeric_limits<int>::max();
std::vector<bool> currsubsed(seq.size(), false);
- bool succeed = true;
lst repls;
if(!algebraic_match_mul_with_mul(*this, it->first, repls, 0, nummatches, subsed, currsubsed))
continue;
- bool foundfirstsubsedfactor = false;
- for (size_t j=0; j<subsed.size(); j++) {
- if (currsubsed[j]) {
- if (foundfirstsubsedfactor)
- subsresult[j] = op(j);
- else {
- foundfirstsubsedfactor = true;
- subsresult[j] = op(j) * power(it->second.subs(ex(repls), subs_options::no_pattern) / it->first.subs(ex(repls), subs_options::no_pattern), nummatches);
- }
+ for (size_t j=0; j<subsed.size(); j++)
+ if (currsubsed[j])
subsed[j] = true;
- }
- }
+ ex subsed_pattern
+ = it->first.subs(ex(repls), subs_options::no_pattern);
+ divide_by *= power(subsed_pattern, nummatches);
+ ex subsed_result
+ = it->second.subs(ex(repls), subs_options::no_pattern);
+ multiply_by *= power(subsed_result, nummatches);
goto retry1;
} else {
-retry2:
- int nummatches = std::numeric_limits<int>::max();
- lst repls;
for (size_t j=0; j<this->nops(); j++) {
- if (!subsed[j] && tryfactsubs(op(j), it->first, nummatches, repls)) {
+ int nummatches = std::numeric_limits<int>::max();
+ lst repls;
+ if (!subsed[j] && tryfactsubs(op(j), it->first, nummatches, repls)){
subsed[j] = true;
- subsresult[j] = op(j) * power(it->second.subs(ex(repls), subs_options::no_pattern) / it->first.subs(ex(repls), subs_options::no_pattern), nummatches);
- goto retry2;
+ ex subsed_pattern
+ = it->first.subs(ex(repls), subs_options::no_pattern);
+ divide_by *= power(subsed_pattern, nummatches);
+ ex subsed_result
+ = it->second.subs(ex(repls), subs_options::no_pattern);
+ multiply_by *= power(subsed_result, nummatches);
}
}
}
if (!subsfound)
return subs_one_level(m, options | subs_options::algebraic);
- exvector ev; ev.reserve(nops());
- for (size_t i=0; i<nops(); i++) {
- if (subsed[i])
- ev.push_back(subsresult[i]);
- else
- ev.push_back(op(i));
- }
-
- return (new mul(ev))->setflag(status_flags::dynallocated);
+ return ((*this)/divide_by)*multiply_by;
}
// protected
return this;
}
-ex mul::thisexpairseq(const epvector & v, const ex & oc) const
+ex mul::thisexpairseq(const epvector & v, const ex & oc, bool do_index_renaming) const
{
- return (new mul(v, oc))->setflag(status_flags::dynallocated);
+ return (new mul(v, oc, do_index_renaming))->setflag(status_flags::dynallocated);
}
-ex mul::thisexpairseq(std::auto_ptr<epvector> vp, const ex & oc) const
+ex mul::thisexpairseq(std::auto_ptr<epvector> vp, const ex & oc, bool do_index_renaming) const
{
- return (new mul(vp, oc))->setflag(status_flags::dynallocated);
+ return (new mul(vp, oc, do_index_renaming))->setflag(status_flags::dynallocated);
}
expair mul::split_ex_to_pair(const ex & e) const
exvector add1_dummy_indices, add2_dummy_indices, add_indices;
for (epvector::const_iterator i=add1begin; i!=add1end; ++i) {
- add_indices = get_all_dummy_indices(i->rest);
+ add_indices = get_all_dummy_indices_safely(i->rest);
add1_dummy_indices.insert(add1_dummy_indices.end(), add_indices.begin(), add_indices.end());
}
for (epvector::const_iterator i=add2begin; i!=add2end; ++i) {
- add_indices = get_all_dummy_indices(i->rest);
+ add_indices = get_all_dummy_indices_safely(i->rest);
add2_dummy_indices.insert(add2_dummy_indices.end(), add_indices.begin(), add_indices.end());
}
size_t n = last_expanded.nops();
exvector distrseq;
distrseq.reserve(n);
- exvector va = get_all_dummy_indices(mul(non_adds));
+ exvector va = get_all_dummy_indices_safely(mul(non_adds));
sort(va.begin(), va.end(), ex_is_less());
for (size_t i=0; i<n; ++i) {