Hello! On Fri, Feb 09, 2007 at 05:39:50PM +0100, Martin Sandve Alnæs wrote:
I believe there is a bug in the implementation of evalm(). Its behaviour should be to do nothing if it is not applicable to the ex it is called on, right?
As of now, eval* methods do behave this way (well, mostly). [I'd prefer them to throw an exception instead, so bugs in code become evident earlier].
The minimal example below throws an exception:
#include <ginac/ginac.h>
using namespace std; using namespace GiNaC;
int main(int argc, char **argv) { ex x = symbol("x"); ex e = sin(x); ex s = e.series(x == 0, 3); cout << "This will crash:" << endl;
Not exactly. This is an uncaught exception.
ex m = s.evalm(); return 0; }
The error is:
terminate called after throwing an instance of 'std::range_error' what(): basic::let_op(): pseries has no operands Aborted (core dumped)
This bug is unlikely to be fixed in GiNaC 1.3.X :( There are two possible work-arounds: 1) catch std::range_error exception, e.g. ex m; try { m = s.evalm(); } catch (std::range_error& oops) { m = s; } This is not exactly correct (one might got std::range_error for some "real" reason)... 2) convert the expression from power series to polynomial: ex m = series_to_poly(s).evalm(); This one is not exaclty fool-proof: it will fail if s is not a power series object...
Of course, it doesn't make much sense to call evalm() on this expression, but it is a problem in an application where we want to call evalm() "just in case" on all ex objects that pass a certain point in the application.
I'd say that such an "just in a case" code is buggy and/or very inefficient in first place.
Thus a "do nothing" behaviour for evalm() is of great importance.
I agree -- at least it should be consistent with behaviour of other eval* methods. @ developers The `pseries' class does not overload evalm(). So default basic::evalm() is used, which needs let_op() or map(). But these are not overloaded too, probably because semantics of such operations is not very clear. Thus default basic::let_op() is used [which throws an exception]... Here is a dumb fix: [PATCH] pseries.{h, cpp}: provide no-op pseries::evalm() Code like this: symbol x; ex test = sin(x).series(x, 5).evalm(); throws an exception. I'd say this is good, because it urges users to fix their sloppy code. But this behaviour is inconsistent with one of other eval* methods which are no-op if operation in question is meaningless. Unfortunately this change is not suitable for GiNaC 1.3 due to the A[PB]I breakage. --- ginac/pseries.cpp | 5 +++++ ginac/pseries.h | 1 + 2 files changed, 6 insertions(+), 0 deletions(-) diff --git a/ginac/pseries.cpp b/ginac/pseries.cpp index db7cef3..a6780a6 100644 --- a/ginac/pseries.cpp +++ b/ginac/pseries.cpp @@ -464,6 +464,11 @@ ex pseries::imag_part() const return (new pseries(var==point, v))->setflag(status_flags::dynallocated); } +ex pseries::evalm() const +{ + return *this; +} + ex pseries::eval_integ() const { epvector *newseq = NULL; diff --git a/ginac/pseries.h b/ginac/pseries.h index ed266c4..e53baf6 100644 --- a/ginac/pseries.h +++ b/ginac/pseries.h @@ -59,6 +59,7 @@ public: ex real_part() const; ex imag_part() const; ex eval_integ() const; + ex evalm() const; protected: ex derivative(const symbol & s) const; -- 1.4.4.4 Best regards, Alexei -- All science is either physics or stamp collecting.