From 0969afc63c7c79d772b1428d1d8f4ba9a7e76c0a Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Tue, 12 Nov 2024 20:51:34 -0500 Subject: [PATCH 01/11] src/sage/libs/giac/giac.pyx: fix signed infinity handling Before this commit, signed Sage infinities would be converted to unsigned Giac infinities: sage: libgiac(+Infinity) Infinity This can mess up your integrals, if nothing else. To fix it, we add an additional case to the Pygen constructor. Sage's AnInfinity class already knows how to convert itself to a Giac-friendly string, and Pygen already knows what to do with those strings -- we just need to put the pieces together. A new test case is added as well. --- src/sage/libs/giac/giac.pyx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sage/libs/giac/giac.pyx b/src/sage/libs/giac/giac.pyx index 91c42f3132c..65279b16504 100644 --- a/src/sage/libs/giac/giac.pyx +++ b/src/sage/libs/giac/giac.pyx @@ -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`` @@ -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 @@ -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() From 4321354c61addc756259d77a454d04740a044fc3 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Fri, 13 Sep 2024 17:47:42 -0400 Subject: [PATCH 02/11] src/sage/symbolic/integration/integral.py: use libgiac for "giac" integration The library interface to libgiac is much more efficient than the pexpect one, but the name algorithm="giac" is more attractive (especially to newcomers) than algorithm="libgiac". We should just Do The Right Thing and use libgiac when "giac" is requested. --- src/sage/symbolic/integration/integral.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/symbolic/integration/integral.py b/src/sage/symbolic/integration/integral.py index 0877d132030..f569ef46c54 100644 --- a/src/sage/symbolic/integration/integral.py +++ b/src/sage/symbolic/integration/integral.py @@ -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 ###################################################### @@ -474,9 +474,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. From ce4add225c0c608e2542516d8c63884c446c6836 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Fri, 13 Sep 2024 17:45:29 -0400 Subject: [PATCH 03/11] src/sage/symbolic/integration/external.py: drop pexpect giac integrator The pexpect integrator is unused now that the "giac" integrator uses libgiac. We also add a few "# needs sage.libs.giac" tags to the tests that use the libgiac integrator, because they obviously will fail when libgiac is not there. --- src/sage/symbolic/integration/external.py | 44 ++--------------------- 1 file changed, 3 insertions(+), 41 deletions(-) diff --git a/src/sage/symbolic/integration/external.py b/src/sage/symbolic/integration/external.py index 5f647228564..ef05676c727 100644 --- a/src/sage/symbolic/integration/external.py +++ b/src/sage/symbolic/integration/external.py @@ -214,53 +214,13 @@ 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 @@ -272,12 +232,14 @@ def libgiac_integrator(expression, v, a=None, b=None): 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) From a9b2b81cd5e10c60b7b7b47760e415da40707ac7 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Fri, 20 Sep 2024 09:37:59 -0400 Subject: [PATCH 04/11] src/sage/calculus/calculus.py: add "needs" for libgiac integration One example in this file integrates with algorithm='giac', which can fail if sage.libs.giac is not available to perform the integration. --- src/sage/calculus/calculus.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index ef4854db676..64881aba812 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -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) From 05c5d4ba1e5951150b73bb26cf86548000336296 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Fri, 20 Sep 2024 09:38:16 -0400 Subject: [PATCH 05/11] src/sage/functions/piecewise.py: add "needs" for libgiac integration One example in this file integrates with algorithm='giac', which can fail if sage.libs.giac is not available to perform the integration. --- src/sage/functions/piecewise.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/functions/piecewise.py b/src/sage/functions/piecewise.py index fc69057ef6f..2986e47960d 100644 --- a/src/sage/functions/piecewise.py +++ b/src/sage/functions/piecewise.py @@ -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 From 1287b718074479e423a90a89fd71b5e98a646659 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Fri, 20 Sep 2024 09:38:35 -0400 Subject: [PATCH 06/11] src/sage/symbolic/integration/integral.py: add "needs" for libgiac integration A few examples in this file integrate with algorithm='giac', which can fail if sage.libs.giac is not available to perform the integration. --- src/sage/symbolic/integration/integral.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/symbolic/integration/integral.py b/src/sage/symbolic/integration/integral.py index f569ef46c54..98a9266f3a0 100644 --- a/src/sage/symbolic/integration/integral.py +++ b/src/sage/symbolic/integration/integral.py @@ -59,6 +59,7 @@ 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)) @@ -207,6 +208,7 @@ 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 @@ -697,6 +699,7 @@ def integrate(expression, v=None, a=None, b=None, algorithm=None, hold=False): Using Giac to integrate the absolute value of a trigonometric expression:: + sage: # needs sage.libs.giac sage: integrate(abs(cos(x)), x, 0, 2*pi, algorithm='giac') 4 sage: result = integrate(abs(cos(x)), x, 0, 2*pi) From b6d1e71eee8cbadb30d02eedcd3da0c6a7513689 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sat, 5 Oct 2024 19:24:33 -0400 Subject: [PATCH 07/11] src/sage/symbolic/integration/integral.py: fixup a "giac" integral test There's one test in this file for an integral where the "libgiac" algorithm prints a warning, but the old "giac" algorithm did not. Now that algorithm="giac" uses libgiac, we expect the warning in that case too. --- src/sage/symbolic/integration/integral.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/sage/symbolic/integration/integral.py b/src/sage/symbolic/integration/integral.py index 98a9266f3a0..5172fa64e90 100644 --- a/src/sage/symbolic/integration/integral.py +++ b/src/sage/symbolic/integration/integral.py @@ -697,10 +697,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: # needs sage.libs.giac - sage: integrate(abs(cos(x)), x, 0, 2*pi, algorithm='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) ... From ff180f2199800f52760bc3e803d895112e9c3bc0 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sat, 5 Oct 2024 19:33:03 -0400 Subject: [PATCH 08/11] src/sage/symbolic/integration/integral.py: update expected giac output One "giac" integral in this file has changed its output slightly now that the "giac" algorithm uses libgiac as opposed to the pexpect interface. The difference between the new and old expected outputs full_simplify() to zero, so this one is nothing to worry about. --- src/sage/symbolic/integration/integral.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/symbolic/integration/integral.py b/src/sage/symbolic/integration/integral.py index 5172fa64e90..aebf84e8e03 100644 --- a/src/sage/symbolic/integration/integral.py +++ b/src/sage/symbolic/integration/integral.py @@ -62,7 +62,7 @@ def __init__(self): 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`:: From 56d5c3a78bbad9650ae2aaace8ecb8c835563fb2 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 6 Oct 2024 07:37:03 -0400 Subject: [PATCH 09/11] src/sage/symbolic/integration/external.py: update a doctest With the recent improvement to the handling of signed infinities in libgiac, this warning about singular points has vanished. --- src/sage/symbolic/integration/external.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/symbolic/integration/external.py b/src/sage/symbolic/integration/external.py index ef05676c727..083858658d4 100644 --- a/src/sage/symbolic/integration/external.py +++ b/src/sage/symbolic/integration/external.py @@ -227,7 +227,6 @@ def libgiac_integrator(expression, v, a=None, b=None): 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:: From f384ef578fa4992f720066faa1315eab42ee9c95 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Tue, 12 Nov 2024 21:02:15 -0500 Subject: [PATCH 10/11] src/sage/symbolic/integration/external.py: update a comment A comment in this file about failing doctests is still partially true (the doctests fail if you remove the workaround), but it mentions a "fixme" that does not exist. We delete the nonsense part. --- src/sage/symbolic/integration/external.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sage/symbolic/integration/external.py b/src/sage/symbolic/integration/external.py index 083858658d4..1390c524300 100644 --- a/src/sage/symbolic/integration/external.py +++ b/src/sage/symbolic/integration/external.py @@ -256,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: From 09572b108b0216703d7a77055ad629383bd8d37b Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Tue, 12 Nov 2024 21:04:31 -0500 Subject: [PATCH 11/11] src/sage/symbolic/integration/integral.py: fix giac integral output Now that libgiac is being used for "giac" integrals, one test is printing out "No checks were made for singular points of antiderivative -1/sageVARx for definite integration in [1,+infinity]" where previously the test was silent. We now "..." the junk away. --- src/sage/symbolic/integration/integral.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/symbolic/integration/integral.py b/src/sage/symbolic/integration/integral.py index aebf84e8e03..4a70d373516 100644 --- a/src/sage/symbolic/integration/integral.py +++ b/src/sage/symbolic/integration/integral.py @@ -212,7 +212,9 @@ def __init__(self): 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