]> www.ginac.de Git - ginac.git/blobdiff - ginac/mul.cpp
Make add::eval(), mul::eval() work without compromise.
[ginac.git] / ginac / mul.cpp
index f8ddd9b2eb8ce2a86a84aecf7547ed7696a7a87b..a83b771d91d8f40f842b67a7528e931037caf4e3 100644 (file)
@@ -435,7 +435,7 @@ ex mul::coeff(const ex & s, int n) const
                for (auto & it : seq)
                        coeffseq.push_back(recombine_pair_to_ex(it).coeff(s,n));
                coeffseq.push_back(overall_coeff);
-               return (new mul(coeffseq))->setflag(status_flags::dynallocated);
+               return dynallocate<mul>(coeffseq);
        }
        
        bool coeff_found = false;
@@ -451,7 +451,7 @@ ex mul::coeff(const ex & s, int n) const
        }
        if (coeff_found) {
                coeffseq.push_back(overall_coeff);
-               return (new mul(coeffseq))->setflag(status_flags::dynallocated);
+               return dynallocate<mul>(coeffseq);
        }
        
        return _ex0;
@@ -468,19 +468,18 @@ ex mul::coeff(const ex & s, int n) const
  *  @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 (new mul(std::move(evaled), overall_coeff))->
-                       setflag(status_flags::dynallocated);
-       }
-
-       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
@@ -501,10 +500,9 @@ ex mul::eval(int level) const
                for (auto & it : addref.seq) {
                        distrseq.push_back(addref.combine_pair_with_coeff_to_pair(it, overall_coeff));
                }
-               return (new add(std::move(distrseq),
-                               ex_to<numeric>(addref.overall_coeff).
-                               mul_dyn(ex_to<numeric>(overall_coeff)))
-                      )->setflag(status_flags::dynallocated | status_flags::evaluated);
+               return dynallocate<add>(std::move(distrseq),
+                                        ex_to<numeric>(addref.overall_coeff).mul_dyn(ex_to<numeric>(overall_coeff)))
+                       .setflag(status_flags::evaluated);
        } else if ((seq_size >= 2) && (! (flags & status_flags::expanded))) {
                // 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
@@ -554,14 +552,13 @@ ex mul::eval(int level) const
 
                        // divide add by the number in place to save at least 2 .eval() calls
                        const add& addref = ex_to<add>(i->rest);
-                       add* primitive = new add(addref);
-                       primitive->setflag(status_flags::dynallocated);
-                       primitive->clearflag(status_flags::hash_calculated);
-                       primitive->overall_coeff = ex_to<numeric>(primitive->overall_coeff).div_dyn(c);
-                       for (epvector::iterator ai = primitive->seq.begin(); ai != primitive->seq.end(); ++ai)
+                       add & primitive = dynallocate<add>(addref);
+                       primitive.clearflag(status_flags::hash_calculated);
+                       primitive.overall_coeff = ex_to<numeric>(primitive.overall_coeff).div_dyn(c);
+                       for (epvector::iterator ai = primitive.seq.begin(); ai != primitive.seq.end(); ++ai)
                                ai->coeff = ex_to<numeric>(ai->coeff).div_dyn(c);
                        
-                       s.push_back(expair(*primitive, _ex1));
+                       s.push_back(expair(primitive, _ex1));
 
                        ++i;
                        ++j;
@@ -571,8 +568,7 @@ ex mul::eval(int level) const
                                s.push_back(*j);
                                ++j;
                        }
-                       return (new mul(std::move(s), ex_to<numeric>(overall_coeff).mul_dyn(oc))
-                              )->setflag(status_flags::dynallocated);
+                       return dynallocate<mul>(std::move(s), ex_to<numeric>(overall_coeff).mul_dyn(oc));
                }
        }
 
@@ -592,10 +588,9 @@ ex mul::evalf(int level) const
 
        --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
@@ -664,11 +659,11 @@ ex mul::evalm() const
                // into that matrix.
                matrix m = ex_to<matrix>(the_matrix->rest);
                s.erase(the_matrix);
-               ex scalar = (new mul(std::move(s), overall_coeff))->setflag(status_flags::dynallocated);
+               ex scalar = dynallocate<mul>(std::move(s), overall_coeff);
                return m.mul_scalar(scalar);
 
        } else
-               return (new mul(std::move(s), overall_coeff))->setflag(status_flags::dynallocated);
+               return dynallocate<mul>(std::move(s), overall_coeff);
 }
 
 ex mul::eval_ncmul(const exvector & v) const
@@ -888,11 +883,11 @@ ex mul::derivative(const symbol & s) const
                expair ep = split_ex_to_pair(power(i->rest, i->coeff - _ex1) *
                                             i->rest.diff(s));
                ep.swap(*i2);
-               addseq.push_back((new mul(mulseq, overall_coeff * i->coeff))->setflag(status_flags::dynallocated));
+               addseq.push_back(dynallocate<mul>(mulseq, overall_coeff * i->coeff));
                ep.swap(*i2);
                ++i; ++i2;
        }
