return 0;
}
+// Bug in expairseq::evalchildren().
+static unsigned exam_paranoia23()
+{
+ unsigned result = 0;
+ symbol x("x");
+
+ epvector v1;
+ v1.push_back(expair(1, 1));
+ v1.push_back(expair(2*x, -1));
+ ex e1 = add(v1); // Should be e==1-2*x,
+ if (!e1.is_equal(1-2*x)) {
+ clog << "Failure constructing " << e1 << " from add.\n";
+ ++result;
+ }
+
+ epvector v2;
+ v2.push_back(expair(x, 1));
+ v2.push_back(expair(1,-1));
+ ex e2 = mul(v2); // Should be e==x;
+ if (!e2.is_equal(x)) {
+ clog << "Failure constructing " << e2 << " from mul.\n";
+ ++result;
+ }
+
+ return result;
+}
+
unsigned exam_paranoia()
{
unsigned result = 0;
result += is_polynomial_false_positive(); cout << '.' << flush;
result += exam_paranoia21(); cout << '.' << flush;
result += exam_paranoia22(); cout << '.' << flush;
+ result += exam_paranoia23(); cout << '.' << flush;
return result;
}
if (!restcoeff.is_zero()) {
if (do_clifford) {
if (clifford_max_label(restcoeff) == -1) {
- coeffseq_cliff.push_back(combine_ex_with_coeff_to_pair(ncmul(restcoeff, dirac_ONE(rl)), i.coeff));
+ coeffseq_cliff.push_back(expair(ncmul(restcoeff, dirac_ONE(rl)), i.coeff));
} else {
- coeffseq_cliff.push_back(combine_ex_with_coeff_to_pair(restcoeff, i.coeff));
+ coeffseq_cliff.push_back(expair(restcoeff, i.coeff));
nonscalar = true;
}
}
- coeffseq.push_back(combine_ex_with_coeff_to_pair(restcoeff, i.coeff));
+ coeffseq.push_back(expair(restcoeff, i.coeff));
}
}
* @param level cut-off in recursive evaluation */
ex add::eval(int level) const
{
- epvector evaled = evalchildren(level);
+ if ((level == 1) && (flags & status_flags::evaluated)) {
+ GINAC_ASSERT(seq.size()>0);
+ GINAC_ASSERT(seq.size()>1 || !overall_coeff.is_zero());
+ return *this;
+ }
+
+ const epvector evaled = evalchildren(level);
if (unlikely(!evaled.empty())) {
- // do more evaluation later
+ // start over evaluating a new object
return dynallocate<add>(std::move(evaled), overall_coeff);
}
GINAC_ASSERT(!is_exactly_a<add>(i.rest));
}
#endif // def DO_GINAC_ASSERT
-
- if (flags & status_flags::evaluated) {
- GINAC_ASSERT(seq.size()>0);
- GINAC_ASSERT(seq.size()>1 || !overall_coeff.is_zero());
- return *this;
- }
-
+
int seq_size = seq.size();
if (seq_size == 0) {
// +(;c) -> c
// than the default implementation in basic::derivative() although
// if performs the same function (differentiate each term).
for (auto & it : seq)
- s.push_back(combine_ex_with_coeff_to_pair(it.rest.diff(y), it.coeff));
+ s.push_back(expair(it.rest.diff(y), it.coeff));
return dynallocate<add>(std::move(s), _ex0);
}
if (is_exactly_a<mul>(e)) {
const mul &mulref(ex_to<mul>(e));
const ex &numfactor = mulref.overall_coeff;
- if (numfactor.is_equal(_ex1))
+ if (likely(numfactor.is_equal(_ex1)))
return expair(e, c);
mul & mulcopy = dynallocate<mul>(mulref);
mulcopy.overall_coeff = _ex1;
if ((level==1) && (flags &status_flags::evaluated))
return *this;
- epvector evaled = evalchildren(level);
+ const epvector evaled = evalchildren(level);
if (!evaled.empty())
return dynallocate<expairseq>(std::move(evaled), overall_coeff).setflag(status_flags::evaluated);
else
{
auto cit = seq.begin(), last = seq.end();
while (cit!=last) {
- const ex &expanded_ex = cit->rest.expand(options);
+ const ex expanded_ex = cit->rest.expand(options);
if (!are_ex_trivially_equal(cit->rest,expanded_ex)) {
// something changed, copy seq, eval and return it
s.reserve(seq.size());
// copy parts of seq which are known not to have changed
- auto cit2 = seq.begin();
- while (cit2!=cit) {
- s.push_back(*cit2);
- ++cit2;
- }
+ s.insert(s.begin(), seq.begin(), cit);
// copy first changed element
- s.push_back(combine_ex_with_coeff_to_pair(expanded_ex,
- cit2->coeff));
- ++cit2;
+ s.push_back(expair(expanded_ex, cit->coeff));
+ ++cit;
// copy rest
- while (cit2!=last) {
- s.push_back(combine_ex_with_coeff_to_pair(cit2->rest.expand(options),
- cit2->coeff));
- ++cit2;
+ while (cit != last) {
+ s.push_back(expair(cit->rest.expand(options), cit->coeff));
+ ++cit;
}
return s;
}
+
++cit;
}
* had to be changed. */
epvector expairseq::evalchildren(int level) const
{
- if (likely(level==1))
- return epvector(); // nothing had to be evaluated
-
if (level == -max_recursion_level)
throw(std::runtime_error("max recursion level reached"));
-
- --level;
+
auto cit = seq.begin(), last = seq.end();
while (cit!=last) {
- const ex evaled_ex = cit->rest.eval(level);
- if (!are_ex_trivially_equal(cit->rest,evaled_ex)) {
-
- // something changed, copy seq, eval and return it
+ const ex evaled_rest = level==1 ? cit->rest : cit->rest.eval(level-1);
+ const expair evaled_pair = combine_ex_with_coeff_to_pair(evaled_rest, cit->coeff);
+ if (unlikely(!evaled_pair.is_equal(*cit))) {
+
+ // something changed: copy seq, eval and return it
epvector s;
s.reserve(seq.size());
-
+
// copy parts of seq which are known not to have changed
- auto cit2 = seq.begin();
- while (cit2!=cit) {
- s.push_back(*cit2);
- ++cit2;
- }
+ s.insert(s.begin(), seq.begin(), cit);
// copy first changed element
- s.push_back(combine_ex_with_coeff_to_pair(evaled_ex,
- cit2->coeff));
- ++cit2;
+ s.push_back(evaled_pair);
+ ++cit;
// copy rest
- while (cit2!=last) {
- s.push_back(combine_ex_with_coeff_to_pair(cit2->rest.eval(level),
- cit2->coeff));
- ++cit2;
+ while (cit != last) {
+ const ex evaled_rest = level==1 ? cit->rest : cit->rest.eval(level-1);
+ s.push_back(combine_ex_with_coeff_to_pair(evaled_rest, cit->coeff));
+ ++cit;
}
- return std::move(s);
+ return s;
}
+
++cit;
}
const ex &subsed_ex = orig_ex.subs(m, options);
if (!are_ex_trivially_equal(orig_ex, subsed_ex)) {
- // Something changed, copy seq, subs and return it
+ // Something changed: copy seq, subs and return it
epvector s;
s.reserve(seq.size());
auto cit = seq.begin(), last = seq.end();
while (cit != last) {
- const ex &subsed_ex = cit->rest.subs(m, options);
- if (!are_ex_trivially_equal(cit->rest, subsed_ex)) {
+ const ex subsed_rest = cit->rest.subs(m, options);
+ const expair subsed_pair = combine_ex_with_coeff_to_pair(subsed_rest, cit->coeff);
+ if (!subsed_pair.is_equal(*cit)) {
- // Something changed, copy seq, subs and return it
+ // Something changed: copy seq, subs and return it
epvector s;
s.reserve(seq.size());
s.insert(s.begin(), seq.begin(), cit);
// Copy first changed element
- s.push_back(combine_ex_with_coeff_to_pair(subsed_ex, cit->coeff));
+ s.push_back(subsed_pair);
++cit;
// Copy rest
ex function::eval(int level) const
{
+ if ((level == 1) && (flags & status_flags::evaluated)) {
+ return *this;
+ }
+
if (level>1) {
// first evaluate children, then we will end up here again
return function(serial,evalchildren(level));
* @param level cut-off in recursive evaluation */
ex mul::eval(int level) const
{
- epvector evaled = evalchildren(level);
- if (unlikely(!evaled.empty())) {
- // do more evaluation later
- return dynallocate<mul>(std::move(evaled), overall_coeff);
- }
-
- if (flags & status_flags::evaluated) {
+ if ((level == 1) && (flags & status_flags::evaluated)) {
GINAC_ASSERT(seq.size()>0);
GINAC_ASSERT(seq.size()>1 || !overall_coeff.is_equal(_ex1));
return *this;
}
-
+
+ const epvector evaled = evalchildren(level);
+ if (unlikely(!evaled.empty())) {
+ // start over evaluating a new object
+ return dynallocate<mul>(std::move(evaled), overall_coeff);
+ }
+
size_t seq_size = seq.size();
if (overall_coeff.is_zero()) {
// *(...,x;0) -> 0
--level;
for (auto & it : seq) {
- s.push_back(combine_ex_with_coeff_to_pair(it.rest.evalf(level),
- it.coeff));
+ s.push_back(expair(it.rest.evalf(level), it.coeff));
}
- return mul(std::move(s), overall_coeff.evalf(level));
+ return dynallocate<mul>(std::move(s), overall_coeff.evalf(level));
}
void mul::find_real_imag(ex & rp, ex & ip) const
expair mul::combine_ex_with_coeff_to_pair(const ex & e,
const ex & c) const
{
+ GINAC_ASSERT(is_exactly_a<numeric>(c));
+
+ // First, try a common shortcut:
+ if (is_exactly_a<symbol>(e))
+ return expair(e, c);
+
// to avoid duplication of power simplification rules,
// we create a temporary power object
// otherwise it would be hard to correctly evaluate
expair mul::combine_pair_with_coeff_to_pair(const expair & p,
const ex & c) const
{
+ GINAC_ASSERT(is_exactly_a<numeric>(p.coeff));
+ GINAC_ASSERT(is_exactly_a<numeric>(c));
+
// to avoid duplication of power simplification rules,
// we create a temporary power object
// otherwise it would be hard to correctly evaluate
if (oc.info(info_flags::numeric))
return thisexpairseq(std::move(s), overall_coeff);
else
- s.push_back(combine_ex_with_coeff_to_pair(oc, _ex1));
+ s.push_back(expair(oc, _ex1));
return thisexpairseq(std::move(s), default_overall_coeff());
}
if (oc.info(info_flags::numeric))
return thisexpairseq(std::move(s), overall_coeff);
else
- s.push_back(combine_ex_with_coeff_to_pair(oc, _ex1));
+ s.push_back(expair(oc, _ex1));
return thisexpairseq(std::move(s), default_overall_coeff());
}
composition_generator compositions(partition);
do {
const std::vector<int>& exponent = compositions.current();
- exvector monomial;
+ epvector monomial;
monomial.reserve(msize);
numeric factor = coeff;
for (unsigned i = 0; i < exponent.size(); ++i) {
// optimize away
} else if (exponent[i] == 1) {
// optimized
- monomial.push_back(r);
+ monomial.push_back(expair(r, _ex1));
if (c != *_num1_p)
factor = factor.mul(c);
} else { // general case exponent[i] > 1
- monomial.push_back(dynallocate<power>(r, exponent[i]));
+ monomial.push_back(expair(r, exponent[i]));
if (c != *_num1_p)
factor = factor.mul(c.power(exponent[i]));
}
}
- result.push_back(a.combine_ex_with_coeff_to_pair(mul(monomial).expand(options), factor));
+ result.push_back(expair(mul(monomial).expand(options), factor));
} while (compositions.next());
} while (partitions.next());
}
GINAC_ASSERT(result.size() == result_size);
-
if (a.overall_coeff.is_zero()) {
return dynallocate<add>(std::move(result)).setflag(status_flags::expanded);
} else {
if (c.is_equal(_ex1)) {
if (is_exactly_a<mul>(r)) {
- result.push_back(a.combine_ex_with_coeff_to_pair(expand_mul(ex_to<mul>(r), *_num2_p, options, true),
- _ex1));
+ result.push_back(expair(expand_mul(ex_to<mul>(r), *_num2_p, options, true),
+ _ex1));
} else {
- result.push_back(a.combine_ex_with_coeff_to_pair(dynallocate<power>(r, _ex2),
- _ex1));
+ result.push_back(expair(dynallocate<power>(r, _ex2),
+ _ex1));
}
} else {
if (is_exactly_a<mul>(r)) {
- result.push_back(a.combine_ex_with_coeff_to_pair(expand_mul(ex_to<mul>(r), *_num2_p, options, true),
- ex_to<numeric>(c).power_dyn(*_num2_p)));
+ result.push_back(expair(expand_mul(ex_to<mul>(r), *_num2_p, options, true),
+ ex_to<numeric>(c).power_dyn(*_num2_p)));
} else {
- result.push_back(a.combine_ex_with_coeff_to_pair(dynallocate<power>(r, _ex2),
- ex_to<numeric>(c).power_dyn(*_num2_p)));
+ result.push_back(expair(dynallocate<power>(r, _ex2),
+ ex_to<numeric>(c).power_dyn(*_num2_p)));
}
}
for (epvector::const_iterator cit1=cit0+1; cit1!=last; ++cit1) {
const ex & r1 = cit1->rest;
const ex & c1 = cit1->coeff;
- result.push_back(a.combine_ex_with_coeff_to_pair(mul(r,r1).expand(options),
- _num2_p->mul(ex_to<numeric>(c)).mul_dyn(ex_to<numeric>(c1))));
+ result.push_back(expair(mul(r,r1).expand(options),
+ _num2_p->mul(ex_to<numeric>(c)).mul_dyn(ex_to<numeric>(c1))));
}
}