From 8dc47e8b91af1b35ce85d51be4f18adaf3940dff Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 5 Mar 2023 21:32:45 -0800 Subject: [PATCH 01/23] sage.calculus: Add # optional - numpy, sympy --- src/sage/calculus/riemann.pyx | 16 +++---- src/sage/calculus/test_sympy.py | 80 ++++++++++++++++----------------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/sage/calculus/riemann.pyx b/src/sage/calculus/riemann.pyx index 1f038f4ec03..6f77ea3f302 100644 --- a/src/sage/calculus/riemann.pyx +++ b/src/sage/calculus/riemann.pyx @@ -1187,10 +1187,10 @@ cpdef complex_to_spiderweb(np.ndarray[COMPLEX_T, ndim = 2] z_values, EXAMPLES:: sage: from sage.calculus.riemann import complex_to_spiderweb - sage: import numpy - sage: zval = numpy.array([[0, 1, 1000],[.2+.3j,1,-.3j],[0,0,0]],dtype = numpy.complex128) - sage: deriv = numpy.array([[.1]],dtype = numpy.float64) - sage: complex_to_spiderweb(zval, deriv,deriv, 4,4,[0,0,0],1,False,0.001) + sage: import numpy # optional - numpy + sage: zval = numpy.array([[0,1,1000], [.2+.3j,1,-.3j], [0,0,0]], dtype=numpy.complex128) # optional - numpy + sage: deriv = numpy.array([[.1]],dtype = numpy.float64) # optional - numpy + sage: complex_to_spiderweb(zval, deriv, deriv, 4, 4, [0,0,0], 1, False, 0.001) # optional - numpy array([[[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]], @@ -1203,7 +1203,7 @@ cpdef complex_to_spiderweb(np.ndarray[COMPLEX_T, ndim = 2] z_values, [1., 1., 1.], [1., 1., 1.]]]) - sage: complex_to_spiderweb(zval, deriv,deriv, 4,4,[0,0,0],1,True,0.001) + sage: complex_to_spiderweb(zval, deriv, deriv, 4, 4, [0,0,0], 1, True, 0.001) # optional - numpy array([[[1. , 1. , 1. ], [1. , 0.05558355, 0.05558355], [0.17301243, 0. , 0. ]], @@ -1277,13 +1277,13 @@ cpdef complex_to_rgb(np.ndarray[COMPLEX_T, ndim = 2] z_values): EXAMPLES:: sage: from sage.calculus.riemann import complex_to_rgb - sage: import numpy - sage: complex_to_rgb(numpy.array([[0, 1, 1000]], dtype = numpy.complex128)) + sage: import numpy # optional - numpy + sage: complex_to_rgb(numpy.array([[0, 1, 1000]], dtype=numpy.complex128)) # optional - numpy array([[[1. , 1. , 1. ], [1. , 0.05558355, 0.05558355], [0.17301243, 0. , 0. ]]]) - sage: complex_to_rgb(numpy.array([[0, 1j, 1000j]], dtype = numpy.complex128)) + sage: complex_to_rgb(numpy.array([[0, 1j, 1000j]], dtype=numpy.complex128)) # optional - numpy array([[[1. , 1. , 1. ], [0.52779177, 1. , 0.05558355], [0.08650622, 0.17301243, 0. ]]]) diff --git a/src/sage/calculus/test_sympy.py b/src/sage/calculus/test_sympy.py index 927e6ee4fb6..a1db950bf10 100644 --- a/src/sage/calculus/test_sympy.py +++ b/src/sage/calculus/test_sympy.py @@ -102,98 +102,98 @@ And here are some actual tests of sympy:: - sage: from sympy import Symbol, cos, sympify, pprint - sage: from sympy.abc import x + sage: from sympy import Symbol, cos, sympify, pprint # optional - sympy + sage: from sympy.abc import x # optional - sympy :: - sage: e = (1/cos(x)^3)._sympy_(); e + sage: e = (1/cos(x)^3)._sympy_(); e # optional - sympy cos(x)**(-3) - sage: f = e.series(x, 0, int(10)); f + sage: f = e.series(x, 0, int(10)); f # optional - sympy 1 + 3*x**2/2 + 11*x**4/8 + 241*x**6/240 + 8651*x**8/13440 + O(x**10) And the pretty-printer. Since unicode characters are not working on some architectures, we disable it:: - sage: from sympy.printing import pprint_use_unicode - sage: prev_use = pprint_use_unicode(False) - sage: pprint(e) + sage: from sympy.printing import pprint_use_unicode # optional - sympy + sage: prev_use = pprint_use_unicode(False) # optional - sympy + sage: pprint(e) # optional - sympy 1 ------- 3 cos (x) - sage: pprint(f) + sage: pprint(f) # optional - sympy 2 4 6 8 3*x 11*x 241*x 8651*x / 10\ 1 + ---- + ----- + ------ + ------- + O\x / 2 8 240 13440 - sage: pprint_use_unicode(prev_use) + sage: pprint_use_unicode(prev_use) # optional - sympy False And the functionality to convert from sympy format to Sage format:: - sage: e._sage_() + sage: e._sage_() # optional - sympy cos(x)^(-3) - sage: e._sage_().taylor(x._sage_(), 0, 8) + sage: e._sage_().taylor(x._sage_(), 0, 8) # optional - sympy 8651/13440*x^8 + 241/240*x^6 + 11/8*x^4 + 3/2*x^2 + 1 - sage: f._sage_() + sage: f._sage_() # optional - sympy 8651/13440*x^8 + 241/240*x^6 + 11/8*x^4 + 3/2*x^2 + Order(x^10) + 1 Mixing SymPy with Sage:: - sage: import sympy - sage: var("x")._sympy_() + var("y")._sympy_() + sage: import sympy # optional - sympy + sage: var("x")._sympy_() + var("y")._sympy_() # optional - sympy x + y - sage: o = var("omega") - sage: s = sympy.Symbol("x") - sage: t1 = s + o - sage: t2 = o + s - sage: type(t1) + sage: o = var("omega") # optional - sympy + sage: s = sympy.Symbol("x") # optional - sympy + sage: t1 = s + o # optional - sympy + sage: t2 = o + s # optional - sympy + sage: type(t1) # optional - sympy - sage: type(t2) + sage: type(t2) # optional - sympy - sage: t1, t2 + sage: t1, t2 # optional - sympy (omega + x, omega + x) - sage: e=sympy.sin(var("y"))+sage.all.cos(sympy.Symbol("x")) - sage: type(e) + sage: e = sympy.sin(var("y"))+sage.all.cos(sympy.Symbol("x")) # optional - sympy + sage: type(e) # optional - sympy - sage: e + sage: e # optional - sympy sin(y) + cos(x) - sage: e=e._sage_() - sage: type(e) + sage: e=e._sage_() # optional - sympy + sage: type(e) # optional - sympy - sage: e + sage: e # optional - sympy cos(x) + sin(y) - sage: e = sage.all.cos(var("y")**3)**4+var("x")**2 - sage: e = e._sympy_() - sage: e + sage: e = sage.all.cos(var("y")**3)**4+var("x")**2 # optional - sympy + sage: e = e._sympy_() # optional - sympy + sage: e # optional - sympy x**2 + cos(y**3)**4 :: - sage: a = sympy.Matrix([1, 2, 3]) - sage: a[1] + sage: a = sympy.Matrix([1, 2, 3]) # optional - sympy + sage: a[1] # optional - sympy 2 :: - sage: sympify(1.5) + sage: sympify(1.5) # optional - sympy 1.50000000000000 - sage: sympify(2) + sage: sympify(2) # optional - sympy 2 - sage: sympify(-2) + sage: sympify(-2) # optional - sympy -2 TESTS: This was fixed in Sympy, see :trac:`14437`:: - sage: from sympy import Function, Symbol, rsolve - sage: u = Function('u') - sage: n = Symbol('n', integer=True) - sage: f = u(n+2) - u(n+1) + u(n)/4 - sage: expand(2**n * rsolve(f,u(n))) + sage: from sympy import Function, Symbol, rsolve # optional - sympy + sage: u = Function('u') # optional - sympy + sage: n = Symbol('n', integer=True) # optional - sympy + sage: f = u(n+2) - u(n+1) + u(n)/4 # optional - sympy + sage: expand(2**n * rsolve(f,u(n))) # optional - sympy 2*C1*n + C0 """ From b88272f82863ff1e29ec1ca82df18000f677b4e1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 3 Jun 2023 18:51:02 -0700 Subject: [PATCH 02/23] sage.calculus: Doctest cosmetics --- src/sage/calculus/riemann.pyx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/sage/calculus/riemann.pyx b/src/sage/calculus/riemann.pyx index 6f77ea3f302..92be0a5edc1 100644 --- a/src/sage/calculus/riemann.pyx +++ b/src/sage/calculus/riemann.pyx @@ -1187,10 +1187,11 @@ cpdef complex_to_spiderweb(np.ndarray[COMPLEX_T, ndim = 2] z_values, EXAMPLES:: sage: from sage.calculus.riemann import complex_to_spiderweb - sage: import numpy # optional - numpy - sage: zval = numpy.array([[0,1,1000], [.2+.3j,1,-.3j], [0,0,0]], dtype=numpy.complex128) # optional - numpy - sage: deriv = numpy.array([[.1]],dtype = numpy.float64) # optional - numpy - sage: complex_to_spiderweb(zval, deriv, deriv, 4, 4, [0,0,0], 1, False, 0.001) # optional - numpy + sage: import numpy # optional - numpy + sage: zval = numpy.array([[0,1,1000], [.2+.3j,1,-.3j], [0,0,0]], # optional - numpy + ....: dtype=numpy.complex128) + sage: deriv = numpy.array([[.1]],dtype = numpy.float64) # optional - numpy + sage: complex_to_spiderweb(zval, deriv, deriv, 4, 4, [0,0,0], 1, False, 0.001) # optional - numpy array([[[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]], @@ -1203,7 +1204,7 @@ cpdef complex_to_spiderweb(np.ndarray[COMPLEX_T, ndim = 2] z_values, [1., 1., 1.], [1., 1., 1.]]]) - sage: complex_to_spiderweb(zval, deriv, deriv, 4, 4, [0,0,0], 1, True, 0.001) # optional - numpy + sage: complex_to_spiderweb(zval, deriv, deriv, 4, 4, [0,0,0], 1, True, 0.001) # optional - numpy array([[[1. , 1. , 1. ], [1. , 0.05558355, 0.05558355], [0.17301243, 0. , 0. ]], @@ -1277,13 +1278,13 @@ cpdef complex_to_rgb(np.ndarray[COMPLEX_T, ndim = 2] z_values): EXAMPLES:: sage: from sage.calculus.riemann import complex_to_rgb - sage: import numpy # optional - numpy - sage: complex_to_rgb(numpy.array([[0, 1, 1000]], dtype=numpy.complex128)) # optional - numpy + sage: import numpy # optional - numpy + sage: complex_to_rgb(numpy.array([[0, 1, 1000]], dtype=numpy.complex128)) # optional - numpy array([[[1. , 1. , 1. ], [1. , 0.05558355, 0.05558355], [0.17301243, 0. , 0. ]]]) - sage: complex_to_rgb(numpy.array([[0, 1j, 1000j]], dtype=numpy.complex128)) # optional - numpy + sage: complex_to_rgb(numpy.array([[0, 1j, 1000j]], dtype=numpy.complex128)) # optional - numpy array([[[1. , 1. , 1. ], [0.52779177, 1. , 0.05558355], [0.08650622, 0.17301243, 0. ]]]) From cc152c114b77ea164db075c63dfe99e7c2d88379 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 3 Jun 2023 18:52:49 -0700 Subject: [PATCH 03/23] sage.calculus: Add # optional --- src/sage/calculus/functional.py | 1 + src/sage/calculus/functions.py | 1 + src/sage/calculus/integration.pyx | 1 + src/sage/calculus/interpolation.pyx | 24 ++++++++++++------------ src/sage/calculus/riemann.pyx | 1 + src/sage/calculus/test_sympy.py | 2 +- src/sage/calculus/wester.py | 1 + 7 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/sage/calculus/functional.py b/src/sage/calculus/functional.py index 285e1394ab1..254e231dec6 100644 --- a/src/sage/calculus/functional.py +++ b/src/sage/calculus/functional.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.symbolic """ Functional notation support for common calculus methods diff --git a/src/sage/calculus/functions.py b/src/sage/calculus/functions.py index 6c47b0d2fc9..4e6d69f3f5e 100644 --- a/src/sage/calculus/functions.py +++ b/src/sage/calculus/functions.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.symbolic r""" Calculus functions """ diff --git a/src/sage/calculus/integration.pyx b/src/sage/calculus/integration.pyx index 04ef352a906..79c5deca158 100644 --- a/src/sage/calculus/integration.pyx +++ b/src/sage/calculus/integration.pyx @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.symbolic """ Numerical Integration diff --git a/src/sage/calculus/interpolation.pyx b/src/sage/calculus/interpolation.pyx index e703f78d7c0..d1375c90abe 100644 --- a/src/sage/calculus/interpolation.pyx +++ b/src/sage/calculus/interpolation.pyx @@ -55,39 +55,39 @@ cdef class Spline: This example is in the GSL documentation:: - sage: v = [(i + sin(i)/2, i+cos(i^2)) for i in range(10)] - sage: s = spline(v) - sage: show(point(v) + plot(s,0,9, hue=.8)) + sage: v = [(i + sin(i)/2, i+cos(i^2)) for i in range(10)] # optional - sage.symbolic + sage: s = spline(v) # optional - sage.symbolic + sage: show(point(v) + plot(s,0,9, hue=.8)) # optional - sage.symbolic We compute the area underneath the spline:: - sage: s.definite_integral(0, 9) + sage: s.definite_integral(0, 9) # optional - sage.symbolic 41.196516041067... The definite integral is additive:: - sage: s.definite_integral(0, 4) + s.definite_integral(4, 9) + sage: s.definite_integral(0, 4) + s.definite_integral(4, 9) # optional - sage.symbolic 41.196516041067... Switching the order of the bounds changes the sign of the integral:: - sage: s.definite_integral(9, 0) + sage: s.definite_integral(9, 0) # optional - sage.symbolic -41.196516041067... We compute the first and second-order derivatives at a few points:: - sage: s.derivative(5) + sage: s.derivative(5) # optional - sage.symbolic -0.16230085261803... - sage: s.derivative(6) + sage: s.derivative(6) # optional - sage.symbolic 0.20997986285714... - sage: s.derivative(5, order=2) + sage: s.derivative(5, order=2) # optional - sage.symbolic -3.08747074561380... - sage: s.derivative(6, order=2) + sage: s.derivative(6, order=2) # optional - sage.symbolic 2.61876848274853... Only the first two derivatives are supported:: - sage: s.derivative(4, order=3) + sage: s.derivative(4, order=3) # optional - sage.symbolic Traceback (most recent call last): ... ValueError: Order of derivative must be 1 or 2. @@ -118,7 +118,7 @@ cdef class Spline: Replace `0`-th point, which changes the spline:: - sage: S[0]=(0,1); S + sage: S[0] = (0,1); S [(0, 1), (2, 3), (4, 5)] sage: S(1.5) 2.5 diff --git a/src/sage/calculus/riemann.pyx b/src/sage/calculus/riemann.pyx index 92be0a5edc1..4dadd44ce17 100644 --- a/src/sage/calculus/riemann.pyx +++ b/src/sage/calculus/riemann.pyx @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.symbolic """ Riemann Mapping diff --git a/src/sage/calculus/test_sympy.py b/src/sage/calculus/test_sympy.py index a1db950bf10..ea41df4881b 100644 --- a/src/sage/calculus/test_sympy.py +++ b/src/sage/calculus/test_sympy.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: optional - sage.symbolic r""" A Sample Session using SymPy diff --git a/src/sage/calculus/wester.py b/src/sage/calculus/wester.py index 766ce586eb2..de0d1d6ef22 100644 --- a/src/sage/calculus/wester.py +++ b/src/sage/calculus/wester.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.symbolic r""" Further examples from Wester's paper From 654f27c03dc7f29466128878678ea36e51e0f0a1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 3 Jun 2023 18:53:52 -0700 Subject: [PATCH 04/23] sage.calculus: Add # optional --- src/sage/calculus/interpolators.pyx | 12 +++++++----- src/sage/calculus/ode.pyx | 6 +++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/sage/calculus/interpolators.pyx b/src/sage/calculus/interpolators.pyx index 662a1fd0ce3..de776562671 100644 --- a/src/sage/calculus/interpolators.pyx +++ b/src/sage/calculus/interpolators.pyx @@ -48,8 +48,9 @@ def polygon_spline(pts): sage: ps = polygon_spline(pts) sage: fx = lambda x: ps.value(x).real sage: fy = lambda x: ps.value(x).imag - sage: show(parametric_plot((fx, fy), (0, 2*pi))) - sage: m = Riemann_Map([lambda x: ps.value(real(x))], [lambda x: ps.derivative(real(x))],0) + sage: show(parametric_plot((fx, fy), (0, 2*pi))) # optional - sage.plot + sage: m = Riemann_Map([lambda x: ps.value(real(x))], + ....: [lambda x: ps.derivative(real(x))], 0) sage: show(m.plot_colored() + m.plot_spiderweb()) Polygon approximation of an circle:: @@ -179,9 +180,10 @@ def complex_cubic_spline(pts): sage: cs = complex_cubic_spline(pts) sage: fx = lambda x: cs.value(x).real sage: fy = lambda x: cs.value(x).imag - sage: show(parametric_plot((fx, fy), (0, 2*pi))) - sage: m = Riemann_Map([lambda x: cs.value(real(x))], [lambda x: cs.derivative(real(x))], 0) - sage: show(m.plot_colored() + m.plot_spiderweb()) + sage: show(parametric_plot((fx, fy), (0, 2*pi))) # optional - sage.plot + sage: m = Riemann_Map([lambda x: cs.value(real(x))], + ....: [lambda x: cs.derivative(real(x))], 0) + sage: show(m.plot_colored() + m.plot_spiderweb()) # optional - sage.plot Polygon approximation of a circle:: diff --git a/src/sage/calculus/ode.pyx b/src/sage/calculus/ode.pyx index 544556ddf72..9e3349e1fc7 100644 --- a/src/sage/calculus/ode.pyx +++ b/src/sage/calculus/ode.pyx @@ -236,14 +236,14 @@ class ode_solver(): sage: T.algorithm="rk8pd" sage: T.function=f_1 sage: T.jacobian=j_1 - sage: T.ode_solve(y_0=[1,0],t_span=[0,100],params=[10.0],num_points=1000) + sage: T.ode_solve(y_0=[1,0], t_span=[0,100], params=[10.0], num_points=1000) sage: import tempfile - sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: + sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # optional - sage.plot ....: T.plot_solution(filename=f.name) The solver line is equivalent to:: - sage: T.ode_solve(y_0=[1,0],t_span=[x/10.0 for x in range(1000)],params = [10.0]) + sage: T.ode_solve(y_0=[1,0], t_span=[x/10.0 for x in range(1000)], params=[10.0]) Let's try a system:: From ddbad8de2f10f5846cf341da1135d7cfdfb3cba7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 18 May 2023 21:04:11 -0700 Subject: [PATCH 05/23] sage.calculus: Doctest cosmetics --- src/sage/calculus/calculus.py | 292 +++++++++++++++++---------------- src/sage/structure/nonexact.py | 2 +- 2 files changed, 154 insertions(+), 140 deletions(-) diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index bd1072a5218..3d963edf95b 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -80,23 +80,23 @@ :: - sage: f(x,y)=x^2*y+y^2+y - sage: f.diff() # gradient + sage: f(x,y) = x^2*y + y^2 + y + sage: f.diff() # gradient (x, y) |--> (2*x*y, x^2 + 2*y + 1) - sage: solve(list(f.diff()),[x,y]) + sage: solve(list(f.diff()), [x,y]) [[x == -I, y == 0], [x == I, y == 0], [x == 0, y == (-1/2)]] sage: H=f.diff(2); H # Hessian matrix [(x, y) |--> 2*y (x, y) |--> 2*x] [(x, y) |--> 2*x (x, y) |--> 2] - sage: H(x=0,y=-1/2) + sage: H(x=0, y=-1/2) [-1 0] [ 0 2] - sage: H(x=0,y=-1/2).eigenvalues() + sage: H(x=0, y=-1/2).eigenvalues() [-1, 2] Here we calculate the Jacobian for the polar coordinate transformation:: - sage: T(r,theta)=[r*cos(theta),r*sin(theta)] + sage: T(r,theta) = [r*cos(theta),r*sin(theta)] sage: T (r, theta) |--> (r*cos(theta), r*sin(theta)) sage: T.diff() # Jacobian matrix @@ -117,7 +117,7 @@ ValueError: No differentiation variable specified. Simplifying symbolic sums is also possible, using the -sum command, which also uses Maxima in the background:: +:func:`sum` command, which also uses Maxima in the background:: sage: k, m = var('k, m') sage: sum(1/k^4, k, 1, oo) @@ -182,19 +182,19 @@ sage: f(x=pi) 0 -We can also make a ``CallableSymbolicExpression``, -which is a ``SymbolicExpression`` that is a function of +We can also make a :class:`CallableSymbolicExpression`, +which is a :class:`SymbolicExpression` that is a function of specified variables in a fixed order. Each -``SymbolicExpression`` has a +:class:`SymbolicExpression` has a ``function(...)`` method that is used to create a -``CallableSymbolicExpression``, as illustrated below:: +:class:`CallableSymbolicExpression`, as illustrated below:: sage: u = log((2-x)/(y+5)) sage: f = u.function(x, y); f (x, y) |--> log(-(x - 2)/(y + 5)) There is an easier way of creating a -``CallableSymbolicExpression``, which relies on the +:class:`CallableSymbolicExpression`, which relies on the Sage preparser. :: @@ -267,7 +267,8 @@ sage: CC(f) 1.12762596520638 + 1.17520119364380*I sage: ComplexField(200)(f) - 1.1276259652063807852262251614026720125478471180986674836290 + 1.1752011936438014568823818505956008151557179813340958702296*I + 1.1276259652063807852262251614026720125478471180986674836290 + + 1.1752011936438014568823818505956008151557179813340958702296*I sage: ComplexField(100)(f) 1.1276259652063807852262251614 + 1.1752011936438014568823818506*I @@ -286,8 +287,9 @@ We can, of course, substitute:: - sage: f(n9=9,n7=n6) - 1/n1 + 1/n2^2 + 1/n3^3 + 1/n4^4 + 1/n5^5 + 1/n6^6 + 1/n6^7 + 1/n8^8 + 387420490/387420489 + sage: f(n9=9, n7=n6) + 1/n1 + 1/n2^2 + 1/n3^3 + 1/n4^4 + 1/n5^5 + 1/n6^6 + 1/n6^7 + 1/n8^8 + + 387420490/387420489 TESTS: @@ -317,7 +319,7 @@ sage: maxima.eval('expand((x+y)^3)') '27' -If the copy of maxima used by the symbolic calculus package were +If the copy of Maxima used by the symbolic calculus package were the same as the default one, then the following would return 27, which would be very confusing indeed! @@ -446,27 +448,27 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False): INPUT: - - ``expression`` - a symbolic expression + - ``expression`` -- a symbolic expression - - ``v`` - a variable or variable name + - ``v`` -- a variable or variable name - - ``a`` - lower endpoint of the sum + - ``a`` -- lower endpoint of the sum - - ``b`` - upper endpoint of the sum + - ``b`` -- upper endpoint of the sum - - ``algorithm`` - (default: ``'maxima'``) one of + - ``algorithm`` -- (default: ``'maxima'``) one of - - ``'maxima'`` - use Maxima (the default) + - ``'maxima'`` -- use Maxima (the default) - - ``'maple'`` - (optional) use Maple + - ``'maple'`` -- (optional) use Maple - - ``'mathematica'`` - (optional) use Mathematica + - ``'mathematica'`` -- (optional) use Mathematica - - ``'giac'`` - (optional) use Giac + - ``'giac'`` -- (optional) use Giac - - ``'sympy'`` - use SymPy + - ``'sympy'`` -- use SymPy - - ``hold`` - (default: ``False``) if ``True`` don't evaluate + - ``hold`` -- (default: ``False``) if ``True``, don't evaluate EXAMPLES:: @@ -493,13 +495,13 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False): And some truncations thereof:: sage: assume(n>1) - sage: symbolic_sum(binomial(n,k),k,1,n) + sage: symbolic_sum(binomial(n,k), k, 1, n) 2^n - 1 - sage: symbolic_sum(binomial(n,k),k,2,n) + sage: symbolic_sum(binomial(n,k), k, 2, n) 2^n - n - 1 - sage: symbolic_sum(binomial(n,k),k,0,n-1) + sage: symbolic_sum(binomial(n,k), k, 0, n-1) 2^n - 1 - sage: symbolic_sum(binomial(n,k),k,1,n-1) + sage: symbolic_sum(binomial(n,k), k, 1, n-1) 2^n - 2 The binomial theorem:: @@ -556,22 +558,22 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False): ... ValueError: Sum is divergent. sage: forget() - sage: assumptions() # check the assumptions were really forgotten + sage: assumptions() # check the assumptions were really forgotten [] A summation performed by Mathematica:: - sage: symbolic_sum(1/(1+k^2), k, -oo, oo, algorithm = 'mathematica') # optional - mathematica + sage: symbolic_sum(1/(1+k^2), k, -oo, oo, algorithm='mathematica') # optional - mathematica pi*coth(pi) An example of this summation with Giac:: - sage: symbolic_sum(1/(1+k^2), k, -oo, oo, algorithm = 'giac') + sage: symbolic_sum(1/(1+k^2), k, -oo, oo, algorithm='giac') (pi*e^(2*pi) - pi*e^(-2*pi))/(e^(2*pi) + e^(-2*pi) - 2) The same summation is solved by SymPy:: - sage: symbolic_sum(1/(1+k^2), k, -oo, oo, algorithm = 'sympy') + sage: symbolic_sum(1/(1+k^2), k, -oo, oo, algorithm='sympy') pi/tanh(pi) SymPy and Maxima 5.39.0 can do the following (see @@ -584,7 +586,7 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False): Use Maple as a backend for summation:: - sage: symbolic_sum(binomial(n,k)*x^k, k, 0, n, algorithm = 'maple') # optional - maple + sage: symbolic_sum(binomial(n,k)*x^k, k, 0, n, algorithm='maple') # optional - maple (x + 1)^n If you don't want to evaluate immediately give the ``hold`` keyword:: @@ -686,17 +688,17 @@ def nintegral(ex, x, a, b, INPUT: - - ``x`` - variable to integrate with respect to + - ``x`` -- variable to integrate with respect to - - ``a`` - lower endpoint of integration + - ``a`` -- lower endpoint of integration - - ``b`` - upper endpoint of integration + - ``b`` -- upper endpoint of integration - - ``desired_relative_error`` - (default: '1e-8') the + - ``desired_relative_error`` -- (default: ``1e-8``) the desired relative error - - ``maximum_num_subintervals`` - (default: 200) - maxima number of subintervals + - ``maximum_num_subintervals`` -- (default: 200) + maximal number of subintervals OUTPUT: @@ -709,26 +711,26 @@ def nintegral(ex, x, a, b, - an error code: - - ``0`` - no problems were encountered + - ``0`` -- no problems were encountered - - ``1`` - too many subintervals were done + - ``1`` -- too many subintervals were done - - ``2`` - excessive roundoff error + - ``2`` -- excessive roundoff error - - ``3`` - extremely bad integrand behavior + - ``3`` -- extremely bad integrand behavior - - ``4`` - failed to converge + - ``4`` -- failed to converge - - ``5`` - integral is probably divergent or slowly + - ``5`` -- integral is probably divergent or slowly convergent - - ``6`` - the input is invalid; this includes the case of - desired_relative_error being too small to be achieved + - ``6`` -- the input is invalid; this includes the case of + ``desired_relative_error`` being too small to be achieved - ALIAS: nintegrate is the same as nintegral + ALIAS: :func:`nintegrate` is the same as :func:`nintegral` REMARK: There is also a function - ``numerical_integral`` that implements numerical + :func:`numerical_integral` that implements numerical integration using the GSL C library. It is potentially much faster and applies to arbitrary user defined functions. @@ -741,7 +743,7 @@ def nintegral(ex, x, a, b, :: sage: f = x - sage: f.nintegral(x,0,1,1e-14) + sage: f.nintegral(x, 0, 1, 1e-14) (0.0, 0.0, 0, 6) EXAMPLES:: @@ -750,7 +752,7 @@ def nintegral(ex, x, a, b, sage: f.nintegral(x, 0, 1) (0.5284822353142306, 4.163...e-11, 231, 0) - We can also use the ``numerical_integral`` function, + We can also use the :func:`numerical_integral` function, which calls the GSL C library. :: @@ -785,7 +787,7 @@ def nintegral(ex, x, a, b, sage: f.nintegrate(x,0,1) (-480.0000000000001, 5.32907051820075...e-12, 21, 0) - It is just because every floating point evaluation of return -480.0 + It is just because every floating point evaluation of `f` returns `-480.0` in floating point. Important note: using PARI/GP one can compute numerical integrals @@ -831,25 +833,25 @@ def symbolic_product(expression, v, a, b, algorithm='maxima', hold=False): INPUT: - - ``expression`` - a symbolic expression + - ``expression`` -- a symbolic expression - - ``v`` - a variable or variable name + - ``v`` -- a variable or variable name - - ``a`` - lower endpoint of the product + - ``a`` -- lower endpoint of the product - - ``b`` - upper endpoint of the prduct + - ``b`` -- upper endpoint of the prduct - - ``algorithm`` - (default: ``'maxima'``) one of + - ``algorithm`` -- (default: ``'maxima'``) one of - - ``'maxima'`` - use Maxima (the default) + - ``'maxima'`` -- use Maxima (the default) - - ``'giac'`` - use Giac + - ``'giac'`` -- use Giac - - ``'sympy'`` - use SymPy + - ``'sympy'`` -- use SymPy - - ``'mathematica'`` - (optional) use Mathematica + - ``'mathematica'`` -- (optional) use Mathematica - - ``hold`` - (default: ``False``) if ``True`` don't evaluate + - ``hold`` - (default: ``False``) if ``True``, don't evaluate EXAMPLES:: @@ -935,50 +937,50 @@ def symbolic_product(expression, v, a, b, algorithm='maxima', hold=False): def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): r""" - Return the minimal polynomial of self, if possible. + Return the minimal polynomial of ``self``, if possible. INPUT: - - ``var`` - polynomial variable name (default 'x') + - ``var`` -- polynomial variable name (default 'x') - - ``algorithm`` - 'algebraic' or 'numerical' (default + - ``algorithm`` -- ``'algebraic'`` or ``'numerical'`` (default both, but with numerical first) - - ``bits`` - the number of bits to use in numerical + - ``bits`` -- the number of bits to use in numerical approx - - ``degree`` - the expected algebraic degree + - ``degree`` -- the expected algebraic degree - - ``epsilon`` - return without error as long as + - ``epsilon`` -- return without error as long as f(self) epsilon, in the case that the result cannot be proven. - All of the above parameters are optional, with epsilon=0, bits and - degree tested up to 1000 and 24 by default respectively. The + All of the above parameters are optional, with epsilon=0, ``bits`` and + ``degree`` tested up to 1000 and 24 by default respectively. The numerical algorithm will be faster if bits and/or degree are given explicitly. The algebraic algorithm ignores the last three parameters. - OUTPUT: The minimal polynomial of self. If the numerical algorithm - is used then it is proved symbolically when epsilon=0 (default). + OUTPUT: The minimal polynomial of ``self``. If the numerical algorithm + is used, then it is proved symbolically when ``epsilon=0`` (default). If the minimal polynomial could not be found, two distinct kinds of errors are raised. If no reasonable candidate was found with the - given bit/degree parameters, a ``ValueError`` will be + given ``bit``/``degree`` parameters, a :class:`ValueError` will be raised. If a reasonable candidate was found but (perhaps due to limits in the underlying symbolic package) was unable to be proved - correct, a ``NotImplementedError`` will be raised. + correct, a :class:`NotImplementedError` will be raised. ALGORITHM: Two distinct algorithms are used, depending on the algorithm parameter. By default, the numerical algorithm is attempted first, then the algebraic one. - Algebraic: Attempt to evaluate this expression in QQbar, using + Algebraic: Attempt to evaluate this expression in ``QQbar``, using cyclotomic fields to resolve exponential and trig functions at - rational multiples of pi, field extensions to handle roots and + rational multiples of `\pi`, field extensions to handle roots and rational exponents, and computing compositums to represent the full expression as an element of a number field where the minimal - polynomial can be computed exactly. The bits, degree, and epsilon + polynomial can be computed exactly. The ``bits``, ``degree``, and ``epsilon`` parameters are ignored. Numerical: Computes a numerical approximation of @@ -989,8 +991,8 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): vanishing. If this fails, and ``epsilon`` is non-zero, return `f` if and only if `f(\mathtt{self}) < \mathtt{epsilon}`. - Otherwise raise a ``ValueError`` (if no suitable - candidate was found) or a ``NotImplementedError`` (if a + Otherwise raise a :class:`ValueError` (if no suitable + candidate was found) or a :class:`NotImplementedError` (if a likely candidate was found but could not be proved correct). EXAMPLES: First some simple examples:: @@ -1014,7 +1016,8 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): sage: sin(pi/7).minpoly() x^6 - 7/4*x^4 + 7/8*x^2 - 7/64 sage: minpoly(exp(I*pi/17)) - x^16 - x^15 + x^14 - x^13 + x^12 - x^11 + x^10 - x^9 + x^8 - x^7 + x^6 - x^5 + x^4 - x^3 + x^2 - x + 1 + x^16 - x^15 + x^14 - x^13 + x^12 - x^11 + x^10 - x^9 + x^8 + - x^7 + x^6 - x^5 + x^4 - x^3 + x^2 - x + 1 Here we verify it gives the same result as the abstract number field. @@ -1027,14 +1030,15 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): sage: (a+b+a*b).absolute_minpoly() x^4 - 22*x^2 - 48*x - 23 - The minpoly function is used implicitly when creating + The :func:`minpoly` function is used implicitly when creating number fields:: sage: x = var('x') sage: eqn = x^3 + sqrt(2)*x + 5 == 0 sage: a = solve(eqn, x)[0].rhs() sage: QQ[a] - Number Field in a with defining polynomial x^6 + 10*x^3 - 2*x^2 + 25 with a = 0.7185272465828846? - 1.721353471724806?*I + Number Field in a with defining polynomial x^6 + 10*x^3 - 2*x^2 + 25 + with a = 0.7185272465828846? - 1.721353471724806?*I Here we solve a cubic and then recover it from its complicated radical expansion. @@ -1043,7 +1047,8 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): sage: f = x^3 - x + 1 sage: a = f.solve(x)[0].rhs(); a - -1/2*(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3)*(I*sqrt(3) + 1) - 1/6*(-I*sqrt(3) + 1)/(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3) + -1/2*(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3)*(I*sqrt(3) + 1) + - 1/6*(-I*sqrt(3) + 1)/(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3) sage: a.minpoly() x^3 - x + 1 @@ -1056,7 +1061,9 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): sage: f = a.minpoly(); f x^8 - 40*x^6 + 352*x^4 - 960*x^2 + 576 sage: f(a) - (sqrt(5) + sqrt(3) + sqrt(2))^8 - 40*(sqrt(5) + sqrt(3) + sqrt(2))^6 + 352*(sqrt(5) + sqrt(3) + sqrt(2))^4 - 960*(sqrt(5) + sqrt(3) + sqrt(2))^2 + 576 + (sqrt(5) + sqrt(3) + sqrt(2))^8 - 40*(sqrt(5) + sqrt(3) + sqrt(2))^6 + + 352*(sqrt(5) + sqrt(3) + sqrt(2))^4 - 960*(sqrt(5) + sqrt(3) + sqrt(2))^2 + + 576 sage: f(a).expand() 0 @@ -1083,9 +1090,11 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): :: sage: cos(pi/33).minpoly(algorithm='algebraic') - x^10 + 1/2*x^9 - 5/2*x^8 - 5/4*x^7 + 17/8*x^6 + 17/16*x^5 - 43/64*x^4 - 43/128*x^3 + 3/64*x^2 + 3/128*x + 1/1024 + x^10 + 1/2*x^9 - 5/2*x^8 - 5/4*x^7 + 17/8*x^6 + 17/16*x^5 + - 43/64*x^4 - 43/128*x^3 + 3/64*x^2 + 3/128*x + 1/1024 sage: cos(pi/33).minpoly(algorithm='numerical') - x^10 + 1/2*x^9 - 5/2*x^8 - 5/4*x^7 + 17/8*x^6 + 17/16*x^5 - 43/64*x^4 - 43/128*x^3 + 3/64*x^2 + 3/128*x + 1/1024 + x^10 + 1/2*x^9 - 5/2*x^8 - 5/4*x^7 + 17/8*x^6 + 17/16*x^5 + - 43/64*x^4 - 43/128*x^3 + 3/64*x^2 + 3/128*x + 1/1024 Sometimes it fails, as it must given that some numbers aren't algebraic:: @@ -1162,12 +1171,12 @@ def limit(ex, dir=None, taylor=False, algorithm='maxima', **argv): INPUT: - - ``dir`` - (default: None); dir may have the value - 'plus' (or '+' or 'right' or 'above') for a limit from above, - 'minus' (or '-' or 'left' or 'below') for a limit from below, or may be omitted + - ``dir`` -- (default: ``None``); may have the value + ``'plus'`` (or ``'+'`` or ``'right'`` or ``'above'``) for a limit from above, + ``'minus'`` (or ``'-'`` or ``'left'`` or ``'below'``) for a limit from below, or may be omitted (implying a two-sided limit is to be computed). - - ``taylor`` - (default: False); if True, use Taylor + - ``taylor`` -- (default: ``False``); if ``True``, use Taylor series, which allows more limits to be computed (but may also crash in some obscure cases due to bugs in Maxima). @@ -1175,8 +1184,8 @@ def limit(ex, dir=None, taylor=False, algorithm='maxima', **argv): .. note:: - The output may also use 'und' (undefined), 'ind' - (indefinite but bounded), and 'infinity' (complex + The output may also use ``und`` (undefined), ``ind`` + (indefinite but bounded), and ``infinity`` (complex infinity). EXAMPLES:: @@ -1488,7 +1497,7 @@ def mma_free_limit(expression, v, a, dir=None): - ``expression`` -- symbolic expression - ``v`` -- variable - ``a`` -- value where the variable goes to - - ``dir`` -- ``'+'``, ``'-'`` or ``None`` (optional, default:``None``) + - ``dir`` -- ``'+'``, ``'-'`` or ``None`` (optional, default: ``None``) EXAMPLES:: @@ -1547,19 +1556,19 @@ def laplace(ex, t, s, algorithm='maxima'): INPUT: - - ``ex`` - a symbolic expression + - ``ex`` -- a symbolic expression - - ``t`` - independent variable + - ``t`` -- independent variable - - ``s`` - transform parameter + - ``s`` -- transform parameter - - ``algorithm`` - (default: ``'maxima'``) one of + - ``algorithm`` -- (default: ``'maxima'``) one of - - ``'maxima'`` - use Maxima (the default) + - ``'maxima'`` -- use Maxima (the default) - - ``'sympy'`` - use SymPy + - ``'sympy'`` -- use SymPy - - ``'giac'`` - use Giac + - ``'giac'`` -- use Giac .. NOTE:: @@ -1622,7 +1631,7 @@ def laplace(ex, t, s, algorithm='maxima'): Next we form the augmented matrix of the above system:: - sage: A = matrix([[s, 16, 270],[1, s, 90+1/s]]) + sage: A = matrix([[s, 16, 270], [1, s, 90+1/s]]) sage: E = A.echelon_form() sage: xt = E[0,2].inverse_laplace(s,t) sage: yt = E[1,2].inverse_laplace(s,t) @@ -1630,11 +1639,11 @@ def laplace(ex, t, s, algorithm='maxima'): -91/2*e^(4*t) + 629/2*e^(-4*t) + 1 sage: yt 91/8*e^(4*t) + 629/8*e^(-4*t) - sage: p1 = plot(xt,0,1/2,rgbcolor=(1,0,0)) - sage: p2 = plot(yt,0,1/2,rgbcolor=(0,1,0)) + sage: p1 = plot(xt, 0, 1/2, rgbcolor=(1,0,0)) # optional - sage.plot + sage: p2 = plot(yt, 0, 1/2, rgbcolor=(0,1,0)) # optional - sage.plot sage: import tempfile - sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: - ....: (p1+p2).save(f.name) + sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # optional - sage.plot + ....: (p1 + p2).save(f.name) Another example:: @@ -1789,19 +1798,19 @@ def inverse_laplace(ex, s, t, algorithm='maxima'): INPUT: - - ``ex`` - a symbolic expression + - ``ex`` -- a symbolic expression - - ``s`` - transform parameter + - ``s`` -- transform parameter - - ``t`` - independent variable + - ``t`` -- independent variable - - ``algorithm`` - (default: ``'maxima'``) one of + - ``algorithm`` -- (default: ``'maxima'``) one of - - ``'maxima'`` - use Maxima (the default) + - ``'maxima'`` -- use Maxima (the default) - - ``'sympy'`` - use SymPy + - ``'sympy'`` -- use SymPy - - ``'giac'`` - use Giac + - ``'giac'`` -- use Giac .. SEEALSO:: @@ -1843,9 +1852,11 @@ def inverse_laplace(ex, s, t, algorithm='maxima'): Transform a rational expression:: - sage: inverse_laplace((2*s^2*exp(-2*s) - exp(-s))/(s^3+1), s, t, algorithm='giac') - -1/3*(sqrt(3)*e^(1/2*t - 1/2)*sin(1/2*sqrt(3)*(t - 1)) - cos(1/2*sqrt(3)*(t - 1))*e^(1/2*t - 1/2) + - e^(-t + 1))*heaviside(t - 1) + 2/3*(2*cos(1/2*sqrt(3)*(t - 2))*e^(1/2*t - 1) + e^(-t + 2))*heaviside(t - 2) + sage: inverse_laplace((2*s^2*exp(-2*s) - exp(-s))/(s^3+1), s, t, + ....: algorithm='giac') + -1/3*(sqrt(3)*e^(1/2*t - 1/2)*sin(1/2*sqrt(3)*(t - 1)) + - cos(1/2*sqrt(3)*(t - 1))*e^(1/2*t - 1/2) + e^(-t + 1))*heaviside(t - 1) + + 2/3*(2*cos(1/2*sqrt(3)*(t - 2))*e^(1/2*t - 1) + e^(-t + 2))*heaviside(t - 2) sage: inverse_laplace(1/(s - 1), s, x) e^x @@ -1955,7 +1966,7 @@ def at(ex, *args, **kwds): We do not import ``at`` at the top level, but we can use it as a synonym for substitution if we import it:: - sage: g = x^3-3 + sage: g = x^3 - 3 sage: from sage.calculus.calculus import at sage: at(g, x=1) -2 @@ -1970,15 +1981,16 @@ def at(ex, *args, **kwds): u(h + x) sage: diff(u(x+h), x) D[0](u)(h + x) - sage: taylor(u(x+h),h,0,4) - 1/24*h^4*diff(u(x), x, x, x, x) + 1/6*h^3*diff(u(x), x, x, x) + 1/2*h^2*diff(u(x), x, x) + h*diff(u(x), x) + u(x) + sage: taylor(u(x+h), h, 0, 4) + 1/24*h^4*diff(u(x), x, x, x, x) + 1/6*h^3*diff(u(x), x, x, x) + + 1/2*h^2*diff(u(x), x, x) + h*diff(u(x), x) + u(x) We compute a Laplace transform:: sage: var('s,t') (s, t) - sage: f=function('f')(t) - sage: f.diff(t,2) + sage: f = function('f')(t) + sage: f.diff(t, 2) diff(f(t), t, t) sage: f.diff(t,2).laplace(t,s) s^2*laplace(f(t), t, s) - s*f(0) - D[0](f)(0) @@ -2078,7 +2090,7 @@ def dummy_laplace(*args): sage: from sage.calculus.calculus import dummy_laplace sage: s,t = var('s,t') sage: f = function('f') - sage: dummy_laplace(f(t),t,s) + sage: dummy_laplace(f(t), t, s) laplace(f(t), t, s) """ return _laplace(args[0], var(repr(args[1])), var(repr(args[2]))) @@ -2086,7 +2098,7 @@ def dummy_laplace(*args): def dummy_inverse_laplace(*args): """ - This function is called to create formal wrappers of inverse laplace + This function is called to create formal wrappers of inverse Laplace transforms that Maxima can't compute: EXAMPLES:: @@ -2094,7 +2106,7 @@ def dummy_inverse_laplace(*args): sage: from sage.calculus.calculus import dummy_inverse_laplace sage: s,t = var('s,t') sage: F = function('F') - sage: dummy_inverse_laplace(F(s),s,t) + sage: dummy_inverse_laplace(F(s), s, t) ilt(F(s), s, t) """ return _inverse_laplace(args[0], var(repr(args[1])), var(repr(args[2]))) @@ -2108,7 +2120,7 @@ def dummy_pochhammer(*args): sage: from sage.calculus.calculus import dummy_pochhammer sage: s,t = var('s,t') - sage: dummy_pochhammer(s,t) + sage: dummy_pochhammer(s, t) gamma(s + t)/gamma(s) """ x, y = args @@ -2224,12 +2236,12 @@ def symbolic_expression_from_maxima_string(x, equals_sub=False, maxima=maxima): INPUT: - - ``x`` - a string + - ``x`` -- a string - - ``equals_sub`` - (default: False) if True, replace + - ``equals_sub`` -- (default: ``False``) if ``True``, replace '=' by '==' in self - - ``maxima`` - (default: the calculus package's + - ``maxima`` -- (default: the calculus package's copy of Maxima) the Maxima interpreter to use. EXAMPLES:: @@ -2415,7 +2427,7 @@ def mapped_opts(v): INPUT: - - ``v`` - an object + - ``v`` -- an object OUTPUT: a string. @@ -2548,13 +2560,13 @@ def symbolic_expression_from_string(s, syms=None, accept_sequence=False, *, pars INPUT: - - ``s`` - a string + - ``s`` -- a string - - ``syms`` - (default: {}) dictionary of - strings to be regarded as symbols or functions ; + - ``syms`` -- (default: ``{}``) dictionary of + strings to be regarded as symbols or functions; keys are pairs (string, number of arguments) - - ``accept_sequence`` - (default: False) controls whether + - ``accept_sequence`` -- (default: ``False``) controls whether to allow a (possibly nested) set of lists and tuples as input @@ -2562,23 +2574,25 @@ def symbolic_expression_from_string(s, syms=None, accept_sequence=False, *, pars EXAMPLES:: + sage: from sage.calculus.calculus import symbolic_expression_from_string sage: y = var('y') - sage: sage.calculus.calculus.symbolic_expression_from_string('[sin(0)*x^2,3*spam+e^pi]',syms={('spam',0):y},accept_sequence=True) + sage: symbolic_expression_from_string('[sin(0)*x^2,3*spam+e^pi]', + ....: syms={('spam',0): y}, accept_sequence=True) [0, 3*y + e^pi] TESTS: Check that the precision is preserved (:trac:`28814`):: - sage: sage.calculus.calculus.symbolic_expression_from_string(str(RealField(100)(1/3))) + sage: symbolic_expression_from_string(str(RealField(100)(1/3))) 0.3333333333333333333333333333 - sage: sage.calculus.calculus.symbolic_expression_from_string(str(RealField(100)(10^-500/3))) + sage: symbolic_expression_from_string(str(RealField(100)(10^-500/3))) 3.333333333333333333333333333e-501 The Giac interface uses a different parser (:trac:`30133`):: sage: from sage.calculus.calculus import SR_parser_giac - sage: sage.calculus.calculus.symbolic_expression_from_string(repr(giac(SR.var('e'))), parser=SR_parser_giac) + sage: symbolic_expression_from_string(repr(giac(SR.var('e'))), parser=SR_parser_giac) e """ if syms is None: diff --git a/src/sage/structure/nonexact.py b/src/sage/structure/nonexact.py index ffb39e5f579..adf60b04102 100644 --- a/src/sage/structure/nonexact.py +++ b/src/sage/structure/nonexact.py @@ -19,7 +19,7 @@ sage: R. = PowerSeriesRing(QQ, default_prec=10) sage: R.default_prec() 10 - sage: cos(x) + sage: cos(x) # optional - sage.symbolic 1 - 1/2*x^2 + 1/24*x^4 - 1/720*x^6 + 1/40320*x^8 + O(x^10) .. NOTE:: From c68e14fb37954c360463d0d946060923634ec69b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 20 May 2023 15:34:11 -0700 Subject: [PATCH 06/23] sage.calculus: Add # optional --- src/sage/calculus/interpolators.pyx | 16 ++++++++-------- src/sage/calculus/ode.pyx | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/sage/calculus/interpolators.pyx b/src/sage/calculus/interpolators.pyx index de776562671..ed6abc6647f 100644 --- a/src/sage/calculus/interpolators.pyx +++ b/src/sage/calculus/interpolators.pyx @@ -51,7 +51,7 @@ def polygon_spline(pts): sage: show(parametric_plot((fx, fy), (0, 2*pi))) # optional - sage.plot sage: m = Riemann_Map([lambda x: ps.value(real(x))], ....: [lambda x: ps.derivative(real(x))], 0) - sage: show(m.plot_colored() + m.plot_spiderweb()) + sage: show(m.plot_colored() + m.plot_spiderweb()) # optional - sage.plot Polygon approximation of an circle:: @@ -118,7 +118,7 @@ cdef class PSpline: sage: ps = polygon_spline(pts) sage: ps.value(.5) (-0.363380227632...-1j) - sage: ps.value(0) - ps.value(2*pi) + sage: ps.value(0) - ps.value(2*pi) # optional - sage.symbolic 0j sage: ps.value(10) (0.26760455264...+1j) @@ -151,7 +151,7 @@ cdef class PSpline: sage: ps = polygon_spline(pts) sage: ps.derivative(1 / 3) (1.27323954473...+0j) - sage: ps.derivative(0) - ps.derivative(2*pi) + sage: ps.derivative(0) - ps.derivative(2*pi) # optional - sage.symbolic 0j sage: ps.derivative(10) (-1.27323954473...+0j) @@ -187,9 +187,9 @@ def complex_cubic_spline(pts): Polygon approximation of a circle:: - sage: pts = [e^(I*t / 25) for t in range(25)] - sage: cs = complex_cubic_spline(pts) - sage: cs.derivative(2) + sage: pts = [e^(I*t / 25) for t in range(25)] # optional - sage.symbolic + sage: cs = complex_cubic_spline(pts) # optional - sage.symbolic + sage: cs.derivative(2) # optional - sage.symbolic (-0.0497765406583...+0.151095006434...j) """ return CCSpline(pts) @@ -271,7 +271,7 @@ cdef class CCSpline: sage: cs = complex_cubic_spline(pts) sage: cs.value(4 / 7) (-0.303961332787...-1.34716728183...j) - sage: cs.value(0) - cs.value(2*pi) + sage: cs.value(0) - cs.value(2*pi) # optional - sage.symbolic 0j sage: cs.value(-2.73452) (0.934561222231...+0.881366116402...j) @@ -302,7 +302,7 @@ cdef class CCSpline: sage: cs = complex_cubic_spline(pts) sage: cs.derivative(3 / 5) (1.40578892327...-0.225417136326...j) - sage: cs.derivative(0) - cs.derivative(2 * pi) + sage: cs.derivative(0) - cs.derivative(2 * pi) # optional - sage.symbolic 0j sage: cs.derivative(-6) (2.52047692949...-1.89392588310...j) diff --git a/src/sage/calculus/ode.pyx b/src/sage/calculus/ode.pyx index 9e3349e1fc7..79d0e65de03 100644 --- a/src/sage/calculus/ode.pyx +++ b/src/sage/calculus/ode.pyx @@ -263,7 +263,7 @@ class ode_solver(): By default T.plot_solution() plots the y_0, to plot general y_i use:: - sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: + sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # optional - sage.plot ....: T.plot_solution(i=0, filename=f.name) ....: T.plot_solution(i=1, filename=f.name) ....: T.plot_solution(i=2, filename=f.name) @@ -274,13 +274,13 @@ class ode_solver(): argument i. :: sage: f = T.interpolate_solution() - sage: plot(f,0,12).show() + sage: plot(f,0,12).show() # optional - sage.plot sage: f = T.interpolate_solution(i=1) - sage: plot(f,0,12).show() + sage: plot(f,0,12).show() # optional - sage.plot sage: f = T.interpolate_solution(i=2) - sage: plot(f,0,12).show() + sage: plot(f,0,12).show() # optional - sage.plot sage: f = T.interpolate_solution() - sage: f(pi) + sage: f(pi) # optional - sage.symbolic 0.5379... The solver attributes may also be set up using arguments to @@ -289,7 +289,7 @@ class ode_solver(): sage: T = ode_solver(g_1,y_0=[0,1,1],scale_abs=[1e-4,1e-4,1e-5],error_rel=1e-4, algorithm="rk8pd") sage: T.ode_solve(t_span=[0,12],num_points=100) sage: f = T.interpolate_solution() - sage: f(pi) + sage: f(pi) # optional - sage.symbolic 0.5379... Unfortunately because Python functions are used, this solver @@ -381,11 +381,11 @@ class ode_solver(): sage: T.function = lambda t,y: [cos(y[0]) * sin(t)] sage: T.jacobian = lambda t,y: [[-sin(y[0]) * sin(t)]] sage: T.ode_solve(y_0=[1],t_span=[0,20],num_points=1000) - sage: T.plot_solution() + sage: T.plot_solution() # optional - sage.plot And with some options:: - sage: T.plot_solution(color='red', axes_labels=["t", "x(t)"]) + sage: T.plot_solution(color='red', axes_labels=["t", "x(t)"]) # optional - sage.plot """ if interpolate: from sage.plot.line import line2d From 933a6eb3f4c1f94241f9158bc781f0cfebc02762 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 31 May 2023 23:15:01 -0700 Subject: [PATCH 07/23] sage.calculus: Modularization fixes --- src/sage/calculus/desolvers.py | 2 +- src/sage/calculus/functions.py | 4 +- src/sage/calculus/interpolation.pyx | 2 +- src/sage/calculus/transforms/all.py | 6 ++- src/sage/calculus/transforms/dft.py | 74 ++++++++++++++++------------ src/sage/calculus/transforms/dwt.pyx | 12 ++--- src/sage/calculus/transforms/fft.pyx | 44 ++++++++--------- 7 files changed, 79 insertions(+), 65 deletions(-) diff --git a/src/sage/calculus/desolvers.py b/src/sage/calculus/desolvers.py index 55ed3a0fe10..1f043d6447b 100644 --- a/src/sage/calculus/desolvers.py +++ b/src/sage/calculus/desolvers.py @@ -1163,7 +1163,7 @@ def eulers_method_2x2_plot(f, g, t0, x0, y0, h, t1): sage: from sage.calculus.desolvers import eulers_method_2x2_plot sage: f = lambda z : z[2]; g = lambda z : -sin(z[1]) - sage: P = eulers_method_2x2_plot(f,g, 0.0, 0.75, 0.0, 0.1, 1.0) + sage: P = eulers_method_2x2_plot(f,g, 0.0, 0.75, 0.0, 0.1, 1.0) # optional - sage.plot """ from sage.plot.line import line diff --git a/src/sage/calculus/functions.py b/src/sage/calculus/functions.py index 4e6d69f3f5e..b84c02fe779 100644 --- a/src/sage/calculus/functions.py +++ b/src/sage/calculus/functions.py @@ -2,9 +2,11 @@ r""" Calculus functions """ -from sage.matrix.constructor import matrix +from sage.misc.lazy_import import lazy_import from sage.structure.element import is_Matrix, is_Vector, Expression +lazy_import('sage.matrix.constructor', 'matrix') + from .functional import diff diff --git a/src/sage/calculus/interpolation.pyx b/src/sage/calculus/interpolation.pyx index d1375c90abe..f9a41295ab7 100644 --- a/src/sage/calculus/interpolation.pyx +++ b/src/sage/calculus/interpolation.pyx @@ -57,7 +57,7 @@ cdef class Spline: sage: v = [(i + sin(i)/2, i+cos(i^2)) for i in range(10)] # optional - sage.symbolic sage: s = spline(v) # optional - sage.symbolic - sage: show(point(v) + plot(s,0,9, hue=.8)) # optional - sage.symbolic + sage: show(point(v) + plot(s,0,9, hue=.8)) # optional - sage.plot sage.symbolic We compute the area underneath the spline:: diff --git a/src/sage/calculus/transforms/all.py b/src/sage/calculus/transforms/all.py index 06ed525b868..379b3b69c37 100644 --- a/src/sage/calculus/transforms/all.py +++ b/src/sage/calculus/transforms/all.py @@ -1,3 +1,5 @@ -from .fft import FastFourierTransform, FFT -from .dwt import WaveletTransform, DWT +from sage.misc.lazy_import import lazy_import + +lazy_import("sage.calculus.transforms.fft", ["FastFourierTransform", "FFT"]) +lazy_import("sage.calculus.transforms.dwt", ["WaveletTransform", "DWT"]) from .dft import IndexedSequence diff --git a/src/sage/calculus/transforms/dft.py b/src/sage/calculus/transforms/dft.py index db18a20e129..4d94412299e 100644 --- a/src/sage/calculus/transforms/dft.py +++ b/src/sage/calculus/transforms/dft.py @@ -71,20 +71,21 @@ # # https://www.gnu.org/licenses/ ########################################################################## -from sage.rings.number_field.number_field import CyclotomicField +from sage.functions.all import sin, cos from sage.misc.lazy_import import lazy_import -from sage.groups.abelian_gps.abelian_group import AbelianGroup -from sage.groups.perm_gps.permgroup_element import is_PermutationGroupElement -from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.rings.real_mpfr import RR -from sage.functions.all import sin, cos -from sage.calculus.transforms.fft import FastFourierTransform -from sage.calculus.transforms.dwt import WaveletTransform from sage.structure.sage_object import SageObject from sage.structure.sequence import Sequence + +lazy_import("sage.calculus.transforms.dwt", "WaveletTransform") +lazy_import("sage.calculus.transforms.fft", "FastFourierTransform") +lazy_import("sage.groups.abelian_gps.abelian_group", "AbelianGroup") +lazy_import("sage.groups.perm_gps.permgroup_element", "PermutationGroupElement") lazy_import("sage.plot.all", ["polygon", "line", "text"]) +lazy_import("sage.rings.number_field.number_field", "CyclotomicField") +lazy_import("sage.rings.real_mpfr", "RR") class IndexedSequence(SageObject): @@ -216,10 +217,9 @@ def _repr_(self): sage: print(s) Indexed sequence: [0, 1, 2] indexed by [0, 1, 2] - sage: I = GF(3) - sage: A = [i^2 for i in I] - sage: s = IndexedSequence(A,I) - sage: s + sage: I = GF(3) # optional - sage.rings.finite_rings + sage: A = [i^2 for i in I] # optional - sage.rings.finite_rings + sage: s = IndexedSequence(A,I); s # optional - sage.rings.finite_rings Indexed sequence: [0, 1, 1] indexed by Finite Field of size 3 """ @@ -240,8 +240,8 @@ def plot_histogram(self, clr=(0, 0, 1), eps=0.4): sage: J = list(range(3)) sage: A = [ZZ(i^2)+1 for i in J] sage: s = IndexedSequence(A,J) - sage: P = s.plot_histogram() - sage: show(P) # Not tested + sage: P = s.plot_histogram() # optional - sage.plot + sage: show(P) # not tested # optional - sage.plot """ # elements must be coercible into RR I = self.index_object() @@ -268,8 +268,8 @@ def plot(self): sage: I = list(range(3)) sage: A = [ZZ(i^2)+1 for i in I] sage: s = IndexedSequence(A,I) - sage: P = s.plot() - sage: show(P) # Not tested + sage: P = s.plot() # optional - sage.plot + sage: show(P) # not tested # optional - sage.plot """ # elements must be coercible into RR I = self.index_object() @@ -286,30 +286,40 @@ def dft(self, chi=lambda x: x): sage: J = list(range(6)) sage: A = [ZZ(1) for i in J] sage: s = IndexedSequence(A,J) - sage: s.dft(lambda x:x^2) + sage: s.dft(lambda x: x^2) Indexed sequence: [6, 0, 0, 6, 0, 0] indexed by [0, 1, 2, 3, 4, 5] sage: s.dft() Indexed sequence: [6, 0, 0, 0, 0, 0] indexed by [0, 1, 2, 3, 4, 5] - sage: G = SymmetricGroup(3) - sage: J = G.conjugacy_classes_representatives() - sage: s = IndexedSequence([1,2,3],J) # 1,2,3 are the values of a class fcn on G - sage: s.dft() # the "scalar-valued Fourier transform" of this class fcn + sage: G = SymmetricGroup(3) # optional - sage.groups + sage: J = G.conjugacy_classes_representatives() # optional - sage.groups + sage: s = IndexedSequence([1,2,3], J) # 1,2,3 are the values of a class fcn on G # optional - sage.groups + sage: s.dft() # the "scalar-valued Fourier transform" of this class fcn # optional - sage.groups Indexed sequence: [8, 2, 2] indexed by [(), (1,2), (1,2,3)] - sage: J = AbelianGroup(2,[2,3],names='ab') - sage: s = IndexedSequence([1,2,3,4,5,6],J) - sage: s.dft() # the precision of output is somewhat random and architecture dependent. - Indexed sequence: [21.0000000000000, -2.99999999999997 - 1.73205080756885*I, -2.99999999999999 + 1.73205080756888*I, -9.00000000000000 + 0.0000000000000485744257349999*I, -0.00000000000000976996261670137 - 0.0000000000000159872115546022*I, -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I] - indexed by Multiplicative Abelian group isomorphic to C2 x C3 - sage: J = CyclicPermutationGroup(6) - sage: s = IndexedSequence([1,2,3,4,5,6],J) - sage: s.dft() # the precision of output is somewhat random and architecture dependent. - Indexed sequence: [21.0000000000000, -2.99999999999997 - 1.73205080756885*I, -2.99999999999999 + 1.73205080756888*I, -9.00000000000000 + 0.0000000000000485744257349999*I, -0.00000000000000976996261670137 - 0.0000000000000159872115546022*I, -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I] - indexed by Cyclic group of order 6 as a permutation group + sage: J = AbelianGroup(2, [2,3], names='ab') # optional - sage.groups + sage: s = IndexedSequence([1,2,3,4,5,6], J) # optional - sage.groups + sage: s.dft() # the precision of output is somewhat random and architecture dependent. # optional - sage.groups + Indexed sequence: [21.0000000000000, + -2.99999999999997 - 1.73205080756885*I, + -2.99999999999999 + 1.73205080756888*I, + -9.00000000000000 + 0.0000000000000485744257349999*I, + -0.00000000000000976996261670137 - 0.0000000000000159872115546022*I, + -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I] + indexed by Multiplicative Abelian group isomorphic to C2 x C3 + sage: J = CyclicPermutationGroup(6) # optional - sage.groups + sage: s = IndexedSequence([1,2,3,4,5,6], J) # optional - sage.groups + sage: s.dft() # the precision of output is somewhat random and architecture dependent. # optional - sage.groups + Indexed sequence: [21.0000000000000, + -2.99999999999997 - 1.73205080756885*I, + -2.99999999999999 + 1.73205080756888*I, + -9.00000000000000 + 0.0000000000000485744257349999*I, + -0.00000000000000976996261670137 - 0.0000000000000159872115546022*I, + -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I] + indexed by Cyclic group of order 6 as a permutation group sage: p = 7; J = list(range(p)); A = [kronecker_symbol(j,p) for j in J] - sage: s = IndexedSequence(A,J) + sage: s = IndexedSequence(A, J) sage: Fs = s.dft() sage: c = Fs.list()[1]; [x/c for x in Fs.list()]; s.list() [0, 1, 1, -1, 1, -1, -1] diff --git a/src/sage/calculus/transforms/dwt.pyx b/src/sage/calculus/transforms/dwt.pyx index 61e0f83d331..33a601c626c 100644 --- a/src/sage/calculus/transforms/dwt.pyx +++ b/src/sage/calculus/transforms/dwt.pyx @@ -63,27 +63,27 @@ def WaveletTransform(n, wavelet_type, wavelet_k): sage: for i in range(1, 11): ....: a[i] = 1 ....: a[128-i] = 1 - sage: a.plot().show(ymin=0) + sage: a.plot().show(ymin=0) # optional - sage.plot sage: a.forward_transform() - sage: a.plot().show() + sage: a.plot().show() # optional - sage.plot sage: a = WaveletTransform(128,'haar',2) sage: for i in range(1, 11): a[i] = 1; a[128-i] = 1 sage: a.forward_transform() - sage: a.plot().show(ymin=0) + sage: a.plot().show(ymin=0) # optional - sage.plot sage: a = WaveletTransform(128,'bspline_centered',103) sage: for i in range(1, 11): a[i] = 1; a[100+i] = 1 sage: a.forward_transform() - sage: a.plot().show(ymin=0) + sage: a.plot().show(ymin=0) # optional - sage.plot This example gives a simple example of wavelet compression:: sage: a = DWT(2048,'daubechies',6) sage: for i in range(2048): a[i]=float(sin((i*5/2048)**2)) - sage: a.plot().show() # long time (7s on sage.math, 2011) + sage: a.plot().show() # long time (7s on sage.math, 2011) # optional - sage.plot sage: a.forward_transform() sage: for i in range(1800): a[2048-i-1] = 0 sage: a.backward_transform() - sage: a.plot().show() # long time (7s on sage.math, 2011) + sage: a.plot().show() # long time (7s on sage.math, 2011) # optional - sage.plot """ cdef size_t _n, _k _n = int(n) diff --git a/src/sage/calculus/transforms/fft.pyx b/src/sage/calculus/transforms/fft.pyx index f0df57f05ec..dc2d54f1489 100644 --- a/src/sage/calculus/transforms/fft.pyx +++ b/src/sage/calculus/transforms/fft.pyx @@ -22,7 +22,6 @@ AUTHORS: from cysignals.memory cimport sig_malloc, sig_free -import sage.libs.pari.all from sage.rings.integer import Integer from sage.rings.complex_mpfr import ComplexNumber @@ -70,9 +69,9 @@ def FastFourierTransform(size, base_ring=None): ....: a[128-i] = 1 sage: a[:6:2] [(0.0, 0.0), (1.0, 0.0), (1.0, 0.0)] - sage: a.plot().show(ymin=0) + sage: a.plot().show(ymin=0) # optional - sage.plot sage: a.forward_transform() - sage: a.plot().show() + sage: a.plot().show() # optional - sage.plot """ return FastFourierTransform_complex(int(size)) @@ -241,17 +240,18 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): EXAMPLES:: sage: a = FastFourierTransform(4) - sage: a._plot_polar(0,2) + sage: a._plot_polar(0,2) # optional - sage.plot Graphics object consisting of 2 graphics primitives """ from sage.plot.point import point + from sage.symbolic.constants import pi, I cdef int i v = [] - pi = sage.symbolic.constants.pi.n() - I = sage.symbolic.constants.I.n() + pi = pi.n() + I = I.n() s = 1/(3*pi) # so arg gets scaled between -1/3 and 1/3. for i from xmin <= i < xmax: @@ -280,16 +280,16 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): EXAMPLES:: sage: a = FastFourierTransform(4) - sage: a._plot_rect(0,3) + sage: a._plot_rect(0,3) # optional - sage.plot Graphics object consisting of 3 graphics primitives """ + from sage.plot.point import point + cdef int i cdef double pr_x, x, h v = [] - point = sage.plot.all.point - for i from xmin <= i < xmax: x = self.data[2*i] h = self.data[2*i+1] @@ -301,10 +301,10 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): Plot a slice of the array. - ``style`` -- Style of the plot, options are ``"rect"`` or ``"polar"`` - - ``rect`` -- height represents real part, color represents - imaginary part. - - ``polar`` -- height represents absolute value, color - represents argument. + - ``rect`` -- height represents real part, color represents + imaginary part. + - ``polar`` -- height represents absolute value, color + represents argument. - ``xmin`` -- The lower bound of the slice to plot. 0 by default. - ``xmax`` -- The upper bound of the slice to plot. ``len(self)`` by default. - ``**args`` -- passed on to the line plotting function. @@ -317,11 +317,11 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: a = FastFourierTransform(16) sage: for i in range(16): a[i] = (random(),random()) - sage: A = plot(a) - sage: B = plot(a, style='polar') - sage: type(A) + sage: A = plot(a) # optional - sage.plot + sage: B = plot(a, style='polar') # optional - sage.plot + sage: type(A) # optional - sage.plot - sage: type(B) + sage: type(B) # optional - sage.plot sage: a = FastFourierTransform(125) sage: b = FastFourierTransform(125) @@ -329,7 +329,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: for i in range(1, 60): b[i]=1 sage: a.forward_transform() sage: a.inverse_transform() - sage: (a.plot()+b.plot()) + sage: a.plot() + b.plot() # optional - sage.plot Graphics object consisting of 250 graphics primitives """ @@ -407,7 +407,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: for i in range(1, 60): b[i]=1 sage: a.forward_transform() sage: a.inverse_transform() - sage: (a.plot()+b.plot()) + sage: a.plot() + b.plot() # optional - sage.plot Graphics object consisting of 250 graphics primitives sage: abs(sum([CDF(a[i])-CDF(b[i]) for i in range(125)])) < 2**-16 True @@ -420,7 +420,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: for i in range(1, 60): b[i]=1 sage: a.forward_transform() sage: a.inverse_transform() - sage: (a.plot()+b.plot()) + sage: a.plot() + b.plot() # optional - sage.plot Graphics object consisting of 256 graphics primitives """ @@ -458,7 +458,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: for i in range(1, 60): b[i]=1 sage: a.forward_transform() sage: a.backward_transform() - sage: (a.plot() + b.plot()).show(ymin=0) # long time (2s on sage.math, 2011) + sage: (a.plot() + b.plot()).show(ymin=0) # long time (2s on sage.math, 2011) # optional - sage.plot sage: abs(sum([CDF(a[i])/125-CDF(b[i]) for i in range(125)])) < 2**-16 True @@ -470,7 +470,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: for i in range(1, 60): b[i]=1 sage: a.forward_transform() sage: a.backward_transform() - sage: (a.plot() + b.plot()).show(ymin=0) + sage: (a.plot() + b.plot()).show(ymin=0) # optional - sage.plot """ cdef gsl_fft_complex_wavetable * wt cdef gsl_fft_complex_workspace * mem From be243bf9403efaf4b5d2fcf6fa361cec3e471f54 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 4 Jun 2023 00:04:30 -0700 Subject: [PATCH 08/23] src/sage/calculus/transforms/dft.py: Fix up --- src/sage/calculus/transforms/dft.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/calculus/transforms/dft.py b/src/sage/calculus/transforms/dft.py index 4d94412299e..1fff64d169f 100644 --- a/src/sage/calculus/transforms/dft.py +++ b/src/sage/calculus/transforms/dft.py @@ -346,7 +346,7 @@ def dft(self, chi=lambda x: x): zeta = CyclotomicField(N).gen() FT = [sum([S[i] * chi(zeta**(i * j)) for i in J]) for j in J] elif (J[0] not in ZZ) and G.is_abelian() and F == ZZ or (F.is_field() and F.base_ring() == QQ): - if is_PermutationGroupElement(J[0]): + if isinstance(J[0], PermutationGroupElement): # J is a CyclicPermGp n = G.order() a = list(n.factor()) From a25a7e0509d460456a4498d3a4eb6e561071700f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 4 Jun 2023 08:17:21 -0700 Subject: [PATCH 09/23] src/sage/calculus/transforms/dft.py: Do not lazy_import RR, keep sage.misc.dev_tools test happy --- src/sage/calculus/transforms/dft.py | 4 +++- src/sage/calculus/transforms/fft.pyx | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/calculus/transforms/dft.py b/src/sage/calculus/transforms/dft.py index 1fff64d169f..22443038086 100644 --- a/src/sage/calculus/transforms/dft.py +++ b/src/sage/calculus/transforms/dft.py @@ -85,7 +85,6 @@ lazy_import("sage.groups.perm_gps.permgroup_element", "PermutationGroupElement") lazy_import("sage.plot.all", ["polygon", "line", "text"]) lazy_import("sage.rings.number_field.number_field", "CyclotomicField") -lazy_import("sage.rings.real_mpfr", "RR") class IndexedSequence(SageObject): @@ -243,6 +242,7 @@ def plot_histogram(self, clr=(0, 0, 1), eps=0.4): sage: P = s.plot_histogram() # optional - sage.plot sage: show(P) # not tested # optional - sage.plot """ + from sage.rings.real_mpfr import RR # elements must be coercible into RR I = self.index_object() N = len(I) @@ -271,6 +271,7 @@ def plot(self): sage: P = s.plot() # optional - sage.plot sage: show(P) # not tested # optional - sage.plot """ + from sage.rings.real_mpfr import RR # elements must be coercible into RR I = self.index_object() S = self.list() @@ -721,6 +722,7 @@ def dwt(self, other="haar", wavelet_k=2): Indexed sequence: [2.82842712474999, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000] indexed by [0, 1, 2, 3, 4, 5, 6, 7] """ + from sage.rings.real_mpfr import RR # elements must be coercible into RR J = self.index_object() # must be = range(N) N = len(J) # must be 1 minus a power of 2 diff --git a/src/sage/calculus/transforms/fft.pyx b/src/sage/calculus/transforms/fft.pyx index dc2d54f1489..ff440421e0b 100644 --- a/src/sage/calculus/transforms/fft.pyx +++ b/src/sage/calculus/transforms/fft.pyx @@ -470,7 +470,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: for i in range(1, 60): b[i]=1 sage: a.forward_transform() sage: a.backward_transform() - sage: (a.plot() + b.plot()).show(ymin=0) # optional - sage.plot + sage: (a.plot() + b.plot()).show(ymin=0) # optional - sage.plot """ cdef gsl_fft_complex_wavetable * wt cdef gsl_fft_complex_workspace * mem From d2b9265cad6ba5f4ea1c3390d421908371ec8090 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 19 Jun 2023 09:01:11 -0700 Subject: [PATCH 10/23] sage.calculus: More # optional --- src/sage/calculus/desolvers.py | 89 +++++++++++++++------------- src/sage/calculus/interpolators.pyx | 1 + src/sage/calculus/riemann.pyx | 2 +- src/sage/calculus/transforms/dft.py | 32 +++++----- src/sage/calculus/transforms/dwt.pyx | 12 ++-- 5 files changed, 71 insertions(+), 65 deletions(-) diff --git a/src/sage/calculus/desolvers.py b/src/sage/calculus/desolvers.py index 1f043d6447b..3dbeca4be8b 100644 --- a/src/sage/calculus/desolvers.py +++ b/src/sage/calculus/desolvers.py @@ -874,8 +874,8 @@ def desolve_system(des, vars, ics=None, ivar=None, algorithm="maxima"): :: - sage: P1 = plot([solx,soly], (0,1)) - sage: P2 = parametric_plot((solx,soly), (0,1)) + sage: P1 = plot([solx,soly], (0,1)) # optional - sage.plot + sage: P2 = parametric_plot((solx,soly), (0,1)) # optional - sage.plot Now type ``show(P1)``, ``show(P2)`` to view these plots. @@ -892,7 +892,8 @@ def desolve_system(des, vars, ics=None, ivar=None, algorithm="maxima"): sage: desolve_system([de1, de2], [x1, x2], ics=[1,1], ivar=t) Traceback (most recent call last): ... - ValueError: Initial conditions aren't complete: number of vars is different from number of dependent variables. Got ics = [1, 1], vars = [x1(t), x2(t)] + ValueError: Initial conditions aren't complete: number of vars is different + from number of dependent variables. Got ics = [1, 1], vars = [x1(t), x2(t)] Check that :trac:`9825` is fixed:: @@ -1013,9 +1014,9 @@ def eulers_method(f, x0, y0, h, x1, algorithm="table"): :: sage: pts = eulers_method(5*x+y-5,0,1,1/2,1,algorithm="none") - sage: P1 = list_plot(pts) - sage: P2 = line(pts) - sage: (P1+P2).show() + sage: P1 = list_plot(pts) # optional - sage.plot + sage: P2 = line(pts) # optional - sage.plot + sage: (P1 + P2).show() # optional - sage.plot AUTHORS: @@ -1430,13 +1431,14 @@ def desolve_system_rk4(des, vars, ics=None, ivar=None, end_points=None, step=0.1 Lotka Volterra system:: sage: from sage.calculus.desolvers import desolve_system_rk4 - sage: x,y,t=var('x y t') - sage: P=desolve_system_rk4([x*(1-y),-y*(1-x)],[x,y],ics=[0,0.5,2],ivar=t,end_points=20) - sage: Q=[ [i,j] for i,j,k in P] - sage: LP=list_plot(Q) + sage: x,y,t = var('x y t') + sage: P = desolve_system_rk4([x*(1-y),-y*(1-x)], [x,y], ics=[0,0.5,2], + ....: ivar=t, end_points=20) + sage: Q = [[i,j] for i,j,k in P] + sage: LP = list_plot(Q) # optional - sage.plot - sage: Q=[ [j,k] for i,j,k in P] - sage: LP=list_plot(Q) + sage: Q = [[j,k] for i,j,k in P] + sage: LP = list_plot(Q) # optional - sage.plot ALGORITHM: @@ -1570,49 +1572,52 @@ def desolve_odeint(des, ics, times, dvars, ivar=None, compute_jac=False, args=() Lotka Volterra Equations:: sage: from sage.calculus.desolvers import desolve_odeint - sage: x,y=var('x,y') - sage: f=[x*(1-y),-y*(1-x)] - sage: sol=desolve_odeint(f,[0.5,2],srange(0,10,0.1),[x,y]) - sage: p=line(zip(sol[:,0],sol[:,1])) - sage: p.show() + sage: x,y = var('x,y') + sage: f = [x*(1-y), -y*(1-x)] + sage: sol = desolve_odeint(f, [0.5,2], srange(0,10,0.1), [x,y]) # optional - scipy + sage: p = line(zip(sol[:,0],sol[:,1])) # optional - sage.plot + sage: p.show() # optional - sage.plot Lorenz Equations:: - sage: x,y,z=var('x,y,z') + sage: x,y,z = var('x,y,z') sage: # Next we define the parameters - sage: sigma=10 - sage: rho=28 - sage: beta=8/3 + sage: sigma = 10 + sage: rho = 28 + sage: beta = 8/3 sage: # The Lorenz equations - sage: lorenz=[sigma*(y-x),x*(rho-z)-y,x*y-beta*z] + sage: lorenz = [sigma*(y-x),x*(rho-z)-y,x*y-beta*z] sage: # Time and initial conditions - sage: times=srange(0,50.05,0.05) - sage: ics=[0,1,1] - sage: sol=desolve_odeint(lorenz,ics,times,[x,y,z],rtol=1e-13,atol=1e-14) + sage: times = srange(0,50.05,0.05) + sage: ics = [0,1,1] + sage: sol = desolve_odeint(lorenz, ics, times, [x,y,z], # optional - scipy + ....: rtol=1e-13, atol=1e-14) One-dimensional stiff system:: - sage: y= var('y') - sage: epsilon=0.01 - sage: f=y^2*(1-y) - sage: ic=epsilon - sage: t=srange(0,2/epsilon,1) - sage: sol=desolve_odeint(f,ic,t,y,rtol=1e-9,atol=1e-10,compute_jac=True) - sage: p=points(zip(t,sol)) - sage: p.show() + sage: y = var('y') + sage: epsilon = 0.01 + sage: f = y^2*(1-y) + sage: ic = epsilon + sage: t = srange(0,2/epsilon,1) + sage: sol = desolve_odeint(f, ic, t, y, # optional - scipy + ....: rtol=1e-9, atol=1e-10, compute_jac=True) + sage: p = points(zip(t,sol)) # optional - scipy sage.plot + sage: p.show() # optional - scipy sage.plot Another stiff system with some optional parameters with no default value:: - sage: y1,y2,y3=var('y1,y2,y3') - sage: f1=77.27*(y2+y1*(1-8.375*1e-6*y1-y2)) - sage: f2=1/77.27*(y3-(1+y1)*y2) - sage: f3=0.16*(y1-y3) - sage: f=[f1,f2,f3] - sage: ci=[0.2,0.4,0.7] - sage: t=srange(0,10,0.01) - sage: v=[y1,y2,y3] - sage: sol=desolve_odeint(f,ci,t,v,rtol=1e-3,atol=1e-4,h0=0.1,hmax=1,hmin=1e-4,mxstep=1000,mxords=17) + sage: y1,y2,y3 = var('y1,y2,y3') + sage: f1 = 77.27*(y2+y1*(1-8.375*1e-6*y1-y2)) + sage: f2 = 1/77.27*(y3-(1+y1)*y2) + sage: f3 = 0.16*(y1-y3) + sage: f = [f1,f2,f3] + sage: ci = [0.2,0.4,0.7] + sage: t = srange(0,10,0.01) + sage: v = [y1,y2,y3] + sage: sol = desolve_odeint(f, ci, t, v, rtol=1e-3, atol=1e-4, # optional - scipy + ....: h0=0.1, hmax=1, hmin=1e-4, mxstep=1000, mxords=17) AUTHOR: diff --git a/src/sage/calculus/interpolators.pyx b/src/sage/calculus/interpolators.pyx index ed6abc6647f..2a4865bb136 100644 --- a/src/sage/calculus/interpolators.pyx +++ b/src/sage/calculus/interpolators.pyx @@ -1,3 +1,4 @@ +# sage.doctest: optional - numpy """ Complex Interpolation diff --git a/src/sage/calculus/riemann.pyx b/src/sage/calculus/riemann.pyx index 4dadd44ce17..1142c5ab0ce 100644 --- a/src/sage/calculus/riemann.pyx +++ b/src/sage/calculus/riemann.pyx @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.symbolic +# sage.doctest: optional - numpy sage.symbolic """ Riemann Mapping diff --git a/src/sage/calculus/transforms/dft.py b/src/sage/calculus/transforms/dft.py index 22443038086..f3715d5305c 100644 --- a/src/sage/calculus/transforms/dft.py +++ b/src/sage/calculus/transforms/dft.py @@ -287,10 +287,10 @@ def dft(self, chi=lambda x: x): sage: J = list(range(6)) sage: A = [ZZ(1) for i in J] sage: s = IndexedSequence(A,J) - sage: s.dft(lambda x: x^2) + sage: s.dft(lambda x: x^2) # optional - sage.rings.number_field Indexed sequence: [6, 0, 0, 6, 0, 0] indexed by [0, 1, 2, 3, 4, 5] - sage: s.dft() + sage: s.dft() # optional - sage.rings.number_field Indexed sequence: [6, 0, 0, 0, 0, 0] indexed by [0, 1, 2, 3, 4, 5] sage: G = SymmetricGroup(3) # optional - sage.groups @@ -319,10 +319,10 @@ def dft(self, chi=lambda x: x): -0.00000000000000976996261670137 - 0.0000000000000159872115546022*I, -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I] indexed by Cyclic group of order 6 as a permutation group - sage: p = 7; J = list(range(p)); A = [kronecker_symbol(j,p) for j in J] - sage: s = IndexedSequence(A, J) - sage: Fs = s.dft() - sage: c = Fs.list()[1]; [x/c for x in Fs.list()]; s.list() + sage: p = 7; J = list(range(p)); A = [kronecker_symbol(j,p) for j in J] # optional - sage.rings.number_field + sage: s = IndexedSequence(A, J) # optional - sage.rings.number_field + sage: Fs = s.dft() # optional - sage.rings.number_field + sage: c = Fs.list()[1]; [x/c for x in Fs.list()]; s.list() # optional - sage.rings.number_field [0, 1, 1, -1, 1, -1, -1] [0, 1, 1, -1, 1, -1, -1] @@ -375,13 +375,13 @@ def idft(self): sage: J = list(range(5)) sage: A = [ZZ(1) for i in J] sage: s = IndexedSequence(A,J) - sage: fs = s.dft(); fs + sage: fs = s.dft(); fs # optional - sage.rings.number_field Indexed sequence: [5, 0, 0, 0, 0] indexed by [0, 1, 2, 3, 4] - sage: it = fs.idft(); it + sage: it = fs.idft(); it # optional - sage.rings.number_field Indexed sequence: [1, 1, 1, 1, 1] indexed by [0, 1, 2, 3, 4] - sage: it == s + sage: it == s # optional - sage.rings.number_field True """ F = self.base_ring() # elements must be coercible into QQ(zeta_N) @@ -401,9 +401,9 @@ def dct(self): EXAMPLES:: sage: J = list(range(5)) - sage: A = [exp(-2*pi*i*I/5) for i in J] - sage: s = IndexedSequence(A,J) - sage: s.dct() + sage: A = [exp(-2*pi*i*I/5) for i in J] # optional - sage.symbolic + sage: s = IndexedSequence(A,J) # optional - sage.symbolic + sage: s.dct() # optional - sage.symbolic Indexed sequence: [0, 1/16*(sqrt(5) + I*sqrt(-2*sqrt(5) + 10) + ... indexed by [0, 1, 2, 3, 4] """ @@ -423,11 +423,11 @@ def dst(self): EXAMPLES:: sage: J = list(range(5)) - sage: I = CC.0; pi = CC(pi) - sage: A = [exp(-2*pi*i*I/5) for i in J] - sage: s = IndexedSequence(A,J) + sage: I = CC.0; pi = CC(pi) # optional - sage.symbolic + sage: A = [exp(-2*pi*i*I/5) for i in J] # optional - sage.symbolic + sage: s = IndexedSequence(A,J) # optional - sage.symbolic - sage: s.dst() # discrete sine + sage: s.dst() # discrete sine # optional - sage.symbolic Indexed sequence: [0.000000000000000, 1.11022302462516e-16 - 2.50000000000000*I, ...] indexed by [0, 1, 2, 3, 4] """ diff --git a/src/sage/calculus/transforms/dwt.pyx b/src/sage/calculus/transforms/dwt.pyx index 33a601c626c..63d169cfce5 100644 --- a/src/sage/calculus/transforms/dwt.pyx +++ b/src/sage/calculus/transforms/dwt.pyx @@ -78,12 +78,12 @@ def WaveletTransform(n, wavelet_type, wavelet_k): This example gives a simple example of wavelet compression:: sage: a = DWT(2048,'daubechies',6) - sage: for i in range(2048): a[i]=float(sin((i*5/2048)**2)) - sage: a.plot().show() # long time (7s on sage.math, 2011) # optional - sage.plot - sage: a.forward_transform() - sage: for i in range(1800): a[2048-i-1] = 0 - sage: a.backward_transform() - sage: a.plot().show() # long time (7s on sage.math, 2011) # optional - sage.plot + sage: for i in range(2048): a[i]=float(sin((i*5/2048)**2)) # optional - sage.symbolic + sage: a.plot().show() # long time (7s on sage.math, 2011) # optional - sage.plot sage.symbolic + sage: a.forward_transform() # optional - sage.symbolic + sage: for i in range(1800): a[2048-i-1] = 0 # optional - sage.symbolic + sage: a.backward_transform() # optional - sage.symbolic + sage: a.plot().show() # long time (7s on sage.math, 2011) # optional - sage.plot sage.symbolic """ cdef size_t _n, _k _n = int(n) From be0ac795f2112f441d375b22fb04529e0d666592 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 19 Jun 2023 09:03:15 -0700 Subject: [PATCH 11/23] src/sage/calculus/transforms/dft.py: Add missing import --- src/sage/calculus/transforms/dft.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/calculus/transforms/dft.py b/src/sage/calculus/transforms/dft.py index f3715d5305c..b87ce51b9ad 100644 --- a/src/sage/calculus/transforms/dft.py +++ b/src/sage/calculus/transforms/dft.py @@ -800,6 +800,7 @@ def idwt(self, other="haar", wavelet_k=2): sage: t.idwt("bspline", 103) == s True """ + from sage.rings.real_mpfr import RR # elements must be coercible into RR J = self.index_object() # must be = range(N) N = len(J) # must be 1 minus a power of 2 From 6ae45a71ffece8b6f5b620b1732db0b29028170b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 19 Jun 2023 10:29:14 -0700 Subject: [PATCH 12/23] src/sage/calculus/transforms/fft.pyx: Fix doc markup --- src/sage/calculus/transforms/fft.pyx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/calculus/transforms/fft.pyx b/src/sage/calculus/transforms/fft.pyx index ff440421e0b..31e5193668f 100644 --- a/src/sage/calculus/transforms/fft.pyx +++ b/src/sage/calculus/transforms/fft.pyx @@ -301,10 +301,12 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): Plot a slice of the array. - ``style`` -- Style of the plot, options are ``"rect"`` or ``"polar"`` + - ``rect`` -- height represents real part, color represents imaginary part. - ``polar`` -- height represents absolute value, color represents argument. + - ``xmin`` -- The lower bound of the slice to plot. 0 by default. - ``xmax`` -- The upper bound of the slice to plot. ``len(self)`` by default. - ``**args`` -- passed on to the line plotting function. From 92bd779d9ca41a119d4537828eda5b818c6131f8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 21 Jun 2023 19:30:02 -0700 Subject: [PATCH 13/23] sage.calculus: Avoid use of symbolics in some doctests --- src/sage/calculus/interpolation.pyx | 22 ++--- src/sage/calculus/interpolators.pyx | 21 +++-- src/sage/calculus/ode.pyx | 129 +++++++++++++++------------- src/sage/calculus/transforms/dft.py | 2 +- 4 files changed, 95 insertions(+), 79 deletions(-) diff --git a/src/sage/calculus/interpolation.pyx b/src/sage/calculus/interpolation.pyx index f9a41295ab7..44fc0838856 100644 --- a/src/sage/calculus/interpolation.pyx +++ b/src/sage/calculus/interpolation.pyx @@ -55,39 +55,39 @@ cdef class Spline: This example is in the GSL documentation:: - sage: v = [(i + sin(i)/2, i+cos(i^2)) for i in range(10)] # optional - sage.symbolic - sage: s = spline(v) # optional - sage.symbolic - sage: show(point(v) + plot(s,0,9, hue=.8)) # optional - sage.plot sage.symbolic + sage: v = [(i + RDF(i).sin()/2, i + RDF(i^2).cos()) for i in range(10)] + sage: s = spline(v) + sage: show(point(v) + plot(s,0,9, hue=.8)) # optional - sage.plot We compute the area underneath the spline:: - sage: s.definite_integral(0, 9) # optional - sage.symbolic + sage: s.definite_integral(0, 9) 41.196516041067... The definite integral is additive:: - sage: s.definite_integral(0, 4) + s.definite_integral(4, 9) # optional - sage.symbolic + sage: s.definite_integral(0, 4) + s.definite_integral(4, 9) 41.196516041067... Switching the order of the bounds changes the sign of the integral:: - sage: s.definite_integral(9, 0) # optional - sage.symbolic + sage: s.definite_integral(9, 0) -41.196516041067... We compute the first and second-order derivatives at a few points:: - sage: s.derivative(5) # optional - sage.symbolic + sage: s.derivative(5) -0.16230085261803... - sage: s.derivative(6) # optional - sage.symbolic + sage: s.derivative(6) 0.20997986285714... - sage: s.derivative(5, order=2) # optional - sage.symbolic + sage: s.derivative(5, order=2) -3.08747074561380... - sage: s.derivative(6, order=2) # optional - sage.symbolic + sage: s.derivative(6, order=2) 2.61876848274853... Only the first two derivatives are supported:: - sage: s.derivative(4, order=3) # optional - sage.symbolic + sage: s.derivative(4, order=3) Traceback (most recent call last): ... ValueError: Order of derivative must be 1 or 2. diff --git a/src/sage/calculus/interpolators.pyx b/src/sage/calculus/interpolators.pyx index 93174e692da..2927921b825 100644 --- a/src/sage/calculus/interpolators.pyx +++ b/src/sage/calculus/interpolators.pyx @@ -119,7 +119,7 @@ cdef class PSpline: sage: ps = polygon_spline(pts) sage: ps.value(.5) (-0.363380227632...-1j) - sage: ps.value(0) - ps.value(2*pi) # optional - sage.symbolic + sage: ps.value(0) - ps.value(2*RDF.pi()) 0j sage: ps.value(10) (0.26760455264...+1j) @@ -152,7 +152,8 @@ cdef class PSpline: sage: ps = polygon_spline(pts) sage: ps.derivative(1 / 3) (1.27323954473...+0j) - sage: ps.derivative(0) - ps.derivative(2*pi) # optional - sage.symbolic + sage: from math import pi + sage: ps.derivative(0) - ps.derivative(2*pi) 0j sage: ps.derivative(10) (-1.27323954473...+0j) @@ -170,7 +171,7 @@ def complex_cubic_spline(pts): INPUT: - - ``pts`` A list or array of complex numbers, or tuples of the form + - ``pts`` -- A list or array of complex numbers, or tuples of the form `(x,y)`. EXAMPLES: @@ -181,6 +182,7 @@ def complex_cubic_spline(pts): sage: cs = complex_cubic_spline(pts) sage: fx = lambda x: cs.value(x).real sage: fy = lambda x: cs.value(x).imag + sage: from math import pi sage: show(parametric_plot((fx, fy), (0, 2*pi))) # optional - sage.plot sage: m = Riemann_Map([lambda x: cs.value(real(x))], ....: [lambda x: cs.derivative(real(x))], 0) @@ -188,9 +190,10 @@ def complex_cubic_spline(pts): Polygon approximation of a circle:: - sage: pts = [e^(I*t / 25) for t in range(25)] # optional - sage.symbolic - sage: cs = complex_cubic_spline(pts) # optional - sage.symbolic - sage: cs.derivative(2) # optional - sage.symbolic + sage: from cmath import exp + sage: pts = [exp(1j * t / 25) for t in range(25)] + sage: cs = complex_cubic_spline(pts) + sage: cs.derivative(2) (-0.0497765406583...+0.151095006434...j) """ return CCSpline(pts) @@ -272,7 +275,8 @@ cdef class CCSpline: sage: cs = complex_cubic_spline(pts) sage: cs.value(4 / 7) (-0.303961332787...-1.34716728183...j) - sage: cs.value(0) - cs.value(2*pi) # optional - sage.symbolic + sage: from math import pi + sage: cs.value(0) - cs.value(2*pi) 0j sage: cs.value(-2.73452) (0.934561222231...+0.881366116402...j) @@ -303,7 +307,8 @@ cdef class CCSpline: sage: cs = complex_cubic_spline(pts) sage: cs.derivative(3 / 5) (1.40578892327...-0.225417136326...j) - sage: cs.derivative(0) - cs.derivative(2 * pi) # optional - sage.symbolic + sage: from math import pi + sage: cs.derivative(0) - cs.derivative(2 * pi) 0j sage: cs.derivative(-6) (2.52047692949...-1.89392588310...j) diff --git a/src/sage/calculus/ode.pyx b/src/sage/calculus/ode.pyx index 79d0e65de03..3375e951676 100644 --- a/src/sage/calculus/ode.pyx +++ b/src/sage/calculus/ode.pyx @@ -109,30 +109,31 @@ cdef int c_f(double t,double* y, double* dydt,void *params): class ode_solver(): r""" - :meth:`ode_solver` is a class that wraps the GSL libraries ode - solver routines To use it instantiate a class,:: + :meth:`ode_solver` is a class that wraps the GSL library's ode solver routines. - sage: T=ode_solver() + To use it, instantiate the class:: - To solve a system of the form ``dy_i/dt=f_i(t,y)``, you must + sage: T = ode_solver() + + To solve a system of the form `dy_i/dt=f_i(t,y)`, you must supply a vector or tuple/list valued function ``f`` representing - ``f_i``. The functions ``f`` and the jacobian should have the + `f_i`. The functions `f` and the jacobian should have the form ``foo(t,y)`` or ``foo(t,y,params)``. ``params`` which is optional allows for your function to depend on one or a tuple of parameters. Note if you use it, ``params`` must be a tuple even if it only has one component. For example if you wanted to solve - `y''+y=0`. You need to write it as a first order system:: + `y''+y=0`, you would need to write it as a first order system:: y_0' = y_1 y_1' = -y_0 In code:: - sage: f = lambda t,y:[y[1],-y[0]] - sage: T.function=f + sage: f = lambda t, y: [y[1], -y[0]] + sage: T.function = f - For some algorithms the jacobian must be supplied as well, the - form of this should be a function return a list of lists of the + For some algorithms, the jacobian must be supplied as well, the + form of this should be a function returning a list of lists of the form ``[ [df_1/dy_1,...,df_1/dy_n], ..., [df_n/dy_1,...,df_n,dy_n], [df_1/dt,...,df_n/dt] ]``. @@ -143,45 +144,45 @@ class ode_solver(): There are a variety of algorithms available for different types of systems. Possible algorithms are - - ``rkf45`` - runga-kutta-felhberg (4,5) + - ``'rkf45'`` -- Runge-Kutta-Fehlberg (4,5) - - ``rk2`` - embedded runga-kutta (2,3) + - ``'rk2'`` -- embedded Runge-Kutta (2,3) - - ``rk4`` - 4th order classical runga-kutta + - ``'rk4'`` -- 4th order classical Runge-Kutta - - ``rk8pd`` - runga-kutta prince-dormand (8,9) + - ``'rk8pd'`` -- Runge-Kutta Prince-Dormand (8,9) - - ``rk2imp`` - implicit 2nd order runga-kutta at gaussian points + - ``'rk2imp'`` -- implicit 2nd order Runge-Kutta at gaussian points - - ``rk4imp`` - implicit 4th order runga-kutta at gaussian points + - ``'rk4imp'`` -- implicit 4th order Runge-Kutta at gaussian points - - ``bsimp`` - implicit burlisch-stoer (requires jacobian) + - ``'bsimp'`` -- implicit Burlisch-Stoer (requires jacobian) - - ``gear1`` - M=1 implicit gear + - ``'gear1'`` -- M=1 implicit gear - - ``gear2`` - M=2 implicit gear + - ``'gear2'`` -- M=2 implicit gear - The default algorithm is ``rkf45``. If you instead wanted to use - ``bsimp`` you would do:: + The default algorithm is ``'rkf45'``. If you instead wanted to use + ``'bsimp'`` you would do:: - sage: T.algorithm="bsimp" + sage: T.algorithm = "bsimp" - The user should supply initial conditions in y_0. For example if - your initial conditions are y_0=1,y_1=1, do:: + The user should supply initial conditions in ``y_0``. For example if + your initial conditions are `y_0=1, y_1=1`, do:: - sage: T.y_0=[1,1] + sage: T.y_0 = [1,1] The actual solver is invoked by the method :meth:`ode_solve`. It has arguments ``t_span``, ``y_0``, ``num_points``, ``params``. ``y_0`` must be supplied either as an argument or above by assignment. Params which are optional and only necessary if your - system uses params can be supplied to ``ode_solve`` or by + system uses ``params`` can be supplied to ``ode_solve`` or by assignment. ``t_span`` is the time interval on which to solve the ode. There are two ways to specify ``t_span``: - * If ``num_points`` is not specified then the sequence ``t_span`` + * If ``num_points`` is not specified, then the sequence ``t_span`` is used as the time points for the solution. Note that the first element ``t_span[0]`` is the initial time, where the initial condition ``y_0`` is the specified solution, and @@ -192,10 +193,10 @@ class ode_solver(): and the solution will be computed at ``num_points`` equally spaced points between ``t_span[0]`` and ``t_span[1]``. The initial condition is also included in the output so that - ``num_points``\ +1 total points are returned. E.g. if ``t_span + ``num_points + 1`` total points are returned. E.g. if ``t_span = [0.0, 1.0]`` and ``num_points = 10``, then solution is returned at the 11 time points ``[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, - 0.6, 0.7, 0.8, 0.9, 1.0]``\ . + 0.6, 0.7, 0.8, 0.9, 1.0]``. (Note that if ``num_points`` is specified and ``t_span`` is not length 2 then ``t_span`` are used as the time points and @@ -203,13 +204,19 @@ class ode_solver(): Error is estimated via the expression ``D_i = error_abs*s_i+error_rel*(a|y_i|+a_dydt*h*|y_i'|)``. The user can - specify ``error_abs`` (1e-10 by default), ``error_rel`` (1e-10 by - default) ``a`` (1 by default), ``a_(dydt)`` (0 by default) and - ``s_i`` (as scaling_abs which should be a tuple and is 1 in all - components by default). If you specify one of ``a`` or ``a_dydt`` + specify + + - ``error_abs`` (1e-10 by default), + - ``error_rel`` (1e-10 by default), + - ``a`` (1 by default), + - ``a_dydt`` (0 by default) and + - ``s_i`` (as ``scaling_abs`` which should be a tuple and is 1 in all + components by default). + + If you specify one of ``a`` or ``a_dydt`` you must specify the other. You may specify ``a`` and ``a_dydt`` without ``scaling_abs`` (which will be taken =1 be default). - ``h`` is the initial step size which is (1e-2) by default. + ``h`` is the initial step size, which is 1e-2 by default. ``ode_solve`` solves the solution as a list of tuples of the form, ``[ (t_0,[y_1,...,y_n]),(t_1,[y_1,...,y_n]),...,(t_n,[y_1,...,y_n])]``. @@ -223,19 +230,21 @@ class ode_solver(): Consider solving the Van der Pol oscillator `x''(t) + ux'(t)(x(t)^2-1)+x(t)=0` between `t=0` and `t= 100`. As a first order system it is `x'=y`, `y'=-x+uy(1-x^2)`. Let us take `u=10` - and use initial conditions `(x,y)=(1,0)` and use the runga-kutta - prince-dormand algorithm. :: + and use initial conditions `(x,y)=(1,0)` and use the Runge-Kutta + Prince-Dormand algorithm. :: - sage: def f_1(t,y,params): - ....: return[y[1],-y[0]-params[0]*y[1]*(y[0]**2-1.0)] + sage: def f_1(t, y, params): + ....: return [y[1], -y[0] - params[0]*y[1]*(y[0]**2-1.0)] - sage: def j_1(t,y,params): - ....: return [ [0.0, 1.0],[-2.0*params[0]*y[0]*y[1]-1.0,-params[0]*(y[0]*y[0]-1.0)], [0.0, 0.0] ] + sage: def j_1(t, y, params): + ....: return [[0.0, 1.0], + ....: [-2.0*params[0]*y[0]*y[1] - 1.0, -params[0]*(y[0]*y[0]-1.0)], + ....: [0.0, 0.0]] - sage: T=ode_solver() - sage: T.algorithm="rk8pd" - sage: T.function=f_1 - sage: T.jacobian=j_1 + sage: T = ode_solver() + sage: T.algorithm = "rk8pd" + sage: T.function = f_1 + sage: T.jacobian = j_1 sage: T.ode_solve(y_0=[1,0], t_span=[0,100], params=[10.0], num_points=1000) sage: import tempfile sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # optional - sage.plot @@ -254,14 +263,14 @@ class ode_solver(): We will not use the jacobian this time and will change the error tolerances. :: - sage: g_1= lambda t,y: [y[1]*y[2],-y[0]*y[2],-0.51*y[0]*y[1]] - sage: T.function=g_1 - sage: T.y_0=[0,1,1] - sage: T.scale_abs=[1e-4,1e-4,1e-5] - sage: T.error_rel=1e-4 - sage: T.ode_solve(t_span=[0,12],num_points=100) + sage: g_1 = lambda t,y: [y[1]*y[2], -y[0]*y[2], -0.51*y[0]*y[1]] + sage: T.function = g_1 + sage: T.y_0 = [0,1,1] + sage: T.scale_abs = [1e-4, 1e-4, 1e-5] + sage: T.error_rel = 1e-4 + sage: T.ode_solve(t_span=[0,12], num_points=100) - By default T.plot_solution() plots the y_0, to plot general y_i use:: + By default ``T.plot_solution()`` plots the `y_0`; to plot general `y_i`, use:: sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # optional - sage.plot ....: T.plot_solution(i=0, filename=f.name) @@ -269,9 +278,9 @@ class ode_solver(): ....: T.plot_solution(i=2, filename=f.name) The method interpolate_solution will return a spline interpolation - through the points found by the solver. By default y_0 is - interpolated. You can interpolate y_i through the keyword - argument i. :: + through the points found by the solver. By default, `y_0` is + interpolated. You can interpolate `y_i` through the keyword + argument ``i``. :: sage: f = T.interpolate_solution() sage: plot(f,0,12).show() # optional - sage.plot @@ -280,22 +289,24 @@ class ode_solver(): sage: f = T.interpolate_solution(i=2) sage: plot(f,0,12).show() # optional - sage.plot sage: f = T.interpolate_solution() - sage: f(pi) # optional - sage.symbolic + sage: from math import pi + sage: f(pi) 0.5379... The solver attributes may also be set up using arguments to ode_solver. The previous example can be rewritten as:: - sage: T = ode_solver(g_1,y_0=[0,1,1],scale_abs=[1e-4,1e-4,1e-5],error_rel=1e-4, algorithm="rk8pd") - sage: T.ode_solve(t_span=[0,12],num_points=100) + sage: T = ode_solver(g_1, y_0=[0,1,1], scale_abs=[1e-4,1e-4,1e-5], + ....: error_rel=1e-4, algorithm="rk8pd") + sage: T.ode_solve(t_span=[0,12], num_points=100) sage: f = T.interpolate_solution() - sage: f(pi) # optional - sage.symbolic + sage: f(pi) 0.5379... Unfortunately because Python functions are used, this solver is slow on systems that require many function evaluations. It is possible to pass a compiled function by deriving from the - class ``ode_sysem`` and overloading ``c_f`` and ``c_j`` with C + class :class:`ode_system` and overloading ``c_f`` and ``c_j`` with C functions that specify the system. The following will work in the notebook: diff --git a/src/sage/calculus/transforms/dft.py b/src/sage/calculus/transforms/dft.py index b87ce51b9ad..02ee036065a 100644 --- a/src/sage/calculus/transforms/dft.py +++ b/src/sage/calculus/transforms/dft.py @@ -423,7 +423,7 @@ def dst(self): EXAMPLES:: sage: J = list(range(5)) - sage: I = CC.0; pi = CC(pi) # optional - sage.symbolic + sage: I = CC.0; pi = CC.pi() # optional - sage.symbolic sage: A = [exp(-2*pi*i*I/5) for i in J] # optional - sage.symbolic sage: s = IndexedSequence(A,J) # optional - sage.symbolic From ec0f34b38294b73d3bc369bc56cf206808be84cb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 29 Jun 2023 14:42:30 -0700 Subject: [PATCH 14/23] src/sage/calculus/transforms/dft.py (dct, dst): Try to avoid using sage.symbolic.constants --- src/sage/calculus/transforms/dft.py | 38 +++++++++++++++++++---------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/sage/calculus/transforms/dft.py b/src/sage/calculus/transforms/dft.py index 02ee036065a..e94bcecfa75 100644 --- a/src/sage/calculus/transforms/dft.py +++ b/src/sage/calculus/transforms/dft.py @@ -16,7 +16,7 @@ - plotting, printing -- :meth:`IndexedSequence.plot`, :meth:`IndexedSequence.plot_histogram`, :meth:`_repr_`, :meth:`__str__` -- dft -- computes the discrete Fourier transform for the following cases: +- :meth:`dft` -- computes the discrete Fourier transform for the following cases: * a sequence (over `\QQ` or :class:`CyclotomicField`) indexed by ``range(N)`` or `\ZZ / N \ZZ` @@ -26,21 +26,21 @@ * a sequence (as above) indexed by a complete set of representatives of the conjugacy classes of a finite matrix group -- idft -- computes the discrete Fourier transform for the following cases: +- :meth:`idft` -- computes the discrete Fourier transform for the following cases: * a sequence (over `\QQ` or CyclotomicField) indexed by ``range(N)`` or `\ZZ / N \ZZ` -- dct, dst (for discrete Fourier/Cosine/Sine transform) +- :meth:`dct`, :meth:`dst` (for discrete Fourier/Cosine/Sine transform) - convolution (in :meth:`IndexedSequence.convolution` and :meth:`IndexedSequence.convolution_periodic`) -- fft, ifft -- (fast Fourier transforms) wrapping GSL's +- :meth:`fft`, :meth:`ifft` -- (fast Fourier transforms) wrapping GSL's ``gsl_fft_complex_forward()``, ``gsl_fft_complex_inverse()``, using William Stein's :func:`FastFourierTransform` -- dwt, idwt -- (fast wavelet transforms) wrapping GSL's ``gsl_dwt_forward()``, +- :meth:`dwt`, :meth:`idwt` -- (fast wavelet transforms) wrapping GSL's ``gsl_dwt_forward()``, ``gsl_dwt_backward()`` using Joshua Kantor's :func:`WaveletTransform` class. Allows for wavelets of type: @@ -293,6 +293,7 @@ def dft(self, chi=lambda x: x): sage: s.dft() # optional - sage.rings.number_field Indexed sequence: [6, 0, 0, 0, 0, 0] indexed by [0, 1, 2, 3, 4, 5] + sage: G = SymmetricGroup(3) # optional - sage.groups sage: J = G.conjugacy_classes_representatives() # optional - sage.groups sage: s = IndexedSequence([1,2,3], J) # 1,2,3 are the values of a class fcn on G # optional - sage.groups @@ -319,6 +320,7 @@ def dft(self, chi=lambda x: x): -0.00000000000000976996261670137 - 0.0000000000000159872115546022*I, -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I] indexed by Cyclic group of order 6 as a permutation group + sage: p = 7; J = list(range(p)); A = [kronecker_symbol(j,p) for j in J] # optional - sage.rings.number_field sage: s = IndexedSequence(A, J) # optional - sage.rings.number_field sage: Fs = s.dft() # optional - sage.rings.number_field @@ -402,17 +404,22 @@ def dct(self): sage: J = list(range(5)) sage: A = [exp(-2*pi*i*I/5) for i in J] # optional - sage.symbolic - sage: s = IndexedSequence(A,J) # optional - sage.symbolic + sage: s = IndexedSequence(A, J) # optional - sage.symbolic sage: s.dct() # optional - sage.symbolic Indexed sequence: [0, 1/16*(sqrt(5) + I*sqrt(-2*sqrt(5) + 10) + ... indexed by [0, 1, 2, 3, 4] """ - from sage.symbolic.constants import pi F = self.base_ring() # elements must be coercible into RR + try: + pi = F.pi() + except AttributeError: + from sage.symbolic.constants import pi + pi = F(pi) + J = self.index_object() # must be = range(N) N = len(J) S = self.list() - PI = 2 * F(pi) / N + PI = 2 * pi / N FT = [sum([S[i] * cos(PI * i * j) for i in J]) for j in J] return IndexedSequence(FT, J) @@ -423,16 +430,21 @@ def dst(self): EXAMPLES:: sage: J = list(range(5)) - sage: I = CC.0; pi = CC.pi() # optional - sage.symbolic - sage: A = [exp(-2*pi*i*I/5) for i in J] # optional - sage.symbolic - sage: s = IndexedSequence(A,J) # optional - sage.symbolic + sage: I = CC.0; pi = CC.pi() + sage: A = [exp(-2*pi*i*I/5) for i in J] + sage: s = IndexedSequence(A, J) - sage: s.dst() # discrete sine # optional - sage.symbolic + sage: s.dst() # discrete sine Indexed sequence: [0.000000000000000, 1.11022302462516e-16 - 2.50000000000000*I, ...] indexed by [0, 1, 2, 3, 4] """ - from sage.symbolic.constants import pi F = self.base_ring() # elements must be coercible into RR + try: + pi = F.pi() + except AttributeError: + from sage.symbolic.constants import pi + pi = F(pi) + J = self.index_object() # must be = range(N) N = len(J) S = self.list() From a49e884b0f56440f81f6ab1969297f6a75436138 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 29 Jun 2023 16:54:27 -0700 Subject: [PATCH 15/23] src/sage/calculus/ode.pyx: Fix markup --- src/sage/calculus/ode.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/calculus/ode.pyx b/src/sage/calculus/ode.pyx index 3375e951676..d8c4f607242 100644 --- a/src/sage/calculus/ode.pyx +++ b/src/sage/calculus/ode.pyx @@ -211,7 +211,7 @@ class ode_solver(): - ``a`` (1 by default), - ``a_dydt`` (0 by default) and - ``s_i`` (as ``scaling_abs`` which should be a tuple and is 1 in all - components by default). + components by default). If you specify one of ``a`` or ``a_dydt`` you must specify the other. You may specify ``a`` and ``a_dydt`` From 917c8922ca97632d563a1ede1f66717a18067c47 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 1 Jul 2023 15:23:46 -0700 Subject: [PATCH 16/23] src/sage/calculus/interpolation.pyx: Make a doctest less sensitive to numerical noise --- src/sage/calculus/interpolation.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/calculus/interpolation.pyx b/src/sage/calculus/interpolation.pyx index 44fc0838856..c77864098a3 100644 --- a/src/sage/calculus/interpolation.pyx +++ b/src/sage/calculus/interpolation.pyx @@ -77,13 +77,13 @@ cdef class Spline: We compute the first and second-order derivatives at a few points:: sage: s.derivative(5) - -0.16230085261803... + -0.1623008526180... sage: s.derivative(6) - 0.20997986285714... + 0.2099798628571... sage: s.derivative(5, order=2) - -3.08747074561380... + -3.0874707456138... sage: s.derivative(6, order=2) - 2.61876848274853... + 2.6187684827485... Only the first two derivatives are supported:: From 69ac23485f2d50729a2334d158cdcbf25ae0cee1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 8 Jul 2023 18:19:01 -0700 Subject: [PATCH 17/23] sage -fixdoctests --only-tags src/sage/calculus/**/*.{py,pyx} --- src/sage/calculus/calculus.py | 6 +- src/sage/calculus/desolvers.py | 32 +++++------ src/sage/calculus/interpolation.pyx | 2 +- src/sage/calculus/interpolators.pyx | 8 +-- src/sage/calculus/ode.pyx | 29 +++++----- src/sage/calculus/riemann.pyx | 18 +++--- src/sage/calculus/test_sympy.py | 82 ++++++++++++++-------------- src/sage/calculus/transforms/dft.py | 60 ++++++++++---------- src/sage/calculus/transforms/dwt.pyx | 20 +++---- src/sage/calculus/transforms/fft.pyx | 26 ++++----- 10 files changed, 144 insertions(+), 139 deletions(-) diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index 393bd24fc02..08e649e91ac 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -1639,10 +1639,10 @@ def laplace(ex, t, s, algorithm='maxima'): -91/2*e^(4*t) + 629/2*e^(-4*t) + 1 sage: yt 91/8*e^(4*t) + 629/8*e^(-4*t) - sage: p1 = plot(xt, 0, 1/2, rgbcolor=(1,0,0)) # optional - sage.plot - sage: p2 = plot(yt, 0, 1/2, rgbcolor=(0,1,0)) # optional - sage.plot + sage: p1 = plot(xt, 0, 1/2, rgbcolor=(1,0,0)) # needs sage.plot + sage: p2 = plot(yt, 0, 1/2, rgbcolor=(0,1,0)) # needs sage.plot sage: import tempfile - sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # optional - sage.plot + sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # needs sage.plot ....: (p1 + p2).save(f.name) Another example:: diff --git a/src/sage/calculus/desolvers.py b/src/sage/calculus/desolvers.py index 3b1bfba2175..b128f851f8f 100644 --- a/src/sage/calculus/desolvers.py +++ b/src/sage/calculus/desolvers.py @@ -874,8 +874,8 @@ def desolve_system(des, vars, ics=None, ivar=None, algorithm="maxima"): :: - sage: P1 = plot([solx,soly], (0,1)) # optional - sage.plot - sage: P2 = parametric_plot((solx,soly), (0,1)) # optional - sage.plot + sage: P1 = plot([solx,soly], (0,1)) # needs sage.plot + sage: P2 = parametric_plot((solx,soly), (0,1)) # needs sage.plot Now type ``show(P1)``, ``show(P2)`` to view these plots. @@ -1014,9 +1014,9 @@ def eulers_method(f, x0, y0, h, x1, algorithm="table"): :: sage: pts = eulers_method(5*x+y-5,0,1,1/2,1,algorithm="none") - sage: P1 = list_plot(pts) # optional - sage.plot - sage: P2 = line(pts) # optional - sage.plot - sage: (P1 + P2).show() # optional - sage.plot + sage: P1 = list_plot(pts) # needs sage.plot + sage: P2 = line(pts) # needs sage.plot + sage: (P1 + P2).show() # needs sage.plot AUTHORS: @@ -1164,7 +1164,7 @@ def eulers_method_2x2_plot(f, g, t0, x0, y0, h, t1): sage: from sage.calculus.desolvers import eulers_method_2x2_plot sage: f = lambda z : z[2]; g = lambda z : -sin(z[1]) - sage: P = eulers_method_2x2_plot(f,g, 0.0, 0.75, 0.0, 0.1, 1.0) # optional - sage.plot + sage: P = eulers_method_2x2_plot(f,g, 0.0, 0.75, 0.0, 0.1, 1.0) # needs sage.plot """ from sage.plot.line import line @@ -1435,10 +1435,10 @@ def desolve_system_rk4(des, vars, ics=None, ivar=None, end_points=None, step=0.1 sage: P = desolve_system_rk4([x*(1-y),-y*(1-x)], [x,y], ics=[0,0.5,2], ....: ivar=t, end_points=20) sage: Q = [[i,j] for i,j,k in P] - sage: LP = list_plot(Q) # optional - sage.plot + sage: LP = list_plot(Q) # needs sage.plot sage: Q = [[j,k] for i,j,k in P] - sage: LP = list_plot(Q) # optional - sage.plot + sage: LP = list_plot(Q) # needs sage.plot ALGORITHM: @@ -1574,9 +1574,9 @@ def desolve_odeint(des, ics, times, dvars, ivar=None, compute_jac=False, args=() sage: from sage.calculus.desolvers import desolve_odeint sage: x,y = var('x,y') sage: f = [x*(1-y), -y*(1-x)] - sage: sol = desolve_odeint(f, [0.5,2], srange(0,10,0.1), [x,y]) # optional - scipy - sage: p = line(zip(sol[:,0],sol[:,1])) # optional - sage.plot - sage: p.show() # optional - sage.plot + sage: sol = desolve_odeint(f, [0.5,2], srange(0,10,0.1), [x,y]) # needs scipy + sage: p = line(zip(sol[:,0],sol[:,1])) # needs scipy sage.plot + sage: p.show() # needs sage.plot Lorenz Equations:: @@ -1590,7 +1590,7 @@ def desolve_odeint(des, ics, times, dvars, ivar=None, compute_jac=False, args=() sage: # Time and initial conditions sage: times = srange(0,50.05,0.05) sage: ics = [0,1,1] - sage: sol = desolve_odeint(lorenz, ics, times, [x,y,z], # optional - scipy + sage: sol = desolve_odeint(lorenz, ics, times, [x,y,z], # needs scipy ....: rtol=1e-13, atol=1e-14) One-dimensional stiff system:: @@ -1600,10 +1600,10 @@ def desolve_odeint(des, ics, times, dvars, ivar=None, compute_jac=False, args=() sage: f = y^2*(1-y) sage: ic = epsilon sage: t = srange(0,2/epsilon,1) - sage: sol = desolve_odeint(f, ic, t, y, # optional - scipy + sage: sol = desolve_odeint(f, ic, t, y, # needs scipy ....: rtol=1e-9, atol=1e-10, compute_jac=True) - sage: p = points(zip(t,sol[:,0])) # optional - scipy sage.plot - sage: p.show() # optional - scipy sage.plot + sage: p = points(zip(t,sol[:,0])) # needs scipy sage.plot + sage: p.show() # needs scipy sage.plot Another stiff system with some optional parameters with no default value:: @@ -1616,7 +1616,7 @@ def desolve_odeint(des, ics, times, dvars, ivar=None, compute_jac=False, args=() sage: ci = [0.2,0.4,0.7] sage: t = srange(0,10,0.01) sage: v = [y1,y2,y3] - sage: sol = desolve_odeint(f, ci, t, v, rtol=1e-3, atol=1e-4, # optional - scipy + sage: sol = desolve_odeint(f, ci, t, v, rtol=1e-3, atol=1e-4, # needs scipy ....: h0=0.1, hmax=1, hmin=1e-4, mxstep=1000, mxords=17) AUTHOR: diff --git a/src/sage/calculus/interpolation.pyx b/src/sage/calculus/interpolation.pyx index 8dfdfbc8429..21b82388461 100644 --- a/src/sage/calculus/interpolation.pyx +++ b/src/sage/calculus/interpolation.pyx @@ -57,7 +57,7 @@ cdef class Spline: sage: v = [(i + RDF(i).sin()/2, i + RDF(i^2).cos()) for i in range(10)] sage: s = spline(v) - sage: show(point(v) + plot(s,0,9, hue=.8)) # optional - sage.plot + sage: show(point(v) + plot(s,0,9, hue=.8)) # needs sage.plot We compute the area underneath the spline:: diff --git a/src/sage/calculus/interpolators.pyx b/src/sage/calculus/interpolators.pyx index a732e960a82..a0f1c61cdc8 100644 --- a/src/sage/calculus/interpolators.pyx +++ b/src/sage/calculus/interpolators.pyx @@ -50,10 +50,10 @@ def polygon_spline(pts): sage: ps = polygon_spline(pts) sage: fx = lambda x: ps.value(x).real sage: fy = lambda x: ps.value(x).imag - sage: show(parametric_plot((fx, fy), (0, 2*pi))) # optional - sage.plot + sage: show(parametric_plot((fx, fy), (0, 2*pi))) # needs sage.plot sage: m = Riemann_Map([lambda x: ps.value(real(x))], ....: [lambda x: ps.derivative(real(x))], 0) - sage: show(m.plot_colored() + m.plot_spiderweb()) # optional - sage.plot + sage: show(m.plot_colored() + m.plot_spiderweb()) # needs sage.plot Polygon approximation of an circle:: @@ -186,10 +186,10 @@ def complex_cubic_spline(pts): sage: fx = lambda x: cs.value(x).real sage: fy = lambda x: cs.value(x).imag sage: from math import pi - sage: show(parametric_plot((fx, fy), (0, 2*pi))) # optional - sage.plot + sage: show(parametric_plot((fx, fy), (0, 2*pi))) # needs sage.plot sage: m = Riemann_Map([lambda x: cs.value(real(x))], ....: [lambda x: cs.derivative(real(x))], 0) - sage: show(m.plot_colored() + m.plot_spiderweb()) # optional - sage.plot + sage: show(m.plot_colored() + m.plot_spiderweb()) # needs sage.plot Polygon approximation of a circle:: diff --git a/src/sage/calculus/ode.pyx b/src/sage/calculus/ode.pyx index 6382b2f407c..a7fbb87dffb 100644 --- a/src/sage/calculus/ode.pyx +++ b/src/sage/calculus/ode.pyx @@ -247,7 +247,7 @@ class ode_solver(): sage: T.jacobian = j_1 sage: T.ode_solve(y_0=[1,0], t_span=[0,100], params=[10.0], num_points=1000) sage: import tempfile - sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # optional - sage.plot + sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # needs sage.plot ....: T.plot_solution(filename=f.name) The solver line is equivalent to:: @@ -272,7 +272,7 @@ class ode_solver(): By default ``T.plot_solution()`` plots the `y_0`; to plot general `y_i`, use:: - sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # optional - sage.plot + sage: with tempfile.NamedTemporaryFile(suffix=".png") as f: # needs sage.plot ....: T.plot_solution(i=0, filename=f.name) ....: T.plot_solution(i=1, filename=f.name) ....: T.plot_solution(i=2, filename=f.name) @@ -283,11 +283,11 @@ class ode_solver(): argument ``i``. :: sage: f = T.interpolate_solution() - sage: plot(f,0,12).show() # optional - sage.plot + sage: plot(f,0,12).show() # needs sage.plot sage: f = T.interpolate_solution(i=1) - sage: plot(f,0,12).show() # optional - sage.plot + sage: plot(f,0,12).show() # needs sage.plot sage: f = T.interpolate_solution(i=2) - sage: plot(f,0,12).show() # optional - sage.plot + sage: plot(f,0,12).show() # needs sage.plot sage: f = T.interpolate_solution() sage: from math import pi sage: f(pi) @@ -335,14 +335,15 @@ class ode_solver(): following (WARNING: the following is *not* automatically doctested):: - sage: T = ode_solver() # not tested - sage: T.algorithm = "bsimp" # not tested - sage: vander = van_der_pol() # not tested - sage: T.function = vander # not tested - sage: T.ode_solve(y_0=[1, 0], t_span=[0, 2000], # not tested + sage: # not tested + sage: T = ode_solver() + sage: T.algorithm = "bsimp" + sage: vander = van_der_pol() + sage: T.function = vander + sage: T.ode_solve(y_0=[1, 0], t_span=[0, 2000], ....: num_points=1000) - sage: from tempfile import NamedTemporaryFile # not tested - sage: with NamedTemporaryFile(suffix=".png") as f: # not tested + sage: from tempfile import NamedTemporaryFile + sage: with NamedTemporaryFile(suffix=".png") as f: ....: T.plot_solution(i=0, filename=f.name) """ @@ -392,11 +393,11 @@ class ode_solver(): sage: T.function = lambda t,y: [cos(y[0]) * sin(t)] sage: T.jacobian = lambda t,y: [[-sin(y[0]) * sin(t)]] sage: T.ode_solve(y_0=[1],t_span=[0,20],num_points=1000) - sage: T.plot_solution() # optional - sage.plot + sage: T.plot_solution() # needs sage.plot And with some options:: - sage: T.plot_solution(color='red', axes_labels=["t", "x(t)"]) # optional - sage.plot + sage: T.plot_solution(color='red', axes_labels=["t", "x(t)"]) # needs sage.plot """ if interpolate: from sage.plot.line import line2d diff --git a/src/sage/calculus/riemann.pyx b/src/sage/calculus/riemann.pyx index adf0cfb75fb..05d5b1ec60a 100644 --- a/src/sage/calculus/riemann.pyx +++ b/src/sage/calculus/riemann.pyx @@ -1,4 +1,4 @@ -# sage.doctest: optional - numpy sage.symbolic +# sage.doctest: needs numpy sage.symbolic """ Riemann Mapping @@ -1190,11 +1190,11 @@ cpdef complex_to_spiderweb(np.ndarray[COMPLEX_T, ndim = 2] z_values, EXAMPLES:: sage: from sage.calculus.riemann import complex_to_spiderweb - sage: import numpy # optional - numpy - sage: zval = numpy.array([[0,1,1000], [.2+.3j,1,-.3j], [0,0,0]], # optional - numpy + sage: import numpy + sage: zval = numpy.array([[0,1,1000], [.2+.3j,1,-.3j], [0,0,0]], ....: dtype=numpy.complex128) - sage: deriv = numpy.array([[.1]],dtype = numpy.float64) # optional - numpy - sage: complex_to_spiderweb(zval, deriv, deriv, 4, 4, [0,0,0], 1, False, 0.001) # optional - numpy + sage: deriv = numpy.array([[.1]],dtype = numpy.float64) + sage: complex_to_spiderweb(zval, deriv, deriv, 4, 4, [0,0,0], 1, False, 0.001) array([[[1., 1., 1.], [1., 1., 1.], [1., 1., 1.]], @@ -1207,7 +1207,7 @@ cpdef complex_to_spiderweb(np.ndarray[COMPLEX_T, ndim = 2] z_values, [1., 1., 1.], [1., 1., 1.]]]) - sage: complex_to_spiderweb(zval, deriv, deriv, 4, 4, [0,0,0], 1, True, 0.001) # optional - numpy + sage: complex_to_spiderweb(zval, deriv, deriv, 4, 4, [0,0,0], 1, True, 0.001) array([[[1. , 1. , 1. ], [1. , 0.05558355, 0.05558355], [0.17301243, 0. , 0. ]], @@ -1281,13 +1281,13 @@ cpdef complex_to_rgb(np.ndarray[COMPLEX_T, ndim = 2] z_values): EXAMPLES:: sage: from sage.calculus.riemann import complex_to_rgb - sage: import numpy # optional - numpy - sage: complex_to_rgb(numpy.array([[0, 1, 1000]], dtype=numpy.complex128)) # optional - numpy + sage: import numpy + sage: complex_to_rgb(numpy.array([[0, 1, 1000]], dtype=numpy.complex128)) array([[[1. , 1. , 1. ], [1. , 0.05558355, 0.05558355], [0.17301243, 0. , 0. ]]]) - sage: complex_to_rgb(numpy.array([[0, 1j, 1000j]], dtype=numpy.complex128)) # optional - numpy + sage: complex_to_rgb(numpy.array([[0, 1j, 1000j]], dtype=numpy.complex128)) array([[[1. , 1. , 1. ], [0.52779177, 1. , 0.05558355], [0.08650622, 0.17301243, 0. ]]]) diff --git a/src/sage/calculus/test_sympy.py b/src/sage/calculus/test_sympy.py index ea41df4881b..d2e73abcafa 100644 --- a/src/sage/calculus/test_sympy.py +++ b/src/sage/calculus/test_sympy.py @@ -102,98 +102,100 @@ And here are some actual tests of sympy:: - sage: from sympy import Symbol, cos, sympify, pprint # optional - sympy - sage: from sympy.abc import x # optional - sympy + sage: from sympy import Symbol, cos, sympify, pprint # needs sympy + sage: from sympy.abc import x # needs sympy :: - sage: e = (1/cos(x)^3)._sympy_(); e # optional - sympy + sage: e = (1/cos(x)^3)._sympy_(); e # needs sympy cos(x)**(-3) - sage: f = e.series(x, 0, int(10)); f # optional - sympy + sage: f = e.series(x, 0, int(10)); f # needs sympy 1 + 3*x**2/2 + 11*x**4/8 + 241*x**6/240 + 8651*x**8/13440 + O(x**10) And the pretty-printer. Since unicode characters are not working on some architectures, we disable it:: - sage: from sympy.printing import pprint_use_unicode # optional - sympy - sage: prev_use = pprint_use_unicode(False) # optional - sympy - sage: pprint(e) # optional - sympy + sage: from sympy.printing import pprint_use_unicode # needs sympy + sage: prev_use = pprint_use_unicode(False) # needs sympy + sage: pprint(e) # needs sympy 1 ------- 3 cos (x) - sage: pprint(f) # optional - sympy + sage: pprint(f) # needs sympy 2 4 6 8 3*x 11*x 241*x 8651*x / 10\ 1 + ---- + ----- + ------ + ------- + O\x / 2 8 240 13440 - sage: pprint_use_unicode(prev_use) # optional - sympy + sage: pprint_use_unicode(prev_use) # needs sympy False And the functionality to convert from sympy format to Sage format:: - sage: e._sage_() # optional - sympy + sage: e._sage_() # needs sympy cos(x)^(-3) - sage: e._sage_().taylor(x._sage_(), 0, 8) # optional - sympy + sage: e._sage_().taylor(x._sage_(), 0, 8) # needs sympy 8651/13440*x^8 + 241/240*x^6 + 11/8*x^4 + 3/2*x^2 + 1 - sage: f._sage_() # optional - sympy + sage: f._sage_() # needs sympy 8651/13440*x^8 + 241/240*x^6 + 11/8*x^4 + 3/2*x^2 + Order(x^10) + 1 Mixing SymPy with Sage:: - sage: import sympy # optional - sympy - sage: var("x")._sympy_() + var("y")._sympy_() # optional - sympy + sage: # needs sympy + sage: import sympy + sage: var("x")._sympy_() + var("y")._sympy_() x + y - sage: o = var("omega") # optional - sympy - sage: s = sympy.Symbol("x") # optional - sympy - sage: t1 = s + o # optional - sympy - sage: t2 = o + s # optional - sympy - sage: type(t1) # optional - sympy + sage: o = var("omega") + sage: s = sympy.Symbol("x") + sage: t1 = s + o + sage: t2 = o + s + sage: type(t1) - sage: type(t2) # optional - sympy + sage: type(t2) - sage: t1, t2 # optional - sympy + sage: t1, t2 (omega + x, omega + x) - sage: e = sympy.sin(var("y"))+sage.all.cos(sympy.Symbol("x")) # optional - sympy - sage: type(e) # optional - sympy + sage: e = sympy.sin(var("y"))+sage.all.cos(sympy.Symbol("x")) + sage: type(e) - sage: e # optional - sympy + sage: e sin(y) + cos(x) - sage: e=e._sage_() # optional - sympy - sage: type(e) # optional - sympy + sage: e=e._sage_() + sage: type(e) - sage: e # optional - sympy + sage: e cos(x) + sin(y) - sage: e = sage.all.cos(var("y")**3)**4+var("x")**2 # optional - sympy - sage: e = e._sympy_() # optional - sympy - sage: e # optional - sympy + sage: e = sage.all.cos(var("y")**3)**4+var("x")**2 + sage: e = e._sympy_() + sage: e x**2 + cos(y**3)**4 :: - sage: a = sympy.Matrix([1, 2, 3]) # optional - sympy - sage: a[1] # optional - sympy + sage: a = sympy.Matrix([1, 2, 3]) # needs sympy + sage: a[1] # needs sympy 2 :: - sage: sympify(1.5) # optional - sympy + sage: sympify(1.5) # needs sympy 1.50000000000000 - sage: sympify(2) # optional - sympy + sage: sympify(2) # needs sympy 2 - sage: sympify(-2) # optional - sympy + sage: sympify(-2) # needs sympy -2 TESTS: This was fixed in Sympy, see :trac:`14437`:: - sage: from sympy import Function, Symbol, rsolve # optional - sympy - sage: u = Function('u') # optional - sympy - sage: n = Symbol('n', integer=True) # optional - sympy - sage: f = u(n+2) - u(n+1) + u(n)/4 # optional - sympy - sage: expand(2**n * rsolve(f,u(n))) # optional - sympy + sage: # needs sympy + sage: from sympy import Function, Symbol, rsolve + sage: u = Function('u') + sage: n = Symbol('n', integer=True) + sage: f = u(n+2) - u(n+1) + u(n)/4 + sage: expand(2**n * rsolve(f,u(n))) 2*C1*n + C0 """ diff --git a/src/sage/calculus/transforms/dft.py b/src/sage/calculus/transforms/dft.py index e94bcecfa75..973101e180a 100644 --- a/src/sage/calculus/transforms/dft.py +++ b/src/sage/calculus/transforms/dft.py @@ -216,9 +216,9 @@ def _repr_(self): sage: print(s) Indexed sequence: [0, 1, 2] indexed by [0, 1, 2] - sage: I = GF(3) # optional - sage.rings.finite_rings - sage: A = [i^2 for i in I] # optional - sage.rings.finite_rings - sage: s = IndexedSequence(A,I); s # optional - sage.rings.finite_rings + sage: I = GF(3) # needs sage.rings.finite_rings + sage: A = [i^2 for i in I] # needs sage.rings.finite_rings + sage: s = IndexedSequence(A,I); s # needs sage.rings.finite_rings Indexed sequence: [0, 1, 1] indexed by Finite Field of size 3 """ @@ -239,8 +239,8 @@ def plot_histogram(self, clr=(0, 0, 1), eps=0.4): sage: J = list(range(3)) sage: A = [ZZ(i^2)+1 for i in J] sage: s = IndexedSequence(A,J) - sage: P = s.plot_histogram() # optional - sage.plot - sage: show(P) # not tested # optional - sage.plot + sage: P = s.plot_histogram() # needs sage.plot + sage: show(P) # not tested, needs sage.plot """ from sage.rings.real_mpfr import RR # elements must be coercible into RR @@ -268,8 +268,8 @@ def plot(self): sage: I = list(range(3)) sage: A = [ZZ(i^2)+1 for i in I] sage: s = IndexedSequence(A,I) - sage: P = s.plot() # optional - sage.plot - sage: show(P) # not tested # optional - sage.plot + sage: P = s.plot() # needs sage.plot + sage: show(P) # not tested, needs sage.plot """ from sage.rings.real_mpfr import RR # elements must be coercible into RR @@ -287,22 +287,23 @@ def dft(self, chi=lambda x: x): sage: J = list(range(6)) sage: A = [ZZ(1) for i in J] sage: s = IndexedSequence(A,J) - sage: s.dft(lambda x: x^2) # optional - sage.rings.number_field + sage: s.dft(lambda x: x^2) # needs sage.rings.number_field Indexed sequence: [6, 0, 0, 6, 0, 0] indexed by [0, 1, 2, 3, 4, 5] - sage: s.dft() # optional - sage.rings.number_field + sage: s.dft() # needs sage.rings.number_field Indexed sequence: [6, 0, 0, 0, 0, 0] indexed by [0, 1, 2, 3, 4, 5] - sage: G = SymmetricGroup(3) # optional - sage.groups - sage: J = G.conjugacy_classes_representatives() # optional - sage.groups - sage: s = IndexedSequence([1,2,3], J) # 1,2,3 are the values of a class fcn on G # optional - sage.groups - sage: s.dft() # the "scalar-valued Fourier transform" of this class fcn # optional - sage.groups + sage: # needs sage.groups + sage: G = SymmetricGroup(3) + sage: J = G.conjugacy_classes_representatives() + sage: s = IndexedSequence([1,2,3], J) # 1,2,3 are the values of a class fcn on G + sage: s.dft() # the "scalar-valued Fourier transform" of this class fcn Indexed sequence: [8, 2, 2] indexed by [(), (1,2), (1,2,3)] - sage: J = AbelianGroup(2, [2,3], names='ab') # optional - sage.groups - sage: s = IndexedSequence([1,2,3,4,5,6], J) # optional - sage.groups - sage: s.dft() # the precision of output is somewhat random and architecture dependent. # optional - sage.groups + sage: J = AbelianGroup(2, [2,3], names='ab') + sage: s = IndexedSequence([1,2,3,4,5,6], J) + sage: s.dft() # the precision of output is somewhat random and architecture dependent. Indexed sequence: [21.0000000000000, -2.99999999999997 - 1.73205080756885*I, -2.99999999999999 + 1.73205080756888*I, @@ -310,9 +311,9 @@ def dft(self, chi=lambda x: x): -0.00000000000000976996261670137 - 0.0000000000000159872115546022*I, -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I] indexed by Multiplicative Abelian group isomorphic to C2 x C3 - sage: J = CyclicPermutationGroup(6) # optional - sage.groups - sage: s = IndexedSequence([1,2,3,4,5,6], J) # optional - sage.groups - sage: s.dft() # the precision of output is somewhat random and architecture dependent. # optional - sage.groups + sage: J = CyclicPermutationGroup(6) + sage: s = IndexedSequence([1,2,3,4,5,6], J) + sage: s.dft() # the precision of output is somewhat random and architecture dependent. Indexed sequence: [21.0000000000000, -2.99999999999997 - 1.73205080756885*I, -2.99999999999999 + 1.73205080756888*I, @@ -321,10 +322,11 @@ def dft(self, chi=lambda x: x): -0.00000000000000621724893790087 - 0.0000000000000106581410364015*I] indexed by Cyclic group of order 6 as a permutation group - sage: p = 7; J = list(range(p)); A = [kronecker_symbol(j,p) for j in J] # optional - sage.rings.number_field - sage: s = IndexedSequence(A, J) # optional - sage.rings.number_field - sage: Fs = s.dft() # optional - sage.rings.number_field - sage: c = Fs.list()[1]; [x/c for x in Fs.list()]; s.list() # optional - sage.rings.number_field + sage: # needs sage.rings.number_field + sage: p = 7; J = list(range(p)); A = [kronecker_symbol(j,p) for j in J] + sage: s = IndexedSequence(A, J) + sage: Fs = s.dft() + sage: c = Fs.list()[1]; [x/c for x in Fs.list()]; s.list() [0, 1, 1, -1, 1, -1, -1] [0, 1, 1, -1, 1, -1, -1] @@ -377,13 +379,13 @@ def idft(self): sage: J = list(range(5)) sage: A = [ZZ(1) for i in J] sage: s = IndexedSequence(A,J) - sage: fs = s.dft(); fs # optional - sage.rings.number_field + sage: fs = s.dft(); fs # needs sage.rings.number_field Indexed sequence: [5, 0, 0, 0, 0] indexed by [0, 1, 2, 3, 4] - sage: it = fs.idft(); it # optional - sage.rings.number_field + sage: it = fs.idft(); it # needs sage.rings.number_field Indexed sequence: [1, 1, 1, 1, 1] indexed by [0, 1, 2, 3, 4] - sage: it == s # optional - sage.rings.number_field + sage: it == s # needs sage.rings.number_field True """ F = self.base_ring() # elements must be coercible into QQ(zeta_N) @@ -403,9 +405,9 @@ def dct(self): EXAMPLES:: sage: J = list(range(5)) - sage: A = [exp(-2*pi*i*I/5) for i in J] # optional - sage.symbolic - sage: s = IndexedSequence(A, J) # optional - sage.symbolic - sage: s.dct() # optional - sage.symbolic + sage: A = [exp(-2*pi*i*I/5) for i in J] # needs sage.symbolic + sage: s = IndexedSequence(A, J) # needs sage.symbolic + sage: s.dct() # needs sage.symbolic Indexed sequence: [0, 1/16*(sqrt(5) + I*sqrt(-2*sqrt(5) + 10) + ... indexed by [0, 1, 2, 3, 4] """ diff --git a/src/sage/calculus/transforms/dwt.pyx b/src/sage/calculus/transforms/dwt.pyx index 9ee04a691b6..31be17846f8 100644 --- a/src/sage/calculus/transforms/dwt.pyx +++ b/src/sage/calculus/transforms/dwt.pyx @@ -64,27 +64,27 @@ def WaveletTransform(n, wavelet_type, wavelet_k): sage: for i in range(1, 11): ....: a[i] = 1 ....: a[128-i] = 1 - sage: a.plot().show(ymin=0) # optional - sage.plot + sage: a.plot().show(ymin=0) # needs sage.plot sage: a.forward_transform() - sage: a.plot().show() # optional - sage.plot + sage: a.plot().show() # needs sage.plot sage: a = WaveletTransform(128,'haar',2) sage: for i in range(1, 11): a[i] = 1; a[128-i] = 1 sage: a.forward_transform() - sage: a.plot().show(ymin=0) # optional - sage.plot + sage: a.plot().show(ymin=0) # needs sage.plot sage: a = WaveletTransform(128,'bspline_centered',103) sage: for i in range(1, 11): a[i] = 1; a[100+i] = 1 sage: a.forward_transform() - sage: a.plot().show(ymin=0) # optional - sage.plot + sage: a.plot().show(ymin=0) # needs sage.plot This example gives a simple example of wavelet compression:: sage: a = DWT(2048,'daubechies',6) - sage: for i in range(2048): a[i]=float(sin((i*5/2048)**2)) # optional - sage.symbolic - sage: a.plot().show() # long time (7s on sage.math, 2011) # optional - sage.plot sage.symbolic - sage: a.forward_transform() # optional - sage.symbolic - sage: for i in range(1800): a[2048-i-1] = 0 # optional - sage.symbolic - sage: a.backward_transform() # optional - sage.symbolic - sage: a.plot().show() # long time (7s on sage.math, 2011) # optional - sage.plot sage.symbolic + sage: for i in range(2048): a[i]=float(sin((i*5/2048)**2)) # needs sage.symbolic + sage: a.plot().show() # long time (7s on sage.math, 2011), needs sage.plot sage.symbolic + sage: a.forward_transform() # needs sage.symbolic + sage: for i in range(1800): a[2048-i-1] = 0 # needs sage.symbolic + sage: a.backward_transform() # needs sage.symbolic + sage: a.plot().show() # long time (7s on sage.math, 2011), needs sage.plot sage.symbolic """ cdef size_t _n, _k _n = int(n) diff --git a/src/sage/calculus/transforms/fft.pyx b/src/sage/calculus/transforms/fft.pyx index bbb8fac4677..897d9ed7040 100644 --- a/src/sage/calculus/transforms/fft.pyx +++ b/src/sage/calculus/transforms/fft.pyx @@ -69,9 +69,9 @@ def FastFourierTransform(size, base_ring=None): ....: a[128-i] = 1 sage: a[:6:2] [(0.0, 0.0), (1.0, 0.0), (1.0, 0.0)] - sage: a.plot().show(ymin=0) # optional - sage.plot + sage: a.plot().show(ymin=0) # needs sage.plot sage: a.forward_transform() - sage: a.plot().show() # optional - sage.plot + sage: a.plot().show() # needs sage.plot """ return FastFourierTransform_complex(int(size)) @@ -242,7 +242,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): EXAMPLES:: sage: a = FastFourierTransform(4) - sage: a._plot_polar(0,2) # optional - sage.plot + sage: a._plot_polar(0,2) # needs sage.plot Graphics object consisting of 2 graphics primitives """ @@ -282,7 +282,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): EXAMPLES:: sage: a = FastFourierTransform(4) - sage: a._plot_rect(0,3) # optional - sage.plot + sage: a._plot_rect(0,3) # needs sage.plot Graphics object consisting of 3 graphics primitives """ from sage.plot.point import point @@ -320,11 +320,11 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: a = FastFourierTransform(16) sage: for i in range(16): a[i] = (random(),random()) - sage: A = plot(a) # optional - sage.plot - sage: B = plot(a, style='polar') # optional - sage.plot - sage: type(A) # optional - sage.plot + sage: A = plot(a) # needs sage.plot + sage: B = plot(a, style='polar') # needs sage.plot + sage: type(A) # needs sage.plot - sage: type(B) # optional - sage.plot + sage: type(B) # needs sage.plot sage: a = FastFourierTransform(125) sage: b = FastFourierTransform(125) @@ -332,7 +332,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: for i in range(1, 60): b[i]=1 sage: a.forward_transform() sage: a.inverse_transform() - sage: a.plot() + b.plot() # optional - sage.plot + sage: a.plot() + b.plot() # needs sage.plot Graphics object consisting of 250 graphics primitives """ @@ -410,7 +410,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: for i in range(1, 60): b[i]=1 sage: a.forward_transform() sage: a.inverse_transform() - sage: a.plot() + b.plot() # optional - sage.plot + sage: a.plot() + b.plot() # needs sage.plot Graphics object consisting of 250 graphics primitives sage: abs(sum([CDF(a[i])-CDF(b[i]) for i in range(125)])) < 2**-16 True @@ -423,7 +423,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: for i in range(1, 60): b[i]=1 sage: a.forward_transform() sage: a.inverse_transform() - sage: a.plot() + b.plot() # optional - sage.plot + sage: a.plot() + b.plot() # needs sage.plot Graphics object consisting of 256 graphics primitives """ @@ -461,7 +461,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: for i in range(1, 60): b[i]=1 sage: a.forward_transform() sage: a.backward_transform() - sage: (a.plot() + b.plot()).show(ymin=0) # long time (2s on sage.math, 2011) # optional - sage.plot + sage: (a.plot() + b.plot()).show(ymin=0) # long time (2s on sage.math, 2011), needs sage.plot sage: abs(sum([CDF(a[i])/125-CDF(b[i]) for i in range(125)])) < 2**-16 True @@ -473,7 +473,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): sage: for i in range(1, 60): b[i]=1 sage: a.forward_transform() sage: a.backward_transform() - sage: (a.plot() + b.plot()).show(ymin=0) # optional - sage.plot + sage: (a.plot() + b.plot()).show(ymin=0) # needs sage.plot """ cdef gsl_fft_complex_wavetable * wt cdef gsl_fft_complex_workspace * mem From 60b459cd2b026ec04a77aced599fcca02fc4384d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 14 Jul 2023 12:18:15 -0700 Subject: [PATCH 18/23] ./sage -fixdoctests --distribution sagemath-modules --only-tags --probe all src/sage/calculus --- src/sage/calculus/desolvers.py | 2 +- src/sage/calculus/transforms/dft.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/calculus/desolvers.py b/src/sage/calculus/desolvers.py index b128f851f8f..afe63ccb954 100644 --- a/src/sage/calculus/desolvers.py +++ b/src/sage/calculus/desolvers.py @@ -1576,7 +1576,7 @@ def desolve_odeint(des, ics, times, dvars, ivar=None, compute_jac=False, args=() sage: f = [x*(1-y), -y*(1-x)] sage: sol = desolve_odeint(f, [0.5,2], srange(0,10,0.1), [x,y]) # needs scipy sage: p = line(zip(sol[:,0],sol[:,1])) # needs scipy sage.plot - sage: p.show() # needs sage.plot + sage: p.show() # needs scipy sage.plot Lorenz Equations:: diff --git a/src/sage/calculus/transforms/dft.py b/src/sage/calculus/transforms/dft.py index 973101e180a..650f9c0de26 100644 --- a/src/sage/calculus/transforms/dft.py +++ b/src/sage/calculus/transforms/dft.py @@ -240,7 +240,7 @@ def plot_histogram(self, clr=(0, 0, 1), eps=0.4): sage: A = [ZZ(i^2)+1 for i in J] sage: s = IndexedSequence(A,J) sage: P = s.plot_histogram() # needs sage.plot - sage: show(P) # not tested, needs sage.plot + sage: show(P) # not tested # needs sage.plot """ from sage.rings.real_mpfr import RR # elements must be coercible into RR @@ -269,7 +269,7 @@ def plot(self): sage: A = [ZZ(i^2)+1 for i in I] sage: s = IndexedSequence(A,I) sage: P = s.plot() # needs sage.plot - sage: show(P) # not tested, needs sage.plot + sage: show(P) # not tested # needs sage.plot """ from sage.rings.real_mpfr import RR # elements must be coercible into RR From 22f82945e9472de77f320735b3de75574914c288 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 14 Jul 2023 12:31:08 -0700 Subject: [PATCH 19/23] sage.calculus: Update # needs from #35095 --- src/sage/calculus/transforms/dft.py | 6 +++--- src/sage/calculus/transforms/dwt.pyx | 13 +++++++------ src/sage/calculus/transforms/fft.pyx | 1 + 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/sage/calculus/transforms/dft.py b/src/sage/calculus/transforms/dft.py index 650f9c0de26..57157dc0196 100644 --- a/src/sage/calculus/transforms/dft.py +++ b/src/sage/calculus/transforms/dft.py @@ -216,9 +216,9 @@ def _repr_(self): sage: print(s) Indexed sequence: [0, 1, 2] indexed by [0, 1, 2] - sage: I = GF(3) # needs sage.rings.finite_rings - sage: A = [i^2 for i in I] # needs sage.rings.finite_rings - sage: s = IndexedSequence(A,I); s # needs sage.rings.finite_rings + sage: I = GF(3) + sage: A = [i^2 for i in I] + sage: s = IndexedSequence(A,I); s Indexed sequence: [0, 1, 1] indexed by Finite Field of size 3 """ diff --git a/src/sage/calculus/transforms/dwt.pyx b/src/sage/calculus/transforms/dwt.pyx index 31be17846f8..807169f2886 100644 --- a/src/sage/calculus/transforms/dwt.pyx +++ b/src/sage/calculus/transforms/dwt.pyx @@ -78,13 +78,14 @@ def WaveletTransform(n, wavelet_type, wavelet_k): This example gives a simple example of wavelet compression:: + sage: # needs sage.symbolic sage: a = DWT(2048,'daubechies',6) - sage: for i in range(2048): a[i]=float(sin((i*5/2048)**2)) # needs sage.symbolic - sage: a.plot().show() # long time (7s on sage.math, 2011), needs sage.plot sage.symbolic - sage: a.forward_transform() # needs sage.symbolic - sage: for i in range(1800): a[2048-i-1] = 0 # needs sage.symbolic - sage: a.backward_transform() # needs sage.symbolic - sage: a.plot().show() # long time (7s on sage.math, 2011), needs sage.plot sage.symbolic + sage: for i in range(2048): a[i]=float(sin((i*5/2048)**2)) + sage: a.plot().show() # long time (7s on sage.math, 2011), needs sage.plot + sage: a.forward_transform() + sage: for i in range(1800): a[2048-i-1] = 0 + sage: a.backward_transform() + sage: a.plot().show() # long time (7s on sage.math, 2011), needs sage.plot """ cdef size_t _n, _k _n = int(n) diff --git a/src/sage/calculus/transforms/fft.pyx b/src/sage/calculus/transforms/fft.pyx index 897d9ed7040..168698957c4 100644 --- a/src/sage/calculus/transforms/fft.pyx +++ b/src/sage/calculus/transforms/fft.pyx @@ -151,6 +151,7 @@ cdef class FastFourierTransform_complex(FastFourierTransform_base): EXAMPLES:: + sage: # needs sage.rings.mpfr sage.symbolic sage: I = CC(I) sage: a = FastFourierTransform(4) sage: a[0] = 1 From 12b3cc1632393a10cceb2254505c062e1dff316b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 14 Jul 2023 12:44:13 -0700 Subject: [PATCH 20/23] src/sage/calculus/ode.pyx: Do not rely on block-level doctest tag for 'not tested' yet --- src/sage/calculus/ode.pyx | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/sage/calculus/ode.pyx b/src/sage/calculus/ode.pyx index a7fbb87dffb..d3712b42ecb 100644 --- a/src/sage/calculus/ode.pyx +++ b/src/sage/calculus/ode.pyx @@ -335,15 +335,14 @@ class ode_solver(): following (WARNING: the following is *not* automatically doctested):: - sage: # not tested - sage: T = ode_solver() - sage: T.algorithm = "bsimp" - sage: vander = van_der_pol() - sage: T.function = vander - sage: T.ode_solve(y_0=[1, 0], t_span=[0, 2000], + sage: T = ode_solver() # not tested + sage: T.algorithm = "bsimp" # not tested + sage: vander = van_der_pol() # not tested + sage: T.function = vander # not tested + sage: T.ode_solve(y_0=[1, 0], t_span=[0, 2000], # not tested ....: num_points=1000) - sage: from tempfile import NamedTemporaryFile - sage: with NamedTemporaryFile(suffix=".png") as f: + sage: from tempfile import NamedTemporaryFile # not tested + sage: with NamedTemporaryFile(suffix=".png") as f: # not tested ....: T.plot_solution(i=0, filename=f.name) """ From 214d9102396497c93da5db16c46b286de1267232 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 1 Aug 2023 11:14:20 -0700 Subject: [PATCH 21/23] # optional -> # needs --- src/sage/calculus/functional.py | 2 +- src/sage/calculus/functions.py | 2 +- src/sage/calculus/integration.pyx | 2 +- src/sage/calculus/interpolators.pyx | 2 +- src/sage/calculus/test_sympy.py | 2 +- src/sage/calculus/wester.py | 2 +- src/sage/structure/nonexact.py | 4 ++-- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/calculus/functional.py b/src/sage/calculus/functional.py index 5de51d1f6d5..03ea8bbd294 100644 --- a/src/sage/calculus/functional.py +++ b/src/sage/calculus/functional.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.symbolic +# sage.doctest: needs sage.symbolic """ Functional notation support for common calculus methods diff --git a/src/sage/calculus/functions.py b/src/sage/calculus/functions.py index b84c02fe779..11a23aac323 100644 --- a/src/sage/calculus/functions.py +++ b/src/sage/calculus/functions.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.symbolic +# sage.doctest: needs sage.symbolic r""" Calculus functions """ diff --git a/src/sage/calculus/integration.pyx b/src/sage/calculus/integration.pyx index 79c5deca158..19b2dc2e4c8 100644 --- a/src/sage/calculus/integration.pyx +++ b/src/sage/calculus/integration.pyx @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.symbolic +# sage.doctest: needs sage.symbolic """ Numerical Integration diff --git a/src/sage/calculus/interpolators.pyx b/src/sage/calculus/interpolators.pyx index a0f1c61cdc8..fb057f0fc2e 100644 --- a/src/sage/calculus/interpolators.pyx +++ b/src/sage/calculus/interpolators.pyx @@ -1,4 +1,4 @@ -# sage.doctest: optional - numpy +# sage.doctest: needs numpy """ Complex Interpolation diff --git a/src/sage/calculus/test_sympy.py b/src/sage/calculus/test_sympy.py index d2e73abcafa..b99d5d7857e 100644 --- a/src/sage/calculus/test_sympy.py +++ b/src/sage/calculus/test_sympy.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.symbolic +# sage.doctest: needs sage.symbolic r""" A Sample Session using SymPy diff --git a/src/sage/calculus/wester.py b/src/sage/calculus/wester.py index de0d1d6ef22..e33409a49ac 100644 --- a/src/sage/calculus/wester.py +++ b/src/sage/calculus/wester.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.symbolic +# sage.doctest: needs sage.symbolic r""" Further examples from Wester's paper diff --git a/src/sage/structure/nonexact.py b/src/sage/structure/nonexact.py index e881848080b..fa5157b3a65 100644 --- a/src/sage/structure/nonexact.py +++ b/src/sage/structure/nonexact.py @@ -9,7 +9,7 @@ sage: R. = PowerSeriesRing(QQ) sage: R.default_prec() 20 - sage: cos(x) # optional - sage.symbolic + sage: cos(x) # needs sage.symbolic 1 - 1/2*x^2 + 1/24*x^4 - 1/720*x^6 + 1/40320*x^8 - 1/3628800*x^10 + 1/479001600*x^12 - 1/87178291200*x^14 + 1/20922789888000*x^16 - 1/6402373705728000*x^18 + O(x^20) @@ -19,7 +19,7 @@ sage: R. = PowerSeriesRing(QQ, default_prec=10) sage: R.default_prec() 10 - sage: cos(x) # optional - sage.symbolic + sage: cos(x) # needs sage.symbolic 1 - 1/2*x^2 + 1/24*x^4 - 1/720*x^6 + 1/40320*x^8 + O(x^10) .. NOTE:: From bfd511fa85865c53c7514fe205b12beb3399edfe Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 1 Aug 2023 11:18:27 -0700 Subject: [PATCH 22/23] typo --- src/sage/calculus/calculus.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index 08e649e91ac..34abf305f70 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -966,7 +966,7 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): If the minimal polynomial could not be found, two distinct kinds of errors are raised. If no reasonable candidate was found with the - given ``bit``/``degree`` parameters, a :class:`ValueError` will be + given ``bits``/``degree`` parameters, a :class:`ValueError` will be raised. If a reasonable candidate was found but (perhaps due to limits in the underlying symbolic package) was unable to be proved correct, a :class:`NotImplementedError` will be raised. From e1decf3e5f76e6cd88fdeaf66d6adb000c5dfa18 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 1 Aug 2023 11:22:38 -0700 Subject: [PATCH 23/23] src/sage/calculus/transforms/dft.py: Replace .all import --- src/sage/calculus/transforms/dft.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/calculus/transforms/dft.py b/src/sage/calculus/transforms/dft.py index 57157dc0196..b413bc0ea81 100644 --- a/src/sage/calculus/transforms/dft.py +++ b/src/sage/calculus/transforms/dft.py @@ -71,7 +71,7 @@ # # https://www.gnu.org/licenses/ ########################################################################## -from sage.functions.all import sin, cos +from sage.functions.trig import sin, cos from sage.misc.lazy_import import lazy_import from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