-       return (new add(addseq))->setflag(status_flags::dynallocated);
+       return dynallocate<add>(addseq);
 }
 
 int mul::compare_same_type(const basic & other) const
@@ -949,12 +944,12 @@ return_type_t mul::return_type_tinfo() const
 
 ex mul::thisexpairseq(const epvector & v, const ex & oc, bool do_index_renaming) const
 {
-       return (new mul(v, oc, do_index_renaming))->setflag(status_flags::dynallocated);
+       return dynallocate<mul>(v, oc, do_index_renaming);
 }
 
 ex mul::thisexpairseq(epvector && vp, const ex & oc, bool do_index_renaming) const
 {
-       return (new mul(std::move(vp), oc, do_index_renaming))->setflag(status_flags::dynallocated);
+       return dynallocate<mul>(std::move(vp), oc, do_index_renaming);
 }
 
 expair mul::split_ex_to_pair(const ex & e) const
@@ -970,6 +965,12 @@ expair mul::split_ex_to_pair(const ex & e) 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
@@ -983,6 +984,9 @@ expair mul::combine_ex_with_coeff_to_pair(const ex & e,
 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
@@ -998,7 +1002,7 @@ ex mul::recombine_pair_to_ex(const expair & p) const
        if (ex_to<numeric>(p.coeff).is_equal(*_num1_p)) 
                return p.rest;
        else
-               return (new power(p.rest,p.coeff))->setflag(status_flags::dynallocated);
+               return dynallocate<power>(p.rest, p.coeff);
 }
 
 bool mul::expair_needs_further_processing(epp it)
@@ -1047,10 +1051,9 @@ void mul::combine_overall_coeff(const ex & c1, const ex & c2)
 bool mul::can_make_flat(const expair & p) const
 {
        GINAC_ASSERT(is_exactly_a<numeric>(p.coeff));
-       // this assertion will probably fail somewhere
-       // it would require a more careful make_flat, obeying the power laws
-       // probably should return true only if p.coeff is integer
-       return ex_to<numeric>(p.coeff).is_equal(*_num1_p);
+
+       // (x*y)^c == x^c*y^c  if c ∈ ℤ
+       return p.coeff.info(info_flags::integer);
 }
 
 bool mul::can_be_further_expanded(const ex & e)
@@ -1135,7 +1138,7 @@ ex mul::expand(unsigned options) const
                                }
 
                                // Compute the new overall coefficient and put it together:
-                               ex tmp_accu = (new add(distrseq, add1.overall_coeff*add2.overall_coeff))->setflag(status_flags::dynallocated);
+                               ex tmp_accu = dynallocate<add>(distrseq, add1.overall_coeff*add2.overall_coeff);
 
                                exvector add1_dummy_indices, add2_dummy_indices, add_indices;
                                lst dummy_subs;
@@ -1169,14 +1172,14 @@ ex mul::expand(unsigned options) const
                                        for (const auto & i1 : add1.seq) {
                                                // Don't push_back expairs which might have a rest that evaluates to a numeric,
                                                // since that would violate an invariant of expairseq:
-                                               const ex rest = (new mul(i1.rest, i2_new))->setflag(status_flags::dynallocated);
+                                               const ex rest = dynallocate<mul>(i1.rest, i2_new);
                                                if (is_exactly_a<numeric>(rest)) {
                                                        oc += ex_to<numeric>(rest).mul(ex_to<numeric>(i1.coeff).mul(ex_to<numeric>(i2.coeff)));
                                                } else {
                                                        distrseq2.push_back(expair(rest, ex_to<numeric>(i1.coeff).mul_dyn(ex_to<numeric>(i2.coeff))));
                                                }
                                        }
-                                       tmp_accu += (new add(distrseq2, oc))->setflag(status_flags::dynallocated);
+                                       tmp_accu += dynallocate<add>(std::move(distrseq2), oc);
                                }
                                last_expanded = tmp_accu;
                        } else {
@@ -1208,7 +1211,7 @@ ex mul::expand(unsigned options) const
                                factors.push_back(split_ex_to_pair(last_expanded.op(i)));
                        else
                                factors.push_back(split_ex_to_pair(rename_dummy_indices_uniquely(va, last_expanded.op(i))));
-                       ex term = (new mul(factors, overall_coeff))->setflag(status_flags::dynallocated);
+                       ex term = dynallocate<mul>(factors, overall_coeff);
                        if (can_be_further_expanded(term)) {
                                distrseq.push_back(term.expand());
                        } else {
@@ -1218,12 +1221,11 @@ ex mul::expand(unsigned options) const
                        }
                }
 
-               return ((new add(distrseq))->
-                       setflag(status_flags::dynallocated | (options == 0 ? status_flags::expanded : 0)));
+               return dynallocate<add>(distrseq).setflag(options == 0 ? status_flags::expanded : 0);
        }
 
        non_adds.push_back(split_ex_to_pair(last_expanded));
-       ex result = (new mul(non_adds, overall_coeff))->setflag(status_flags::dynallocated);
+       ex result = dynallocate<mul>(non_adds, overall_coeff);
        if (can_be_further_expanded(result)) {
                return result.expand();
        } else {