Skip to content

Commit

Permalink
sagemathgh-38686: Use the faster libgiac interface for "giac" integra…
Browse files Browse the repository at this point in the history
…tion

    
While working on sagemath#38668, I
noticed that all of our examples that use giac for integration do so
with `algorithm='giac'`. This uses the pexpect interface that is much
slower (and simply sloppier) than the library interface that would be
used with `algorithm='libgiac'`.

To fix this, I could just change those examples to
`algorithm='libgiac'`, but since the libgiac interface is better in
every way, that seems kind of rude to me. Most users aren't going to
know what lib-anything is, and if they just want to use giac, they're
going to try `algorithm='giac'`. So instead this PR makes
`algorithm='giac'` do the right thing, and use the better interface.
I've left the `algorithm='libgiac'` alone for now to avoid breaking any
code.

Afterwards I have removed the pexpect giac integrator entirely, because
there's no reason to use it, and no other code in sagelib uses it.
    
URL: sagemath#38686
Reported by: Michael Orlitzky
Reviewer(s): Dima Pasechnik, Tobias Diez
  • Loading branch information
Release Manager committed Dec 5, 2024
2 parents c2fb907 + 09572b1 commit a6f5fae
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 53 deletions.
1 change: 1 addition & 0 deletions src/sage/calculus/calculus.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@
Ensure that :issue:`25626` is fixed. As the form of the answer is dependent of
the giac version, we simplify it (see :issue:`34037`)::
sage: # needs sage.libs.giac
sage: t = SR.var('t')
sage: integrate(exp(t)/(t + 1)^2, t, algorithm='giac').full_simplify()
((t + 1)*Ei(t + 1) - e^(t + 1))/(t*e + e)
Expand Down
1 change: 1 addition & 0 deletions src/sage/functions/piecewise.py
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,7 @@ def integral(self, parameters, variable, x=None, a=None, b=None, definite=False,
Check that the algorithm keyword can be used::
sage: # needs sage.libs.giac
sage: ex = piecewise([([0, 1], 1), ((1, oo), 1/x**2)])
sage: integral(ex, x, 0, 100, algorithm='sympy')
199/100
Expand Down
10 changes: 10 additions & 0 deletions src/sage/libs/giac/giac.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,13 @@ TESTS::
sage: libgiac(-11^1000)
-2469932918005826334124088385085221477709733385238396234869182951830739390375433175367866116456946191973803561189036523363533798726571008961243792655536655282201820357872673322901148243453211756020067624545609411212063417307681204817377763465511222635167942816318177424600927358163388910854695041070577642045540560963004207926938348086979035423732739933235077042750354729095729602516751896320598857608367865475244863114521391548985943858154775884418927768284663678512441565517194156946312753546771163991252528017732162399536497445066348868438762510366191040118080751580689254476068034620047646422315123643119627205531371694188794408120267120500325775293645416335230014278578281272863450085145349124727476223298887655183167465713337723258182649072572861625150703747030550736347589416285606367521524529665763903537989935510874657420361426804068643262800901916285076966174176854351055183740078763891951775452021781225066361670593917001215032839838911476044840388663443684517735022039957481918726697789827894303408292584258328090724141496484460001
Ensure that signed infinities get converted correctly::
sage: libgiac(+Infinity)
+infinity
sage: libgiac(-Infinity)
-infinity
.. SEEALSO::
``libgiac``, ``giacsettings``, ``Pygen``,``loadgiacgen``
Expand Down Expand Up @@ -159,6 +166,7 @@ from sage.rings.integer_ring import ZZ
from sage.rings.rational_field import QQ
from sage.rings.finite_rings.integer_mod_ring import IntegerModRing
from sage.rings.integer cimport Integer
from sage.rings.infinity import AnInfinity
from sage.rings.rational cimport Rational
from sage.structure.element cimport Matrix
Expand Down Expand Up @@ -860,6 +868,8 @@ cdef class Pygen(GiacMethods_base):
s = s._giac_init_()
except AttributeError:
s = SRexpressiontoGiac(s)
elif isinstance(s, AnInfinity):
s = s._giac_init_()
if not isinstance(s, str):
s = s.__str__()
sig_on()
Expand Down
52 changes: 6 additions & 46 deletions src/sage/symbolic/integration/external.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,70 +214,31 @@ def fricas_integrator(expression, v, a=None, b=None, noPole=True):
return result


def giac_integrator(expression, v, a=None, b=None):
r"""
Integration using Giac.
EXAMPLES::
sage: from sage.symbolic.integration.external import giac_integrator
sage: giac_integrator(sin(x), x)
-cos(x)
sage: giac_integrator(1/(x^2+6), x, -oo, oo)
1/6*sqrt(6)*pi
TESTS::
sage: giac_integrator(e^(-x^2)*log(x), x)
integrate(e^(-x^2)*log(x), x)
Check that :issue:`30133` is fixed::
sage: ee = SR.var('e')
sage: giac_integrator(ee^x, x)
e^x/log(e)
sage: y = SR.var('π')
sage: giac_integrator(cos(y), y)
sin(π)
Check that :issue:`29966` is fixed::
sage: giac_integrator(sqrt(x + sqrt(x)), x)
1/12*(2*sqrt(x)*(4*sqrt(x) + 1) - 3)*sqrt(x + sqrt(x))...
"""
ex = expression._giac_()
if a is None:
result = ex.integrate(v._giac_())
else:
result = ex.integrate(v._giac_(), a._giac_(), b._giac_())
if 'integrate' in format(result) or 'integration' in format(result):
return expression.integrate(v, a, b, hold=True)
return result._sage_()


def libgiac_integrator(expression, v, a=None, b=None):
r"""
Integration using libgiac.
EXAMPLES::
sage: # needs sage.libs.giac
sage: import sage.libs.giac
...
sage: from sage.symbolic.integration.external import libgiac_integrator
sage: libgiac_integrator(sin(x), x)
-cos(x)
sage: libgiac_integrator(1/(x^2+6), x, -oo, oo)
No checks were made for singular points of antiderivative...
1/6*sqrt(6)*pi
TESTS::
sage: # needs sage.libs.giac
sage: libgiac_integrator(e^(-x^2)*log(x), x)
integrate(e^(-x^2)*log(x), x)
The following integral fails with the Giac Pexpect interface, but works
with libgiac (:issue:`31873`)::
sage: # needs sage.libs.giac
sage: a, x = var('a,x')
sage: f = sec(2*a*x)
sage: F = libgiac_integrator(f, x)
Expand All @@ -295,10 +256,9 @@ def libgiac_integrator(expression, v, a=None, b=None):
return expression.integrate(v, a, b, hold=True)

from sage.libs.giac.giac import Pygen
# We call Pygen on first argument because otherwise some expressions
# involving derivatives result in doctest failures in interfaces/sympy.py
# -- related to the fixme note in sage.libs.giac.giac.GiacFunction.__call__
# regarding conversion of lists.
# We call Pygen on first argument because otherwise some
# expressions involving derivatives result in doctest failures in
# sage/interfaces/sympy.py
if a is None:
result = libgiac.integrate(Pygen(expression), v)
else:
Expand Down
24 changes: 17 additions & 7 deletions src/sage/symbolic/integration/integral.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
available_integrators['sympy'] = external.sympy_integrator
available_integrators['mathematica_free'] = external.mma_free_integrator
available_integrators['fricas'] = external.fricas_integrator
available_integrators['giac'] = external.giac_integrator
available_integrators['giac'] = external.libgiac_integrator
available_integrators['libgiac'] = external.libgiac_integrator

######################################################
Expand Down Expand Up @@ -59,9 +59,10 @@ def __init__(self):
Check for :issue:`28913`::
sage: # needs sage.libs.giac
sage: Ex = (1-2*x^(1/3))^(3/4)/x
sage: integrate(Ex, x, algorithm='giac') # long time
4*(-2*x^(1/3) + 1)^(3/4) + 6*arctan((-2*x^(1/3) + 1)^(1/4)) - 3*log((-2*x^(1/3) + 1)^(1/4) + 1) + 3*log(abs((-2*x^(1/3) + 1)^(1/4) - 1))
4*(-2*x^(1/3) + 1)^(3/4) + 6*arctan((-2*x^(1/3) + 1)^(1/4)) - 3*log(abs((-2*x^(1/3) + 1)^(1/4) + 1)) + 3*log(abs((-2*x^(1/3) + 1)^(1/4) - 1))
Check for :issue:`29833`::
Expand Down Expand Up @@ -207,10 +208,13 @@ def __init__(self):
Check for :issue:`32354`::
sage: # needs sage.libs.giac
sage: ex = 1/max_symbolic(x, 1)**2
sage: integral(ex, x, 0, 2, algorithm='giac')
3/2
sage: integral(1/max_symbolic(x, 1)**2, x, 0, oo, algorithm='giac')
sage: result = integral(1/max_symbolic(x, 1)**2, x, 0, oo, algorithm='giac')
...
sage: result
2
"""
# The automatic evaluation routine will try these integrators
Expand Down Expand Up @@ -474,9 +478,9 @@ def integrate(expression, v=None, a=None, b=None, algorithm=None, hold=False):
- ``'fricas'`` -- use FriCAS (the optional fricas spkg has to be installed)
- ``'giac'`` -- use Giac
- ``'giac'`` -- use libgiac
- ``'libgiac'`` -- use libgiac
- ``'libgiac'`` -- use libgiac (alias for ``'giac'``)
To prevent automatic evaluation, use the ``hold`` argument.
Expand Down Expand Up @@ -695,9 +699,15 @@ def integrate(expression, v=None, a=None, b=None, algorithm=None, hold=False):
sage: integrate(f(x), x, 1, 2, algorithm='sympy') # needs sympy
-1/2*pi + arctan(8) + arctan(5) + arctan(2) + arctan(1/2)
Using Giac to integrate the absolute value of a trigonometric expression::
Using Giac to integrate the absolute value of a trigonometric
expression. If Giac is installed, this will be attempted
automatically in the event that Maxima is unable to integrate the
expression::
sage: integrate(abs(cos(x)), x, 0, 2*pi, algorithm='giac')
sage: # needs sage.libs.giac
sage: result = integrate(abs(cos(x)), x, 0, 2*pi, algorithm='giac')
...
sage: result
4
sage: result = integrate(abs(cos(x)), x, 0, 2*pi)
...
Expand Down

0 comments on commit a6f5fae

Please sign in to comment.