[GiNaC-list] Bug with evalm()?

Sheplyakov Alexei varg at theor.jinr.ru
Fri Feb 9 19:46:43 CET 2007


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;
 	ex derivative(const symbol & s) const;

Best regards,

All science is either physics or stamp collecting.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 827 bytes
Desc: Digital signature
Url : http://www.cebix.net/pipermail/ginac-list/attachments/20070209/5368c305/attachment.pgp

More information about the GiNaC-list mailing list