It is possible to get an error estimate back from mpmath, as follows:
sage: mpmath.quad(lambda a: mpmath.exp(a)*mpmath.sin(1000*a),
[0,mpmath.pi], error=True)
(mpf('-0.71920642950258207'), mpf('1.0'))
sage: mpmath.quad(lambda a: mpmath.exp(a)*mpmath.sin(1000*a),
[0,mpmath.pi], maxdegree=15, error=True)
(mpf('-0.022140670492108779'), mpf('1.0e-37'))
Currently it doesn't seem to work with mpmath.call (because
mpmath_to_sage doesn't know what to do with a tuple).
The error estimates are also somewhat bogus (in both examples above --
the first value has been capped to 1.0, if I remember correctly what
the code does, and the second is an extrapolate of the quadrature
error alone and clearly doesn't account for the arithmetic error). But
it should be sufficient to correctly detect a problem and signal a
warning in the Sage wrapper code in typical cases.
I'm currently working on rewriting the integration code in mpmath to
handle error estimates more rigorously and flexibly. This will work
much better in a future version of mpmath.
Fredrik
Hi Maldun,
I think that improvement of numerical integration would be excellent.
I've been somewhat disappointed with the numerical integration in sage
in the past. Probably most of the functionality is actually in sage or
in components of sage, but it isn't exposed too well. (Or else I have
always used the wrong functions, or haven't tried in a while.)
I have some more thoughts below.
In sage it seems there are a few different ways to get a numeric
approximation to an integral. There are the top level functions integral
and numerical_integral (and their synonyms), and then symbolic
expressions have a method nintegrate. So if f is a symbolic expression,
1.) numerical_integral(f, 0, 1)
2.) integral(f, x, 0, 1).n() and
3.) f.nintegrate(x, 0, 1)
do 3 different things. Maybe there are also other "top level" ways of
definite integration that don't require either an import statement or a
direct call to mpmath.
I think I would like 1 and 3 to do the exact same thing. I don't know if
there is a good reason for them to be different. (I do know that I might
often be interested in integrating things that aren't symbolic
expressions, though.) I think that the behavior of integral().n() that
you list above is reasonable, though. If it fails like in the first
example you have above, then that is probably a _different_ bug. And the
second example is a type of problem we will probably always have to deal
with. (I have a similar example that came up in the "real world" that I
might try to dig up because I think it will have the same bad behavior.)
A different behavior that I would find reasonable is for integral().n()
to _never_ do numeric integration. If integral() can't get an exact
answer, then integral().n() could just give an error and ask the user to
call numerical_integral() if that's what's wanted.
If integral().n() always did numeric integration, then it would of
course suffer from the problems below.
> Then on the other hand if we would just hand over things to libraries
> like pari and mpmath we get no hint if our results are trustworthy.
> Consider following simple example of an oscillating integral:
>
> sage: mpmath.call(mpmath.quad,lambda a:
> mpmath.exp(a)*mpmath.sin(1000*a),[0,pi])
> -1.458868938634994559655
> sage: integrate(sin(1000*x)*exp(x),x,0,pi)
> -1000/1000001*e^pi + 1000/1000001
> sage: integrate(sin(1000*x)*exp(x),x,0,pi).n()
> -0.0221406704921088
>
> Do you see the problems?! These are caused by the high oscillation,
> but we get no warning.
> If you use scipy you would get the following:
>
> sage: import scipy
> sage: import scipy.integrate
> sage: scipy.integrate.quad(lambda a: exp(a)*sin(1000*a),0,pi)
> Warning: The integral is probably divergent, or slowly convergent.
> (-0.1806104043408597, 0.092211010882734368)
>
> That's how it should be: The user has to be informed if the result
> could be wrong, and is then able to choose another method. But in the
> current state, bad bad things could happen...
>
Printed warnings like this can be useful, but they can also be annoying,
especially if the numeric integration routine is not called from
interactive code. And they might not be necessary in an example like
above where the error estimate returned is almost as big as the answer
returned. At the very least, if a warning might be printed to standard
output I would like a way to turn it off.
mpmath's approach might be good, where it seems the error is only
returned if requested. Perhaps the default might be to print a warning
if the error is not requested and the answer is suspected to be bad, but
to not print any warning if the error is going to be returned.
> I already posted this issue on the mpmath devel-group. I hope Fredrik
> Johansson reads this also.
>
> Any thoughts or hints about that?
>
My main other thought is: Thanks for trying to improve numerical
integration. Since I've already said so much I may try to look at the
code/tickets soon to see if I have an opinion on how things should be
done, instead of just opinions on what I would like.
> greez,
> maldun
>
This is, of course, true, provided that no information is known about
the function except for its values on a set of measure 0. However, it is
certainly possible for a numeric integration routine to provide rigorous
error bounds provided that some additional constraints are satisfied.
For example, many functions have bounded variation, or have a bounded
derivative, or are strictly increasing. And I have found situations
where I would like to provide that information to an integration routine
and have it use it in order to provide me information about the error
bound. And it probably isn't unreasonable for an integration routine to
guess at that information, and to provide error bounds that are rigorous
assuming a set of not unreasonable hypotheses about the function it is
integrating.
>
> A nasty function: f(x) := if member(x,evaluation_point_set) then 0
> else 1.
> integrate(f,a,b) should be b-a. The numerical integration program
> returns 0.
>
I am aware that this type of problem can actually occur in real world
examples, but I suspect that in the specific case of numeric integration
it can be somewhat alleviated by using random sampling to choose an
initial evaluation_point_set. Regardless, the existence of unsolvable
problems should not stop us from solving the solvable problems.
> In sage it seems there are a few different ways to get a numeric
> approximation to an integral. There are the top level functions
> integral and numerical_integral (and their synonyms), and then
> symbolic expressions have a method nintegrate. So if f is a symbolic
> expression,
>
> 1.) numerical_integral(f, 0, 1)
> 2.) integral(f, x, 0, 1).n() and
> 3.) f.nintegrate(x, 0, 1)
>
> do 3 different things. Maybe there are also other "top level" ways of
> definite integration that don't require either an import statement or
> a direct call to mpmath.
>
> I think I would like 1 and 3 to do the exact same thing. I don't know
> if there is a good reason for them to be different. (I do know that I
> might often be interested in integrating things that aren't symbolic
> expressions, though.) I think that the behavior of integral().n() that
> you list above is reasonable, though. If it fails like in the first
> example you have above, then that is probably a _different_ bug. And
> the second example is a type of problem we will probably always have
> to deal with. (I have a similar example that came up in the "real
> world" that I might try to dig up because I think it will have the
> same bad behavior.)
AFAIK, the reason 1 and 3 work differently is mostly historic. Fixing
this could be a part of #7763:
http://trac.sagemath.org/sage_trac/ticket/7763
The behavior of integral().n() has to be different from
numerical_integral() since integral() first tries to integrate
symbolically.
One can use integral(..., hold=True).n() to get a similar effect, but
the options you can pass to the numerical evaluation routines of
symbolic expressions are limited at the moment.
> A different behavior that I would find reasonable is for
> integral().n() to _never_ do numeric integration. If integral() can't
> get an exact answer, then integral().n() could just give an error and
> ask the user to call numerical_integral() if that's what's wanted.
I would be OK with this as well.
> If integral().n() always did numeric integration, then it would of
> course suffer from the problems below.
How does doing N[Integrate[ ... ]] in MMA compare to using NIntegrate?
Cheers,
Burcin
If you use the standard Python warning framework, this would be easy.
Jason
I never thought I'd hear anyone used the term "design document" in relation to
Sage!
Seriously, Sage does need to
* Document the requirements for Sage
* Document a specification
* Document how those design requirements will be met
You clearly have hit a problem with numerical integration, but it seems to me
this lack of any design is hurting Sage in many areas. There's no logical path
that gets taken, based on a design.
dave