res.append(H(lst{-2,1,3},numeric(1)/3).hold() - -Li(lst{2,1,3},lst{-numeric(1)/3,-1,1}).hold());
res.append(H(lst{-2,1,3},numeric(98)/100).hold() - -Li(lst{2,1,3},lst{-numeric(98)/100,-1,1}).hold());
res.append(H(lst{-2,1,3},numeric(245)/100).hold() - -Li(lst{2,1,3},lst{-numeric(245)/100,-1,1}).hold());
- res.append(H(lst{-3,1,-2,0,0},numeric(3)/10).hold() - convert_H_to_Li(lst{-3,1,-2,0,0},numeric(3)/10).eval());
+ res.append(H(lst{-3,1,-2,0,0},numeric(3)/10).hold() - convert_H_to_Li(lst{-3,1,-2,0,0},numeric(3)/10));
for (lst::const_iterator it = res.begin(); it != res.end(); it++) {
ex diff = abs((*it).evalf());
f = e*y;
g = f - e*y;
- // After .expand(), g should be zero:
- if (!g.expand().is_zero()) {
- clog << "e = (x + z*x); f = e*y; expand(f - e*y) erroneously returned "
- << g.expand() << endl;
- ++result;
- }
// After .eval(), g should be zero:
- if (!g.eval().is_zero()) {
- clog << "e = (x + z*x); f = e*y; eval(f - e*y) erroneously returned "
- << g.eval() << endl;
- ++result;
- }
- // This actually worked already back in April 1999.
- // But we are *very* paranoic!
- if (!g.expand().eval().is_zero()) {
- clog << "e = (x + z*x); f = e*y; eval(expand(f - e*y)) erroneously returned "
- << g.expand().eval() << endl;
+ if (!g.is_zero()) {
+ clog << "e = (x + z*x); f = e*y; g = (f - e*y) erroneously returned g == "
+ << g << endl;
++result;
}
<< f << endl;
++result;
}
- if (!f.eval().is_equal(y)) {
- clog << "e = x*y - y; eval(e.subs(x == 2)) erroneously returned "
- << f.eval() << endl;
- ++result;
- }
- if (!f.expand().is_equal(y)) {
- clog << "e = x*y - y; expand(e.subs(x == 2)) erroneously returned "
- << f.expand() << endl;
- ++result;
- }
return result;
}
<< g << endl;
++result;
}
- if (!g.is_zero()) {
- clog << "e = pow(x,2) + x + 1; f = pow(x,2) + x + 1; g = e-f; g.eval() erroneously returned "
- << g.eval() << endl;
- ++result;
- }
return result;
}
ex r;
try {
- r = pow(b,e).eval();
+ r = pow(b, e);
if (!(r-2*sqrt(ex(2))).is_zero()) {
clog << "2^(3/2) erroneously returned " << r << " instead of 2*sqrt(2)" << endl;
++result;
c.s << "<" << sp.left << "|" << sp.right << ">";
}
-template <> ex sprod::eval(int level) const
+template <> ex sprod::eval() const
{
// symmetric scalar product
const sprod_s & sp = get_struct();
Internally, the anonymous evaluator in GiNaC is implemented by the methods
@example
-ex ex::eval(int level = 0) const;
-ex basic::eval(int level = 0) const;
+ex ex::eval() const;
+ex basic::eval() const;
@end example
but unless you are extending GiNaC with your own classes or functions, there
@{
...
public:
- ex eval(int level = 0) const;
+ ex eval() const override;
...
@};
-ex mystring::eval(int level) const
+ex mystring::eval() const
@{
string new_str;
for (size_t i=0; i<str.length(); i++) @{
if (new_str.length() == 0)
return 0;
- else
- return mystring(new_str).hold();
+
+ return mystring(new_str).hold();
@}
@end example
-The @code{level} argument is used to limit the recursion depth of the
-evaluation. We don't have any subexpressions in the @code{mystring}
-class so we are not concerned with this. If we had, we would call the
-@code{eval()} functions of the subexpressions with @code{level - 1} as
-the argument if @code{level != 1}. The @code{hold()} member function
-sets a flag in the object that prevents further evaluation. Otherwise
-we might end up in an endless loop. When you want to return the object
-unmodified, use @code{return this->hold();}.
+The @code{hold()} member function sets a flag in the object that prevents
+further evaluation. Otherwise we might end up in an endless loop. When you
+want to return the object unmodified, use @code{return this->hold();}.
+
+If our class had subobjects, we would have to evaluate them first (unless
+they are all of type @code{ex}, which are automatically evaluated). We don't
+have any subexpressions in the @code{mystring} class, so we are not concerned
+with this.
Let's confirm that it works:
@cindex @code{calchash()}
@cindex @code{is_equal_same_type()}
@example
-unsigned calchash() const;
-bool is_equal_same_type(const basic & other) const;
+unsigned calchash() const override;
+bool is_equal_same_type(const basic & other) const override;
@end example
The @code{calchash()} method returns an @code{unsigned} hash value for the
might want to provide:
@example
-bool info(unsigned inf) const;
-ex evalf(int level = 0) const;
-ex series(const relational & r, int order, unsigned options = 0) const;
-ex derivative(const symbol & s) const;
+bool info(unsigned inf) const override;
+ex evalf(int level = 0) const override;
+ex series(const relational & r, int order, unsigned options = 0) const override;
+ex derivative(const symbol & s) const override;
@end example
If your class stores sub-expressions (see the scalar product example in the
@cindex @code{let_op()}
@example
-size_t nops() cont;
-ex op(size_t i) const;
-ex & let_op(size_t i);
-ex subs(const lst & ls, const lst & lr, unsigned options = 0) const;
-ex map(map_function & f) const;
+size_t nops() const override;
+ex op(size_t i) const override;
+ex & let_op(size_t i) override;
+ex subs(const lst & ls, const lst & lr, unsigned options = 0) const override;
+ex map(map_function & f) const override;
@end example
@code{let_op()} is a variant of @code{op()} that allows write access. The
* an expression that contain a plain number.
* - +(;c) -> c
* - +(x;0) -> x
- *
- * @param level cut-off in recursive evaluation */
-ex add::eval(int level) const
+ */
+ex add::eval() const
{
- if ((level == 1) && (flags & status_flags::evaluated)) {
+ if (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);
+ const epvector evaled = evalchildren();
if (unlikely(!evaled.empty())) {
// start over evaluating a new object
return dynallocate<add>(std::move(evaled), overall_coeff);
int degree(const ex & s) const override;
int ldegree(const ex & s) const override;
ex coeff(const ex & s, int n=1) const override;
- ex eval(int level=0) const override;
+ ex eval() const override;
ex evalm() const override;
ex series(const relational & r, int order, unsigned options = 0) const override;
ex normal(exmap & repl, exmap & rev_lookup, int level=0) const override;
}
/** Perform automatic non-interruptive term rewriting rules. */
-ex basic::eval(int level) const
+ex basic::eval() const
{
// There is nothing to do for basic objects:
return hold();
}
// evaluation
- virtual ex eval(int level = 0) const;
+ virtual ex eval() const;
virtual ex evalf(int level = 0) const;
virtual ex evalm() const;
virtual ex eval_integ() const;
size_t nops() const override { return this->seq.size(); }
ex op(size_t i) const override;
ex & let_op(size_t i) override;
- ex eval(int level = 0) const override;
ex subs(const exmap & m, unsigned options = 0) const override;
void read_archive(const archive_node &n, lst &sym_lst) override
void do_print_tree(const print_tree & c, unsigned level) const;
void do_print_python(const print_python & c, unsigned level) const;
void do_print_python_repr(const print_python_repr & c, unsigned level) const;
- STLT evalchildren(int level) const;
STLT subschildren(const exmap & m, unsigned options = 0) const;
};
return *it;
}
-template <template <class T, class = std::allocator<T>> class C>
-ex container<C>::eval(int level) const
-{
- if (level == 1)
- return hold();
- else
- return thiscontainer(evalchildren(level));
-}
-
template <template <class T, class = std::allocator<T>> class C>
ex container<C>::subs(const exmap & m, unsigned options) const
{
c.s << closebracket;
}
-template <template <class T, class = std::allocator<T>> class C>
-typename container<C>::STLT container<C>::evalchildren(int level) const
-{
- if (level == 1)
- return this->seq;
- else if (level == -max_recursion_level)
- throw std::runtime_error("max recursion level reached");
-
- STLT s;
- this->reserve(s, this->seq.size());
-
- --level;
- const_iterator it = this->seq.begin(), itend = this->seq.end();
- while (it != itend) {
- s.push_back(it->eval(level));
- ++it;
- }
-
- return s;
-}
-
template <template <class T, class = std::allocator<T>> class C>
typename container<C>::STLT container<C>::subschildren(const exmap & m, unsigned options) const
{
// apply eval() once more. The recursion stops when eval() calls
// hold() or returns an object that already has its "evaluated"
// flag set, such as a symbol or a numeric.
- const ex & tmpex = other.eval(1);
+ const ex & tmpex = other.eval();
// Eventually, the eval() recursion goes through the "else" branch
// below, which assures that the object pointed to by tmpex.bp is
const_postorder_iterator postorder_end() const noexcept;
// evaluation
- ex eval(int level = 0) const { return bp->eval(level); }
+ ex eval() const { return bp->eval(); }
ex evalf(int level = 0) const { return bp->evalf(level); }
ex evalm() const { return bp->evalm(); }
ex eval_ncmul(const exvector & v) const { return bp->eval_ncmul(v); }
inline ex collect(const ex & thisex, const ex & s, bool distributed = false)
{ return thisex.collect(s, distributed); }
-inline ex eval(const ex & thisex, int level = 0)
-{ return thisex.eval(level); }
+inline ex eval(const ex & thisex)
+{ return thisex.eval(); }
inline ex evalf(const ex & thisex, int level = 0)
{ return thisex.evalf(level); }
}
/** Perform coefficient-wise automatic term rewriting rules in this class. */
-ex expairseq::eval(int level) const
+ex expairseq::eval() const
{
- if ((level==1) && (flags &status_flags::evaluated))
+ if (flags &status_flags::evaluated)
return *this;
- const epvector evaled = evalchildren(level);
+ const epvector evaled = evalchildren();
if (!evaled.empty())
return dynallocate<expairseq>(std::move(evaled), overall_coeff).setflag(status_flags::evaluated);
else
* @see expairseq::eval()
* @return epvector containing evaluated pairs, empty if no members
* had to be changed. */
-epvector expairseq::evalchildren(int level) const
+epvector expairseq::evalchildren() const
{
- if (level == -max_recursion_level)
- throw(std::runtime_error("max recursion level reached"));
-
auto cit = seq.begin(), last = seq.end();
while (cit!=last) {
- 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);
+ const expair evaled_pair = combine_ex_with_coeff_to_pair(cit->rest, cit->coeff);
if (unlikely(!evaled_pair.is_equal(*cit))) {
// something changed: copy seq, eval and return it
// copy rest
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));
+ s.push_back(combine_ex_with_coeff_to_pair(cit->rest, cit->coeff));
++cit;
}
return s;
size_t nops() const override;
ex op(size_t i) const override;
ex map(map_function & f) const override;
- ex eval(int level=0) const override;
+ ex eval() const override;
ex to_rational(exmap & repl) const override;
ex to_polynomial(exmap & repl) const override;
bool match(const ex & pattern, exmap& repl_lst) const override;
void combine_same_terms_sorted_seq();
bool is_canonical() const;
epvector expandchildren(unsigned options) const;
- epvector evalchildren(int level) const;
+ epvector evalchildren() const;
epvector subschildren(const exmap & m, unsigned options = 0) const;
// member variables
s2 += e.op(i);
}
}
- s1 = s1.eval();
- s2 = s2.eval();
return factor(s1, options) + s2.map(*this);
}
return e.map(*this);
c.s << std::string(level + c.delta_indent, ' ') << "=====" << std::endl;
}
-ex fderivative::eval(int level) const
+ex fderivative::eval() const
{
- if (level > 1) {
- // first evaluate children, then we will end up here again
- return fderivative(serial, parameter_set, evalchildren(level));
- }
-
// No parameters specified? Then return the function itself
if (parameter_set.empty())
return function(serial, seq);
// functions overriding virtual functions from base classes
public:
void print(const print_context & c, unsigned level = 0) const override;
- ex eval(int level = 0) const override;
+ ex eval() const override;
ex evalf(int level = 0) const override;
ex series(const relational & r, int order, unsigned options = 0) const override;
ex thiscontainer(const exvector & v) const override;
}
}
-ex function::eval(int level) const
+ex function::eval() const
{
- if ((level == 1) && (flags & status_flags::evaluated)) {
+ if (flags & status_flags::evaluated) {
return *this;
}
- if (level>1) {
- // first evaluate children, then we will end up here again
- return function(serial,evalchildren(level));
- }
-
GINAC_ASSERT(serial<registered_functions().size());
const function_options &opt = registered_functions()[serial];
void print(const print_context & c, unsigned level = 0) const override;
unsigned precedence() const override {return 70;}
ex expand(unsigned options=0) const override;
- ex eval(int level=0) const override;
+ ex eval() const override;
ex evalf(int level=0) const override;
ex eval_ncmul(const exvector & v) const override;
unsigned calchash() const override;
return inherited::compare_same_type(other);
}
-ex indexed::eval(int level) const
+ex indexed::eval() const
{
- // First evaluate children, then we will end up here again
- if (level > 1)
- return indexed(ex_to<symmetry>(symtree), evalchildren(level));
-
const ex &base = seq[0];
// If the base object is 0, the whole object is 0
public:
unsigned precedence() const override {return 55;}
bool info(unsigned inf) const override;
- ex eval(int level = 0) const override;
+ ex eval() const override;
ex real_part() const override;
ex imag_part() const override;
exvector get_free_indices() const override;
Gparameter pendint;
ex result = G_transform(pendint, a, scale, gsyms, flag_trailing_zeros_only);
// replace dummy symbols with their values
- result = result.eval().expand();
+ result = result.expand();
result = result.subs(subslst).evalf();
if (!is_a<numeric>(result))
throw std::logic_error("G_do_trafo: G_transform returned non-numeric result");
return f.compare(o.f);
}
-ex integral::eval(int level) const
+ex integral::eval() const
{
- if ((level==1) && (flags & status_flags::evaluated))
+ if (flags & status_flags::evaluated)
return *this;
- if (level == -max_recursion_level)
- throw(std::runtime_error("max recursion level reached"));
- ex eintvar = (level==1) ? x : x.eval(level-1);
- ex ea = (level==1) ? a : a.eval(level-1);
- ex eb = (level==1) ? b : b.eval(level-1);
- ex ef = (level==1) ? f : f.eval(level-1);
+ if (!f.has(x) && !haswild(f))
+ return b*f-a*f;
- if (!ef.has(eintvar) && !haswild(ef))
- return eb*ef-ea*ef;
-
- if (ea==eb)
+ if (a==b)
return _ex0;
- if (are_ex_trivially_equal(eintvar,x) && are_ex_trivially_equal(ea,a) &&
- are_ex_trivially_equal(eb,b) && are_ex_trivially_equal(ef,f))
- return this->hold();
- return dynallocate<integral>(eintvar, ea, eb, ef).setflag(status_flags::evaluated);
+ return this->hold();
}
ex integral::evalf(int level) const
// functions overriding virtual functions from base classes
public:
unsigned precedence() const override {return 45;}
- ex eval(int level=0) const override;
+ ex eval() const override;
ex evalf(int level=0) const override;
int degree(const ex & s) const override;
int ldegree(const ex & s) const override;
return m[i];
}
-/** Evaluate matrix entry by entry. */
-ex matrix::eval(int level) const
-{
- // check if we have to do anything at all
- if ((level==1)&&(flags & status_flags::evaluated))
- return *this;
-
- // emergency break
- if (level == -max_recursion_level)
- throw (std::runtime_error("matrix::eval(): recursion limit exceeded"));
-
- // eval() entry by entry
- exvector m2(row*col);
- --level;
- for (unsigned r=0; r<row; ++r)
- for (unsigned c=0; c<col; ++c)
- m2[r*col+c] = m[r*col+c].eval(level);
-
- return dynallocate<matrix>(row, col, std::move(m2)).setflag(status_flags::evaluated);
-}
-
ex matrix::subs(const exmap & mp, unsigned options) const
{
exvector m2(row * col);
size_t nops() const override;
ex op(size_t i) const override;
ex & let_op(size_t i) override;
- ex eval(int level=0) const override;
ex evalm() const override {return *this;}
ex subs(const exmap & m, unsigned options = 0) const override;
ex eval_indexed(const basic & i) const override;
inline ex expand(const matrix & m, unsigned options = 0)
{ return m.expand(options); }
-inline ex eval(const matrix & m, int level = 0)
-{ return m.eval(level); }
-
inline ex evalf(const matrix & m, int level = 0)
{ return m.evalf(level); }
* - *(+(x1,x2,...);c) -> *(+(*(x1,c),*(x2,c),...))
* - *(x;1) -> x
* - *(;c) -> c
- *
- * @param level cut-off in recursive evaluation */
-ex mul::eval(int level) const
+ */
+ex mul::eval() const
{
- if ((level == 1) && (flags & status_flags::evaluated)) {
+ if (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);
+ const epvector evaled = evalchildren();
if (unlikely(!evaled.empty())) {
// start over evaluating a new object
return dynallocate<mul>(std::move(evaled), overall_coeff);
int ldegree(const ex & s) const override;
ex coeff(const ex & s, int n = 1) const override;
bool has(const ex & other, unsigned options = 0) const override;
- ex eval(int level=0) const override;
+ ex eval() const override;
ex evalf(int level=0) const override;
ex real_part() const override;
ex imag_part() const override;
* - ncmul(...,c1,...,c2,...) -> *(c1,c2,ncmul(...)) (pull out commutative elements)
* - ncmul(x1,y1,x2,y2) -> *(ncmul(x1,x2),ncmul(y1,y2)) (collect elements of same type)
* - ncmul(x1,x2,x3,...) -> x::eval_ncmul(x1,x2,x3,...)
- *
- * @param level cut-off in recursive evaluation */
-ex ncmul::eval(int level) const
+ */
+ex ncmul::eval() const
{
// The following additional rule would be nice, but produces a recursion,
// which must be trapped by introducing a flag that the sub-ncmuls()
// ncmul(ncmul(x1,x2,...),X,ncmul(y1,y2,...)
// (X noncommutative_composite)
- if ((level==1) && (flags & status_flags::evaluated)) {
+ if (flags & status_flags::evaluated) {
return *this;
}
- exvector evaledseq=evalchildren(level);
-
// ncmul(...,*(x1,x2),...,ncmul(x3,x4),...) ->
// ncmul(...,x1,x2,...,x3,x4,...) (associativity)
size_t factors = 0;
- for (auto & it : evaledseq)
+ for (auto & it : seq)
factors += count_factors(it);
exvector assocseq;
assocseq.reserve(factors);
- make_flat_inserter mf(evaledseq, true);
- for (auto & it : evaledseq) {
+ make_flat_inserter mf(seq, true);
+ for (auto & it : seq) {
ex factor = mf.handle_factor(it, 1);
append_factors(assocseq, factor);
}
--i;
ev.push_back(i->conjugate());
}
- return dynallocate<ncmul>(std::move(ev)).eval();
+ return dynallocate<ncmul>(std::move(ev));
}
ex ncmul::real_part() const
int ldegree(const ex & s) const override;
ex expand(unsigned options=0) const override;
ex coeff(const ex & s, int n=1) const override;
- ex eval(int level=0) const override;
+ ex eval() const override;
ex evalm() const override;
exvector get_free_indices() const override;
ex thiscontainer(const exvector & v) const override;
* @param v vector of sym_desc structs (filled in) */
static void get_symbol_stats(const ex &a, const ex &b, sym_desc_vec &v)
{
- collect_symbols(a.eval(), v); // eval() to expand assigned symbols
- collect_symbols(b.eval(), v);
+ collect_symbols(a, v);
+ collect_symbols(b, v);
for (auto & it : v) {
int deg_a = a.degree(it.sym);
int deg_b = b.degree(it.sym);
/** Evaluation of numbers doesn't do anything at all. */
-ex numeric::eval(int level) const
+ex numeric::eval() const
{
- // Warning: if this is ever gonna do something, the ex ctors from all kinds
- // of numbers should be checking for status_flags::evaluated.
return this->hold();
}
int ldegree(const ex & s) const override;
ex coeff(const ex & s, int n = 1) const override;
bool has(const ex &other, unsigned options = 0) const override;
- ex eval(int level = 0) const override;
+ ex eval() const override;
ex evalf(int level = 0) const override;
ex subs(const exmap & m, unsigned options = 0) const override { return subs_one_level(m, options); } // overwrites basic::subs() for performance reasons
ex normal(exmap & repl, exmap & rev_lookup, int level = 0) const override;
* - ^(*(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)
- *
- * @param level cut-off in recursive evaluation */
-ex power::eval(int level) const
+ */
+ex power::eval() const
{
- if ((level==1) && (flags & status_flags::evaluated))
+ if (flags & status_flags::evaluated)
return *this;
- else if (level == -max_recursion_level)
- throw(std::runtime_error("max recursion level reached"));
-
- const ex & ebasis = level==1 ? basis : basis.eval(level-1);
- const ex & eexponent = level==1 ? exponent : exponent.eval(level-1);
-
+
const numeric *num_basis = nullptr;
const numeric *num_exponent = nullptr;
-
- if (is_exactly_a<numeric>(ebasis)) {
- num_basis = &ex_to<numeric>(ebasis);
+
+ if (is_exactly_a<numeric>(basis)) {
+ num_basis = &ex_to<numeric>(basis);
}
- if (is_exactly_a<numeric>(eexponent)) {
- num_exponent = &ex_to<numeric>(eexponent);
+ if (is_exactly_a<numeric>(exponent)) {
+ num_exponent = &ex_to<numeric>(exponent);
}
// ^(x,0) -> 1 (0^0 also handled here)
- if (eexponent.is_zero()) {
- if (ebasis.is_zero())
+ if (exponent.is_zero()) {
+ if (basis.is_zero())
throw (std::domain_error("power::eval(): pow(0,0) is undefined"));
else
return _ex1;
}
// ^(x,1) -> x
- if (eexponent.is_equal(_ex1))
- return ebasis;
+ if (exponent.is_equal(_ex1))
+ return basis;
// ^(0,c1) -> 0 or exception (depending on real value of c1)
- if ( ebasis.is_zero() && num_exponent ) {
+ if (basis.is_zero() && num_exponent) {
if ((num_exponent->real()).is_zero())
throw (std::domain_error("power::eval(): pow(0,I) is undefined"));
else if ((num_exponent->real()).is_negative())
}
// ^(1,x) -> 1
- if (ebasis.is_equal(_ex1))
+ if (basis.is_equal(_ex1))
return _ex1;
// power of a function calculated by separate rules defined for this function
- if (is_exactly_a<function>(ebasis))
- return ex_to<function>(ebasis).power(eexponent);
+ if (is_exactly_a<function>(basis))
+ return ex_to<function>(basis).power(exponent);
// Turn (x^c)^d into x^(c*d) in the case that x is positive and c is real.
- if (is_exactly_a<power>(ebasis) && ebasis.op(0).info(info_flags::positive) && ebasis.op(1).info(info_flags::real))
- return power(ebasis.op(0), ebasis.op(1) * eexponent);
+ if (is_exactly_a<power>(basis) && basis.op(0).info(info_flags::positive) && basis.op(1).info(info_flags::real))
+ return power(basis.op(0), basis.op(1) * exponent);
if ( num_exponent ) {
// ^(^(x,c1),c2) -> ^(x,c1*c2)
// (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<power>(basis)) {
+ const power & sub_power = ex_to<power>(basis);
const ex & sub_basis = sub_power.basis;
const ex & sub_exponent = sub_power.exponent;
if (is_exactly_a<numeric>(sub_exponent)) {
}
// ^(*(x,y,z),c1) -> *(x^c1,y^c1,z^c1) (c1 integer)
- if (num_exponent->is_integer() && is_exactly_a<mul>(ebasis)) {
- return expand_mul(ex_to<mul>(ebasis), *num_exponent, 0);
+ if (num_exponent->is_integer() && is_exactly_a<mul>(basis)) {
+ return expand_mul(ex_to<mul>(basis), *num_exponent, 0);
}
// (2*x + 6*y)^(-4) -> 1/16*(x + 3*y)^(-4)
- if (num_exponent->is_integer() && is_exactly_a<add>(ebasis)) {
- numeric icont = ebasis.integer_content();
+ if (num_exponent->is_integer() && is_exactly_a<add>(basis)) {
+ numeric icont = basis.integer_content();
const numeric lead_coeff =
- ex_to<numeric>(ex_to<add>(ebasis).seq.begin()->coeff).div(icont);
+ ex_to<numeric>(ex_to<add>(basis).seq.begin()->coeff).div(icont);
const bool canonicalizable = lead_coeff.is_integer();
const bool unit_normal = lead_coeff.is_pos_integer();
icont = icont.mul(*_num_1_p);
if (canonicalizable && (icont != *_num1_p)) {
- const add& addref = ex_to<add>(ebasis);
+ const add& addref = ex_to<add>(basis);
add & addp = dynallocate<add>(addref);
addp.clearflag(status_flags::hash_calculated);
addp.overall_coeff = ex_to<numeric>(addp.overall_coeff).div_dyn(icont);
// ^(*(...,x;c1),c2) -> *(^(*(...,x;1),c2),c1^c2) (c1, c2 numeric(), c1>0)
// ^(*(...,x;c1),c2) -> *(^(*(...,x;-1),c2),(-c1)^c2) (c1, c2 numeric(), c1<0)
- if (is_exactly_a<mul>(ebasis)) {
+ if (is_exactly_a<mul>(basis)) {
GINAC_ASSERT(!num_exponent->is_integer()); // should have been handled above
- const mul & mulref = ex_to<mul>(ebasis);
+ const mul & mulref = ex_to<mul>(basis);
if (!mulref.overall_coeff.is_equal(_ex1)) {
const numeric & num_coeff = ex_to<numeric>(mulref.overall_coeff);
if (num_coeff.is_real()) {
// ^(nc,c1) -> ncmul(nc,nc,...) (c1 positive integer, unless nc is a matrix)
if (num_exponent->is_pos_integer() &&
- ebasis.return_type() != return_types::commutative &&
- !is_a<matrix>(ebasis)) {
- return ncmul(exvector(num_exponent->to_int(), ebasis));
+ basis.return_type() != return_types::commutative &&
+ !is_a<matrix>(basis)) {
+ return ncmul(exvector(num_exponent->to_int(), basis));
}
}
-
- if (are_ex_trivially_equal(ebasis,basis) &&
- are_ex_trivially_equal(eexponent,exponent)) {
- return this->hold();
- }
- return dynallocate<power>(ebasis, eexponent).setflag(status_flags::evaluated);
+
+ return this->hold();
}
ex power::evalf(int level) const
int degree(const ex & s) const override;
int ldegree(const ex & s) const override;
ex coeff(const ex & s, int n = 1) const override;
- ex eval(int level=0) const override;
+ ex eval() const override;
ex evalf(int level=0) const override;
ex evalm() const override;
ex series(const relational & s, int order, unsigned options = 0) const override;
}
/** Perform coefficient-wise automatic term rewriting rules in this class. */
-ex pseries::eval(int level) const
+ex pseries::eval() const
{
- if (level == 1)
- return this->hold();
-
- if (level == -max_recursion_level)
- throw (std::runtime_error("pseries::eval(): recursion limit exceeded"));
+ if (flags & status_flags::evaluated) {
+ return *this;
+ }
// Construct a new series with evaluated coefficients
epvector new_seq;
new_seq.reserve(seq.size());
epvector::const_iterator it = seq.begin(), itend = seq.end();
while (it != itend) {
- new_seq.push_back(expair(it->rest.eval(level-1), it->coeff));
+ new_seq.push_back(expair(it->rest, it->coeff));
++it;
}
return dynallocate<pseries>(relational(var,point), std::move(new_seq)).setflag(status_flags::evaluated);
int ldegree(const ex &s) const override;
ex coeff(const ex &s, int n = 1) const override;
ex collect(const ex &s, bool distributed = false) const override;
- ex eval(int level=0) const override;
+ ex eval() const override;
ex evalf(int level=0) const override;
ex series(const relational & r, int order, unsigned options = 0) const override;
ex subs(const exmap & m, unsigned options = 0) const override;
return *this;
}
-ex relational::eval(int level) const
-{
- if (level==1)
- return this->hold();
-
- if (level == -max_recursion_level)
- throw(std::runtime_error("max recursion level reached"));
-
- return dynallocate<relational>(lh.eval(level-1), rh.eval(level-1), o).setflag(status_flags::evaluated);
-}
-
ex relational::subs(const exmap & m, unsigned options) const
{
const ex & subsed_lh = lh.subs(m, options);
ex op(size_t i) const override;
ex map(map_function & f) const override;
ex subs(const exmap & m, unsigned options = 0) const override;
- ex eval(int level=0) const override;
/** Save (a.k.a. serialize) object into archive. */
void archive(archive_node& n) const override;
// All these are just defaults that can be specialized by the user
public:
// evaluation
- ex eval(int level = 0) const override { return hold(); }
+ ex eval() const override { return hold(); }
ex evalf(int level = 0) const override { return inherited::evalf(level); }
ex evalm() const override { return inherited::evalm(); }
protected:
// functions overriding virtual functions from base classes
public:
bool info(unsigned inf) const override;
- ex eval(int level = 0) const override { return *this; } // for performance reasons
+ ex eval() const override { return *this; } // for performance reasons
ex evalf(int level = 0) const override { return *this; } // overwrites basic::evalf() for performance reasons
ex series(const relational & s, int order, unsigned options = 0) const override;
ex subs(const exmap & m, unsigned options = 0) const override { return subs_one_level(m, options); } // overwrites basic::subs() for performance reasons
if (i == assigned_symbol_table.end())
$$ = $1;
else
- $$ = i->second.eval();
+ $$ = i->second;
}
| '\'' T_SYMBOL '\'' {$$ = $2;}
| T_LITERAL {$$ = $1;}
static ex f_convert_H_to_Li(const exprseq &e) {return convert_H_to_Li(e[0], e[1]);}
static ex f_degree(const exprseq &e) {return e[0].degree(e[1]);}
static ex f_denom(const exprseq &e) {return e[0].denom();}
-static ex f_eval1(const exprseq &e) {return e[0].eval();}
static ex f_evalf1(const exprseq &e) {return e[0].evalf();}
static ex f_evalm(const exprseq &e) {return e[0].evalm();}
static ex f_eval_integ(const exprseq &e) {return e[0].eval_integ();}
return fail();
}
-static ex f_eval2(const exprseq &e)
-{
- CHECK_ARG(1, numeric, eval);
- return e[0].eval(ex_to<numeric>(e[1]).to_int());
-}
-
static ex f_evalf2(const exprseq &e)
{
CHECK_ARG(1, numeric, evalf);
{"diff", f_diff2, 2},
{"diff", f_diff3, 3},
{"divide", f_divide, 2},
- {"eval", f_eval1, 1},
- {"eval", f_eval2, 2},
{"evalf", f_evalf1, 1},
{"evalf", f_evalf2, 2},
{"evalm", f_evalm, 1},
static ex f_ginac_function(const exprseq &es, int serial)
{
- return GiNaC::function(serial, es).eval(1);
+ return GiNaC::function(serial, es);
}
// All registered GiNaC functions