From 8dc47e8b91af1b35ce85d51be4f18adaf3940dff Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 5 Mar 2023 21:32:45 -0800 Subject: [PATCH 01/87] 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/87] 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/87] 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/87] 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/87] 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/87] 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/87] 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/87] 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/87] 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/87] 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/87] 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/87] 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/87] 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/87] 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/87] 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/87] 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 a643483402380899dd365c21e433a7074dfdfbd5 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sun, 2 Jul 2023 16:28:12 +0200 Subject: [PATCH 17/87] move @run_once from ipython_extension to misc.misc It made the sympy interface depend on IPython... --- src/sage/interfaces/sympy.py | 2 +- src/sage/misc/misc.py | 35 +++++++++++++++++++++++++++++ src/sage/repl/ipython_extension.py | 36 +----------------------------- 3 files changed, 37 insertions(+), 36 deletions(-) diff --git a/src/sage/interfaces/sympy.py b/src/sage/interfaces/sympy.py index 9ca4203b648..a334c241127 100644 --- a/src/sage/interfaces/sympy.py +++ b/src/sage/interfaces/sympy.py @@ -1016,7 +1016,7 @@ def _sympysage_true(self): #------------------------------------------------------------------ -from sage.repl.ipython_extension import run_once +from sage.misc.misc import run_once @run_once def sympy_init(): diff --git a/src/sage/misc/misc.py b/src/sage/misc/misc.py index d7eec3a8cda..0a3dfa6831b 100644 --- a/src/sage/misc/misc.py +++ b/src/sage/misc/misc.py @@ -38,6 +38,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +import functools import os import pdb import warnings @@ -1132,3 +1133,37 @@ def inject_variable_test(name, value, depth): inject_variable(name, value) else: inject_variable_test(name, value, depth - 1) + + +# from https://stackoverflow.com/questions/4103773/efficient-way-of-having-a-function-only-execute-once-in-a-loop +def run_once(func): + """ + Runs a function (successfully) only once. + + The running can be reset by setting the ``has_run`` attribute to False + + TESTS:: + + sage: from sage.repl.ipython_extension import run_once + sage: @run_once + ....: def foo(work): + ....: if work: + ....: return 'foo worked' + ....: raise RuntimeError("foo didn't work") + sage: foo(False) + Traceback (most recent call last): + ... + RuntimeError: foo didn't work + sage: foo(True) + 'foo worked' + sage: foo(False) + sage: foo(True) + """ + @functools.wraps(func) + def wrapper(*args, **kwargs): + if not wrapper.has_run: + result = func(*args, **kwargs) + wrapper.has_run = True + return result + wrapper.has_run = False + return wrapper diff --git a/src/sage/repl/ipython_extension.py b/src/sage/repl/ipython_extension.py index 11cbdde579c..4ea72a97b1b 100644 --- a/src/sage/repl/ipython_extension.py +++ b/src/sage/repl/ipython_extension.py @@ -68,6 +68,7 @@ from sage.repl.load import load_wrap from sage.env import SAGE_IMPORTALL, SAGE_STARTUP_FILE from sage.misc.lazy_import import LazyImport +from sage.misc.misc import run_once @magics_class class SageMagics(Magics): @@ -583,41 +584,6 @@ def all_globals(): return all_jupyter -# from https://stackoverflow.com/questions/4103773/efficient-way-of-having-a-function-only-execute-once-in-a-loop -from functools import wraps -def run_once(func): - """ - Runs a function (successfully) only once. - - The running can be reset by setting the ``has_run`` attribute to False - - TESTS:: - - sage: from sage.repl.ipython_extension import run_once - sage: @run_once - ....: def foo(work): - ....: if work: - ....: return 'foo worked' - ....: raise RuntimeError("foo didn't work") - sage: foo(False) - Traceback (most recent call last): - ... - RuntimeError: foo didn't work - sage: foo(True) - 'foo worked' - sage: foo(False) - sage: foo(True) - """ - @wraps(func) - def wrapper(*args, **kwargs): - if not wrapper.has_run: - result = func(*args, **kwargs) - wrapper.has_run = True - return result - wrapper.has_run = False - return wrapper - - @run_once def load_ipython_extension(ip): """ From 874119d58e45deaac1d79bcf8aac611f6d22e444 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sun, 2 Jul 2023 16:59:27 +0200 Subject: [PATCH 18/87] more careful handling of the recursion limit --- src/sage/functions/transcendental.py | 6 ++--- src/sage/misc/misc.py | 33 ++++++++++++++++++++++++++++ src/sage/rings/qqbar.py | 8 +++---- 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/sage/functions/transcendental.py b/src/sage/functions/transcendental.py index 63670423fc5..265a75e91a2 100644 --- a/src/sage/functions/transcendental.py +++ b/src/sage/functions/transcendental.py @@ -17,6 +17,7 @@ # **************************************************************************** import sys +from sage.misc.misc import increase_recursion_limit from sage.rings.integer_ring import ZZ from sage.rings.real_mpfr import RR from sage.rings.real_double import RDF @@ -545,9 +546,8 @@ def _eval_(self, x): max = x.parent()(1.1)*x + 10 abs_prec = (-self.approximate(max).log2() + rel_prec + 2*max.log2()).ceil() self._f = {} - if sys.getrecursionlimit() < max + 10: - sys.setrecursionlimit(int(max) + 10) - self._compute_power_series(max.floor(), abs_prec, cache_ring=x.parent()) + with increase_recursion_limit(int(max)): + self._compute_power_series(max.floor(), abs_prec, cache_ring=x.parent()) return self._f[n](2*(x-n-x.parent()(0.5))) def power_series(self, n, abs_prec): diff --git a/src/sage/misc/misc.py b/src/sage/misc/misc.py index 0a3dfa6831b..090dea33293 100644 --- a/src/sage/misc/misc.py +++ b/src/sage/misc/misc.py @@ -38,9 +38,11 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +import contextlib import functools import os import pdb +import sys import warnings from .lazy_string import lazy_string @@ -1167,3 +1169,34 @@ def wrapper(*args, **kwargs): return result wrapper.has_run = False return wrapper + + +@contextlib.contextmanager +def increase_recursion_limit(increment): + r""" + Context manager to temporarily change the Python maximum recursion depth. + + INPUT: + + - `increment`: increment to add to the current limit + + EXAMPLES:: + + sage: from sage.misc.misc import increase_recursion_limit + sage: def rec(n): None if n == 0 else rec(n-1) + sage: rec(10000) + Traceback (most recent call last): + ... + RecursionError: maximum recursion depth exceeded... + sage: with increase_recursion_limit(10000): rec(10000) + sage: rec(10000) + Traceback (most recent call last): + ... + RecursionError: maximum recursion depth exceeded... + """ + old_limit = sys.getrecursionlimit() + sys.setrecursionlimit(old_limit + increment) + try: + yield + finally: + sys.setrecursionlimit(old_limit) diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index f8eaf63c934..4ffa5704e83 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -560,6 +560,7 @@ from sage.misc.fast_methods import Singleton from sage.misc.cachefunc import cached_method from sage.misc.lazy_string import lazy_string +from sage.misc.misc import increase_recursion_limit from sage.structure.coerce import parent_is_numerical, parent_is_real_numerical from sage.structure.sage_object import SageObject from sage.structure.richcmp import (richcmp, richcmp_method, @@ -8543,9 +8544,7 @@ def exactify(self): sage: sys.setrecursionlimit(old_recursion_limit) """ import sys - old_recursion_limit = sys.getrecursionlimit() - sys.setrecursionlimit(old_recursion_limit + 10) - try: + with increase_recursion_limit(10): left = self._left right = self._right left.exactify() @@ -8560,8 +8559,7 @@ def exactify(self): return ANRational(value) else: return ANExtensionElement(gen, value) - finally: - sys.setrecursionlimit(old_recursion_limit) + # These are the functions used to add, subtract, multiply, and divide # algebraic numbers. Basically, we try to compute exactly if both From 864d8421d90c259c62a8c6c905dcb9cb9447af5d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 4 Jul 2023 07:48:18 +0200 Subject: [PATCH 19/87] recognizable series: properly deal with zero --- src/sage/combinat/recognizable_series.py | 53 ++++++++++++++++++++---- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/src/sage/combinat/recognizable_series.py b/src/sage/combinat/recognizable_series.py index 89737a780df..6fb1dea3242 100644 --- a/src/sage/combinat/recognizable_series.py +++ b/src/sage/combinat/recognizable_series.py @@ -1105,6 +1105,11 @@ def minimized(self): sage: all(c == d and v == w ....: for (c, v), (d, w) in islice(zip(iter(S), iter(M)), 20)) True + + TESTS:: + + sage: Rec((Matrix([[0]]), Matrix([[0]])), vector([1]), vector([0])).minimized().linear_representation() + ((), Finite family {0: [], 1: []}, ()) """ return self._minimized_right_()._minimized_left_() @@ -1341,6 +1346,11 @@ def _rmul_(self, other): sage: 1 * E is E True + :: + + sage: 0 * E is Seq2.zero() + True + We test that ``_rmul_`` and ``_lmul_`` are actually called:: sage: def print_name(f): @@ -1359,9 +1369,11 @@ def _rmul_(self, other): _lmul_ 2-regular sequence 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, ... """ + P = self.parent() + if other.is_zero(): + return P._zero_() if other.is_one(): return self - P = self.parent() return P.element_class(P, self.mu, other*self.left, self.right) def _lmul_(self, other): @@ -1398,6 +1410,11 @@ def _lmul_(self, other): sage: E * 1 is E True + :: + + sage: E * 0 is Seq2.zero() + True + The following is not tested, as `MS^i` for integers `i` does not work, thus ``vector([m])`` fails. (See :trac:`21317` for details.) @@ -1414,9 +1431,11 @@ def _lmul_(self, other): sage: M # not tested sage: M.linear_representation() # not tested """ + P = self.parent() + if other.is_zero(): + return P._zero_() if other.is_one(): return self - P = self.parent() return P.element_class(P, self.mu, self.left, self.right*other) @minimize_result @@ -1913,6 +1932,28 @@ def some_elements(self): break yield self(mu, *LR) + @cached_method + def _zero_(self): + r""" + Return the zero element of this :class:`RecognizableSeriesSpace`, + i.e. the unique neutral element for `+`. + + TESTS:: + + sage: Rec = RecognizableSeriesSpace(ZZ, [0, 1]) + sage: Z = Rec._zero_(); Z + 0 + sage: Z.linear_representation() + ((), Finite family {0: [], 1: []}, ()) + """ + from sage.matrix.constructor import Matrix + from sage.modules.free_module_element import vector + from sage.sets.family import Family + + return self.element_class( + self, Family(self.alphabet(), lambda a: Matrix()), + vector([]), vector([])) + @cached_method def one_hadamard(self): r""" @@ -1985,13 +2026,7 @@ def _element_constructor_(self, data, ValueError: left or right vector is None """ if isinstance(data, int) and data == 0: - from sage.matrix.constructor import Matrix - from sage.modules.free_module_element import vector - from sage.sets.family import Family - - return self.element_class( - self, Family(self.alphabet(), lambda a: Matrix()), - vector([]), vector([])) + return self._zero_() if type(data) == self.element_class and data.parent() == self: element = data From 37a1b2a69baac6f7c7d6b003c345e2059f4f4c0b Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 4 Jul 2023 08:00:49 +0200 Subject: [PATCH 20/87] recognizable series: embed coefficient ring --- src/sage/combinat/recognizable_series.py | 48 ++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/sage/combinat/recognizable_series.py b/src/sage/combinat/recognizable_series.py index 6fb1dea3242..eded74b6b88 100644 --- a/src/sage/combinat/recognizable_series.py +++ b/src/sage/combinat/recognizable_series.py @@ -1954,6 +1954,37 @@ def _zero_(self): self, Family(self.alphabet(), lambda a: Matrix()), vector([]), vector([])) + @cached_method + def one(self): + r""" + Return the one element of this :class:`RecognizableSeriesSpace`, + i.e. the embedding of the unique neutral element for `*` in the + coefficient ring. + + EXAMPLES:: + + sage: Rec = RecognizableSeriesSpace(ZZ, [0, 1]) + sage: O = Rec.one(); O + [] + ... + sage: O.linear_representation() + ((1), Finite family {0: [0], 1: [0]}, (1)) + + TESTS: + + sage: Rec.one() is Rec.one() + True + """ + from sage.matrix.constructor import Matrix + from sage.modules.free_module_element import vector + + R = self.coefficient_ring() + one = R.one() + zero = R.zero() + return self.element_class(self, + len(self.alphabet())*[Matrix([[zero]])], + vector([one]), + vector([one])) + @cached_method def one_hadamard(self): r""" @@ -2008,6 +2039,19 @@ def _element_constructor_(self, data, sage: Rec(S) is S True + :: + + sage: A = Rec(42); A + 42*[] + ... + sage: A.linear_representation() + ((42), Finite family {0: [0], 1: [0]}, (1)) + sage: Z = Rec(0); Z + 0 + sage: Z.linear_representation() + ((), Finite family {0: [], 1: []}, ()) + + :: + sage: Rec((M0, M1)) Traceback (most recent call last): ... @@ -2034,6 +2078,10 @@ def _element_constructor_(self, data, elif isinstance(data, RecognizableSeries): element = self.element_class(self, data.mu, data.left, data.right) + elif data in self.coefficient_ring(): + c = self.coefficient_ring()(data) + return c * self.one() + else: mu = data if left is None or right is None: From 32e6b77b3bc849d1de133457d9190e707e6c4fe3 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 4 Jul 2023 08:03:50 +0200 Subject: [PATCH 21/87] cleanup old, unreadable dict creations --- src/sage/combinat/recognizable_series.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/recognizable_series.py b/src/sage/combinat/recognizable_series.py index eded74b6b88..d2752dbad2c 100644 --- a/src/sage/combinat/recognizable_series.py +++ b/src/sage/combinat/recognizable_series.py @@ -456,7 +456,7 @@ def immutable(m): return m if isinstance(mu, dict): - mu = dict((a, immutable(M)) for a, M in mu.items()) + mu = {a: immutable(M) for a, M in mu.items()} mu = Family(mu) if not mu.is_finite(): @@ -1284,7 +1284,7 @@ def _add_(self, other): result = P.element_class( P, - dict((a, self.mu[a].block_sum(other.mu[a])) for a in P.alphabet()), + {a: self.mu[a].block_sum(other.mu[a]) for a in P.alphabet()}, vector(tuple(self.left) + tuple(other.left)), vector(tuple(self.right) + tuple(other.right))) @@ -1541,8 +1541,7 @@ def tensor_product(left, right): return T result = P.element_class( P, - dict((a, tensor_product(self.mu[a], other.mu[a])) - for a in P.alphabet()), + {a: tensor_product(self.mu[a], other.mu[a]) for a in P.alphabet()}, vector(tensor_product(Matrix(self.left), Matrix(other.left))), vector(tensor_product(Matrix(self.right), Matrix(other.right)))) @@ -2012,7 +2011,7 @@ def one_hadamard(self): from sage.modules.free_module_element import vector one = self.coefficient_ring()(1) - return self(dict((a, Matrix([[one]])) for a in self.alphabet()), + return self({a: Matrix([[one]]) for a in self.alphabet()}, vector([one]), vector([one])) def _element_constructor_(self, data, From a57f92d30fc3ec62a9089397119ad2d31ca939ba Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 4 Jul 2023 09:37:18 +0200 Subject: [PATCH 22/87] k-regular sequences: fix .one() --- src/sage/combinat/k_regular_sequence.py | 33 +++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 1ec99957aa8..e28fec3f183 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -918,6 +918,39 @@ def _n_to_index_(self, n): except OverflowError: raise ValueError('value {} of index is negative'.format(n)) from None + @cached_method + def one(self): + r""" + Return the one element of this :class:`kRegularSequenceSpace`, + i.e. the unique neutral element for `*` and also + the embedding of the unique neutral element for `*` in the + coefficient ring. + + EXAMPLES:: + + sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: O = Seq2.one(); O + 2-regular sequence 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... + sage: O.linear_representation() + ((1), Finite family {0: [1], 1: [0]}, (1)) + + TESTS: + + sage: Seq2.one() is Seq2.one() + True + """ + from sage.matrix.constructor import Matrix + from sage.modules.free_module_element import vector + + R = self.coefficient_ring() + one = R.one() + zero = R.zero() + return self.element_class(self, + [Matrix([[one]])] + + (self.k-1)*[Matrix([[zero]])], + vector([one]), + vector([one])) + def from_recurrence(self, *args, **kwds): r""" Construct the unique `k`-regular sequence which fulfills the given From ceb3c79f1473e0eab61c5a38333f97d1660459a2 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 4 Jul 2023 09:37:54 +0200 Subject: [PATCH 23/87] k-regular sequences: implement convolution --- src/sage/combinat/k_regular_sequence.py | 85 +++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index e28fec3f183..861013a13f1 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -673,6 +673,91 @@ def forward_differences(self, **kwds): """ return self.subsequence(1, {1: 1, 0: -1}, **kwds) + @minimize_result + def _mul_(self, other): + r""" + Return the product of this `k`-regular sequence with ``other``, + where the multiplication is convolution. + + INPUT: + + - ``other`` -- a :class:`kRegularSequence` + + - ``minimize`` -- (default: ``None``) a boolean or ``None``. + If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation, + if ``False``, then not. If this argument is ``None``, then + the default specified by the parent's ``minimize_results`` is used. + + OUTPUT: + + A :class:`kRegularSequence` + + EXAMPLES:: + + sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), + ....: vector([1, 0]), vector([1, 1])) + sage: E + 2-regular sequence 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, ... + sage: E * E + 2-regular sequence 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, ... + + sage: o = Seq2.one_hadamard() + sage: E * o + 2-regular sequence 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, ... + sage: E * o == E.partial_sums(include_n=True) + True + sage: E * o == o * E + True + """ + from sage.arith.srange import srange + from sage.matrix.constructor import Matrix + from sage.matrix.special import zero_matrix + from sage.modules.free_module_element import vector + + P = self.parent() + k = P.k + + def tensor_product(left, right): + T = left.tensor_product(right) + T.subdivide() + return T + + matrices_0 = {r: sum(tensor_product(self.mu[s], other.mu[r-s]) + for s in srange(0, r+1)) + for r in P.alphabet()} + matrices_1 = {r: sum(tensor_product(self.mu[s], other.mu[k+r-s]) + for s in srange(r+1, k)) + for r in P.alphabet()} + left = vector(tensor_product(Matrix(self.left), Matrix(other.left))) + right = vector(tensor_product(Matrix(self.right), Matrix(other.right))) + + def linear_representation_morphism_recurrence_order_1(A, B): + r""" + Return the morphism of a linear representation + for the sequence `z_n` satisfying + `z_{2n+r} = A_r z_n + B_r z_{n-1}`. + """ + Z = zero_matrix(A[0].dimensions()[0]) + + def blocks(r): + upper = list([A[s], B[s], Z] + for s in reversed(srange(max(0, r-2), r+1))) + lower = list([Z, A[s], B[s]] + for s in reversed(srange(k-3+len(upper), k))) + return upper + lower + + return {r: Matrix.block(blocks(r)) for r in P.alphabet()} + + result = P.element_class( + P, + linear_representation_morphism_recurrence_order_1(matrices_0, + matrices_1), + vector(list(left) + (2*len(list(left)))*[0]), + vector(list(right) + (2*len(list(right)))*[0])) + + return result + @minimize_result def partial_sums(self, include_n=False): r""" From bb3d701ab23b965648546390af9e699f7d3b261d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 4 Jul 2023 09:38:22 +0200 Subject: [PATCH 24/87] k-regular sequences: extend category to Algebra --- src/sage/combinat/k_regular_sequence.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 861013a13f1..69d856d8ed6 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -895,7 +895,10 @@ class kRegularSequenceSpace(RecognizableSeriesSpace): Element = kRegularSequence @classmethod - def __normalize__(cls, k, coefficient_ring, **kwds): + def __normalize__(cls, k, + coefficient_ring, + category=None, + **kwds): r""" Normalizes the input in order to ensure a unique representation. @@ -906,13 +909,17 @@ def __normalize__(cls, k, coefficient_ring, **kwds): sage: Seq2 = kRegularSequenceSpace(2, ZZ) sage: Seq2.category() - Category of modules over Integer Ring + Category of algebras over Integer Ring sage: Seq2.alphabet() {0, 1} """ from sage.arith.srange import srange + from sage.categories.algebras import Algebras + category = category or Algebras(coefficient_ring) nargs = super().__normalize__(coefficient_ring, - alphabet=srange(k), **kwds) + alphabet=srange(k), + category=category, + **kwds) return (k,) + nargs def __init__(self, k, *args, **kwds): From 07101368baaca56f5b8f1cbeda804e1388eac259 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 4 Jul 2023 09:44:09 +0200 Subject: [PATCH 25/87] k-regular sequences: convolution/docs --- src/sage/combinat/k_regular_sequence.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 69d856d8ed6..5790e598b36 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -677,7 +677,9 @@ def forward_differences(self, **kwds): def _mul_(self, other): r""" Return the product of this `k`-regular sequence with ``other``, - where the multiplication is convolution. + where the multiplication is convolution of power series. + + The operator `*` is mapped to :meth:`convolution`. INPUT: @@ -699,14 +701,28 @@ def _mul_(self, other): ....: vector([1, 0]), vector([1, 1])) sage: E 2-regular sequence 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, ... + + We can build the convolution (in the sense of power-series) of `E` by + itself via:: + + sage: E.convolution(E) + 2-regular sequence 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, ... + + This is the same as using multiplication operator:: + sage: E * E 2-regular sequence 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, ... + Building :meth:`partial_sums` can also be seen as a convolution:: + sage: o = Seq2.one_hadamard() sage: E * o 2-regular sequence 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, ... sage: E * o == E.partial_sums(include_n=True) True + + TESTS:: + sage: E * o == o * E True """ @@ -758,6 +774,8 @@ def blocks(r): return result + convolution = _mul_ + @minimize_result def partial_sums(self, include_n=False): r""" From 91b4fc650ebc168b0f36764ba89ca1945c9ca1d7 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 4 Jul 2023 11:23:56 +0200 Subject: [PATCH 26/87] convolution: rename variables --- src/sage/combinat/k_regular_sequence.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 5790e598b36..959c0008bfd 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -748,18 +748,18 @@ def tensor_product(left, right): left = vector(tensor_product(Matrix(self.left), Matrix(other.left))) right = vector(tensor_product(Matrix(self.right), Matrix(other.right))) - def linear_representation_morphism_recurrence_order_1(A, B): + def linear_representation_morphism_recurrence_order_1(C, D): r""" Return the morphism of a linear representation for the sequence `z_n` satisfying - `z_{2n+r} = A_r z_n + B_r z_{n-1}`. + `z_{kn+r} = C_r z_n + D_r z_{n-1}`. """ - Z = zero_matrix(A[0].dimensions()[0]) + Z = zero_matrix(C[0].dimensions()[0]) def blocks(r): - upper = list([A[s], B[s], Z] + upper = list([C[s], D[s], Z] for s in reversed(srange(max(0, r-2), r+1))) - lower = list([Z, A[s], B[s]] + lower = list([Z, C[s], D[s]] for s in reversed(srange(k-3+len(upper), k))) return upper + lower From 69ac23485f2d50729a2334d158cdcbf25ae0cee1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 8 Jul 2023 18:19:01 -0700 Subject: [PATCH 27/87] 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 28/87] ./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 29/87] 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 30/87] 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 f130733da1dde57faade54c20d2785af8dea8c04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 15 Jul 2023 18:16:50 +0200 Subject: [PATCH 31/87] note about docker in README.md --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index f086349a015..fa120722d85 100644 --- a/README.md +++ b/README.md @@ -416,6 +416,18 @@ You need to install `sage_conf`, a wheelhouse of various python packages. You ca **NOTE:** You can find `sage` and `sagemath` pip packages but with these packages, you will encounter `ModuleNotFoundError`. +Sagemath Docker image +--------------------- + +[![Docker Status](http://dockeri.co/image/sagemath/sagemath)](https://hub.docker.com/r/sagemath/sagemath) + +Sagemath is available on Docker Hub and can be downloaded by: +``` bash +docker pull sagemath/sagemath +``` + +Currently, the docker image is not up to date. + Troubleshooting --------------- From 43f9419a652eedf965959b9897763694975f5df9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 16 Jul 2023 09:13:21 +0200 Subject: [PATCH 32/87] some details in dirichlet.py --- src/sage/modular/dirichlet.py | 28 ++++++++++++++-------------- src/sage/sandpiles/sandpile.py | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/sage/modular/dirichlet.py b/src/sage/modular/dirichlet.py index 68b4eaaa4f1..47e33ccb706 100644 --- a/src/sage/modular/dirichlet.py +++ b/src/sage/modular/dirichlet.py @@ -63,9 +63,9 @@ from sage.arith.functions import lcm from sage.arith.misc import bernoulli, kronecker, factor, gcd, fundamental_discriminant, euler_phi, valuation +from sage.arith.misc import binomial, factorial from sage.categories.map import Map from sage.categories.objects import Objects -from sage.functions.other import binomial, factorial from sage.libs.pari import pari from sage.misc.cachefunc import cached_method from sage.misc.fast_methods import WithEqualityById @@ -75,10 +75,9 @@ from sage.rings.finite_rings.integer_mod import Mod from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.rings.integer import Integer -from sage.rings.integer_ring import ZZ from sage.rings.number_field.number_field import CyclotomicField, NumberField, NumberField_generic from sage.rings.power_series_ring import PowerSeriesRing -from sage.rings.rational_field import RationalField, QQ, is_RationalField +from sage.rings.rational_field import QQ, is_RationalField from sage.rings.ring import is_Ring from sage.structure.element import MultiplicativeGroupElement from sage.structure.factory import UniqueFactory @@ -88,7 +87,7 @@ from sage.structure.sequence import Sequence -def trivial_character(N, base_ring=RationalField()): +def trivial_character(N, base_ring=QQ): r""" Return the trivial character of the given modulus, with values in the given base ring. @@ -135,14 +134,14 @@ def kronecker_character(d): raise ValueError("d must be nonzero") D = fundamental_discriminant(d) - G = DirichletGroup(abs(D), RationalField()) + G = DirichletGroup(abs(D), QQ) return G([kronecker(D, u) for u in G.unit_gens()]) def kronecker_character_upside_down(d): """ Return the quadratic Dirichlet character (./d) of conductor d, for - d0. + d > 0. EXAMPLES:: @@ -157,11 +156,11 @@ def kronecker_character_upside_down(d): if d <= 0: raise ValueError("d must be positive") - G = DirichletGroup(d, RationalField()) + G = DirichletGroup(d, QQ) return G([kronecker(u.lift(), d) for u in G.unit_gens()]) -def is_DirichletCharacter(x): +def is_DirichletCharacter(x) -> bool: r""" Return ``True`` if ``x`` is of type ``DirichletCharacter``. @@ -639,7 +638,7 @@ def bernoulli(self, k, algorithm='recurrence', cache=True, **opts): .. MATH:: \sum_{a=1}^N \frac{\varepsilon(a) t e^{at}}{e^{Nt}-1} - = sum_{k=0}^{\infty} \frac{B_{k,\varepsilon}}{k!} t^k. + = \sum_{k=0}^{\infty} \frac{B_{k,\varepsilon}}{k!} t^k. ALGORITHM: @@ -707,8 +706,9 @@ def bernoulli(self, k, algorithm='recurrence', cache=True, **opts): def S(n): return sum(v[r] * r**n for r in range(1, N)) - ber = K(sum(binomial(k, j) * bernoulli(j, **opts) * - N**(j - 1) * S(k - j) for j in range(k + 1))) + + ber = sum(binomial(k, j) * bernoulli(j, **opts) * + N**(j - 1) * S(k - j) for j in range(k + 1)) elif algorithm == "definition": # This is better since it computes the same thing, but requires # no arith in a poly ring over a number field. @@ -721,7 +721,7 @@ def S(n): h = [0] + [g * ((n * t).exp(prec)) for n in range(1, N + 1)] ber = sum([self(a) * h[a][k] for a in range(1, N + 1)]) * factorial(k) else: - raise ValueError("algorithm = '%s' unknown" % algorithm) + raise ValueError(f"algorithm = '{algorithm}' unknown") if cache: self.__bernoulli[k] = ber @@ -998,7 +998,7 @@ def fixed_field_polynomial(self, algorithm="pari"): G, chi = self._pari_init_() K = pari.charker(G, chi) H = pari.galoissubcyclo(G, K) - P = PolynomialRing(RationalField(), "x") + P = PolynomialRing(QQ, "x") x = P.gen() return H.sage({"x": x}) @@ -2943,7 +2943,7 @@ def _automorphisms(self): if p == 0: Auts = [e for e in range(1, n) if gcd(e, n) == 1] else: - if not ZZ(p).is_prime(): + if not Integer(p).is_prime(): raise NotImplementedError("Automorphisms for finite non-field base rings not implemented") # The automorphisms in characteristic p are # k-th powering for diff --git a/src/sage/sandpiles/sandpile.py b/src/sage/sandpiles/sandpile.py index 2d09a660d65..02d2021b2fb 100644 --- a/src/sage/sandpiles/sandpile.py +++ b/src/sage/sandpiles/sandpile.py @@ -326,7 +326,7 @@ from sage.combinat.set_partition import SetPartitions from sage.combinat.vector_partition import IntegerVectorsIterator from sage.functions.log import exp -from sage.functions.other import binomial +from sage.arith.misc import binomial from sage.geometry.polyhedron.constructor import Polyhedron from sage.graphs.graph import Graph from sage.graphs.digraph import DiGraph From 3edc2ae17d92a053e95ed41c419c30f9a6b8583b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 22 Jul 2023 09:03:54 +0200 Subject: [PATCH 33/87] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fa120722d85..da504962c4c 100644 --- a/README.md +++ b/README.md @@ -426,7 +426,7 @@ Sagemath is available on Docker Hub and can be downloaded by: docker pull sagemath/sagemath ``` -Currently, the docker image is not up to date. +Currently, only stable versions are kept up to date. Troubleshooting --------------- From 7c8e14f8a9ff154c7f58817715d34705df24b16d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 22 Jul 2023 09:58:45 +0200 Subject: [PATCH 34/87] refresh descent_two_isogeny.pyx --- .../elliptic_curves/descent_two_isogeny.pyx | 335 +++++++++++------- 1 file changed, 216 insertions(+), 119 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx b/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx index 59c38c633e8..e8600029e39 100644 --- a/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx +++ b/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx @@ -29,7 +29,8 @@ from sage.libs.flint.nmod_poly cimport * from sage.libs.flint.ulong_extras cimport * from cypari2.paridecl cimport (GEN, cgetg, t_POL, set_gel, gel, stoi, lg, - evalvarn, evalsigne, Z_issquare, hyperellratpoints) + evalvarn, evalsigne, Z_issquare, + hyperellratpoints) from cypari2.stack cimport clear_stack from sage.libs.pari.convert_gmp cimport _new_GEN_from_mpz_t @@ -44,7 +45,7 @@ cdef unsigned long valuation(mpz_t a, mpz_t p): cdef mpz_t aa cdef unsigned long v mpz_init(aa) - v = mpz_remove(aa,a,p) + v = mpz_remove(aa, a, p) mpz_clear(aa) return v @@ -92,22 +93,25 @@ cdef int padic_square(mpz_t a, mpz_t p): cdef mpz_t aa cdef int result - if mpz_sgn(a) == 0: return 1 + if mpz_sgn(a) == 0: + return 1 - v = valuation(a,p) - if v & 1: return 0 + v = valuation(a, p) + if v & 1: + return 0 - mpz_init_set(aa,a) + mpz_init_set(aa, a) while v: v -= 1 mpz_divexact(aa, aa, p) - if mpz_cmp_ui(p, 2)==0: - result = (mpz_fdiv_ui(aa, 8) == 1) + if mpz_cmp_ui(p, 2) == 0: + result = bool(mpz_fdiv_ui(aa, 8) == 1) else: - result = (mpz_legendre(aa, p) == 1) + result = bool(mpz_legendre(aa, p) == 1) mpz_clear(aa) return result + def test_padic_square(a, p): """ Doctest function for cdef int padic_square(mpz_t, unsigned long). @@ -117,13 +121,14 @@ def test_padic_square(a, p): sage: from sage.schemes.elliptic_curves.descent_two_isogeny import test_padic_square as ps sage: for i in [1..300]: ....: for p in prime_range(100): - ....: if not Qp(p)(i).is_square()==bool(ps(i,p)): + ....: if Qp(p)(i).is_square() != bool(ps(i,p)): ....: print(i, p) """ cdef Integer A = Integer(a) cdef Integer P = Integer(p) return padic_square(A.value, P.value) + cdef int lemma6(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t x, mpz_t p, unsigned long nu): """ @@ -147,7 +152,7 @@ cdef int lemma6(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, if padic_square(g_of_x, p): mpz_clear(g_of_x) - return +1 # soluble + return +1 # soluble mpz_init_set(g_prime_of_x, x) mpz_mul(g_prime_of_x, a, x) @@ -159,17 +164,21 @@ cdef int lemma6(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_add(g_prime_of_x, g_prime_of_x, d) lambd = valuation(g_of_x, p) - if mpz_sgn(g_prime_of_x)==0: - if lambd >= 2*nu: result = 0 # undecided + if mpz_sgn(g_prime_of_x) == 0: + if lambd >= 2*nu: + result = 0 # undecided else: mu = valuation(g_prime_of_x, p) - if lambd > 2*mu: result = +1 # soluble - elif lambd >= 2*nu and mu >= nu: result = 0 # undecided + if lambd > 2*mu: + result = +1 # soluble + elif lambd >= 2*nu and mu >= nu: + result = 0 # undecided mpz_clear(g_prime_of_x) mpz_clear(g_of_x) return result + cdef int lemma7(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t x, mpz_t p, unsigned long nu): """ @@ -209,28 +218,33 @@ cdef int lemma7(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, while mpz_even_p(g_of_x_odd_part): mpz_divexact_ui(g_of_x_odd_part, g_of_x_odd_part, 2) g_of_x_odd_part_mod_4 = mpz_fdiv_ui(g_of_x_odd_part, 4) - if mpz_sgn(g_prime_of_x)==0: - if lambd >= 2*nu: result = 0 # undecided + if mpz_sgn(g_prime_of_x) == 0: + if lambd >= 2*nu: + result = 0 # undecided elif lambd == 2*nu-2 and g_of_x_odd_part_mod_4==1: - result = 0 # undecided + result = 0 # undecided else: mu = valuation(g_prime_of_x, p) - if lambd > 2*mu: result = +1 # soluble + if lambd > 2*mu: + result = +1 # soluble elif nu > mu: - if lambd >= mu+nu: result = +1 # soluble + if lambd >= mu+nu: + result = +1 # soluble elif lambd+1 == mu+nu and (lambd & 1) == 0: - result = +1 # soluble + result = +1 # soluble elif lambd+2 == mu+nu and (lambd & 1) == 0 and g_of_x_odd_part_mod_4 == 1: result = +1 # soluble else: # nu <= mu - if lambd >= 2*nu: result = 0 # undecided + if lambd >= 2*nu: + result = 0 # undecided elif lambd+2 == 2*nu and g_of_x_odd_part_mod_4==1: - result = 0 # undecided + result = 0 # undecided mpz_clear(g_prime_of_x) mpz_clear(g_of_x) return result + cdef int Zp_soluble_BSD(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t x_k, mpz_t p, unsigned long k): """ @@ -245,9 +259,9 @@ cdef int Zp_soluble_BSD(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, cdef mpz_t s if mpz_cmp_ui(p, 2) == 0: - code = lemma7(a,b,c,d,e,x_k,p,k) + code = lemma7(a, b, c, d, e, x_k, p, k) else: - code = lemma6(a,b,c,d,e,x_k,p,k) + code = lemma6(a, b, c, d, e, x_k, p, k) if code == 1: return 1 if code == -1: @@ -260,11 +274,12 @@ cdef int Zp_soluble_BSD(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_pow_ui(s, p, k) mpz_mul_ui(s, s, t) mpz_add(s, s, x_k) - code = Zp_soluble_BSD(a,b,c,d,e,s,p,k+1) + code = Zp_soluble_BSD(a, b, c, d, e, s, p, k+1) t += 1 mpz_clear(s) return code + cdef bint Zp_soluble_siksek(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t pp, unsigned long pp_ui, nmod_poly_factor_t f_factzn, nmod_poly_t f, @@ -288,24 +303,28 @@ cdef bint Zp_soluble_siksek(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, v_min = valuation(a, pp) if mpz_cmp_ui(b, 0) != 0: v = valuation(b, pp) - if v < v_min: v_min = v + if v < v_min: + v_min = v if mpz_cmp_ui(c, 0) != 0: v = valuation(c, pp) - if v < v_min: v_min = v + if v < v_min: + v_min = v if mpz_cmp_ui(d, 0) != 0: v = valuation(d, pp) - if v < v_min: v_min = v + if v < v_min: + v_min = v if mpz_cmp_ui(e, 0) != 0: v = valuation(e, pp) - if v < v_min: v_min = v - for 0 <= v < v_min: + if v < v_min: + v_min = v + for v in range(v_min): mpz_divexact(a, a, pp) mpz_divexact(b, b, pp) mpz_divexact(c, c, pp) mpz_divexact(d, d, pp) mpz_divexact(e, e, pp) - if not v_min%2: + if not v_min % 2: # Step I in Alg. 5.3.1 of Siksek's thesis nmod_poly_set_coeff_ui(f, 0, mpz_fdiv_ui(e, pp_ui)) nmod_poly_set_coeff_ui(f, 1, mpz_fdiv_ui(d, pp_ui)) @@ -389,7 +408,7 @@ cdef bint Zp_soluble_siksek(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_divexact(ccc, ccc, pp) mpz_divexact(ddd, ddd, pp) mpz_divexact(eee, eee, pp) - # now aaa,bbb,ccc,ddd,eee represents h(x) + # now aaa, bbb, ccc, ddd, eee represents h(x) result = 0 mpz_init(tt) @@ -463,8 +482,10 @@ cdef bint Zp_soluble_siksek(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, roots[j] = pp_ui - nmod_poly_get_coeff_ui(&f_factzn.p[i], 0) j += 1 - if not has_roots: return 0 - if has_single_roots: return 1 + if not has_roots: + return 0 + if has_single_roots: + return 1 result = 0 if j > 0: @@ -515,36 +536,50 @@ cdef bint Zp_soluble_siksek_large_p(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, cdef mpz_t aa, bb, cc, dd, ee cdef mpz_t aaa, bbb, ccc, ddd, eee cdef mpz_t qq, rr, ss, tt - cdef Integer A,B,C,D,E,P + cdef Integer A, B, C, D, E, P # Step 0: divide out all common p from the quartic v_min = valuation(a, pp) if mpz_cmp_ui(b, 0) != 0: v = valuation(b, pp) - if v < v_min: v_min = v + if v < v_min: + v_min = v if mpz_cmp_ui(c, 0) != 0: v = valuation(c, pp) - if v < v_min: v_min = v + if v < v_min: + v_min = v if mpz_cmp_ui(d, 0) != 0: v = valuation(d, pp) - if v < v_min: v_min = v + if v < v_min: + v_min = v if mpz_cmp_ui(e, 0) != 0: v = valuation(e, pp) - if v < v_min: v_min = v - for 0 <= v < v_min: + if v < v_min: + v_min = v + for v in range(v_min): mpz_divexact(a, a, pp) mpz_divexact(b, b, pp) mpz_divexact(c, c, pp) mpz_divexact(d, d, pp) mpz_divexact(e, e, pp) - if not v_min%2: + if not v_min % 2: # Step I in Alg. 5.3.1 of Siksek's thesis - A = Integer(0); B = Integer(0); C = Integer(0); D = Integer(0); E = Integer(0); P = Integer(0) - mpz_set(A.value, a); mpz_set(B.value, b); mpz_set(C.value, c); mpz_set(D.value, d); mpz_set(E.value, e); mpz_set(P.value, pp) - f = ntl.ZZ_pX([E,D,C,B,A], P) - f /= ntl.ZZ_pX([A], P) # now f is monic, and we are done with A,B,C,D,E - mpz_set(qq, A.value) # qq is the leading coefficient of the polynomial + A = Integer(0) + B = Integer(0) + C = Integer(0) + D = Integer(0) + E = Integer(0) + P = Integer(0) + mpz_set(A.value, a) + mpz_set(B.value, b) + mpz_set(C.value, c) + mpz_set(D.value, d) + mpz_set(E.value, e) + mpz_set(P.value, pp) + f = ntl.ZZ_pX([E, D, C, B, A], P) + f /= ntl.ZZ_pX([A], P) # now f is monic, and we are done with A,B,C,D,E + mpz_set(qq, A.value) # qq is the leading coefficient of the polynomial f_factzn = f.factor() result = 0 for factor, exponent in f_factzn: @@ -627,7 +662,7 @@ cdef bint Zp_soluble_siksek_large_p(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_divexact(ccc, ccc, pp) mpz_divexact(ddd, ddd, pp) mpz_divexact(eee, eee, pp) - # now aaa,bbb,ccc,ddd,eee represents h(x) + # now aaa, bbb, ccc, ddd, eee represents h(x) result = 0 mpz_init(tt) @@ -683,10 +718,20 @@ cdef bint Zp_soluble_siksek_large_p(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, return result else: # Step II in Alg. 5.3.1 of Siksek's thesis - A = Integer(0); B = Integer(0); C = Integer(0); D = Integer(0); E = Integer(0); P = Integer(0) - mpz_set(A.value, a); mpz_set(B.value, b); mpz_set(C.value, c); mpz_set(D.value, d); mpz_set(E.value, e); mpz_set(P.value, pp) - f = ntl.ZZ_pX([E,D,C,B,A], P) - f /= ntl.ZZ_pX([A], P) # now f is monic + A = Integer(0) + B = Integer(0) + C = Integer(0) + D = Integer(0) + E = Integer(0) + P = Integer(0) + mpz_set(A.value, a) + mpz_set(B.value, b) + mpz_set(C.value, c) + mpz_set(D.value, d) + mpz_set(E.value, e) + mpz_set(P.value, pp) + f = ntl.ZZ_pX([E, D, C, B, A], P) + f /= ntl.ZZ_pX([A], P) # now f is monic f_factzn = f.factor() has_roots = 0 @@ -702,8 +747,10 @@ cdef bint Zp_soluble_siksek_large_p(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_set(roots[j], A.value) j += 1 - if not has_roots: return 0 - if has_single_roots: return 1 + if not has_roots: + return 0 + if has_single_roots: + return 1 result = 0 if j > 0: @@ -749,25 +796,27 @@ cdef bint Qp_soluble_siksek(mpz_t A, mpz_t B, mpz_t C, mpz_t D, mpz_t E, locally soluble at p. """ cdef int result = 0 - cdef mpz_t a,b,c,d,e + cdef mpz_t a, b, c, d, e cdef nmod_poly_t f nmod_poly_init(f, P) - mpz_init_set(a,A) - mpz_init_set(b,B) - mpz_init_set(c,C) - mpz_init_set(d,D) - mpz_init_set(e,E) + mpz_init_set(a, A) + mpz_init_set(b, B) + mpz_init_set(c, C) + mpz_init_set(d, D) + mpz_init_set(e, E) - if Zp_soluble_siksek(a,b,c,d,e,p,P,f_factzn, f, f1, linear): + if Zp_soluble_siksek(a, b, c, d, e, + p, P, f_factzn, f, f1, linear): result = 1 else: - mpz_set(a,A) - mpz_set(b,B) - mpz_set(c,C) - mpz_set(d,D) - mpz_set(e,E) - if Zp_soluble_siksek(e,d,c,b,a,p,P,f_factzn, f, f1, linear): + mpz_set(a, A) + mpz_set(b, B) + mpz_set(c, C) + mpz_set(d, D) + mpz_set(e, E) + if Zp_soluble_siksek(e, d, c, b, a, + p, P,f_factzn, f, f1, linear): result = 1 mpz_clear(a) @@ -778,6 +827,7 @@ cdef bint Qp_soluble_siksek(mpz_t A, mpz_t B, mpz_t C, mpz_t D, mpz_t E, nmod_poly_clear(f) return result + cdef bint Qp_soluble_siksek_large_p(mpz_t A, mpz_t B, mpz_t C, mpz_t D, mpz_t E, mpz_t p, fmpz_poly_t f1, fmpz_poly_t linear): """ @@ -786,7 +836,7 @@ cdef bint Qp_soluble_siksek_large_p(mpz_t A, mpz_t B, mpz_t C, mpz_t D, mpz_t E, FLINT. """ cdef int result = 0 - cdef mpz_t a,b,c,d,e + cdef mpz_t a, b, c, d, e mpz_init_set(a,A) mpz_init_set(b,B) @@ -794,7 +844,8 @@ cdef bint Qp_soluble_siksek_large_p(mpz_t A, mpz_t B, mpz_t C, mpz_t D, mpz_t E, mpz_init_set(d,D) mpz_init_set(e,E) - if Zp_soluble_siksek_large_p(a,b,c,d,e,p,f1,linear): + if Zp_soluble_siksek_large_p(a, b, c, d, e, + p, f1, linear): result = 1 else: mpz_set(a,A) @@ -820,9 +871,11 @@ cdef bint Qp_soluble_BSD(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t p): cdef mpz_t zero cdef int result = 0 mpz_init_set_ui(zero, 0) - if Zp_soluble_BSD(a,b,c,d,e,zero,p,0): + if Zp_soluble_BSD(a, b, c, d, e, + zero, p, 0): result = 1 - elif Zp_soluble_BSD(e,d,c,b,a,zero,p,1): + elif Zp_soluble_BSD(e, d, c, b, a, + zero, p, 1): result = 1 mpz_clear(zero) return result @@ -843,17 +896,20 @@ cdef bint Qp_soluble(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, mpz_t p): if mpz_fits_ulong_p(p): nmod_poly_factor_init(f_factzn) pp = mpz_get_ui(p) - sik_sol = Qp_soluble_siksek(a,b,c,d,e,p,pp,f_factzn,f1,linear) + sik_sol = Qp_soluble_siksek(a, b, c, d, e, + p, pp, f_factzn, f1,linear) nmod_poly_factor_clear(f_factzn) else: - sik_sol = Qp_soluble_siksek_large_p(a,b,c,d,e,p,f1,linear) + sik_sol = Qp_soluble_siksek_large_p(a, b, c, d, e, + p, f1, linear) fmpz_poly_clear(f1) fmpz_poly_clear(linear) else: sik_sol = bsd_sol return sik_sol -def test_qpls(a,b,c,d,e,p): + +def test_qpls(a, b, c, d, e, p): """ Testing function for Qp_soluble. @@ -863,10 +919,15 @@ def test_qpls(a,b,c,d,e,p): sage: tq(1,2,3,4,5,7) 1 """ - cdef Integer A,B,C,D,E,P - cdef int i, result - cdef mpz_t aa,bb,cc,dd,ee,pp - A=Integer(a); B=Integer(b); C=Integer(c); D=Integer(d); E=Integer(e); P=Integer(p) + cdef Integer A, B, C, D, E, P + cdef int result + cdef mpz_t aa, bb, cc, dd, ee, pp + A = Integer(a) + B = Integer(b) + C = Integer(c) + D = Integer(d) + E = Integer(e) + P = Integer(p) mpz_init_set(aa, A.value) mpz_init_set(bb, B.value) mpz_init_set(cc, C.value) @@ -882,24 +943,33 @@ def test_qpls(a,b,c,d,e,p): mpz_clear(pp) return result + cdef int everywhere_locally_soluble(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e) except -1: """ Returns whether the quartic has local solutions at all primes p. """ - cdef Integer A,B,C,D,E,Delta,p + cdef Integer A, B, C, D, E, Delta,p cdef mpz_t mpz_2 - A=Integer(0); B=Integer(0); C=Integer(0); D=Integer(0); E=Integer(0) - mpz_set(A.value, a); mpz_set(B.value, b); mpz_set(C.value, c); mpz_set(D.value, d); mpz_set(E.value, e) + A = Integer(0) + B = Integer(0) + C = Integer(0) + D = Integer(0) + E = Integer(0) + mpz_set(A.value, a) + mpz_set(B.value, b) + mpz_set(C.value, c) + mpz_set(D.value, d) + mpz_set(E.value, e) f = (((A*x_ZZ + B)*x_ZZ + C)*x_ZZ + D)*x_ZZ + E # RR soluble: - if mpz_sgn(a)!=1: + if mpz_sgn(a) != 1: if not real_roots(f): return 0 # Q2 soluble: mpz_init_set_ui(mpz_2, 2) - if not Qp_soluble(a,b,c,d,e,mpz_2): + if not Qp_soluble(a, b, c, d, e, mpz_2): mpz_clear(mpz_2) return 0 mpz_clear(mpz_2) @@ -907,12 +977,15 @@ cdef int everywhere_locally_soluble(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e) # Odd finite primes Delta = f.discriminant() for p in prime_divisors(Delta): - if p == 2: continue - if not Qp_soluble(a,b,c,d,e,p.value): return 0 + if p == 2: + continue + if not Qp_soluble(a, b, c, d, e, p.value): + return 0 return 1 -def test_els(a,b,c,d,e): + +def test_els(a, b, c, d, e): """ Doctest function for cdef int everywhere_locally_soluble(mpz_t, mpz_t, mpz_t, mpz_t, mpz_t). @@ -928,10 +1001,15 @@ def test_els(a,b,c,d,e): ....: except ValueError: ....: continue """ - cdef Integer A,B,C,D,E,Delta - A=Integer(a); B=Integer(b); C=Integer(c); D=Integer(d); E=Integer(e) + cdef Integer A,B,C,D,E + A = Integer(a) + B = Integer(b) + C = Integer(c) + D = Integer(d) + E = Integer(e) return everywhere_locally_soluble(A.value, B.value, C.value, D.value, E.value) + cdef int count(mpz_t c_mpz, mpz_t d_mpz, mpz_t *p_list, unsigned long p_list_len, int global_limit_small, int global_limit_large, int verbosity, bint selmer_only, mpz_t n1, mpz_t n2) except -1: @@ -955,7 +1033,6 @@ cdef int count(mpz_t c_mpz, mpz_t d_mpz, mpz_t *p_list, unsigned long p_list_len mpz_clear(c_sq_mpz) mpz_clear(d_prime_mpz) - # Set up coefficient array, and static variables cdef mpz_t *coeffs = sig_malloc(5 * sizeof(mpz_t)) for i in range(5): @@ -991,7 +1068,8 @@ cdef int count(mpz_t c_mpz, mpz_t d_mpz, mpz_t *p_list, unsigned long p_list_len if mpz_tstbit(j, i): mpz_mul(coeffs[4], coeffs[4], p_div_d_mpz[i]) if verbosity > 3: - a_Int = Integer(0); mpz_set(a_Int.value, coeffs[4]) + a_Int = Integer(0) + mpz_set(a_Int.value, coeffs[4]) print('\nSquarefree divisor:', a_Int) mpz_divexact(coeffs[0], d_mpz, coeffs[4]) found_global_points = 0 @@ -1001,10 +1079,13 @@ cdef int count(mpz_t c_mpz, mpz_t d_mpz, mpz_t *p_list, unsigned long p_list_len found_global_points = ratpoints_mpz_exists_only(coeffs, 4, global_limit_small) if found_global_points: if verbosity > 2: - a_Int = Integer(0); mpz_set(a_Int.value, coeffs[4]) - c_Int = Integer(0); mpz_set(c_Int.value, coeffs[2]) - e_Int = Integer(0); mpz_set(e_Int.value, coeffs[0]) - print('Found small global point, quartic (%d,%d,%d,%d,%d)'%(a_Int,0,c_Int,0,e_Int)) + a_Int = Integer(0) + mpz_set(a_Int.value, coeffs[4]) + c_Int = Integer(0) + mpz_set(c_Int.value, coeffs[2]) + e_Int = Integer(0) + mpz_set(e_Int.value, coeffs[0]) + print('Found small global point, quartic (%d,%d,%d,%d,%d)' % (a_Int, 0, c_Int, 0, e_Int)) mpz_add_ui(n1, n1, 1) mpz_add_ui(n2, n2, 1) if verbose: @@ -1018,10 +1099,13 @@ cdef int count(mpz_t c_mpz, mpz_t d_mpz, mpz_t *p_list, unsigned long p_list_len break if els: if verbosity > 2: - a_Int = Integer(0); mpz_set(a_Int.value, coeffs[4]) - c_Int = Integer(0); mpz_set(c_Int.value, coeffs[2]) - e_Int = Integer(0); mpz_set(e_Int.value, coeffs[0]) - print('ELS without small global points, quartic (%d,%d,%d,%d,%d)'%(a_Int,0,c_Int,0,e_Int)) + a_Int = Integer(0) + mpz_set(a_Int.value, coeffs[4]) + c_Int = Integer(0) + mpz_set(c_Int.value, coeffs[2]) + e_Int = Integer(0) + mpz_set(e_Int.value, coeffs[0]) + print('ELS without small global points, quartic (%d,%d,%d,%d,%d)' % (a_Int, 0, c_Int, 0, e_Int)) mpz_add_ui(n2, n2, 1) if not selmer_only: if verbose: @@ -1044,11 +1128,12 @@ cdef int count(mpz_t c_mpz, mpz_t d_mpz, mpz_t *p_list, unsigned long p_list_len sig_free(coeffs) return 0 + def two_descent_by_two_isogeny(E, - int global_limit_small=10, - int global_limit_large=10000, - int verbosity=0, - bint selmer_only=0, bint proof=1): + int global_limit_small=10, + int global_limit_large=10000, + int verbosity=0, + bint selmer_only=0, bint proof=1): """ Given an elliptic curve E with a two-isogeny phi : E --> E' and dual isogeny phi', runs a two-isogeny descent on E, returning n1, n2, n1' and n2'. Here @@ -1127,7 +1212,7 @@ def two_descent_by_two_isogeny(E, cdef Integer a1, a2, a3, a4, a6, s2, s4, s6 cdef Integer c, d, x0 cdef list x_list - assert E.torsion_order()%2==0, 'Need rational two-torsion for isogeny descent.' + assert E.torsion_order() % 2 == 0, 'Need rational two-torsion for isogeny descent.' if verbosity > 0: print('\n2-isogeny') if verbosity > 1: @@ -1137,21 +1222,30 @@ def two_descent_by_two_isogeny(E, a3 = Integer(E.a3()) a4 = Integer(E.a4()) a6 = Integer(E.a6()) - if a1==0 and a3==0: - s2=a2; s4=a4; s6=a6 + if a1 == 0 == a3: + s2 = a2 + s4 = a4 + s6 = a6 else: - s2=a1*a1+4*a2; s4=8*(a1*a3+2*a4); s6=16*(a3*a3+4*a6) + s2 = a1*a1+4*a2 + s4 = 8*(a1*a3+2*a4) + s6 = 16*(a3*a3+4*a6) f = ((x_ZZ + s2)*x_ZZ + s4)*x_ZZ + s6 - x_list = f.roots() # over ZZ -- use FLINT directly? + x_list = f.roots() # over ZZ -- use FLINT directly? x0 = x_list[0][0] - c = 3*x0+s2; d = (c+s2)*x0+s4 + c = 3*x0+s2 + d = (c+s2)*x0+s4 return two_descent_by_two_isogeny_work(c, d, - global_limit_small, global_limit_large, verbosity, selmer_only, proof) + global_limit_small, + global_limit_large, verbosity, + selmer_only, proof) def two_descent_by_two_isogeny_work(Integer c, Integer d, - int global_limit_small=10, int global_limit_large=10000, - int verbosity=0, bint selmer_only=0, bint proof=1): + int global_limit_small=10, + int global_limit_large=10000, + int verbosity=0, bint selmer_only=0, + bint proof=1): """ Do all the work in doing a two-isogeny descent. @@ -1176,7 +1270,7 @@ def two_descent_by_two_isogeny_work(Integer c, Integer d, cdef unsigned long i, j, p, p_list_len cdef Integer P, n1, n2, n1_prime, n2_prime, c_prime, d_prime cdef object PO - cdef bint found, too_big, d_neg, d_prime_neg + cdef bint found, d_neg, d_prime_neg cdef n_factor_t fact cdef list primes mpz_init_set(c_mpz, c.value) @@ -1212,7 +1306,7 @@ def two_descent_by_two_isogeny_work(Integer c, Integer d, p = fact.p[i] found = 0 for j in range(p_list_len): - if mpz_cmp_ui(p_list_mpz[j], p)==0: + if mpz_cmp_ui(p_list_mpz[j], p) == 0: found = 1 break if not found: @@ -1230,7 +1324,8 @@ def two_descent_by_two_isogeny_work(Integer c, Integer d, if PO not in primes: primes.append(PO) P = Integer(2) - if P not in primes: primes.append(P) + if P not in primes: + primes.append(P) p_list_len = len(primes) p_list_mpz = sig_malloc(p_list_len * sizeof(mpz_t)) for i in range(p_list_len): @@ -1244,12 +1339,14 @@ def two_descent_by_two_isogeny_work(Integer c, Integer d, if verbosity > 1: c_prime = -2*c d_prime = c*c-4*d - print('\nnew curve is y^2 == x( x^2 + (%d)x + (%d) )'%(int(c),int(d))) + print('\nnew curve is y^2 == x( x^2 + (%d)x + (%d) )' % (int(c), int(d))) print('new isogenous curve is' + - ' y^2 == x( x^2 + (%d)x + (%d) )'%(int(c_prime),int(d_prime))) + ' y^2 == x( x^2 + (%d)x + (%d) )' % (int(c_prime), int(d_prime))) - n1 = Integer(0); n2 = Integer(0) - n1_prime = Integer(0); n2_prime = Integer(0) + n1 = Integer(0) + n2 = Integer(0) + n1_prime = Integer(0) + n2_prime = Integer(0) count(c.value, d.value, p_list_mpz, p_list_len, global_limit_small, global_limit_large, verbosity, selmer_only, n1.value, n2.value) @@ -1303,7 +1400,7 @@ cdef bint ratpoints_mpz_exists_only(mpz_t *coeffs, long degree, long H) except - # PARI checks only for affine points, so we manually check for # points at infinity (of the smooth model) cdef int r - if degree % 2 == 1 or Z_issquare(gel(pol, degree+2)): + if degree % 2 or Z_issquare(gel(pol, degree+2)): r = 1 else: R = hyperellratpoints(pol, stoi(H), 1) From 2b0a6f679b03621c5e897b2636c546160c860ebb Mon Sep 17 00:00:00 2001 From: Antonio Rojas Date: Sun, 23 Jul 2023 09:15:03 +0200 Subject: [PATCH 35/87] Adapt to new Singular sat API --- src/sage/rings/polynomial/multi_polynomial_ideal.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 7bf29415157..58ebb0a6002 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -2446,7 +2446,11 @@ def saturation(self, other): (Ideal (y, x^5) of Multivariate Polynomial Ring in x, y, z over Algebraic Field, 4) """ from sage.libs.singular.function_factory import ff - sat = ff.elim__lib.sat + # function renamed in singular > 4.2.3p4 + try: + sat = ff.elim__lib.sat_with_exp + except NameError: + sat = ff.elim__lib.sat R = self.ring() ideal, expo = sat(self, other) return (R.ideal(ideal), ZZ(expo)) From 641c2d17ce2cf3d2116cfe4b1b6f791f3017394a Mon Sep 17 00:00:00 2001 From: John Cremona Date: Mon, 24 Jul 2023 15:43:40 +0100 Subject: [PATCH 36/87] 35983: fix and doctest --- .../elliptic_curves/ell_curve_isogeny.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index 7ce401587f1..57d8f97bc76 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -1250,6 +1250,19 @@ def _call_(self, P): sage: phi = E.isogeny(3^99*P) # optional - sage.rings.finite_rings sage: phi(Q)._order # optional - sage.rings.finite_rings 27 + + Test for :trac:`35983`:: + + sage: E = EllipticCurve([1,0,0,-1,0]) # optional - sage.rings.finite_rings + sage: P = E([1,0]) # optional - sage.rings.finite_rings + sage: P.order() # optional - sage.rings.finite_rings + +Infinity + sage: phi = E.isogenies_prime_degree(2)[0] # optional - sage.rings.finite_rings + sage: Q = phi(P); Q # optional - sage.rings.finite_rings + (0 : 1 : 1) + sage: Q.order() # optional - sage.rings.finite_rings + +Infinity + """ if P.is_zero(): return self._codomain(0) @@ -1281,9 +1294,11 @@ def _call_(self, P): xP = self.__posti_ratl_maps[0](xP) Q = self._codomain(xP, yP) - if hasattr(P, '_order') and P._order.gcd(self._degree).is_one(): + if hasattr(P, '_order'): + if P.has_infinite_order() or P._order.gcd(self._degree).is_one(): + Q._order = P._order # TODO: For non-coprime degree, the order of the point - # gets reduced by a divisor of the degree when passing + # may get reduced by a divisor of the degree when passing # through the isogeny. We could run something along the # lines of order_from_multiple() to determine the new # order, but this probably shouldn't happen by default From 90d347d8c93932c77b8725cbd8c4f2a1275a1137 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Jul 2023 09:02:17 +0200 Subject: [PATCH 37/87] Apply suggestions from code review Co-authored-by: cheuberg --- src/sage/combinat/k_regular_sequence.py | 2 +- src/sage/combinat/recognizable_series.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 959c0008bfd..2c194ab17ab 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -1044,7 +1044,7 @@ def one(self): sage: O.linear_representation() ((1), Finite family {0: [1], 1: [0]}, (1)) - TESTS: + TESTS:: sage: Seq2.one() is Seq2.one() True diff --git a/src/sage/combinat/recognizable_series.py b/src/sage/combinat/recognizable_series.py index d2752dbad2c..3344efb0c88 100644 --- a/src/sage/combinat/recognizable_series.py +++ b/src/sage/combinat/recognizable_series.py @@ -1968,7 +1968,7 @@ def one(self): sage: O.linear_representation() ((1), Finite family {0: [0], 1: [0]}, (1)) - TESTS: + TESTS:: sage: Rec.one() is Rec.one() True From 4ed1e49e790b2ceb65354f1fe7cf2d2832aa112d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Jul 2023 09:10:01 +0200 Subject: [PATCH 38/87] make description of method "one" more precise --- src/sage/combinat/k_regular_sequence.py | 4 ++-- src/sage/combinat/recognizable_series.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index e9516be3c0f..72934d782d9 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -1440,8 +1440,8 @@ def one(self): r""" Return the one element of this :class:`kRegularSequenceSpace`, i.e. the unique neutral element for `*` and also - the embedding of the unique neutral element for `*` in the - coefficient ring. + the embedding of the one of the coefficient ring into + this :class:`kRegularSequenceSpace`. EXAMPLES:: diff --git a/src/sage/combinat/recognizable_series.py b/src/sage/combinat/recognizable_series.py index 36f214e94db..37518e0e1f2 100644 --- a/src/sage/combinat/recognizable_series.py +++ b/src/sage/combinat/recognizable_series.py @@ -1994,8 +1994,8 @@ def _zero_(self): def one(self): r""" Return the one element of this :class:`RecognizableSeriesSpace`, - i.e. the embedding of the unique neutral element for `*` in the - coefficient ring. + i.e. the embedding of the one of the coefficient ring into + this :class:`RecognizableSeriesSpace`. EXAMPLES:: From 133374e70f9332e5185f239de766c16416847453 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 25 Jul 2023 09:14:24 +0200 Subject: [PATCH 39/87] break line in doctest --- src/sage/combinat/recognizable_series.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/recognizable_series.py b/src/sage/combinat/recognizable_series.py index 37518e0e1f2..c20a6c1ee62 100644 --- a/src/sage/combinat/recognizable_series.py +++ b/src/sage/combinat/recognizable_series.py @@ -1141,7 +1141,8 @@ def minimized(self): TESTS:: - sage: Rec((Matrix([[0]]), Matrix([[0]])), vector([1]), vector([0])).minimized().linear_representation() + sage: Rec((Matrix([[0]]), Matrix([[0]])), + ....: vector([1]), vector([0])).minimized().linear_representation() ((), Finite family {0: [], 1: []}, ()) """ return self._minimized_right_()._minimized_left_() From ecf7d966841a37ffc38684da08c2360df21b3a95 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 27 Jul 2023 15:39:35 +0200 Subject: [PATCH 40/87] gap: revise make_gap_list, make_gap_matrix --- src/sage/libs/gap/element.pyx | 49 +++++++++++++++++++----------- src/sage/libs/gap/gap_includes.pxd | 4 --- 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/src/sage/libs/gap/element.pyx b/src/sage/libs/gap/element.pyx index 35067c59c0f..1dc53c81f67 100644 --- a/src/sage/libs/gap/element.pyx +++ b/src/sage/libs/gap/element.pyx @@ -47,16 +47,23 @@ cdef Obj make_gap_list(sage_list) except NULL: The list of the elements in ``a`` as a Gap ``Obj``. """ - cdef GapElement l = libgap.eval('[]') + cdef Obj l cdef GapElement elem - for x in sage_list: - if not isinstance(x, GapElement): - elem = libgap(x) - else: - elem = x + cdef int i + try: + GAP_Enter() + l = GAP_NewPlist(0) - AddList(l.value, elem.value) - return l.value + for i, x in enumerate(sage_list): + if not isinstance(x, GapElement): + elem = libgap(x) + else: + elem = x + + GAP_AssList(l, i + 1, elem.value) + return l + finally: + GAP_Leave() cdef Obj make_gap_matrix(sage_list, gap_ring) except NULL: @@ -77,22 +84,30 @@ cdef Obj make_gap_matrix(sage_list, gap_ring) except NULL: The list of the elements in ``sage_list`` as a Gap ``Obj``. """ - cdef GapElement l = libgap.eval('[]') + cdef Obj l cdef GapElement elem cdef GapElement one + cdef int i if gap_ring is not None: one = gap_ring.One() else: one = libgap(1) - for x in sage_list: - if not isinstance(x, GapElement): - elem = libgap(x) - elem = elem * one - else: - elem = x - AddList(l.value, elem.value) - return l.value + try: + GAP_Enter() + l = GAP_NewPlist(0) + + for i, x in enumerate(sage_list): + if not isinstance(x, GapElement): + elem = libgap(x) + elem = elem * one + else: + elem = x + + GAP_AssList(l, i + 1, elem.value) + return l + finally: + GAP_Leave() cdef char *capture_stdout(Obj func, Obj obj): diff --git a/src/sage/libs/gap/gap_includes.pxd b/src/sage/libs/gap/gap_includes.pxd index 32ee925001f..840b8a0042e 100644 --- a/src/sage/libs/gap/gap_includes.pxd +++ b/src/sage/libs/gap/gap_includes.pxd @@ -96,10 +96,6 @@ cdef extern from "gap/lists.h" nogil: Obj ELM_LIST(Obj lst, int pos) -cdef extern from "gap/listfunc.h" nogil: - void AddList(Obj list, Obj obj) - - cdef extern from "gap/objects.h" nogil: bint IS_MUTABLE_OBJ(Obj obj) Obj SHALLOW_COPY_OBJ(Obj obj) From 8501e47b91d38d3bf2f6e75df65c5bb6415dc5de Mon Sep 17 00:00:00 2001 From: John Cremona Date: Thu, 27 Jul 2023 15:56:15 +0100 Subject: [PATCH 41/87] #35983: remove line --- src/sage/schemes/elliptic_curves/ell_curve_isogeny.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index 57d8f97bc76..e5e35f2a139 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -1303,7 +1303,6 @@ def _call_(self, P): # lines of order_from_multiple() to determine the new # order, but this probably shouldn't happen by default # as it'll be detrimental to performance in some cases. - Q._order = P._order return Q def __getitem__(self, i): From 5a4215255f84531b4d35aa7717320c7608e02010 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sat, 29 Jul 2023 09:05:59 +0900 Subject: [PATCH 42/87] Do not run pytest without filenames --- src/bin/sage-runtests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/sage-runtests b/src/bin/sage-runtests index 4131161647d..c9ceccaaf43 100755 --- a/src/bin/sage-runtests +++ b/src/bin/sage-runtests @@ -177,7 +177,7 @@ if __name__ == "__main__": # we do not silently hide typos. filenames = [f for f in args.filenames if f.endswith("_test.py") or not os.path.isfile(f)] - if filenames or not args.filenames: + if filenames: print(f"Running pytest on {filenames} with options {pytest_options}") exit_code_pytest = pytest.main(filenames + pytest_options) if exit_code_pytest == 5: From a61da7fe5d80effdfc2a1bd8c4486151df0f364a Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sat, 29 Jul 2023 12:46:43 +0900 Subject: [PATCH 43/87] No filenamrs is equivalent to src/sage --- src/bin/sage-runtests | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/bin/sage-runtests b/src/bin/sage-runtests index c9ceccaaf43..06000348ce0 100755 --- a/src/bin/sage-runtests +++ b/src/bin/sage-runtests @@ -171,12 +171,17 @@ if __name__ == "__main__": pytest_options = [] if args.verbose: pytest_options.append("-v") - # #31924: Do not run pytest on individual Python files unless - # they match the pytest file pattern. However, pass names - # of directories. We use 'not os.path.isfile(f)' for this so that - # we do not silently hide typos. - filenames = [f for f in args.filenames - if f.endswith("_test.py") or not os.path.isfile(f)] + + # #35999: no filenames in arguments is equivalent to "src/sage" + if not args.filenames: + filenames = [os.path.join(os.environ.get('SAGE_SRC'), "sage")] + else: + # #31924: Do not run pytest on individual Python files unless + # they match the pytest file pattern. However, pass names + # of directories. We use 'not os.path.isfile(f)' for this so that + # we do not silently hide typos. + filenames = [f for f in args.filenames + if f.endswith("_test.py") or not os.path.isfile(f)] if filenames: print(f"Running pytest on {filenames} with options {pytest_options}") exit_code_pytest = pytest.main(filenames + pytest_options) From 2af5fdb995cbc87aee6f1f627ef90c64316e373b Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sun, 30 Jul 2023 00:36:14 +0900 Subject: [PATCH 44/87] Use src not src/sage --- src/bin/sage-runtests | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/sage-runtests b/src/bin/sage-runtests index 06000348ce0..9409bb38da8 100755 --- a/src/bin/sage-runtests +++ b/src/bin/sage-runtests @@ -172,9 +172,9 @@ if __name__ == "__main__": if args.verbose: pytest_options.append("-v") - # #35999: no filenames in arguments is equivalent to "src/sage" + # #35999: no filenames in arguments is equivalent to "src" if not args.filenames: - filenames = [os.path.join(os.environ.get('SAGE_SRC'), "sage")] + filenames = [os.environ.get('SAGE_SRC')] else: # #31924: Do not run pytest on individual Python files unless # they match the pytest file pattern. However, pass names From c3befb502983d82746ec9f9dc8a9523e3a8e6543 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sun, 30 Jul 2023 10:19:15 +0200 Subject: [PATCH 45/87] use "positive" partial sums algorithm --- src/sage/combinat/k_regular_sequence.py | 48 +++++++++++++++++-------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 1ec99957aa8..d76d2de7281 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -728,20 +728,36 @@ def partial_sums(self, include_n=False): 1: [0 0] [0 1]}, (1, 1)) + sage: P = E.partial_sums(minimize=False) sage: P.linear_representation() - ((1, 0, -1, 0), - Finite family {0: [ 0 1| 0 0] - [ 0 2| 0 -1] - [-----+-----] - [ 0 0| 0 1] - [ 0 0| 0 1], - 1: [0 1|0 0] + ((1, 0, 0, 0), + Finite family {0: [0 1|0 0] [0 2|0 0] [---+---] + [0 0|0 1] + [0 0|0 1], + 1: [0 1|0 1] + [0 2|0 1] + [---+---] [0 0|0 0] [0 0|0 1]}, - (1, 1, 1, 1)) + (0, 0, 1, 1)) + + sage: P = E.partial_sums(include_n=True, minimize=False) + sage: P.linear_representation() + ((1, 0, 1, 0), + Finite family {0: [0 1|0 0] + [0 2|0 0] + [---+---] + [0 0|0 1] + [0 0|0 1], + 1: [0 1|0 1] + [0 2|0 1] + [---+---] + [0 0|0 0] + [0 0|0 1]}, + (0, 0, 1, 1)) """ from itertools import chain from sage.matrix.constructor import Matrix @@ -752,17 +768,21 @@ def partial_sums(self, include_n=False): A = P.alphabet() k = P.k dim = self.dimension() - - B = {r: sum(self.mu[a] for a in A[r:]) for r in A} Z = zero_matrix(dim) - B[k] = Z + + z = A[0] + assert z == 0 + B = {z: Z} + for r in A: + B[r+1] = B[r] + self.mu[r] + C = B[k] result = P.element_class( P, - {r: Matrix.block([[B[0], -B[r + 1]], [Z, self.mu[r]]]) for r in A}, + {r: Matrix.block([[C, B[r]], [Z, self.mu[r]]]) for r in A}, vector(chain(self.left, - (dim * (0,) if include_n else -self.left))), - vector(chain(self.right, self.right))) + (dim * (0,) if not include_n else self.left))), + vector(chain(dim * (0,), self.right))) return result From c8114d8031d83516f628fb045331ed371233347f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 30 Jul 2023 15:15:43 +0200 Subject: [PATCH 46/87] Update descent_two_isogeny.pyx minor details as suggested --- .../schemes/elliptic_curves/descent_two_isogeny.pyx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx b/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx index e8600029e39..5fc182c8954 100644 --- a/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx +++ b/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx @@ -170,7 +170,7 @@ cdef int lemma6(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, else: mu = valuation(g_prime_of_x, p) if lambd > 2*mu: - result = +1 # soluble + result = 1 # soluble elif lambd >= 2*nu and mu >= nu: result = 0 # undecided @@ -226,14 +226,14 @@ cdef int lemma7(mpz_t a, mpz_t b, mpz_t c, mpz_t d, mpz_t e, else: mu = valuation(g_prime_of_x, p) if lambd > 2*mu: - result = +1 # soluble + result = 1 # soluble elif nu > mu: if lambd >= mu+nu: - result = +1 # soluble + result = 1 # soluble elif lambd+1 == mu+nu and (lambd & 1) == 0: - result = +1 # soluble + result = 1 # soluble elif lambd+2 == mu+nu and (lambd & 1) == 0 and g_of_x_odd_part_mod_4 == 1: - result = +1 # soluble + result = 1 # soluble else: # nu <= mu if lambd >= 2*nu: result = 0 # undecided @@ -1001,7 +1001,7 @@ def test_els(a, b, c, d, e): ....: except ValueError: ....: continue """ - cdef Integer A,B,C,D,E + cdef Integer A, B, C, D, E A = Integer(a) B = Integer(b) C = Integer(c) From 3fe2f171369b9e6e43e65f5ffcbd6e922bbcaec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 30 Jul 2023 18:13:18 +0200 Subject: [PATCH 47/87] partial cython-lint cleanup in mod_sym_num --- .../schemes/elliptic_curves/mod_sym_num.pyx | 111 ++++++++---------- 1 file changed, 50 insertions(+), 61 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/mod_sym_num.pyx b/src/sage/schemes/elliptic_curves/mod_sym_num.pyx index 6a88b4147e9..65742f28d72 100644 --- a/src/sage/schemes/elliptic_curves/mod_sym_num.pyx +++ b/src/sage/schemes/elliptic_curves/mod_sym_num.pyx @@ -273,7 +273,8 @@ cdef llong llxgcd(llong a, llong b, llong *ss, llong *tt) except -1: tt[0] = q * qsign return a -def _test_llfunctions(a,b): + +def _test_llfunctions(a, b): r""" Doctest function for the above three functions. Given a, b this returns the absolute value of a, @@ -300,6 +301,7 @@ def _test_llfunctions(a,b): assert a*a4 + b*a5 == a3 return (a1,a2,a3,a4,a5) + # ================================ # this is a llong version of a function in @@ -391,7 +393,8 @@ cdef int proj_normalise(llong N, llong u, llong v, #verbose(" leaving proj_normalise with s=%s, t=%s"%(u,v), level=5) return 0 -def _test_proj_normalise(N,u,v): + +def _test_proj_normalise(N, u, v): r""" The doctest function for proj_normalise. @@ -411,9 +414,10 @@ def _test_proj_normalise(N,u,v): (1, 7) """ cdef llong uu, vv - ans = proj_normalise(N,u,v,&uu,&vv) + _ = proj_normalise(N,u,v,&uu,&vv) return (Integer(uu), Integer(vv)) + cdef int best_proj_point(llong u, llong v, llong N, llong* uu, llong* vv) except -1: r""" @@ -518,7 +522,8 @@ cdef int best_proj_point(llong u, llong v, llong N, vv[0] = t1 return 0 -def _test_best_proj_point(u,v,N): + +def _test_best_proj_point(u, v, N): r""" Doctest function of best_proj_point. @@ -546,6 +551,7 @@ def _test_best_proj_point(u,v,N): assert a == 0 return (Integer(uu), Integer(vv)) + #====================================================================== cdef class _CuspsForModularSymbolNumerical: @@ -614,7 +620,7 @@ cdef class _CuspsForModularSymbolNumerical: four [a,b,c,d] corresponds to [[a,b],[c,d]]. """ - cdef llong Q, B, c, g, x, y + cdef llong Q, B, c, x, y #verbose(" enter atkin_lehner for cusp r=%s"%self._r, level=5) Q = self._width @@ -623,7 +629,7 @@ cdef class _CuspsForModularSymbolNumerical: if llgcd(Q, B) != 1: raise ValueError("This cusp is not in the Atkin-Lehner " "orbit of oo.") - g = llxgcd( self._a * Q, self._m, &x, &y) + _ = llxgcd( self._a * Q, self._m, &x, &y) res[0] = Q * x res[1] = y res[2] = -c * self._N_level @@ -633,7 +639,8 @@ cdef class _CuspsForModularSymbolNumerical: # level=5) return 0 -def _test_cusps(r,N): + +def _test_cusps(r, N): r""" Doctest function for the above class. @@ -658,12 +665,12 @@ def _test_cusps(r,N): sage: _test_cusps(5/27,27) (1, 1, [[11, -2], [-27, 5]]) """ - cdef llong *wQ = [0L,0L,0L,0L] - rc = _CuspsForModularSymbolNumerical(r,N) + cdef llong *wQ = [0L, 0L, 0L, 0L] + rc = _CuspsForModularSymbolNumerical(r, N) a1 = rc._width a2 = rc.is_unitary() if a2: - a3 = rc.atkin_lehner(wQ) + _ = rc.atkin_lehner(wQ) a = Integer(wQ[0]) b = Integer(wQ[1]) c = Integer(wQ[2]) @@ -802,7 +809,7 @@ cdef class ModularSymbolNumerical: sig_free(self._ans_num) sig_free(self._ans) -# == basics ================ + # == basics ================ def __repr__(self): """ @@ -815,7 +822,7 @@ cdef class ModularSymbolNumerical: sage: M Numerical modular symbol attached to Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field """ - return "Numerical modular symbol attached to %s"%(self._E) + return "Numerical modular symbol attached to %s" % (self._E) def elliptic_curve(self): r""" @@ -867,9 +874,8 @@ cdef class ModularSymbolNumerical: 0 sage: M(112379/43568779) 5 - """ - cdef llong Q - cdef Rational ra, ans + """ + cdef Rational ra if sign == 0: sign = self._global_sign @@ -882,7 +888,7 @@ cdef class ModularSymbolNumerical: ra = Rational( (0,1) ) elif isinstance(r, sage.rings.infinity.PlusInfinity): return Rational(0) - else: #who knows + else: # who knows raise ValueError("The modular symbol can be evaluated at a " "rational number only.") if use_twist: @@ -892,7 +898,6 @@ cdef class ModularSymbolNumerical: return self._twisted_symbol(ra, sign=sign) return self._evaluate(ra, sign=sign) - def approximative_value(self, r, int sign=0, int prec=20, use_twist=True): r""" The numerical modular symbol evaluated at rational. @@ -936,14 +941,12 @@ cdef class ModularSymbolNumerical: sage: M.approximative_value(1/7,prec=10) # abs tol 1e-11 0.999999972802649 """ - cdef llong Q cdef Rational ra cdef ComplexNumber ans cdef double eps cdef object L cdef int cinf - if sign == 0: sign = self._global_sign @@ -953,7 +956,7 @@ cdef class ModularSymbolNumerical: ra = r elif isinstance(r, Integer): ra = Rational( (0,1) ) - else: #who knows + else: # who knows raise ValueError("The modular symbol can be evaluated at a" "rational number only.") if use_twist: @@ -981,8 +984,7 @@ cdef class ModularSymbolNumerical: else: return ans.imag()/ self._om2 - -# == initialisation ======== + # == initialisation ======== def _set_epsQs(self): r""" @@ -997,10 +999,9 @@ cdef class ModularSymbolNumerical: sage: E = EllipticCurve("20a2") sage: M = E.modular_symbol(implementation="num") #indirect doctest """ - self._epsQs = dict( - [d,prod(self._E.root_number(p) - for p in d.prime_divisors() )] - for d in Integer( self._N_E ).divisors()) + self._epsQs = {d: prod(self._E.root_number(p) + for p in d.prime_divisors()) + for d in Integer(self._N_E).divisors()} def _set_den_bounds(self): r""" @@ -1152,11 +1153,11 @@ cdef class ModularSymbolNumerical: EXAMPLES:: sage: E = EllipticCurve("63a2") - sage: M =E.modular_symbol(implementation="num") + sage: M = E.modular_symbol(implementation="num") sage: M(3/4, use_twist=True) # indirect doctest -1 """ - cdef Integer D, ell, de, ve, Dmax, DD, Nmin + cdef Integer D, ell cdef RealNumber qq, Db #verbose(" enter _set_up_twist", level=5) @@ -1200,7 +1201,6 @@ cdef class ModularSymbolNumerical: qq = self._om1 * Db/self._Mt._om2 * 2 assert self._twist_q == Rational( ( qq.round(),2)) - def _round(self, RealNumber val, int sign, int unitary): r""" Round the numerical approximation to the rational. @@ -1343,7 +1343,6 @@ cdef class ModularSymbolNumerical: # last n such that ans[n] is allowed self._lans = T - def clear_cache(self): r""" Clear the cached values in all methods of this class @@ -1362,8 +1361,7 @@ cdef class ModularSymbolNumerical: for me in cadi: cadi[me].clear_cache() - -#================== Low level summation ========= + #================== Low level summation ========= def _integration_to_tau(self, ComplexNumber tau, int number_of_terms, int prec): @@ -1648,8 +1646,7 @@ cdef class ModularSymbolNumerical: # " %s, %s, ... %s"%(res[0], res[1], res[m-1]), level=5) return res - -#================ + #================ def _get_truncation_and_prec(self, double y, double eps): r""" @@ -1867,7 +1864,7 @@ cdef class ModularSymbolNumerical: ra = sig_malloc( m * sizeof(double)) if ra is NULL: raise MemoryError - oi = self._partial_real_sums_double(y, m, T, ra) + _ = self._partial_real_sums_double(y, m, T, ra) res = [ra[j] for j in range(m)] sig_free(ra) #verbose(" leaving _kappa with" @@ -1925,8 +1922,8 @@ cdef class ModularSymbolNumerical: # " and eps=%s"%(r,eps), level=5) cdef: llong m, Q, epsQ, a, u - double yy, taui, zz, epsi - int T, prec, j, oi, preci + double yy, taui + int T, prec, j double complex tauc, tauphc, int1c, int2c, twopii, ze1, ze2, su ComplexNumber tau, tauph, int1, int2 llong * wQ = [0L, 0L, 0L, 0L] @@ -1934,7 +1931,7 @@ cdef class ModularSymbolNumerical: rc = _CuspsForModularSymbolNumerical(r, self._N_E) Q = rc._width - oi = rc.atkin_lehner(wQ) + _ = rc.atkin_lehner(wQ) m = rc._m epsQ = self._epsQs[Q] r = rc._r @@ -1970,7 +1967,6 @@ cdef class ModularSymbolNumerical: verbose(" yields %s"%int2, level=2) return int2 + int1 - elif not use_partials: # prec = 53 taui = (Q) taui = sqrt(taui) @@ -2051,7 +2047,7 @@ cdef class ModularSymbolNumerical: RealNumber x1, x2, s complex tau0c, tau1c, int1c, int2c, ze1, ze2, su, twopii llong g, u, v, uu, vv, D, a, aa, m, mm, Q, QQ, z, xi, xixi - int oi, j, preci + int oi, j double x1d, x2d, sd #verbose(" enter _from_r_to_rr_approx_direct with r=%s," @@ -2225,7 +2221,6 @@ cdef class ModularSymbolNumerical: llong * wQ = [0L, 0L, 0L, 0L] llong * wQQ = [0L, 0L, 0L, 0L] Integer epsQ, epsQQ - Rational csq, x double s, yy ComplexNumber ans, ans2 int T=0, prec=0, T1=0, T2=0, oi @@ -2698,7 +2693,7 @@ cdef class ModularSymbolNumerical: #verbose(" enter _symbol_non_unitary with r=%s," # " sign=%s"%(r,sign), level=5) cdef: - llong a, m, B, Q, N_ell, aell, u, N = self._N_E + llong m, B, N_ell, aell, u, N = self._N_E Integer ell Rational r2, res @@ -2707,9 +2702,7 @@ cdef class ModularSymbolNumerical: rc = _CuspsForModularSymbolNumerical(r, N) r = rc._r - a = rc._a m = rc._m - Q = rc._width B = llgcd(m, N) # find a prime congruent to 1 modulo B @@ -2722,14 +2715,14 @@ cdef class ModularSymbolNumerical: aell = Integer(self._ans[ell]) N_ell = ell + 1 - aell # {ell * r , r} - verbose(" Compute symbol {ell*r -> r} = {%s -> %s}"%(ell*r,r), + verbose(" Compute symbol {ell*r -> r} = {%s -> %s}" % (ell*r, r), level=4) res = self.transportable_symbol(ell * r, r, sign=sign) # {(r + u)/ ell, r} u = Integer(0) while u < ell: r2 = (r+u) / ell - verbose(" Compute symbol {r2-> r} = {%s -> %s}"%(r2,r), + verbose(" Compute symbol {r2-> r} = {%s -> %s}" % (r2, r), level=4) res += self.transportable_symbol(r2, r, sign=sign) u += 1 @@ -2781,7 +2774,6 @@ cdef class ModularSymbolNumerical: cdef: llong c, d, x, y, N = self._N_E, Mu, Mv, Qu, Qv, du=1, dv=1 Rational r, rr, res - int oi #verbose(" enter _manin_symbol_with_cache with u=%s, v=%s," # " sign =%s"%(u,v,sign), level=5) @@ -2802,9 +2794,9 @@ cdef class ModularSymbolNumerical: Mv = llgcd(v,N) Qv = N/Mv isunitary = ( llgcd(Qu,Mu) == 1 and llgcd(Qv,Mv) == 1 ) - if isunitary: # unitary case - oi = best_proj_point(u, v, self._N_E, &c, &d) - else: # at least one of the two cusps is not unitary + if isunitary: # unitary case + _ = best_proj_point(u, v, self._N_E, &c, &d) + else: # at least one of the two cusps is not unitary du = llgcd(Qu,Mu) dv = llgcd(Qv,Mv) NMM = N/Mv/Mu @@ -2986,10 +2978,9 @@ cdef class ModularSymbolNumerical: return res + # =============================== -# =============================== - - @cached_method # not sure this is not a waist + @cached_method # not sure this is not a waist def _evaluate(self, Rational r, int sign=0): r""" Given a rational number `r` this computes the modular symbol @@ -3417,16 +3408,14 @@ cdef class ModularSymbolNumerical: #verbose(" enter _symbol_nonunitary_approx with r=%s," # " eps=%s"%(r,eps), level=5) cdef: - llong a, m, B, Q, N_ell, aell, u, N = self._N_E + llong m, B, N_ell, aell, u, N = self._N_E Integer ell Rational r2 ComplexNumber res rc = _CuspsForModularSymbolNumerical(r, N) r = rc._r - a = rc._a m = rc._m - Q = rc._width B = llgcd(m, N) # find a prime congruent to 1 modulo B @@ -3619,7 +3608,8 @@ def _test_init(E): e2 = M._eps_minus e3 = M._eps_unitary_plus e4 = M._eps_unitary_minus - return e, [a1,a2,a3,a4,a5], [t1,t2,t3,t4], [e1,e2,e3,e4] + return e, [a1, a2, a3, a4, a5], [t1, t2, t3, t4], [e1, e2, e3, e4] + def _test_integration(E, a, b, T): r""" @@ -3661,6 +3651,7 @@ def _test_integration(E, a, b, T): ans = M._integration_to_tau_double(c,tt) return ans + def _test_integration_via_partials(E, y, m, T): r""" Doctest for the numerical integration in @@ -3692,15 +3683,13 @@ def _test_integration_via_partials(E, y, m, T): sage: _test_integration_via_partials(E,0.03,3,7000) # abs tol 1e-11 [0.49198993741342784, 0.6601504274130793, 0.3177042713926389] """ - cdef int oi, mm = (m) + cdef int mm = (m) cdef double * ra ra = sig_malloc( mm * sizeof(double)) if ra is NULL: raise MemoryError M = ModularSymbolNumerical(E) - yy = (y) - tt = T - oi = M._partial_real_sums_double(y, m, T, ra) + _ = M._partial_real_sums_double(y, m, T, ra) res = [ra[j] for j in range(m)] sig_free(ra) return res From f31ff720b3c8d65185881522f395c74b1463c835 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 30 Jul 2023 11:41:29 -0700 Subject: [PATCH 48/87] pkgs/sagemath-meataxe/README.rst: Remove markup unknown to PyPI --- pkgs/sagemath-meataxe/README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/sagemath-meataxe/README.rst b/pkgs/sagemath-meataxe/README.rst index 088ce86478b..659edb3cf9f 100644 --- a/pkgs/sagemath-meataxe/README.rst +++ b/pkgs/sagemath-meataxe/README.rst @@ -28,8 +28,8 @@ About this pip-installable source distribution This pip-installable source distribution ``sagemath-meataxe`` is a small optional distribution for use with ``sagemath-standard``. -This distribution provides the SageMath modules :mod:`sage.libs.meataxe` -and :mod:`sage.matrix.matrix_gfpn_dense`. +This distribution provides the SageMath modules ``sage.libs.meataxe`` +and ``sage.matrix.matrix_gfpn_dense``. It provides a specialized implementation of matrices over the finite field F_q, where q <= 255, using the `SharedMeatAxe ` From f1b9e57873c37e32233dd1116228e2d8058d1d47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 31 Jul 2023 09:30:17 +0200 Subject: [PATCH 49/87] minor cleanup in binary quadratic forms over ZZ --- src/sage/quadratic_forms/binary_qf.py | 39 +++++++++++++-------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/sage/quadratic_forms/binary_qf.py b/src/sage/quadratic_forms/binary_qf.py index 96247522baf..f678dc6b3b1 100755 --- a/src/sage/quadratic_forms/binary_qf.py +++ b/src/sage/quadratic_forms/binary_qf.py @@ -137,8 +137,7 @@ def __init__(self, a, b=None, c=None): """ from sage.rings.polynomial.multi_polynomial import MPolynomial if b is None and c is None: - if (isinstance(a, (list, tuple)) - and len(a) == 3): + if isinstance(a, (list, tuple)) and len(a) == 3: a, b, c = a elif a == 0: a = b = c = 0 @@ -215,8 +214,8 @@ def __mul__(self, right): return BinaryQF(self.__pari__().qfbcompraw(right)) # ...or a 2x2 matrix... if (isinstance(right.parent(), MatrixSpace) - and right.nrows() == right.ncols() == 2): - aa,bb,cc,dd = right.list() + and right.nrows() == right.ncols() == 2): + aa, bb, cc, dd = right.list() A = self.polynomial()(aa, cc) C = self.polynomial()(bb, dd) B = self.polynomial()(aa + bb, cc + dd) - A - C @@ -536,10 +535,10 @@ def from_polynomial(poly): if not isinstance(R, MPolynomialRing_base) or R.ngens() != 2: raise TypeError(f'not a bivariate polynomial ring: {R}') if not all(mon.degree() == 2 for mon in poly.monomials()): - raise ValueError(f'polynomial has monomials of degree != 2') - x,y = R.gens() + raise ValueError('polynomial has monomials of degree != 2') + x, y = R.gens() coeffs = (poly.monomial_coefficient(mon) for mon in (x**2, x*y, y**2)) - a,b,c = map(ZZ, coeffs) + a, b, c = map(ZZ, coeffs) return BinaryQF(a, b, c) @cached_method @@ -924,7 +923,7 @@ def reduced_form(self, transformation=False, algorithm="default"): 'supported using PARI') if transformation: - y,g = self.__pari__().qfbredsl2() + y, g = self.__pari__().qfbredsl2() return BinaryQF(y), Matrix(ZZ, g) return BinaryQF(self.__pari__().qfbred()) @@ -1153,7 +1152,7 @@ def cycle(self, proper=False): 'implemented for non-square discriminants') if proper: # Prop 6.10.5 in Buchmann Vollmer - C = list(self.cycle(proper=False)) # make a copy so we can modify it + C = list(self.cycle(proper=False)) # make a copy that we can modify if len(C) % 2: C += C for i in range(len(C)//2): @@ -1316,7 +1315,7 @@ def is_equivalent(self, other, proper=True): sage: Q1.is_equivalent(Q2, proper=True) # optional - sage.libs.pari True """ - if type(other) != type(self): + if not isinstance(other, BinaryQF): raise TypeError("%s is not a BinaryQF" % other) if self.discriminant() != other.discriminant(): return False @@ -1342,7 +1341,7 @@ def is_equivalent(self, other, proper=True): return is_properly_equiv else: g = gcd(a, b) - return is_properly_equiv or ((gcd(ao,b) == g) and ((a*ao - g**2) % (b*g) == 0)) + return is_properly_equiv or ((gcd(ao, b) == g) and ((a*ao - g**2) % (b*g) == 0)) proper_cycle = otherred.cycle(proper=True) @@ -1654,13 +1653,13 @@ def solve_integer(self, n, *, algorithm="general"): # https://math.stackexchange.com/a/980075 w = self.discriminant().sqrt() r = (-self._b + (w if w != self._b else -w)) / (2*self._a) - p,q = r.as_integer_ratio() - g,u,v = p.xgcd(q) - M = Matrix(ZZ, [[v,p],[-u,q]]) + p, q = r.as_integer_ratio() + g, u, v = p.xgcd(q) + M = Matrix(ZZ, [[v, p], [-u, q]]) elif self._c: - M = Matrix(ZZ, [[0,1],[1,0]]) + M = Matrix(ZZ, [[0, 1], [1, 0]]) else: - M = Matrix(ZZ, [[1,0],[0,1]]) + M = Matrix(ZZ, [[1, 0], [0, 1]]) assert M.is_unit() Q = self.matrix_action_right(M) assert not Q._c @@ -1845,7 +1844,7 @@ def BinaryQF_reduced_representatives(D, primitive_only=False, proper=True): c = ZZ(0) # -b/2 < a <= b/2 for a in xsrange((-b/2).floor() + 1, (b/2).floor() + 1): - if (not primitive_only) or (gcd([a,b,c]) == 1): + if not primitive_only or (gcd([a, b, c]) == 1): form_list.append(BinaryQF(a, b, c)) # We follow the description of Buchmann/Vollmer 6.7.1. They # enumerate all reduced forms. We only want representatives. @@ -1879,14 +1878,14 @@ def BinaryQF_reduced_representatives(D, primitive_only=False, proper=True): a4 = 4*a s = D + a*a4 w = 1+(s-1).isqrt() if s > 0 else 0 - if w%2 != D%2: + if w % 2 != D % 2: w += 1 for b in xsrange(w, a+1, 2): t = b*b-D if t % a4 == 0: c = t // a4 - if (not primitive_only) or gcd([a, b, c]) == 1: - if b>0 and a>b and c>a: + if not primitive_only or gcd([a, b, c]) == 1: + if c > a > b > 0: form_list.append(BinaryQF([a, -b, c])) form_list.append(BinaryQF([a, b, c])) if not proper or D > 0: From 05de6cc4a2f69679d0159d5e2d8f56479745c897 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Jul 2023 16:19:31 +0200 Subject: [PATCH 50/87] algorithm block --- src/sage/combinat/k_regular_sequence.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 72934d782d9..fd8e42f7849 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -1052,6 +1052,12 @@ def _mul_(self, other): A :class:`kRegularSequence` + ALGORITHM: + + See pdf attached to + `github pull request #35894 `_ + which contains a draft describing the details of the used algorithm. + EXAMPLES:: sage: Seq2 = kRegularSequenceSpace(2, ZZ) From 15de625bf914bcf5391c26a4c017707ff6149379 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Jul 2023 18:33:30 +0200 Subject: [PATCH 51/87] remove experimental warning --- src/sage/combinat/k_regular_sequence.py | 15 --------------- src/sage/combinat/recognizable_series.py | 16 ---------------- 2 files changed, 31 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 2461c28f0d0..273d8141290 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -6,21 +6,6 @@ found, for example, on the :wikipedia:`k-regular_sequence` or in [AS2003]_. - -.. WARNING:: - - As this code is experimental, warnings are thrown when a - `k`-regular sequence space is created for the first time in a - session (see :class:`sage.misc.superseded.experimental`). - - TESTS:: - - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - doctest:...: FutureWarning: This class/method/function is - marked as experimental. It, its functionality or its interface - might change without a formal deprecation. - See https://github.com/sagemath/sage/issues/21202 for details. - :: sage: import logging diff --git a/src/sage/combinat/recognizable_series.py b/src/sage/combinat/recognizable_series.py index 3812deb62d0..8e373995835 100644 --- a/src/sage/combinat/recognizable_series.py +++ b/src/sage/combinat/recognizable_series.py @@ -27,20 +27,6 @@ In particular, minimization is called before checking if a series is nonzero. -.. WARNING:: - - As this code is experimental, warnings are thrown when a - recognizable series space is created for the first time in a - session (see :class:`sage.misc.superseded.experimental`). - - TESTS:: - - sage: Rec = RecognizableSeriesSpace(ZZ, [0, 1]) - doctest:...: FutureWarning: This class/method/function is - marked as experimental. It, its functionality or its interface - might change without a formal deprecation. - See https://github.com/sagemath/sage/issues/21202 for details. - Various ======= @@ -79,7 +65,6 @@ from functools import wraps from sage.misc.cachefunc import cached_method -from sage.misc.superseded import experimental from sage.structure.element import ModuleElement from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation @@ -1741,7 +1726,6 @@ def __normalize__(cls, return (coefficient_ring, indices, category, minimize_results) - @experimental(issue_number=21202) def __init__(self, coefficient_ring, indices, category, minimize_results): r""" See :class:`RecognizableSeriesSpace` for details. From edf629887eb2f83b9135bc21e2271e0dae8281ab Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Jul 2023 18:37:19 +0200 Subject: [PATCH 52/87] rename to RegularSequenceRing --- src/sage/combinat/all.py | 2 +- src/sage/combinat/k_regular_sequence.py | 184 +++++++++++------------ src/sage/combinat/recognizable_series.py | 10 +- 3 files changed, 98 insertions(+), 98 deletions(-) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 0f43e6bbcfe..27d4926f1cd 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -277,7 +277,7 @@ lazy_import('sage.combinat.binary_recurrence_sequences', 'BinaryRecurrenceSequence') lazy_import('sage.combinat.recognizable_series', 'RecognizableSeriesSpace') -lazy_import('sage.combinat.k_regular_sequence', 'kRegularSequenceSpace') +lazy_import('sage.combinat.k_regular_sequence', 'RegularSequenceRing') # Six Vertex Model lazy_import('sage.combinat.six_vertex_model', 'SixVertexModel') diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 273d8141290..49f2d6c62bb 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -20,7 +20,7 @@ The binary sum of digits `S(n)` of a nonnegative integer `n` satisfies `S(2n) = S(n)` and `S(2n+1) = S(n) + 1`. We model this by the following:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[1, 0], [1, 1]])), ....: left=vector([0, 1]), right=vector([1, 0])) sage: S @@ -161,7 +161,7 @@ class DegeneratedSequenceError(RuntimeError): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1])) Traceback (most recent call last): ... @@ -180,7 +180,7 @@ def __init__(self, parent, mu, left=None, right=None): INPUT: - - ``parent`` -- an instance of :class:`kRegularSequenceSpace` + - ``parent`` -- an instance of :class:`RegularSequenceRing` - ``mu`` -- a family of square matrices, all of which have the same dimension. The indices of this family are `0,...,k-1`. @@ -198,7 +198,7 @@ def __init__(self, parent, mu, left=None, right=None): from the right to the matrix product. If ``None``, then this multiplication is skipped. - When created via the parent :class:`kRegularSequenceSpace`, then + When created via the parent :class:`RegularSequenceRing`, then the following option is available. - ``allow_degenerated_sequence`` -- (default: ``False``) a boolean. If set, then @@ -209,7 +209,7 @@ def __init__(self, parent, mu, left=None, right=None): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: S = Seq2((Matrix([[3, 0], [6, 1]]), Matrix([[0, 1], [-6, 5]])), ....: vector([1, 0]), vector([0, 1])); S 2-regular sequence 0, 1, 3, 5, 9, 11, 15, 19, 27, 29, ... @@ -230,7 +230,7 @@ def __init__(self, parent, mu, left=None, right=None): .. SEEALSO:: :doc:`k-regular sequence `, - :class:`kRegularSequenceSpace`. + :class:`RegularSequenceRing`. TESTS:: @@ -247,7 +247,7 @@ def _repr_(self): TESTS:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: s = Seq2((Matrix([[3, 0], [6, 1]]), Matrix([[0, 1], [-6, 5]])), ....: vector([1, 0]), vector([0, 1])) sage: repr(s) # indirect doctest @@ -273,7 +273,7 @@ def coefficient_of_n(self, n, **kwds): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[0, -1], [1, 2]])), ....: left=vector([0, 1]), right=vector([1, 0])) sage: S[7] @@ -293,7 +293,7 @@ def coefficient_of_n(self, n, **kwds): :: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: W = Seq2.indices() sage: M0 = Matrix([[1, 0], [0, 1]]) sage: M1 = Matrix([[0, -1], [1, 2]]) @@ -315,7 +315,7 @@ def __iter__(self): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[0, -1], [1, 2]])), ....: left=vector([0, 1]), right=vector([1, 0])) sage: from itertools import islice @@ -342,7 +342,7 @@ def is_degenerated(self): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1])) # indirect doctest Traceback (most recent call last): ... @@ -375,7 +375,7 @@ def _error_if_degenerated_(self): TESTS:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: Seq2((Matrix([[3, 2], [0, 1]]), Matrix([[2, 0], [1, 3]])), # indirect doctest ....: left=vector([0, 1]), right=vector([1, 0])) Traceback (most recent call last): @@ -418,7 +418,7 @@ def regenerated(self): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) The following linear representation of `S` is chosen badly (is degenerated, see :meth:`is_degenerated`), as `\mu(0)` applied on @@ -509,7 +509,7 @@ def transposed(self, allow_degenerated_sequence=False): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: U = Seq2((Matrix([[3, 2], [0, 1]]), Matrix([[2, 0], [1, 3]])), ....: left=vector([0, 1]), right=vector([1, 0]), ....: allow_degenerated_sequence=True) @@ -561,7 +561,7 @@ def _minimized_right_(self): TESTS:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: Seq2((Matrix([[3, 0], [2, 1]]), Matrix([[2, 1], [0, 3]])), # indirect doctest ....: left=vector([1, 0]), right=vector([0, 1])).minimized() 2-regular sequence 0, 1, 3, 5, 9, 11, 15, 19, 27, 29, ... @@ -600,7 +600,7 @@ def subsequence(self, a, b): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) We consider the sequence `C` with `C(n) = n` and the following linear representation @@ -873,7 +873,7 @@ def shift_left(self, b=1, **kwds): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: C = Seq2((Matrix([[2, 0], [0, 1]]), Matrix([[2, 1], [0, 1]])), ....: vector([1, 0]), vector([0, 1])); C 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... @@ -919,7 +919,7 @@ def shift_right(self, b=1, **kwds): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: C = Seq2((Matrix([[2, 0], [0, 1]]), Matrix([[2, 1], [0, 1]])), ....: vector([1, 0]), vector([0, 1])); C 2-regular sequence 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... @@ -966,7 +966,7 @@ def backward_differences(self, **kwds): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: C = Seq2((Matrix([[2, 0], [2, 1]]), Matrix([[0, 1], [-2, 3]])), ....: vector([1, 0]), vector([0, 1])) sage: C @@ -1003,7 +1003,7 @@ def forward_differences(self, **kwds): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: C = Seq2((Matrix([[2, 0], [2, 1]]), Matrix([[0, 1], [-2, 3]])), ....: vector([1, 0]), vector([0, 1])) sage: C @@ -1051,7 +1051,7 @@ def _mul_(self, other): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), ....: vector([1, 0]), vector([1, 1])) sage: E @@ -1155,7 +1155,7 @@ def partial_sums(self, include_n=False): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), ....: vector([1, 0]), vector([1, 1])) @@ -1195,7 +1195,7 @@ def partial_sums(self, include_n=False): sage: H 2-regular sequence 0, 2, 10, 16, 50, 62, 80, 98, 250, 274, ... - We can :meth:`~kRegularSequenceSpace.guess` the correct representation:: + We can :meth:`~RegularSequenceRing.guess` the correct representation:: sage: from itertools import islice sage: L = []; ps = 0 @@ -1274,22 +1274,22 @@ def partial_sums(self, include_n=False): return result -def _pickle_kRegularSequenceSpace(k, coefficients, category): +def _pickle_RegularSequenceRing(k, coefficients, category): r""" Pickle helper. TESTS:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) - sage: from sage.combinat.k_regular_sequence import _pickle_kRegularSequenceSpace - sage: _pickle_kRegularSequenceSpace( + sage: Seq2 = RegularSequenceRing(2, ZZ) + sage: from sage.combinat.k_regular_sequence import _pickle_RegularSequenceRing + sage: _pickle_RegularSequenceRing( ....: Seq2.k, Seq2.coefficient_ring(), Seq2.category()) Space of 2-regular sequences over Integer Ring """ - return kRegularSequenceSpace(k, coefficients, category=category) + return RegularSequenceRing(k, coefficients, category=category) -class kRegularSequenceSpace(RecognizableSeriesSpace): +class RegularSequenceRing(RecognizableSeriesSpace): r""" The space of `k`-regular Sequences over the given ``coefficient_ring``. @@ -1304,9 +1304,9 @@ class kRegularSequenceSpace(RecognizableSeriesSpace): EXAMPLES:: - sage: kRegularSequenceSpace(2, ZZ) + sage: RegularSequenceRing(2, ZZ) Space of 2-regular sequences over Integer Ring - sage: kRegularSequenceSpace(3, ZZ) + sage: RegularSequenceRing(3, ZZ) Space of 3-regular sequences over Integer Ring .. SEEALSO:: @@ -1325,11 +1325,11 @@ def __normalize__(cls, k, Normalizes the input in order to ensure a unique representation. - For more information see :class:`kRegularSequenceSpace`. + For more information see :class:`RegularSequenceRing`. TESTS:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: Seq2.category() Category of algebras over Integer Ring sage: Seq2.alphabet() @@ -1346,7 +1346,7 @@ def __normalize__(cls, k, def __init__(self, k, *args, **kwds): r""" - See :class:`kRegularSequenceSpace` for details. + See :class:`RegularSequenceRing` for details. INPUT: @@ -1357,15 +1357,15 @@ def __init__(self, k, *args, **kwds): TESTS:: - sage: kRegularSequenceSpace(2, ZZ) + sage: RegularSequenceRing(2, ZZ) Space of 2-regular sequences over Integer Ring - sage: kRegularSequenceSpace(3, ZZ) + sage: RegularSequenceRing(3, ZZ) Space of 3-regular sequences over Integer Ring :: sage: from itertools import islice - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: TestSuite(Seq2).run( # long time ....: elements=tuple(islice(Seq2.some_elements(), 4))) @@ -1383,11 +1383,11 @@ def __reduce__(self): TESTS:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: loads(dumps(Seq2)) # indirect doctest Space of 2-regular sequences over Integer Ring """ - return _pickle_kRegularSequenceSpace, \ + return _pickle_RegularSequenceRing, \ (self.k, self.coefficient_ring(), self.category()) def _repr_(self): @@ -1398,7 +1398,7 @@ def _repr_(self): TESTS:: - sage: repr(kRegularSequenceSpace(2, ZZ)) # indirect doctest + sage: repr(RegularSequenceRing(2, ZZ)) # indirect doctest 'Space of 2-regular sequences over Integer Ring' """ return 'Space of {}-regular sequences over {}'.format(self.k, self.base()) @@ -1416,7 +1416,7 @@ def _n_to_index_(self, n): TESTS:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: Seq2._n_to_index_(6) word: 011 sage: Seq2._n_to_index_(-1) @@ -1435,14 +1435,14 @@ def _n_to_index_(self, n): @cached_method def one(self): r""" - Return the one element of this :class:`kRegularSequenceSpace`, + Return the one element of this :class:`RegularSequenceRing`, i.e. the unique neutral element for `*` and also the embedding of the one of the coefficient ring into - this :class:`kRegularSequenceSpace`. + this :class:`RegularSequenceRing`. EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: O = Seq2.one(); O 2-regular sequence 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... sage: O.linear_representation() @@ -1477,7 +1477,7 @@ def some_elements(self): EXAMPLES:: - sage: tuple(kRegularSequenceSpace(2, ZZ).some_elements()) + sage: tuple(RegularSequenceRing(2, ZZ).some_elements()) (2-regular sequence 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, ..., 2-regular sequence 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, ..., 2-regular sequence 1, 1, 0, 1, -1, 0, 0, 1, -2, -1, ..., @@ -1490,18 +1490,18 @@ def some_elements(self): """ return iter(element.regenerated() for element - in super(kRegularSequenceSpace, self).some_elements( + in super(RegularSequenceRing, self).some_elements( allow_degenerated_sequence=True)) def _element_constructor_(self, *args, **kwds): r""" Return a `k`-regular sequence. - See :class:`kRegularSequenceSpace` for details. + See :class:`RegularSequenceRing` for details. TESTS:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: Seq2((Matrix([2]), Matrix([3])), vector([1]), vector([1])) Traceback (most recent call last): ... @@ -1517,7 +1517,7 @@ def _element_constructor_(self, *args, **kwds): 2-regular sequence 1, 3, 6, 9, 12, 18, 18, 27, 24, 36, ... """ allow_degenerated_sequence = kwds.pop('allow_degenerated_sequence', False) - element = super(kRegularSequenceSpace, self)._element_constructor_(*args, **kwds) + element = super(RegularSequenceRing, self)._element_constructor_(*args, **kwds) if not allow_degenerated_sequence: element._error_if_degenerated_() return element @@ -1583,7 +1583,7 @@ def guess(self, f, n_verify=100, max_exponent=10, sequence=None): Let us guess a `2`-linear representation for `s(n)`:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: import logging sage: logging.getLogger().setLevel(logging.INFO) sage: S1 = Seq2.guess(s); S1 @@ -1673,7 +1673,7 @@ def guess(self, f, n_verify=100, max_exponent=10, sequence=None): sage: S.is_degenerated() True - However, we can :meth:`~kRegularSequenceSpace.guess` a `2`-regular sequence of dimension `2`:: + However, we can :meth:`~RegularSequenceRing.guess` a `2`-regular sequence of dimension `2`:: sage: G = Seq2.guess(lambda n: S[n]) sage: G @@ -1716,7 +1716,7 @@ def guess(self, f, n_verify=100, max_exponent=10, sequence=None): 1: [1]}, (1)) - We :meth:`~kRegularSequenceSpace.guess` some partial sums sequences:: + We :meth:`~RegularSequenceRing.guess` some partial sums sequences:: sage: S = Seq2((Matrix([1]), Matrix([2])), vector([1]), vector([1])) sage: S @@ -1741,7 +1741,7 @@ def guess(self, f, n_verify=100, max_exponent=10, sequence=None): :: - sage: Seq3 = kRegularSequenceSpace(3, QQ) + sage: Seq3 = RegularSequenceRing(3, QQ) sage: S = Seq3((Matrix([1]), Matrix([3]), Matrix([2])), vector([1]), vector([1])) sage: S 3-regular sequence 1, 3, 2, 3, 9, 6, 2, 6, 4, 3, ... @@ -1774,7 +1774,7 @@ def guess(self, f, n_verify=100, max_exponent=10, sequence=None): :: - sage: R = kRegularSequenceSpace(2, QQ) + sage: R = RegularSequenceRing(2, QQ) sage: one = R.one_hadamard() sage: S = R.guess(lambda n: sum(n.bits()), sequence=one) + one sage: T = R.guess(lambda n: n*n, sequence=S, n_verify=4); T @@ -1978,7 +1978,7 @@ def from_recurrence(self, *args, **kwds): :: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: var('n') n sage: function('f') @@ -2010,7 +2010,7 @@ def from_recurrence(self, *args, **kwds): + l + 1) + ... + c_{r,u} f(k^m n + u)` for some integers `0 \leq r < k^M`, `M > m \geq 0` and `l \leq u`, and some coefficients `c_{r,j}` from the (semi)ring ``coefficients`` - of the corresponding :class:`kRegularSequenceSpace`, valid + of the corresponding :class:`RegularSequenceRing`, valid for all integers `n \geq \text{offset}` for some integer `\text{offset} \geq \max(-l/k^m, 0)` (default: ``0``), and there is an equation of this form (with the same @@ -2066,7 +2066,7 @@ def from_recurrence(self, *args, **kwds): Stern--Brocot Sequence:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: var('n') n sage: function('f') @@ -2140,7 +2140,7 @@ def from_recurrence(self, *args, **kwds): Number of Non-Zero Elements in the Generalized Pascal's Triangle (see [LRS2017]_):: - sage: Seq2 = kRegularSequenceSpace(2, QQ) + sage: Seq2 = RegularSequenceRing(2, QQ) sage: P = Seq2.from_recurrence([ ....: f(4*n) == 5/3*f(2*n) - 1/3*f(2*n + 1), ....: f(4*n + 1) == 4/3*f(2*n) + 1/3*f(2*n + 1), @@ -2323,7 +2323,7 @@ class RecurrenceParser(): the construction of a `k`-linear representation for the sequence satisfying these recurrence relations. - This is used by :meth:`kRegularSequenceSpace.from_recurrence` + This is used by :meth:`RegularSequenceRing.from_recurrence` to construct a :class:`kRegularSequence`. """ @@ -2338,7 +2338,7 @@ def __init__(self, k, coefficient_ring): - ``coefficient_ring`` -- a ring. These are the same parameters used when creating - a :class:`kRegularSequenceSpace`. + a :class:`RegularSequenceRing`. TESTS:: @@ -2351,20 +2351,20 @@ def __init__(self, k, coefficient_ring): def parse_recurrence(self, equations, function, var): r""" - Parse recurrence relations as admissible in :meth:`kRegularSequenceSpace.from_recurrence`. + Parse recurrence relations as admissible in :meth:`RegularSequenceRing.from_recurrence`. INPUT: All parameters are explained in the high-level method - :meth:`kRegularSequenceSpace.from_recurrence`. + :meth:`RegularSequenceRing.from_recurrence`. OUTPUT: a tuple consisting of - - ``M``, ``m`` -- see :meth:`kRegularSequenceSpace.from_recurrence` + - ``M``, ``m`` -- see :meth:`RegularSequenceRing.from_recurrence` - - ``coeffs`` -- see :meth:`kRegularSequenceSpace.from_recurrence` + - ``coeffs`` -- see :meth:`RegularSequenceRing.from_recurrence` - - ``initial_values`` -- see :meth:`kRegularSequenceSpace.from_recurrence` + - ``initial_values`` -- see :meth:`RegularSequenceRing.from_recurrence` EXAMPLES:: @@ -2393,7 +2393,7 @@ def parse_recurrence(self, equations, function, var): .. SEEALSO:: - :meth:`kRegularSequenceSpace.from_recurrence` + :meth:`RegularSequenceRing.from_recurrence` TESTS: @@ -2738,7 +2738,7 @@ def parse_recurrence(self, equations, function, var): This results in giving the correct (see :trac:`33158`) minimization in:: - sage: Seq2 = kRegularSequenceSpace(2, QQ) + sage: Seq2 = RegularSequenceRing(2, QQ) sage: P = Seq2.from_recurrence(equations, f, n) sage: P 2-regular sequence 1, 2, 3, 3, 4, 5, 5, 4, 5, 7, ... @@ -2938,12 +2938,12 @@ def parse_one_summand(summand, eq): def parse_direct_arguments(self, M, m, coeffs, initial_values): r""" Check whether the direct arguments as admissible in - :meth:`kRegularSequenceSpace.from_recurrence` are valid. + :meth:`RegularSequenceRing.from_recurrence` are valid. INPUT: All parameters are explained in the high-level method - :meth:`kRegularSequenceSpace.from_recurrence`. + :meth:`RegularSequenceRing.from_recurrence`. OUTPUT: a tuple consisting of the input parameters @@ -2972,7 +2972,7 @@ def parse_direct_arguments(self, M, m, coeffs, initial_values): .. SEEALSO:: - :meth:`kRegularSequenceSpace.from_recurrence` + :meth:`RegularSequenceRing.from_recurrence` TESTS: @@ -3115,12 +3115,12 @@ def parse_direct_arguments(self, M, m, coeffs, initial_values): def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}): r""" Determine parameters from recurrence relations as admissible in - :meth:`kRegularSequenceSpace.from_recurrence`. + :meth:`RegularSequenceRing.from_recurrence`. INPUT: All parameters are explained in the high-level method - :meth:`kRegularSequenceSpace.from_recurrence`. + :meth:`RegularSequenceRing.from_recurrence`. OUTPUT: a namedtuple ``recurrence_rules`` consisting of @@ -3160,7 +3160,7 @@ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}) .. SEEALSO:: - :meth:`kRegularSequenceSpace.from_recurrence` + :meth:`RegularSequenceRing.from_recurrence` TESTS:: @@ -3184,7 +3184,7 @@ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}) :: - sage: Seq3 = kRegularSequenceSpace(3, ZZ) + sage: Seq3 = RegularSequenceRing(3, ZZ) sage: RP.parameters(1, 0, {(0, 0): 1}, {}, 0, ....: {0: Seq3.zero()}) Traceback (most recent call last): @@ -3262,12 +3262,12 @@ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}) raise ValueError(f"Indices {invalid_indices} for inhomogeneities are no " f"integers between 0 and {k**M - 1}.") - Seq = kRegularSequenceSpace(k, coefficient_ring) + Seq = RegularSequenceRing(k, coefficient_ring) inhomogeneities.update({i: inhomogeneities[i] * Seq.one_hadamard() for i in inhomogeneities if inhomogeneities[i] in coefficient_ring}) invalid = {i: inhomogeneities[i] for i in inhomogeneities - if not (isinstance(inhomogeneities[i].parent(), kRegularSequenceSpace) and + if not (isinstance(inhomogeneities[i].parent(), RegularSequenceRing) and inhomogeneities[i].parent().k == k)} if invalid: raise ValueError(f"Inhomogeneities {invalid} are neither {k}-regular " @@ -3311,7 +3311,7 @@ def values(self, *, M, m, l, u, ll, coeffs, initial_values, last_value_needed, offset, inhomogeneities): r""" Determine enough values of the corresponding recursive sequence by - applying the recurrence relations given in :meth:`kRegularSequenceSpace.from_recurrence` + applying the recurrence relations given in :meth:`RegularSequenceRing.from_recurrence` to the values given in ``initial_values``. INPUT: @@ -3323,7 +3323,7 @@ def values(self, *, M, m, l, u, ll, coeffs, see [HKL2022]_, Theorem A - ``coeffs`` -- a dictionary where ``coeffs[(r, j)]`` is the - coefficient `c_{r,j}` as given in :meth:`kRegularSequenceSpace.from_recurrence`. + coefficient `c_{r,j}` as given in :meth:`RegularSequenceRing.from_recurrence`. If ``coeffs[(r, j)]`` is not given for some ``r`` and ``j``, then it is assumed to be zero. @@ -3356,7 +3356,7 @@ def values(self, *, M, m, l, u, ll, coeffs, .. SEEALSO:: - :meth:`kRegularSequenceSpace.from_recurrence` + :meth:`RegularSequenceRing.from_recurrence` TESTS: @@ -3437,7 +3437,7 @@ def values(self, *, M, m, l, u, ll, coeffs, :: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: RP.values(M=1, m=0, l=0, u=0, ll=0, ....: coeffs={(0, 0): 0, (1, 1): 0}, initial_values={}, ....: last_value_needed=10, offset=0, @@ -3544,7 +3544,7 @@ def ind(self, M, m, ll, uu): .. SEEALSO:: - :meth:`kRegularSequenceSpace.from_recurrence` + :meth:`RegularSequenceRing.from_recurrence` """ from sage.arith.srange import srange @@ -3596,7 +3596,7 @@ def shifted_inhomogeneities(self, recurrence_rules): sage: from collections import namedtuple sage: from sage.combinat.k_regular_sequence import RecurrenceParser sage: RP = RecurrenceParser(2, ZZ) - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[1, 0], [1, 1]])), ....: left=vector([0, 1]), right=vector([1, 0])) sage: S @@ -3629,7 +3629,7 @@ def shifted_inhomogeneities(self, recurrence_rules): TESTS:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: var('n') n sage: function('f') @@ -3662,7 +3662,7 @@ def shifted_inhomogeneities(self, recurrence_rules): .. SEEALSO:: - :meth:`kRegularSequenceSpace.from_recurrence` + :meth:`RegularSequenceRing.from_recurrence` """ from sage.arith.srange import srange from sage.functions.other import floor @@ -3708,7 +3708,7 @@ def v_eval_n(self, recurrence_rules, n): .. SEEALSO:: - :meth:`kRegularSequenceSpace.from_recurrence` + :meth:`RegularSequenceRing.from_recurrence` """ from itertools import chain @@ -3887,7 +3887,7 @@ def matrix(self, recurrence_rules, rem, correct_offset=True): .. SEEALSO:: - :meth:`kRegularSequenceSpace.from_recurrence` + :meth:`RegularSequenceRing.from_recurrence` """ from itertools import chain @@ -4015,7 +4015,7 @@ def left(self, recurrence_rules): :: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: RRD = namedtuple('recurrence_rules_dim', ....: ['M', 'm', 'll', 'uu', 'dim', 'inhomogeneities']) sage: recurrence_rules = RRD(M=3, m=2, ll=0, uu=9, dim=5, @@ -4025,7 +4025,7 @@ def left(self, recurrence_rules): .. SEEALSO:: - :meth:`kRegularSequenceSpace.from_recurrence` + :meth:`RegularSequenceRing.from_recurrence` """ from sage.modules.free_module_element import vector @@ -4053,7 +4053,7 @@ def right(self, recurrence_rules): .. SEEALSO:: - :meth:`kRegularSequenceSpace.from_recurrence` + :meth:`RegularSequenceRing.from_recurrence` TESTS: @@ -4108,18 +4108,18 @@ def __call__(self, *args, **kwds): given in ``equations``. This is the main method of :class:`RecurrenceParser` and - is called by :meth:`kRegularSequenceSpace.from_recurrence` + is called by :meth:`RegularSequenceRing.from_recurrence` to construct a :class:`kRegularSequence`. INPUT: All parameters are explained in the high-level method - :meth:`kRegularSequenceSpace.from_recurrence`. + :meth:`RegularSequenceRing.from_recurrence`. OUTPUT: a linear representation ``(left, mu, right)`` Many examples can be found in - :meth:`kRegularSequenceSpace.from_recurrence`. + :meth:`RegularSequenceRing.from_recurrence`. TESTS:: diff --git a/src/sage/combinat/recognizable_series.py b/src/sage/combinat/recognizable_series.py index 8e373995835..95e77c8f11a 100644 --- a/src/sage/combinat/recognizable_series.py +++ b/src/sage/combinat/recognizable_series.py @@ -1282,7 +1282,7 @@ def _add_(self, other): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), ....: vector([1, 0]), vector([1, 1])) sage: E @@ -1321,7 +1321,7 @@ def _neg_(self): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), ....: vector([1, 0]), vector([1, 1])) sage: -E @@ -1348,7 +1348,7 @@ def _rmul_(self, other): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), ....: vector([1, 0]), vector([1, 1])) sage: M = 2 * E # indirect doctest @@ -1412,7 +1412,7 @@ def _lmul_(self, other): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), ....: vector([1, 0]), vector([1, 1])) sage: M = E * 2 # indirect doctest @@ -1482,7 +1482,7 @@ def hadamard_product(self, other): EXAMPLES:: - sage: Seq2 = kRegularSequenceSpace(2, ZZ) + sage: Seq2 = RegularSequenceRing(2, ZZ) sage: E = Seq2((Matrix([[0, 1], [0, 1]]), Matrix([[0, 0], [0, 1]])), ....: vector([1, 0]), vector([1, 1])) From c079adaf27eb855e7f8cc6badee3f653028c9962 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Mon, 31 Jul 2023 18:38:10 +0200 Subject: [PATCH 53/87] rename to RegularSequence --- src/sage/combinat/k_regular_sequence.py | 40 ++++++++++++------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 49f2d6c62bb..576b8ee4f79 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -157,7 +157,7 @@ def value(D, k): class DegeneratedSequenceError(RuntimeError): r""" Exception raised if a degenerated sequence - (see :meth:`~kRegularSequence.is_degenerated`) is detected. + (see :meth:`~RegularSequence.is_degenerated`) is detected. EXAMPLES:: @@ -173,7 +173,7 @@ class DegeneratedSequenceError(RuntimeError): pass -class kRegularSequence(RecognizableSeries): +class RegularSequence(RecognizableSeries): def __init__(self, parent, mu, left=None, right=None): r""" A `k`-regular sequence. @@ -410,7 +410,7 @@ def regenerated(self): OUTPUT: - A :class:`kRegularSequence` + A :class:`RegularSequence` ALGORITHM: @@ -502,7 +502,7 @@ def transposed(self, allow_degenerated_sequence=False): OUTPUT: - A :class:`kRegularSequence` + A :class:`RegularSequence` Each of the matrices in :meth:`mu ` is transposed. Additionally the vectors :meth:`left ` and :meth:`right ` are switched. @@ -553,7 +553,7 @@ def _minimized_right_(self): OUTPUT: - A :class:`kRegularSequence` + A :class:`RegularSequence` .. SEEALSO:: @@ -591,7 +591,7 @@ def subsequence(self, a, b): OUTPUT: - A :class:`kRegularSequence` + A :class:`RegularSequence` .. NOTE:: @@ -864,7 +864,7 @@ def shift_left(self, b=1, **kwds): OUTPUT: - A :class:`kRegularSequence` + A :class:`RegularSequence` .. NOTE:: @@ -910,7 +910,7 @@ def shift_right(self, b=1, **kwds): OUTPUT: - A :class:`kRegularSequence` + A :class:`RegularSequence` .. NOTE:: @@ -958,7 +958,7 @@ def backward_differences(self, **kwds): OUTPUT: - A :class:`kRegularSequence` + A :class:`RegularSequence` .. NOTE:: @@ -999,7 +999,7 @@ def forward_differences(self, **kwds): OUTPUT: - A :class:`kRegularSequence` + A :class:`RegularSequence` EXAMPLES:: @@ -1032,7 +1032,7 @@ def _mul_(self, other): INPUT: - - ``other`` -- a :class:`kRegularSequence` + - ``other`` -- a :class:`RegularSequence` - ``minimize`` -- (default: ``None``) a boolean or ``None``. If ``True``, then :meth:`~RecognizableSeries.minimized` is called after the operation, @@ -1041,7 +1041,7 @@ def _mul_(self, other): OUTPUT: - A :class:`kRegularSequence` + A :class:`RegularSequence` ALGORITHM: @@ -1151,7 +1151,7 @@ def partial_sums(self, include_n=False): OUTPUT: - A :class:`kRegularSequence` + A :class:`RegularSequence` EXAMPLES:: @@ -1312,9 +1312,9 @@ class RegularSequenceRing(RecognizableSeriesSpace): .. SEEALSO:: :doc:`k-regular sequence `, - :class:`kRegularSequence`. + :class:`RegularSequence`. """ - Element = kRegularSequence + Element = RegularSequence @classmethod def __normalize__(cls, k, @@ -1372,7 +1372,7 @@ def __init__(self, k, *args, **kwds): .. SEEALSO:: :doc:`k-regular sequence `, - :class:`kRegularSequence`. + :class:`RegularSequence`. """ self.k = k super().__init__(*args, **kwds) @@ -1546,7 +1546,7 @@ def guess(self, f, n_verify=100, max_exponent=10, sequence=None): OUTPUT: - A :class:`kRegularSequence` + A :class:`RegularSequence` ALGORITHM: @@ -2060,7 +2060,7 @@ def from_recurrence(self, *args, **kwds): in [HKL2022]_, Corollary D. All inhomogeneities have to be regular sequences from ``self`` or elements of ``coefficient_ring``. - OUTPUT: a :class:`kRegularSequence` + OUTPUT: a :class:`RegularSequence` EXAMPLES: @@ -2324,7 +2324,7 @@ class RecurrenceParser(): for the sequence satisfying these recurrence relations. This is used by :meth:`RegularSequenceRing.from_recurrence` - to construct a :class:`kRegularSequence`. + to construct a :class:`RegularSequence`. """ def __init__(self, k, coefficient_ring): @@ -4109,7 +4109,7 @@ def __call__(self, *args, **kwds): This is the main method of :class:`RecurrenceParser` and is called by :meth:`RegularSequenceRing.from_recurrence` - to construct a :class:`kRegularSequence`. + to construct a :class:`RegularSequence`. INPUT: From 88f0ba4c1fc1c18b5579851e2607c1b8b6d6bf06 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 1 Aug 2023 09:40:38 +0200 Subject: [PATCH 54/87] rename to src/sage/combinat/regular_sequence.py --- src/sage/combinat/{k_regular_sequence.py => regular_sequence.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/sage/combinat/{k_regular_sequence.py => regular_sequence.py} (100%) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/regular_sequence.py similarity index 100% rename from src/sage/combinat/k_regular_sequence.py rename to src/sage/combinat/regular_sequence.py From 4c7c29c12f7698dd323e4d912d95ea02e6ba1640 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 1 Aug 2023 09:47:30 +0200 Subject: [PATCH 55/87] rename follow-up: adapt new path in sources --- src/doc/en/reference/combinat/module_list.rst | 2 +- src/sage/combinat/all.py | 2 +- src/sage/combinat/recognizable_series.py | 2 +- src/sage/combinat/regular_sequence.py | 38 +++++++++---------- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst index a4f05a0fdc7..92ae74b30db 100644 --- a/src/doc/en/reference/combinat/module_list.rst +++ b/src/doc/en/reference/combinat/module_list.rst @@ -143,7 +143,6 @@ Comprehensive Module List sage/combinat/integer_vector_weighted sage/combinat/integer_vectors_mod_permgroup sage/combinat/interval_posets - sage/combinat/k_regular_sequence sage/combinat/k_tableau sage/combinat/kazhdan_lusztig sage/combinat/key_polynomial @@ -206,6 +205,7 @@ Comprehensive Module List sage/combinat/quickref sage/combinat/ranker sage/combinat/recognizable_series + sage/combinat/regular_sequence sage/combinat/restricted_growth sage/combinat/ribbon sage/combinat/ribbon_shaped_tableau diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 27d4926f1cd..79690ff7305 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -277,7 +277,7 @@ lazy_import('sage.combinat.binary_recurrence_sequences', 'BinaryRecurrenceSequence') lazy_import('sage.combinat.recognizable_series', 'RecognizableSeriesSpace') -lazy_import('sage.combinat.k_regular_sequence', 'RegularSequenceRing') +lazy_import('sage.combinat.regular_sequence', 'RegularSequenceRing') # Six Vertex Model lazy_import('sage.combinat.six_vertex_model', 'SixVertexModel') diff --git a/src/sage/combinat/recognizable_series.py b/src/sage/combinat/recognizable_series.py index 95e77c8f11a..ba100089379 100644 --- a/src/sage/combinat/recognizable_series.py +++ b/src/sage/combinat/recognizable_series.py @@ -33,7 +33,7 @@ .. SEEALSO:: - :mod:`k-regular sequence `, + :mod:`k-regular sequence `, :mod:`sage.rings.cfinite_sequence`, :mod:`sage.combinat.binary_recurrence_sequences`. diff --git a/src/sage/combinat/regular_sequence.py b/src/sage/combinat/regular_sequence.py index 576b8ee4f79..1d10d6efc2f 100644 --- a/src/sage/combinat/regular_sequence.py +++ b/src/sage/combinat/regular_sequence.py @@ -110,7 +110,7 @@ def pad_right(T, length, zero=0): EXAMPLES:: - sage: from sage.combinat.k_regular_sequence import pad_right + sage: from sage.combinat.regular_sequence import pad_right sage: pad_right((1, 2, 3), 10) (1, 2, 3, 0, 0, 0, 0, 0, 0, 0) sage: pad_right((1, 2, 3), 2) @@ -147,7 +147,7 @@ def value(D, k): EXAMPLES:: - sage: from sage.combinat.k_regular_sequence import value + sage: from sage.combinat.regular_sequence import value sage: value(42.digits(7), 7) 42 """ @@ -229,7 +229,7 @@ def __init__(self, parent, mu, left=None, right=None): .. SEEALSO:: - :doc:`k-regular sequence `, + :doc:`k-regular sequence `, :class:`RegularSequenceRing`. TESTS:: @@ -1281,7 +1281,7 @@ def _pickle_RegularSequenceRing(k, coefficients, category): TESTS:: sage: Seq2 = RegularSequenceRing(2, ZZ) - sage: from sage.combinat.k_regular_sequence import _pickle_RegularSequenceRing + sage: from sage.combinat.regular_sequence import _pickle_RegularSequenceRing sage: _pickle_RegularSequenceRing( ....: Seq2.k, Seq2.coefficient_ring(), Seq2.category()) Space of 2-regular sequences over Integer Ring @@ -1311,7 +1311,7 @@ class RegularSequenceRing(RecognizableSeriesSpace): .. SEEALSO:: - :doc:`k-regular sequence `, + :doc:`k-regular sequence `, :class:`RegularSequence`. """ Element = RegularSequence @@ -1371,7 +1371,7 @@ def __init__(self, k, *args, **kwds): .. SEEALSO:: - :doc:`k-regular sequence `, + :doc:`k-regular sequence `, :class:`RegularSequence`. """ self.k = k @@ -2342,9 +2342,9 @@ def __init__(self, k, coefficient_ring): TESTS:: - sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: from sage.combinat.regular_sequence import RecurrenceParser sage: RecurrenceParser(2, ZZ) - + """ self.k = k self.coefficient_ring = coefficient_ring @@ -2368,7 +2368,7 @@ def parse_recurrence(self, equations, function, var): EXAMPLES:: - sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: from sage.combinat.regular_sequence import RecurrenceParser sage: RP = RecurrenceParser(2, ZZ) sage: var('n') n @@ -2949,7 +2949,7 @@ def parse_direct_arguments(self, M, m, coeffs, initial_values): EXAMPLES:: - sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: from sage.combinat.regular_sequence import RecurrenceParser sage: RP = RecurrenceParser(2, ZZ) sage: RP.parse_direct_arguments(2, 1, ....: {(0, -2): 3, (0, 0): 1, (0, 1): 2, @@ -3143,7 +3143,7 @@ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}) EXAMPLES:: - sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: from sage.combinat.regular_sequence import RecurrenceParser sage: RP = RecurrenceParser(2, ZZ) sage: RP.parameters(2, 1, ....: {(0, -2): 3, (0, 0): 1, (0, 1): 2, (1, -2): 6, (1, 0): 4, @@ -3345,7 +3345,7 @@ def values(self, *, M, m, l, u, ll, coeffs, Stern--Brocot Sequence:: - sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: from sage.combinat.regular_sequence import RecurrenceParser sage: RP = RecurrenceParser(2, ZZ) sage: RP.values(M=1, m=0, l=0, u=1, ll=0, ....: coeffs={(0, 0): 1, (1, 0): 1, (1, 1): 1}, @@ -3531,7 +3531,7 @@ def ind(self, M, m, ll, uu): EXAMPLES:: - sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: from sage.combinat.regular_sequence import RecurrenceParser sage: RP = RecurrenceParser(2, ZZ) sage: RP.ind(3, 1, -3, 3) {(0, 0): 0, (1, -1): 3, (1, -2): 2, (1, -3): 1, @@ -3594,7 +3594,7 @@ def shifted_inhomogeneities(self, recurrence_rules): EXAMPLES:: sage: from collections import namedtuple - sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: from sage.combinat.regular_sequence import RecurrenceParser sage: RP = RecurrenceParser(2, ZZ) sage: Seq2 = RegularSequenceRing(2, ZZ) sage: S = Seq2((Matrix([[1, 0], [0, 1]]), Matrix([[1, 0], [1, 1]])), @@ -3698,7 +3698,7 @@ def v_eval_n(self, recurrence_rules, n): Stern--Brocot Sequence:: - sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: from sage.combinat.regular_sequence import RecurrenceParser sage: RP = RecurrenceParser(2, ZZ) sage: SB_rules = RP.parameters( ....: 1, 0, {(0, 0): 1, (1, 0): 1, (1, 1): 1}, @@ -3762,7 +3762,7 @@ def matrix(self, recurrence_rules, rem, correct_offset=True): right-hand sides of the recurrence relations correspond to the entries of the matrices. :: - sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: from sage.combinat.regular_sequence import RecurrenceParser sage: RP = RecurrenceParser(2, ZZ) sage: var('n') n @@ -4005,7 +4005,7 @@ def left(self, recurrence_rules): EXAMPLES:: sage: from collections import namedtuple - sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: from sage.combinat.regular_sequence import RecurrenceParser sage: RP = RecurrenceParser(2, ZZ) sage: RRD = namedtuple('recurrence_rules_dim', ....: ['dim', 'inhomogeneities']) @@ -4059,7 +4059,7 @@ def right(self, recurrence_rules): Stern--Brocot Sequence:: - sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: from sage.combinat.regular_sequence import RecurrenceParser sage: RP = RecurrenceParser(2, ZZ) sage: var('n') n @@ -4123,7 +4123,7 @@ def __call__(self, *args, **kwds): TESTS:: - sage: from sage.combinat.k_regular_sequence import RecurrenceParser + sage: from sage.combinat.regular_sequence import RecurrenceParser sage: RP = RecurrenceParser(2, ZZ) sage: var('n') n From cd04076827a14c9642a922ea65e81aef86da78cc Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Tue, 1 Aug 2023 10:00:56 +0200 Subject: [PATCH 56/87] consistent title of module --- src/sage/combinat/regular_sequence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/regular_sequence.py b/src/sage/combinat/regular_sequence.py index 1d10d6efc2f..59dd21d81b7 100644 --- a/src/sage/combinat/regular_sequence.py +++ b/src/sage/combinat/regular_sequence.py @@ -1,6 +1,6 @@ # sage.doctest: optional - sage.combinat sage.modules sage.symbolic r""" -`k`-regular Sequences +`k`-regular sequences An introduction and formal definition of `k`-regular sequences can be found, for example, on the :wikipedia:`k-regular_sequence` or in From 214d9102396497c93da5db16c46b286de1267232 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 1 Aug 2023 11:14:20 -0700 Subject: [PATCH 57/87] # 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 58/87] 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 59/87] 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 From 590c29ee41a91648454797cba3e278722283b35b Mon Sep 17 00:00:00 2001 From: Antonio Rojas Date: Tue, 1 Aug 2023 21:34:43 +0200 Subject: [PATCH 60/87] Fix version, add link to PR --- src/sage/rings/polynomial/multi_polynomial_ideal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 58ebb0a6002..c799d2530e3 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -2446,7 +2446,7 @@ def saturation(self, other): (Ideal (y, x^5) of Multivariate Polynomial Ring in x, y, z over Algebraic Field, 4) """ from sage.libs.singular.function_factory import ff - # function renamed in singular > 4.2.3p4 + # function renamed in singular > 4.3.2p4, see https://github.com/sagemath/sage/pull/35980 try: sat = ff.elim__lib.sat_with_exp except NameError: From 94bbe17282732a8152ca153f1b970356ee69f46c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 1 Aug 2023 15:17:32 -0700 Subject: [PATCH 61/87] pkgs/sagemath*/MANIFEST.in: Exclude all__*.py files of other distributions --- pkgs/sagemath-bliss/MANIFEST.in | 5 +++-- pkgs/sagemath-categories/MANIFEST.in.m4 | 4 +++- pkgs/sagemath-coxeter3/MANIFEST.in | 5 +++-- pkgs/sagemath-environment/MANIFEST.in | 12 ++++++++++-- pkgs/sagemath-mcqd/MANIFEST.in | 5 +++-- pkgs/sagemath-meataxe/MANIFEST.in | 5 +++-- pkgs/sagemath-objects/MANIFEST.in | 4 ++-- pkgs/sagemath-repl/MANIFEST.in | 5 +++-- pkgs/sagemath-sirocco/MANIFEST.in | 5 +++-- pkgs/sagemath-tdlib/MANIFEST.in | 5 +++-- 10 files changed, 36 insertions(+), 19 deletions(-) diff --git a/pkgs/sagemath-bliss/MANIFEST.in b/pkgs/sagemath-bliss/MANIFEST.in index 689b87560e0..6d981b9d30e 100644 --- a/pkgs/sagemath-bliss/MANIFEST.in +++ b/pkgs/sagemath-bliss/MANIFEST.in @@ -1,5 +1,3 @@ -global-include all__sagemath_bliss.py - include VERSION.txt graft sage/graphs/bliss_cpp @@ -7,6 +5,9 @@ graft sage/graphs/bliss_cpp global-exclude *.c global-exclude *.cpp +global-exclude all__sagemath_*.* +global-include all__sagemath_bliss.py + global-exclude __pycache__ global-exclude *.py[co] global-exclude *.bak diff --git a/pkgs/sagemath-categories/MANIFEST.in.m4 b/pkgs/sagemath-categories/MANIFEST.in.m4 index 361132e0cfa..b2e35673ec0 100644 --- a/pkgs/sagemath-categories/MANIFEST.in.m4 +++ b/pkgs/sagemath-categories/MANIFEST.in.m4 @@ -3,7 +3,6 @@ prune sage include VERSION.txt -global-include all__sagemath_categories.py graft sage/categories # Exclude what is already shipped in sagemath-objects exclude sage/categories/action.* @@ -42,6 +41,9 @@ graft sage/typeset # dep of sage.categories.tensor global-exclude *.c global-exclude *.cpp +global-exclude all__sagemath_*.* +global-include all__sagemath_categories.py + global-exclude __pycache__ global-exclude *.py[co] global-exclude *.bak diff --git a/pkgs/sagemath-coxeter3/MANIFEST.in b/pkgs/sagemath-coxeter3/MANIFEST.in index 003ab8d5180..a69f2e71363 100644 --- a/pkgs/sagemath-coxeter3/MANIFEST.in +++ b/pkgs/sagemath-coxeter3/MANIFEST.in @@ -1,7 +1,5 @@ prune sage -global-include all__sagemath_coxeter3.py - include VERSION.txt graft sage/libs/coxeter3 @@ -9,6 +7,9 @@ graft sage/libs/coxeter3 global-exclude *.c global-exclude *.cpp +global-exclude all__sagemath_*.* +global-include all__sagemath_coxeter3.py + global-exclude __pycache__ global-exclude *.py[co] global-exclude *.bak diff --git a/pkgs/sagemath-environment/MANIFEST.in b/pkgs/sagemath-environment/MANIFEST.in index 36f8fae1845..ca4266e2bf4 100644 --- a/pkgs/sagemath-environment/MANIFEST.in +++ b/pkgs/sagemath-environment/MANIFEST.in @@ -1,7 +1,5 @@ prune sage -global-include all__sagemath_environment.py - include sage/env.py include sage/version.py include sage/misc/package.py @@ -12,4 +10,14 @@ graft sage/features include VERSION.txt +global-exclude all__*.py +global-include all__sagemath_environment.py + +global-exclude __pycache__ global-exclude *.py[co] +global-exclude *.bak +global-exclude *.so +global-exclude *~ +prune .tox +prune build +prune dist diff --git a/pkgs/sagemath-mcqd/MANIFEST.in b/pkgs/sagemath-mcqd/MANIFEST.in index 392d97b78e0..801e1b3e48d 100644 --- a/pkgs/sagemath-mcqd/MANIFEST.in +++ b/pkgs/sagemath-mcqd/MANIFEST.in @@ -1,7 +1,5 @@ prune sage -global-include all__sagemath_mcqd.py - include VERSION.txt include sage/graphs/mcqd.p* @@ -9,6 +7,9 @@ include sage/graphs/mcqd.p* global-exclude *.c global-exclude *.cpp +global-exclude all__sagemath_*.* +global-include all__sagemath_mcqd.py + global-exclude __pycache__ global-exclude *.py[co] global-exclude *.bak diff --git a/pkgs/sagemath-meataxe/MANIFEST.in b/pkgs/sagemath-meataxe/MANIFEST.in index 4cf78dd5d02..c69ce68fc40 100644 --- a/pkgs/sagemath-meataxe/MANIFEST.in +++ b/pkgs/sagemath-meataxe/MANIFEST.in @@ -1,7 +1,5 @@ prune sage -global-include all__sagemath_meataxe.py - include VERSION.txt include sage/libs/meataxe.p* @@ -10,6 +8,9 @@ include sage/matrix/matrix_gfpn_dense.p* global-exclude *.c global-exclude *.cpp +global-exclude all__sagemath_*.* +global-include all__sagemath_meataxe.py + global-exclude __pycache__ global-exclude *.py[co] global-exclude *.bak diff --git a/pkgs/sagemath-objects/MANIFEST.in b/pkgs/sagemath-objects/MANIFEST.in index 00c5e0dc4a1..98b6910849a 100644 --- a/pkgs/sagemath-objects/MANIFEST.in +++ b/pkgs/sagemath-objects/MANIFEST.in @@ -3,8 +3,6 @@ graft sage/cpython include VERSION.txt -global-include all__sagemath_objects.py - graft sage/structure include sage/categories/action.* include sage/categories/algebra_functor.* @@ -85,6 +83,8 @@ graft sage/libs/gmp include sage/misc/misc.* # some_tuples used in sage.misc.sage_unittest include sage/misc/timing.p* # walltime, cputime used in sage.doctest +global-exclude all__*.py +global-include all__sagemath_objects.py global-exclude *.c global-exclude *.cpp diff --git a/pkgs/sagemath-repl/MANIFEST.in b/pkgs/sagemath-repl/MANIFEST.in index c54f63b15ee..ba331ec2931 100644 --- a/pkgs/sagemath-repl/MANIFEST.in +++ b/pkgs/sagemath-repl/MANIFEST.in @@ -1,7 +1,5 @@ prune sage -global-include all__sagemath_repl.py - graft sage/doctest graft sage/repl include sage/misc/banner.py @@ -11,6 +9,9 @@ include sage/misc/sage_eval.py include VERSION.txt +global-exclude all__*.py +global-include all__sagemath_repl.py + global-exclude __pycache__ global-exclude *.py[co] global-exclude *.bak diff --git a/pkgs/sagemath-sirocco/MANIFEST.in b/pkgs/sagemath-sirocco/MANIFEST.in index 7fab4dffc5d..815a868524d 100644 --- a/pkgs/sagemath-sirocco/MANIFEST.in +++ b/pkgs/sagemath-sirocco/MANIFEST.in @@ -1,10 +1,11 @@ -global-include all__sagemath_sirocco.py - include VERSION.txt global-exclude *.c global-exclude *.cpp +global-exclude all__sagemath_*.* +global-include all__sagemath_sirocco.py + global-exclude __pycache__ global-exclude *.py[co] global-exclude *.bak diff --git a/pkgs/sagemath-tdlib/MANIFEST.in b/pkgs/sagemath-tdlib/MANIFEST.in index f3fbc97a588..614186d89ab 100644 --- a/pkgs/sagemath-tdlib/MANIFEST.in +++ b/pkgs/sagemath-tdlib/MANIFEST.in @@ -1,5 +1,3 @@ -global-include all__sagemath_tdlib.py - include VERSION.txt global-exclude *.c @@ -7,6 +5,9 @@ global-exclude *.cpp include sage/graphs/graph_decompositions/sage_tdlib.cpp +global-exclude all__sagemath_*.* +global-include all__sagemath_tdlib.py + global-exclude __pycache__ global-exclude *.py[co] global-exclude *.bak From 832614025b2af662b595b15e3bb8e2c6808bcd02 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Wed, 2 Aug 2023 09:32:37 +0900 Subject: [PATCH 62/87] Use previously declared SAGE_SRC --- src/bin/sage-runtests | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/sage-runtests b/src/bin/sage-runtests index 9409bb38da8..7be6a587624 100755 --- a/src/bin/sage-runtests +++ b/src/bin/sage-runtests @@ -172,9 +172,9 @@ if __name__ == "__main__": if args.verbose: pytest_options.append("-v") - # #35999: no filenames in arguments is equivalent to "src" + # #35999: no filename in arguments defaults to "src" if not args.filenames: - filenames = [os.environ.get('SAGE_SRC')] + filenames = [SAGE_SRC] else: # #31924: Do not run pytest on individual Python files unless # they match the pytest file pattern. However, pass names From b194d33e7335f7a4783dc298de0e8787122ab851 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 1 Aug 2023 20:09:15 -0700 Subject: [PATCH 63/87] .github/workflows/build.yml: Run make build after testing the modularized distribution, before testing --- .github/workflows/build.yml | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8d936616077..ada020d8722 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -103,12 +103,24 @@ jobs: run: pyright working-directory: ./worktree-image - - name: Build (fallback to non-incremental) - id: build + - name: Clean (fallback to non-incremental) + id: clean if: always() && steps.worktree.outcome == 'success' && steps.incremental.outcome != 'success' run: | set -ex - ./bootstrap && make doc-clean doc-uninstall sagelib-clean && git clean -fx src/sage && ./config.status && make build + ./bootstrap && make doc-clean doc-uninstall sagelib-clean && git clean -fx src/sage && ./config.status + working-directory: ./worktree-image + env: + MAKE: make -j2 + SAGE_NUM_THREADS: 2 + + - name: Build + # This step is needed because building the modularized distributions installs some optional packages, + # so the editable install of sagelib needs to build the corresponding optional extension modules. + id: build + if: always() && (steps.incremental.outcome == 'success' || steps.clean.outcome == 'success') + run: | + make build working-directory: ./worktree-image env: MAKE: make -j2 @@ -125,14 +137,14 @@ jobs: COLUMNS: 120 - name: Test all files (sage -t --all --long) - if: always() && (steps.incremental.outcome == 'success' || steps.build.outcome == 'success') + if: always() && steps.build.outcome == 'success' run: | ../sage -python -m pip install coverage ../sage -python -m coverage run ./bin/sage-runtests --all --long -p2 --random-seed=286735480429121101562228604801325644303 working-directory: ./worktree-image/src - name: Prepare coverage results - if: always() && (steps.incremental.outcome == 'success' || steps.build.outcome == 'success') + if: always() && steps.build.outcome == 'success' run: | ./venv/bin/python3 -m coverage combine src/.coverage/ ./venv/bin/python3 -m coverage xml @@ -140,7 +152,7 @@ jobs: working-directory: ./worktree-image - name: Upload coverage to codecov - if: always() && (steps.incremental.outcome == 'success' || steps.build.outcome == 'success') + if: always() && steps.build.outcome == 'success' uses: codecov/codecov-action@v3 with: files: ./worktree-image/coverage.xml From 535b63a2da9adba5174ec08600d235accb89de09 Mon Sep 17 00:00:00 2001 From: Antonio Rojas Date: Wed, 2 Aug 2023 08:19:54 +0200 Subject: [PATCH 64/87] Improve comment --- src/sage/rings/polynomial/multi_polynomial_ideal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index c799d2530e3..76ca6021a22 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -2446,7 +2446,7 @@ def saturation(self, other): (Ideal (y, x^5) of Multivariate Polynomial Ring in x, y, z over Algebraic Field, 4) """ from sage.libs.singular.function_factory import ff - # function renamed in singular > 4.3.2p4, see https://github.com/sagemath/sage/pull/35980 + # function renamed in singular > 4.3.2p4, see issue #35980 try: sat = ff.elim__lib.sat_with_exp except NameError: From 767fc2c6d7571513b1ff268c774ddd0f7b4a8c42 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 2 Aug 2023 09:30:12 +0100 Subject: [PATCH 65/87] fix accidental damage to classical_geometries.py from 94bca97cfe9 G was renamed to g in 3 places in docs of CossidentePenttilaGraph --- src/sage/graphs/generators/classical_geometries.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index 680402dc476..e473c3a5524 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -1264,19 +1264,19 @@ def CossidentePenttilaGraph(q): For `q=3` one gets Sims-Gewirtz graph. :: - sage: g = graphs.CossidentePenttilaGraph(3) # optional - gap_packages (grape) + sage: G = graphs.CossidentePenttilaGraph(3) # optional - gap_packages (grape) sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) (56, 10, 0, 2) For `q>3` one gets new graphs. :: - sage: g = graphs.CossidentePenttilaGraph(5) # optional - gap_packages (grape) + sage: G = graphs.CossidentePenttilaGraph(5) # optional - gap_packages (grape) sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) (378, 52, 1, 8) TESTS:: - sage: g = graphs.CossidentePenttilaGraph(7) # optional - gap_packages (grape) # long time + sage: G = graphs.CossidentePenttilaGraph(7) # optional - gap_packages (grape) # long time sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) # long time (1376, 150, 2, 18) sage: graphs.CossidentePenttilaGraph(2) From 50baf64b75369ccac66a1340ea593d11f14a772e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 12 Jul 2023 12:49:39 -0700 Subject: [PATCH 66/87] src/bin/sage-fixdoctests: Do not act on 'NameError: x' --- src/bin/sage-fixdoctests | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bin/sage-fixdoctests b/src/bin/sage-fixdoctests index 0c06d448887..a644c6e4d10 100755 --- a/src/bin/sage-fixdoctests +++ b/src/bin/sage-fixdoctests @@ -224,6 +224,8 @@ def process_block(block, src_in_lines, file_optional_tags): # NameError from top level, so keep it brief if m := re.match("NameError: name '(.*)'", got[index_NameError:]): name = m.group(1) + if name == 'x': # Don't mark it '# needs sage.symbolic'; that's almost always wrong + return if feature := name_feature(name): add_tags = [feature.name] else: From 7302ff3ac8834961cc703d7e48770c053d846438 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 12 Jul 2023 16:09:02 -0700 Subject: [PATCH 67/87] src/bin/sage-fixdoctests: Run doctester for all files in parallel, handle directories --- src/bin/sage-fixdoctests | 85 ++++++++++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 30 deletions(-) diff --git a/src/bin/sage-fixdoctests b/src/bin/sage-fixdoctests index a644c6e4d10..074eb280347 100755 --- a/src/bin/sage-fixdoctests +++ b/src/bin/sage-fixdoctests @@ -40,7 +40,7 @@ import sys from argparse import ArgumentParser, FileType from pathlib import Path -from sage.doctest.control import skipfile +from sage.doctest.control import DocTestDefaults, DocTestController from sage.doctest.parsing import parse_file_optional_tags, parse_optional_tags, unparse_optional_tags, update_optional_tags from sage.env import SAGE_ROOT from sage.features import PythonModule @@ -307,17 +307,21 @@ def process_block(block, src_in_lines, file_optional_tags): # set input and output files -if len(args.filename) == 2 and not args.overwrite and not args.no_overwrite: - inputs, outputs = [args.filename[0]], [args.filename[1]] - print("sage-fixdoctests: When passing two filenames, the second one is taken as an output filename; " - "this is deprecated. To pass two input filenames, use the option --overwrite.") -elif args.no_overwrite: - inputs, outputs = args.filename, [input + ".fixed" for input in args.filename] -else: - inputs = outputs = args.filename +def output_filename(filename): + if len(args.filename) == 2 and not args.overwrite and not args.no_overwrite: + if args.filename[0] == filename: + print("sage-fixdoctests: When passing two filenames, the second one is taken as an output filename; " + "this is deprecated. To pass two input filenames, use the option --overwrite.") + return args.filename[1] + return filename + ".fixed" + if args.no_overwrite: + return filename + ".fixed" + return filename # Test the doctester, putting the output of the test into sage's temporary directory -if not args.no_test: +if args.no_test: + doc_out = '' +else: executable = f'{os.path.relpath(args.venv)}/bin/sage' if args.venv else 'sage' environment_args = f'--environment {args.environment} ' if args.environment != runtest_default_environment else '' long_args = f'--long ' if args.long else '' @@ -331,38 +335,54 @@ if not args.no_test: if status := os.waitstatus_to_exitcode(os.system(f'{cmdline} > {shlex.quote(doc_file)}')): print(f'Doctester exited with error status {status}') sys.exit(status) + # Run the doctester, putting the output of the test into sage's temporary directory + input_args = " ".join(shlex.quote(f) for f in args.filename) + cmdline = f'{shlex.quote(executable)} -t -p {environment_args}{long_args}{probe_args}{lib_args}{input_args}' + print(f'Running "{cmdline}"') + os.system(f'{cmdline} > {shlex.quote(doc_file)}') -for input, output in zip(inputs, outputs): - if (skipfile_result := skipfile(input, True, log=print)) is True: - continue - - if args.no_test: - doc_out = '' - else: - # Run the doctester, putting the output of the test into sage's temporary directory - cmdline = f'{shlex.quote(executable)} -t {environment_args}{long_args}{probe_args}{lib_args}{shlex.quote(input)}' - print(f'Running "{cmdline}"') - os.system(f'{cmdline} > {shlex.quote(doc_file)}') - - with open(doc_file, 'r') as doc: - doc_out = doc.read() + with open(doc_file, 'r') as doc: + doc_out = doc.read() # echo control messages for m in re.finditer('^Skipping .*', doc_out, re.MULTILINE): print('sage-runtests: ' + m.group(0)) - break - else: - sep = "**********************************************************************\n" - doctests = doc_out.split(sep) + +sep = "**********************************************************************\n" +doctests = doc_out.split(sep) + +seen = set() + +def block_filename(block): + if not (m := re.match('File "([^"]*)", line ([0-9]+), in ', block)): + return None + return m.group(1) + +def expanded_filename_args(): + DD = DocTestDefaults(optional='all') + DC = DocTestController(DD, args.filename) + DC.add_files() + DC.expand_files_into_sources() + for source in DC.sources: + yield source.path + +def process_grouped_blocks(grouped_iterator): + + for input, blocks in grouped_iterator: + + if not input: # Blocks of noise + continue + if input in seen: + continue + seen.add(input) with open(input, 'r') as test_file: src_in = test_file.read() src_in_lines = src_in.splitlines() shallow_copy_of_src_in_lines = list(src_in_lines) - file_optional_tags = set(parse_file_optional_tags(enumerate(src_in_lines))) - for block in doctests: + for block in blocks: process_block(block, src_in_lines, file_optional_tags) # Now source line numbers do not matter any more, and lines can be real lines again @@ -394,6 +414,7 @@ for input, output in zip(inputs, outputs): persistent_optional_tags = {} if src_in_lines != shallow_copy_of_src_in_lines: + output = output_filename(input) with open(output, 'w') as test_output: for line in src_in_lines: if line is None: @@ -411,3 +432,7 @@ for input, output in zip(inputs, outputs): subprocess.call(['git', '--no-pager', 'diff', relative], cwd=SAGE_ROOT) else: print(f"No fixes made in '{input}'") + +process_grouped_blocks( + itertools.chain(itertools.groupby(doctests, block_filename), + ((filename, []) for filename in expanded_filename_args()))) From 255e2d82ac247ecb6cb0642397c7d23cd62bca88 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 16 Jul 2023 21:08:16 -0700 Subject: [PATCH 68/87] sage -fixdoctests: Handle ImportError too --- src/bin/sage-fixdoctests | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/bin/sage-fixdoctests b/src/bin/sage-fixdoctests index 074eb280347..3a0b904b8b3 100755 --- a/src/bin/sage-fixdoctests +++ b/src/bin/sage-fixdoctests @@ -189,8 +189,12 @@ def process_block(block, src_in_lines, file_optional_tags): return # Error testing. - if m := re.search(r"ModuleNotFoundError: No module named '([^']*)'", block): - module = m.group(1) + if m := re.search(r"(?:ModuleNotFoundError: No module named|ImportError: cannot import name '([^']*)' from) '([^']*)'", block): + if m.group(1): + # "ImportError: cannot import name 'function_field_polymod' from 'sage.rings.function_field' (unknown location)" + module = m.group(2) + '.' + m.group(1) + else: + module = m.group(2) asked_why = re.search('#.*(why|explain)', src_in_lines[first_line_num - 1]) optional = module_feature(module) if optional and optional.name not in file_optional_tags: From f631de2af8b58859bab72d116198eaae8e951d17 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 15 Jul 2023 16:07:49 -0700 Subject: [PATCH 69/87] sage -t --if-installed: Ignore all files except .py and .pyx --- src/sage/doctest/control.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index 4844662073d..9261c69dd4b 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -281,6 +281,10 @@ def skipfile(filename, tested_optional_tags=False, *, if log: log(f"Skipping '{filename}' because it does not have one of the recognized file name extensions") return True + if if_installed and ext not in ('.py', '.pyx'): + if log: + log(f"Skipping '{filename}' because it is not the source file of a Python module") + return True if "jupyter_execute" in filename: if log: log(f"Skipping '{filename}' because it is created by the jupyter-sphinx extension for internal use and should not be tested") From 771be4bacb6ce300a7e5b3c42e01b433b09cd45a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 2 Aug 2023 20:19:20 +0200 Subject: [PATCH 70/87] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index da504962c4c..17e405190d6 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ your Windows. Make sure you allocate WSL sufficient RAM; 5GB is known to work, w Then all instructions for installation in Linux apply. As an alternative, you can also run Linux on Windows using Docker (see -above) or other virtualization solutions. +below) or other virtualization solutions. [macOS] Preparing the Platform ------------------------------ @@ -416,12 +416,12 @@ You need to install `sage_conf`, a wheelhouse of various python packages. You ca **NOTE:** You can find `sage` and `sagemath` pip packages but with these packages, you will encounter `ModuleNotFoundError`. -Sagemath Docker image ---------------------- +SageMath Docker images +---------------------- [![Docker Status](http://dockeri.co/image/sagemath/sagemath)](https://hub.docker.com/r/sagemath/sagemath) -Sagemath is available on Docker Hub and can be downloaded by: +SageMath is available on Docker Hub and can be downloaded by: ``` bash docker pull sagemath/sagemath ``` From b0be9aaede582f887d3575fd4600fa93a2c3f3f4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 4 Jul 2023 19:45:51 -0700 Subject: [PATCH 71/87] ./sage -fixdoctests --probe all --distribution sagemath-graphs --only-tags src/sage/graphs/generators/classical_geometries.py; ./sage -fixdoctests src/sage/graphs/generators/classical_geometries.py --- .../graphs/generators/classical_geometries.py | 335 ++++++++++-------- 1 file changed, 179 insertions(+), 156 deletions(-) diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index 680402dc476..4e2b861b423 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -51,7 +51,7 @@ def SymplecticPolarGraph(d, q, algorithm=None): sage: g = graphs.SymplecticPolarGraph(6,2) sage: g.is_strongly_regular(parameters=True) (63, 30, 13, 15) - sage: set(g.spectrum()) == {-5, 3, 30} + sage: set(g.spectrum()) == {-5, 3, 30} # needs sage.rings.number_field True The parameters of `Sp(4,q)` are the same as of `O(5,q)`, but they are @@ -60,20 +60,32 @@ def SymplecticPolarGraph(d, q, algorithm=None): sage: G = graphs.SymplecticPolarGraph(4,3) sage: G.is_strongly_regular(parameters=True) (40, 12, 2, 4) - sage: O = graphs.OrthogonalPolarGraph(5,3) - sage: O.is_strongly_regular(parameters=True) + sage: O = graphs.OrthogonalPolarGraph(5,3) # needs sage.libs.gap + sage: O.is_strongly_regular(parameters=True) # optional - EXPECTED (40, 12, 2, 4) - sage: O.is_isomorphic(G) + sage: O.is_strongly_regular(parameters=True) # optional - GOT (with --distribution 'sagemath-graphs[modules]') + Traceback (most recent call last): + ... + File "", line 1, in + O.is_strongly_regular(parameters=True) + AttributeError: 'function' object has no attribute 'is_strongly_regular' + sage: O.is_isomorphic(G) # optional - EXPECTED False - sage: S = graphs.SymplecticPolarGraph(6,4,algorithm="gap") # not tested (long time) # optional - sage.libs.gap - sage: S.is_strongly_regular(parameters=True) # not tested (long time) # optional - sage.libs.gap + sage: O.is_isomorphic(G) # optional - GOT (with --distribution 'sagemath-graphs[modules]') + Traceback (most recent call last): + ... + File "", line 1, in + O.is_isomorphic(G) + AttributeError: 'function' object has no attribute 'is_isomorphic' + sage: S = graphs.SymplecticPolarGraph(6,4,algorithm="gap") # not tested (long time), needs sage.libs.gap + sage: S.is_strongly_regular(parameters=True) # not tested (long time), needs sage.libs.gap (1365, 340, 83, 85) TESTS:: - sage: graphs.SymplecticPolarGraph(4,4,algorithm="gap").is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: graphs.SymplecticPolarGraph(4,4,algorithm="gap").is_strongly_regular(parameters=True) # needs sage.libs.gap (85, 20, 3, 5) - sage: graphs.SymplecticPolarGraph(4,4).is_strongly_regular(parameters=True) + sage: graphs.SymplecticPolarGraph(4,4).is_strongly_regular(parameters=True) # needs sage.libs.pari (85, 20, 3, 5) sage: graphs.SymplecticPolarGraph(4,4,algorithm="blah") Traceback (most recent call last): @@ -147,31 +159,31 @@ def AffineOrthogonalPolarGraph(d, q, sign="+"): The :meth:`Brouwer-Haemers graph ` is isomorphic to `VO^-(4,3)`:: - sage: g = graphs.AffineOrthogonalPolarGraph(4,3,"-") - sage: g.is_isomorphic(graphs.BrouwerHaemersGraph()) + sage: g = graphs.AffineOrthogonalPolarGraph(4,3,"-") # needs sage.libs.gap + sage: g.is_isomorphic(graphs.BrouwerHaemersGraph()) # optional - NameError: 'g' (with --distribution 'sagemath-graphs[modules]') True Some examples from `Brouwer's table or strongly regular graphs `_:: - sage: g = graphs.AffineOrthogonalPolarGraph(6,2,"-"); g + sage: g = graphs.AffineOrthogonalPolarGraph(6,2,"-"); g # needs sage.libs.gap Affine Polar Graph VO^-(6,2): Graph on 64 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # optional - NameError: 'g' (with --distribution 'sagemath-graphs[modules]') (64, 27, 10, 12) - sage: g = graphs.AffineOrthogonalPolarGraph(6,2,"+"); g + sage: g = graphs.AffineOrthogonalPolarGraph(6,2,"+"); g # needs sage.libs.gap Affine Polar Graph VO^+(6,2): Graph on 64 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # optional - NameError: 'g' (with --distribution 'sagemath-graphs[modules]') (64, 35, 18, 20) When ``sign is None``:: - sage: g = graphs.AffineOrthogonalPolarGraph(5,2,None); g + sage: g = graphs.AffineOrthogonalPolarGraph(5,2,None); g # needs sage.libs.gap Affine Polar Graph VO^-(5,2): Graph on 32 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # optional - NameError: 'g' (with --distribution 'sagemath-graphs[modules]') False - sage: g.is_regular() + sage: g.is_regular() # optional - NameError: 'g' (with --distribution 'sagemath-graphs[modules]') True - sage: g.is_vertex_transitive() + sage: g.is_vertex_transitive() # optional - NameError: 'g' (with --distribution 'sagemath-graphs[modules]') True """ if sign in ["+", "-"]: @@ -224,14 +236,14 @@ def _orthogonal_polar_graph(m, q, sign="+", point_type=[0]): Petersen graph:: sage: from sage.graphs.generators.classical_geometries import _orthogonal_polar_graph - sage: g = _orthogonal_polar_graph(3,5,point_type=[2,3]) # optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: g = _orthogonal_polar_graph(3,5,point_type=[2,3]) # needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (10, 3, 0, 1) A locally Petersen graph (a.k.a. Doro graph, a.k.a. Hall graph):: - sage: g = _orthogonal_polar_graph(4,5,'-',point_type=[2,3]) # optional - sage.libs.gap - sage: g.is_distance_regular(parameters=True) # optional - sage.libs.gap + sage: g = _orthogonal_polar_graph(4,5,'-',point_type=[2,3]) # needs sage.libs.gap + sage: g.is_distance_regular(parameters=True) # needs sage.libs.gap ([10, 6, 4, None], [None, 1, 2, 5]) Various big and slow to build graphs: @@ -250,20 +262,20 @@ def _orthogonal_polar_graph(m, q, sign="+", point_type=[0]): `NO^+(6,3)`:: - sage: g = _orthogonal_polar_graph(6,3,point_type=[1]) # optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: g = _orthogonal_polar_graph(6,3,point_type=[1]) # needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (117, 36, 15, 9) `NO^-(6,3)`:: - sage: g = _orthogonal_polar_graph(6,3,'-',point_type=[1]) # optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: g = _orthogonal_polar_graph(6,3,'-',point_type=[1]) # needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (126, 45, 12, 18) `NO^{-,\perp}(5,5)`:: - sage: g = _orthogonal_polar_graph(5,5,point_type=[2,3]) # long time, optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # long time, optional - sage.libs.gap + sage: g = _orthogonal_polar_graph(5,5,point_type=[2,3]) # long time, needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # long time, needs sage.libs.gap (300, 65, 10, 15) `NO^{+,\perp}(5,5)`:: @@ -274,11 +286,12 @@ def _orthogonal_polar_graph(m, q, sign="+", point_type=[0]): TESTS:: - sage: g = _orthogonal_polar_graph(5,3,point_type=[-1]) # optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: # needs sage.libs.gap + sage: g = _orthogonal_polar_graph(5,3,point_type=[-1]) + sage: g.is_strongly_regular(parameters=True) (45, 12, 3, 3) - sage: g = _orthogonal_polar_graph(5,3,point_type=[1]) # optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: g = _orthogonal_polar_graph(5,3,point_type=[1]) + sage: g.is_strongly_regular(parameters=True) (36, 15, 6, 6) """ @@ -342,34 +355,35 @@ def OrthogonalPolarGraph(m, q, sign="+"): EXAMPLES:: - sage: G = graphs.OrthogonalPolarGraph(6,3,"+"); G # optional - sage.libs.gap + sage: # needs sage.libs.gap + sage: G = graphs.OrthogonalPolarGraph(6,3,"+"); G Orthogonal Polar Graph O^+(6, 3): Graph on 130 vertices - sage: G.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: G.is_strongly_regular(parameters=True) (130, 48, 20, 16) - sage: G = graphs.OrthogonalPolarGraph(6,3,"-"); G # optional - sage.libs.gap + sage: G = graphs.OrthogonalPolarGraph(6,3,"-"); G Orthogonal Polar Graph O^-(6, 3): Graph on 112 vertices - sage: G.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: G.is_strongly_regular(parameters=True) (112, 30, 2, 10) - sage: G = graphs.OrthogonalPolarGraph(5,3); G # optional - sage.libs.gap + sage: G = graphs.OrthogonalPolarGraph(5,3); G Orthogonal Polar Graph O(5, 3): Graph on 40 vertices - sage: G.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: G.is_strongly_regular(parameters=True) (40, 12, 2, 4) - sage: G = graphs.OrthogonalPolarGraph(8,2,"+"); G # optional - sage.libs.gap + sage: G = graphs.OrthogonalPolarGraph(8,2,"+"); G Orthogonal Polar Graph O^+(8, 2): Graph on 135 vertices - sage: G.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: G.is_strongly_regular(parameters=True) (135, 70, 37, 35) - sage: G = graphs.OrthogonalPolarGraph(8,2,"-"); G # optional - sage.libs.gap + sage: G = graphs.OrthogonalPolarGraph(8,2,"-"); G Orthogonal Polar Graph O^-(8, 2): Graph on 119 vertices - sage: G.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: G.is_strongly_regular(parameters=True) (119, 54, 21, 27) TESTS:: - sage: G = graphs.OrthogonalPolarGraph(4,3,"") # optional - sage.libs.gap + sage: G = graphs.OrthogonalPolarGraph(4,3,"") # needs sage.libs.gap Traceback (most recent call last): ... ValueError: sign must be equal to either '-' or '+' when m is even - sage: G = graphs.OrthogonalPolarGraph(5,3,"-") # optional - sage.libs.gap + sage: G = graphs.OrthogonalPolarGraph(5,3,"-") # needs sage.libs.gap Traceback (most recent call last): ... ValueError: sign must be equal to either '' or '+' when m is odd @@ -417,43 +431,45 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): `NO^-(4,2)` is isomorphic to Petersen graph:: - sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,2,'-'); g # optional - sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,2,'-'); g # needs sage.libs.gap NO^-(4, 2): Graph on 10 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (10, 3, 0, 1) `NO^-(6,2)` and `NO^+(6,2)`:: - sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,2,'-') # optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: # needs sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,2,'-') + sage: g.is_strongly_regular(parameters=True) (36, 15, 6, 6) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,2,'+'); g # optional - sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,2,'+'); g NO^+(6, 2): Graph on 28 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: g.is_strongly_regular(parameters=True) (28, 15, 6, 10) `NO^+(8,2)`:: - sage: g = graphs.NonisotropicOrthogonalPolarGraph(8,2,'+') # optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(8,2,'+') # needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (120, 63, 30, 36) Wilbrink's graphs for `q=5`:: - sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,perp=1) # optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # long time, optional - sage.libs.gap + sage: # needs sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,perp=1) + sage: g.is_strongly_regular(parameters=True) # long time (325, 60, 15, 10) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'-',perp=1) # optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # long time, optional - sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'-',perp=1) + sage: g.is_strongly_regular(parameters=True) # long time (300, 65, 10, 15) Wilbrink's graphs:: - sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,4,'+') # optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,4,'+') # needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (136, 75, 42, 40) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,4,'-') # optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,4,'-') # needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (120, 51, 18, 24) sage: g = graphs.NonisotropicOrthogonalPolarGraph(7,4,'+'); g # not tested (long time) NO^+(7, 4): Graph on 2080 vertices @@ -462,29 +478,29 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): TESTS:: - sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,2); g # optional - sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,2); g # needs sage.libs.gap NO^+(4, 2): Graph on 6 vertices - sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,3,'-') # optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,3,'-') # needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (15, 6, 1, 3) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(3,5,'-',perp=1); g # optional - sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(3,5,'-',perp=1); g # needs sage.libs.gap NO^-,perp(3, 5): Graph on 10 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (10, 3, 0, 1) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'+') # long time, optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # long time, optional - sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'+') # long time, needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # long time, needs sage.libs.gap (117, 36, 15, 9) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'-'); g # long time, optional - sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'-'); g # long time, needs sage.libs.gap NO^-(6, 3): Graph on 126 vertices - sage: g.is_strongly_regular(parameters=True) # long time, optional - sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # long time, needs sage.libs.gap (126, 45, 12, 18) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'-') # long time, optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # long time, optional - sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'-') # long time, needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # long time, needs sage.libs.gap (300, 104, 28, 40) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'+') # long time, optional - sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # long time, optional - sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'+') # long time, needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # long time, needs sage.libs.gap (325, 144, 68, 60) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,4,'+') # optional - sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,4,'+') Traceback (most recent call last): ... ValueError: for m even q must be 2 or 3 @@ -565,9 +581,9 @@ def _polar_graph(m, q, g, intersection_size=None): TESTS:: sage: from sage.graphs.generators.classical_geometries import _polar_graph - sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2)) # optional - sage.libs.gap + sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2)) # needs sage.libs.gap Graph on 45 vertices - sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2), intersection_size=1) # optional - sage.libs.gap + sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2), intersection_size=1) # needs sage.libs.gap Graph on 27 vertices """ from sage.libs.gap.libgap import libgap @@ -609,20 +625,21 @@ def UnitaryPolarGraph(m, q, algorithm="gap"): EXAMPLES:: - sage: G = graphs.UnitaryPolarGraph(4,2); G # optional - sage.libs.gap + sage: # needs sage.libs.gap + sage: G = graphs.UnitaryPolarGraph(4,2); G Unitary Polar Graph U(4, 2); GQ(4, 2): Graph on 45 vertices - sage: G.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: G.is_strongly_regular(parameters=True) (45, 12, 3, 3) - sage: graphs.UnitaryPolarGraph(5,2).is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: graphs.UnitaryPolarGraph(5,2).is_strongly_regular(parameters=True) (165, 36, 3, 9) - sage: graphs.UnitaryPolarGraph(6,2) # not tested (long time) # optional - sage.libs.gap + sage: graphs.UnitaryPolarGraph(6,2) # not tested (long time) Unitary Polar Graph U(6, 2): Graph on 693 vertices TESTS:: - sage: graphs.UnitaryPolarGraph(4,3, algorithm="gap").is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: graphs.UnitaryPolarGraph(4,3, algorithm="gap").is_strongly_regular(parameters=True) # needs sage.libs.gap (280, 36, 8, 4) - sage: graphs.UnitaryPolarGraph(4,3).is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: graphs.UnitaryPolarGraph(4,3).is_strongly_regular(parameters=True) # needs sage.libs.gap (280, 36, 8, 4) sage: graphs.UnitaryPolarGraph(4,3, algorithm="foo") Traceback (most recent call last): @@ -676,18 +693,18 @@ def NonisotropicUnitaryPolarGraph(m, q): EXAMPLES:: - sage: g = graphs.NonisotropicUnitaryPolarGraph(5,2); g # optional - sage.libs.gap + sage: g = graphs.NonisotropicUnitaryPolarGraph(5,2); g # needs sage.libs.gap NU(5, 2): Graph on 176 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (176, 135, 102, 108) TESTS:: - sage: graphs.NonisotropicUnitaryPolarGraph(4,2).is_strongly_regular(parameters=True) # optional - sage.libs.gap + sage: graphs.NonisotropicUnitaryPolarGraph(4,2).is_strongly_regular(parameters=True) # needs sage.libs.gap (40, 27, 18, 18) - sage: graphs.NonisotropicUnitaryPolarGraph(4,3).is_strongly_regular(parameters=True) # long time, optional - sage.libs.gap + sage: graphs.NonisotropicUnitaryPolarGraph(4,3).is_strongly_regular(parameters=True) # long time, needs sage.libs.gap (540, 224, 88, 96) - sage: graphs.NonisotropicUnitaryPolarGraph(6,6) # optional - sage.libs.gap + sage: graphs.NonisotropicUnitaryPolarGraph(6,6) Traceback (most recent call last): ... ValueError: q must be a prime power @@ -742,16 +759,16 @@ def UnitaryDualPolarGraph(m, q): The point graph of a generalized quadrangle (see :wikipedia:`Generalized_quadrangle`, [PT2009]_) of order (8,4):: - sage: G = graphs.UnitaryDualPolarGraph(5,2); G # long time # optional - sage.libs.gap + sage: G = graphs.UnitaryDualPolarGraph(5,2); G # long time, needs sage.libs.gap Unitary Dual Polar Graph DU(5, 2); GQ(8, 4): Graph on 297 vertices - sage: G.is_strongly_regular(parameters=True) # long time # optional - sage.libs.gap + sage: G.is_strongly_regular(parameters=True) # long time, needs sage.libs.gap (297, 40, 7, 5) Another way to get the generalized quadrangle of order (2,4):: - sage: G = graphs.UnitaryDualPolarGraph(4,2); G # optional - sage.libs.gap + sage: G = graphs.UnitaryDualPolarGraph(4,2); G # needs sage.libs.gap Unitary Dual Polar Graph DU(4, 2); GQ(2, 4): Graph on 27 vertices - sage: G.is_isomorphic(graphs.OrthogonalPolarGraph(6,2,'-')) # optional - sage.libs.gap + sage: G.is_isomorphic(graphs.OrthogonalPolarGraph(6,2,'-')) # needs sage.libs.gap True A bigger graph:: @@ -763,7 +780,7 @@ def UnitaryDualPolarGraph(m, q): TESTS:: - sage: graphs.UnitaryDualPolarGraph(6,6) # optional - sage.libs.gap + sage: graphs.UnitaryDualPolarGraph(6,6) # needs sage.libs.gap Traceback (most recent call last): ... GAPError: Error, must be a prime or a finite field @@ -800,11 +817,11 @@ def SymplecticDualPolarGraph(m, q): TESTS:: - sage: G = graphs.SymplecticDualPolarGraph(6,2); G # optional - sage.libs.gap + sage: G = graphs.SymplecticDualPolarGraph(6,2); G # needs sage.libs.gap Symplectic Dual Polar Graph DSp(6, 2): Graph on 135 vertices - sage: G.is_distance_regular(parameters=True) # optional - sage.libs.gap + sage: G.is_distance_regular(parameters=True) # needs sage.libs.gap ([14, 12, 8, None], [None, 1, 3, 7]) - sage: graphs.SymplecticDualPolarGraph(6,6) # optional - sage.libs.gap + sage: graphs.SymplecticDualPolarGraph(6,6) # needs sage.libs.gap Traceback (most recent call last): ... GAPError: Error, must be a prime or a finite field @@ -848,13 +865,13 @@ def TaylorTwographDescendantSRG(q, clique_partition=False): EXAMPLES:: - sage: g = graphs.TaylorTwographDescendantSRG(3); g # optional - sage.rings.finite_rings + sage: g = graphs.TaylorTwographDescendantSRG(3); g # needs sage.rings.finite_rings Taylor two-graph descendant SRG: Graph on 27 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (27, 10, 1, 5) sage: from sage.combinat.designs.twographs import taylor_twograph - sage: T = taylor_twograph(3) # long time, optional - sage.rings.finite_rings - sage: g.is_isomorphic(T.descendant(T.ground_set()[1])) # long time, optional - sage.rings.finite_rings + sage: T = taylor_twograph(3) # long time, needs sage.rings.finite_rings + sage: g.is_isomorphic(T.descendant(T.ground_set()[1])) # long time, needs sage.rings.finite_rings True sage: g = graphs.TaylorTwographDescendantSRG(5) # not tested (long time) sage: g.is_strongly_regular(parameters=True) # not tested (long time) @@ -862,14 +879,14 @@ def TaylorTwographDescendantSRG(q, clique_partition=False): TESTS:: - sage: g,l,_ = graphs.TaylorTwographDescendantSRG(3, clique_partition=True) # optional - sage.rings.finite_rings - sage: all(g.is_clique(x) for x in l) # optional - sage.rings.finite_rings + sage: g,l,_ = graphs.TaylorTwographDescendantSRG(3, clique_partition=True) # needs sage.rings.finite_rings + sage: all(g.is_clique(x) for x in l) # needs sage.rings.finite_rings True - sage: graphs.TaylorTwographDescendantSRG(4) # optional - sage.rings.finite_rings + sage: graphs.TaylorTwographDescendantSRG(4) Traceback (most recent call last): ... ValueError: q must be an odd prime power - sage: graphs.TaylorTwographDescendantSRG(6) # optional - sage.rings.finite_rings + sage: graphs.TaylorTwographDescendantSRG(6) Traceback (most recent call last): ... ValueError: q must be an odd prime power @@ -922,9 +939,9 @@ def TaylorTwographSRG(q): EXAMPLES:: - sage: t = graphs.TaylorTwographSRG(3); t # optional - sage.rings.finite_rings + sage: t = graphs.TaylorTwographSRG(3); t # needs sage.rings.finite_rings Taylor two-graph SRG: Graph on 28 vertices - sage: t.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings + sage: t.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (28, 15, 6, 10) """ G, l, v0 = TaylorTwographDescendantSRG(q, clique_partition=True) @@ -959,13 +976,13 @@ def AhrensSzekeresGeneralizedQuadrangleGraph(q, dual=False): EXAMPLES:: - sage: g = graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5); g # optional - sage.rings.finite_rings + sage: g = graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5); g AS(5); GQ(4, 6): Graph on 125 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) (125, 28, 3, 7) - sage: g = graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5, dual=True); g # optional - sage.rings.finite_rings + sage: g = graphs.AhrensSzekeresGeneralizedQuadrangleGraph(5, dual=True); g AS(5)*; GQ(6, 4): Graph on 175 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) (175, 30, 5, 5) """ from sage.combinat.designs.incidence_structures import IncidenceStructure @@ -1029,35 +1046,37 @@ def T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None, using the built-in construction:: - sage: g = graphs.T2starGeneralizedQuadrangleGraph(4); g # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: g = graphs.T2starGeneralizedQuadrangleGraph(4); g T2*(O,4); GQ(3, 5): Graph on 64 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) (64, 18, 2, 6) - sage: g = graphs.T2starGeneralizedQuadrangleGraph(4, dual=True); g # optional - sage.rings.finite_rings + sage: g = graphs.T2starGeneralizedQuadrangleGraph(4, dual=True); g T2*(O,4)*; GQ(5, 3): Graph on 96 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) (96, 20, 4, 4) supplying your own hyperoval:: - sage: F = GF(4,'b') # optional - sage.rings.finite_rings - sage: O = [vector(F,(0,0,0,1)),vector(F,(0,0,1,0))] + [vector(F, (0,1,x^2,x)) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: F = GF(4,'b') + sage: O = [vector(F,(0,0,0,1)),vector(F,(0,0,1,0))] + [vector(F, (0,1,x^2,x)) ....: for x in F] - sage: g = graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F); g # optional - sage.rings.finite_rings + sage: g = graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F); g T2*(O,4); GQ(3, 5): Graph on 64 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) (64, 18, 2, 6) TESTS:: - sage: F = GF(4,'b') # repeating a point... - sage: O = [vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] # optional - sage.rings.finite_rings - sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F) # optional - sage.rings.finite_rings + sage: F = GF(4,'b') # repeating a point... # needs sage.libs.pari + sage: O = [vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] # needs sage.rings.finite_rings + sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F) # needs sage.rings.finite_rings Traceback (most recent call last): ... RuntimeError: incorrect hyperoval size - sage: O = [vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] # optional - sage.rings.finite_rings - sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F) # optional - sage.rings.finite_rings + sage: O = [vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] # needs sage.rings.finite_rings + sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F) # needs sage.rings.finite_rings Traceback (most recent call last): ... RuntimeError: incorrect hyperoval @@ -1149,35 +1168,36 @@ def HaemersGraph(q, hyperoval=None, hyperoval_matching=None, field=None, check_h using the built-in constructions:: - sage: g = graphs.HaemersGraph(4); g # optional - sage.rings.finite_rings + sage: g = graphs.HaemersGraph(4); g # needs sage.rings.finite_rings Haemers(4): Graph on 96 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (96, 19, 2, 4) supplying your own hyperoval_matching:: - sage: g = graphs.HaemersGraph(4, hyperoval_matching=((0,5),(1,4),(2,3))); g # optional - sage.rings.finite_rings + sage: g = graphs.HaemersGraph(4, hyperoval_matching=((0,5),(1,4),(2,3))); g # needs sage.rings.finite_rings Haemers(4): Graph on 96 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (96, 19, 2, 4) TESTS:: - sage: F=GF(4,'b') # repeating a point... # optional - sage.rings.finite_rings - sage: O=[vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] # optional - sage.rings.finite_rings - sage: graphs.HaemersGraph(4, hyperoval=O, field=F) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: F=GF(4,'b') # repeating a point... + sage: O=[vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] + sage: graphs.HaemersGraph(4, hyperoval=O, field=F) Traceback (most recent call last): ... RuntimeError: incorrect hyperoval size - sage: O=[vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] # optional - sage.rings.finite_rings - sage: graphs.HaemersGraph(4, hyperoval=O, field=F) # optional - sage.rings.finite_rings + sage: O=[vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] + sage: graphs.HaemersGraph(4, hyperoval=O, field=F) Traceback (most recent call last): ... RuntimeError: incorrect hyperoval - sage: g = graphs.HaemersGraph(8); g # not tested (long time) # optional - sage.rings.finite_rings + sage: g = graphs.HaemersGraph(8); g # not tested (long time), needs sage.rings.finite_rings Haemers(8): Graph on 640 vertices - sage: g.is_strongly_regular(parameters=True) # not tested (long time) # optional - sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) # not tested (long time), needs sage.rings.finite_rings (640, 71, 6, 8) """ @@ -1372,9 +1392,9 @@ def Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None, check_hyperov using the built-in construction:: - sage: g = graphs.Nowhere0WordsTwoWeightCodeGraph(8); g # optional - sage.rings.finite_rings + sage: g = graphs.Nowhere0WordsTwoWeightCodeGraph(8); g # needs sage.rings.finite_rings Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (196, 60, 14, 20) sage: g = graphs.Nowhere0WordsTwoWeightCodeGraph(16) # not tested (long time) sage: g.is_strongly_regular(parameters=True) # not tested (long time) @@ -1382,24 +1402,25 @@ def Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None, check_hyperov supplying your own hyperoval:: + sage: # needs sage.rings.finite_rings sage: F = GF(8) - sage: O = [vector(F,(0,0,1)),vector(F,(0,1,0))] + [vector(F, (1,x^2,x)) # optional - sage.rings.finite_rings + sage: O = [vector(F,(0,0,1)),vector(F,(0,1,0))] + [vector(F, (1,x^2,x)) ....: for x in F] - sage: g = graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F); g # optional - sage.rings.finite_rings + sage: g = graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F); g Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices - sage: g.is_strongly_regular(parameters=True) # optional - sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) (196, 60, 14, 20) TESTS:: - sage: F = GF(8) # repeating a point... # optional - sage.rings.finite_rings - sage: O = [vector(F,(1,0,0)),vector(F,(0,1,0))]+[vector(F, (1,x^2,x)) for x in F] # optional - sage.rings.finite_rings - sage: graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F) # optional - sage.rings.finite_rings + sage: F = GF(8) # repeating a point... # needs sage.rings.finite_rings + sage: O = [vector(F,(1,0,0)),vector(F,(0,1,0))]+[vector(F, (1,x^2,x)) for x in F] # needs sage.rings.finite_rings + sage: graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F) # needs sage.rings.finite_rings Traceback (most recent call last): ... RuntimeError: incorrect hyperoval size - sage: O = [vector(F,(1,1,0)),vector(F,(0,1,0))]+[vector(F, (1,x^2,x)) for x in F] # optional - sage.rings.finite_rings - sage: graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F) + sage: O = [vector(F,(1,1,0)),vector(F,(0,1,0))]+[vector(F, (1,x^2,x)) for x in F] # needs sage.rings.finite_rings + sage: graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F) # optional - NameError: 'F' (with --distribution 'sagemath-graphs[modules]') Traceback (most recent call last): ... RuntimeError: incorrect hyperoval @@ -1467,13 +1488,14 @@ def OrthogonalDualPolarGraph(e, d, q): EXAMPLES:: - sage: G = graphs.OrthogonalDualPolarGraph(1,3,2) # optional - sage.libs.gap - sage: G.is_distance_regular(True) # optional - sage.libs.gap + sage: # needs sage.libs.gap + sage: G = graphs.OrthogonalDualPolarGraph(1,3,2) + sage: G.is_distance_regular(True) ([7, 6, 4, None], [None, 1, 3, 7]) - sage: G = graphs.OrthogonalDualPolarGraph(0,3,3) # long time # optional - sage.libs.gap - sage: G.is_distance_regular(True) # long time # optional - sage.libs.gap + sage: G = graphs.OrthogonalDualPolarGraph(0,3,3) # long time + sage: G.is_distance_regular(True) # long time ([39, 36, 27, None], [None, 1, 4, 13]) - sage: G.order() # long time # optional - sage.libs.gap + sage: G.order() # long time 1120 REFERENCES: @@ -1482,17 +1504,18 @@ def OrthogonalDualPolarGraph(e, d, q): TESTS:: - sage: G = graphs.OrthogonalDualPolarGraph(0,3,2) # optional - sage.libs.gap - sage: G.is_distance_regular(True) # optional - sage.libs.gap + sage: # needs sage.libs.gap + sage: G = graphs.OrthogonalDualPolarGraph(0,3,2) + sage: G.is_distance_regular(True) ([14, 12, 8, None], [None, 1, 3, 7]) - sage: G = graphs.OrthogonalDualPolarGraph(-1,3,2) # long time # optional - sage.libs.gap - sage: G.is_distance_regular(True) # long time # optional - sage.libs.gap + sage: G = graphs.OrthogonalDualPolarGraph(-1,3,2) # long time + sage: G.is_distance_regular(True) # long time ([28, 24, 16, None], [None, 1, 3, 7]) - sage: G = graphs.OrthogonalDualPolarGraph(1,3,4) # optional - sage.libs.gap - sage: G.is_distance_regular(True) # optional - sage.libs.gap + sage: G = graphs.OrthogonalDualPolarGraph(1,3,4) + sage: G.is_distance_regular(True) ([21, 20, 16, None], [None, 1, 5, 21]) - sage: G = graphs.OrthogonalDualPolarGraph(1,4,2) # optional - sage.libs.gap - sage: G.is_distance_regular(True) # optional - sage.libs.gap + sage: G = graphs.OrthogonalDualPolarGraph(1,4,2) + sage: G.is_distance_regular(True) ([15, 14, 12, 8, None], [None, 1, 3, 7, 15]) """ from sage.libs.gap.libgap import libgap From ce9e3674f6b76657bb7781134c183a8866e4a32d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 2 Aug 2023 15:49:38 -0700 Subject: [PATCH 72/87] src/sage/graphs/generators/classical_geometries.py: Fix up # needs --- .../graphs/generators/classical_geometries.py | 143 +++++++++--------- 1 file changed, 71 insertions(+), 72 deletions(-) diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index 4e2b861b423..7ef70020a14 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -48,7 +48,7 @@ def SymplecticPolarGraph(d, q, algorithm=None): Computation of the spectrum of `Sp(6,2)`:: - sage: g = graphs.SymplecticPolarGraph(6,2) + sage: g = graphs.SymplecticPolarGraph(6, 2) sage: g.is_strongly_regular(parameters=True) (63, 30, 13, 15) sage: set(g.spectrum()) == {-5, 3, 30} # needs sage.rings.number_field @@ -57,28 +57,18 @@ def SymplecticPolarGraph(d, q, algorithm=None): The parameters of `Sp(4,q)` are the same as of `O(5,q)`, but they are not isomorphic if `q` is odd:: - sage: G = graphs.SymplecticPolarGraph(4,3) + sage: G = graphs.SymplecticPolarGraph(4, 3) sage: G.is_strongly_regular(parameters=True) (40, 12, 2, 4) - sage: O = graphs.OrthogonalPolarGraph(5,3) # needs sage.libs.gap - sage: O.is_strongly_regular(parameters=True) # optional - EXPECTED + + sage: # needs sage.libs.gap + sage: O = graphs.OrthogonalPolarGraph(5, 3) + sage: O.is_strongly_regular(parameters=True) (40, 12, 2, 4) - sage: O.is_strongly_regular(parameters=True) # optional - GOT (with --distribution 'sagemath-graphs[modules]') - Traceback (most recent call last): - ... - File "", line 1, in - O.is_strongly_regular(parameters=True) - AttributeError: 'function' object has no attribute 'is_strongly_regular' - sage: O.is_isomorphic(G) # optional - EXPECTED + sage: O.is_isomorphic(G) False - sage: O.is_isomorphic(G) # optional - GOT (with --distribution 'sagemath-graphs[modules]') - Traceback (most recent call last): - ... - File "", line 1, in - O.is_isomorphic(G) - AttributeError: 'function' object has no attribute 'is_isomorphic' - sage: S = graphs.SymplecticPolarGraph(6,4,algorithm="gap") # not tested (long time), needs sage.libs.gap - sage: S.is_strongly_regular(parameters=True) # not tested (long time), needs sage.libs.gap + sage: S = graphs.SymplecticPolarGraph(6, 4, algorithm="gap") # not tested (long time) + sage: S.is_strongly_regular(parameters=True) # not tested (long time) (1365, 340, 83, 85) TESTS:: @@ -160,30 +150,32 @@ def AffineOrthogonalPolarGraph(d, q, sign="+"): `VO^-(4,3)`:: sage: g = graphs.AffineOrthogonalPolarGraph(4,3,"-") # needs sage.libs.gap - sage: g.is_isomorphic(graphs.BrouwerHaemersGraph()) # optional - NameError: 'g' (with --distribution 'sagemath-graphs[modules]') + sage: g.is_isomorphic(graphs.BrouwerHaemersGraph()) # needs sage.libs.gap True Some examples from `Brouwer's table or strongly regular graphs `_:: - sage: g = graphs.AffineOrthogonalPolarGraph(6,2,"-"); g # needs sage.libs.gap + sage: # needs sage.libs.gap + sage: g = graphs.AffineOrthogonalPolarGraph(6,2,"-"); g Affine Polar Graph VO^-(6,2): Graph on 64 vertices - sage: g.is_strongly_regular(parameters=True) # optional - NameError: 'g' (with --distribution 'sagemath-graphs[modules]') + sage: g.is_strongly_regular(parameters=True) (64, 27, 10, 12) - sage: g = graphs.AffineOrthogonalPolarGraph(6,2,"+"); g # needs sage.libs.gap + sage: g = graphs.AffineOrthogonalPolarGraph(6,2,"+"); g Affine Polar Graph VO^+(6,2): Graph on 64 vertices - sage: g.is_strongly_regular(parameters=True) # optional - NameError: 'g' (with --distribution 'sagemath-graphs[modules]') + sage: g.is_strongly_regular(parameters=True) (64, 35, 18, 20) When ``sign is None``:: - sage: g = graphs.AffineOrthogonalPolarGraph(5,2,None); g # needs sage.libs.gap + sage: # needs sage.libs.gap + sage: g = graphs.AffineOrthogonalPolarGraph(5,2,None); g Affine Polar Graph VO^-(5,2): Graph on 32 vertices - sage: g.is_strongly_regular(parameters=True) # optional - NameError: 'g' (with --distribution 'sagemath-graphs[modules]') + sage: g.is_strongly_regular(parameters=True) False - sage: g.is_regular() # optional - NameError: 'g' (with --distribution 'sagemath-graphs[modules]') + sage: g.is_regular() True - sage: g.is_vertex_transitive() # optional - NameError: 'g' (with --distribution 'sagemath-graphs[modules]') + sage: g.is_vertex_transitive() True """ if sign in ["+", "-"]: @@ -275,7 +267,7 @@ def _orthogonal_polar_graph(m, q, sign="+", point_type=[0]): `NO^{-,\perp}(5,5)`:: sage: g = _orthogonal_polar_graph(5,5,point_type=[2,3]) # long time, needs sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # long time, needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # long time # needs sage.libs.gap (300, 65, 10, 15) `NO^{+,\perp}(5,5)`:: @@ -465,11 +457,12 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): Wilbrink's graphs:: - sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,4,'+') # needs sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap + sage: # needs sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,4,'+') + sage: g.is_strongly_regular(parameters=True) (136, 75, 42, 40) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,4,'-') # needs sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,4,'-') + sage: g.is_strongly_regular(parameters=True) (120, 51, 18, 24) sage: g = graphs.NonisotropicOrthogonalPolarGraph(7,4,'+'); g # not tested (long time) NO^+(7, 4): Graph on 2080 vertices @@ -478,27 +471,28 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): TESTS:: - sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,2); g # needs sage.libs.gap + sage: # needs sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,2); g NO^+(4, 2): Graph on 6 vertices - sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,3,'-') # needs sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(4,3,'-') + sage: g.is_strongly_regular(parameters=True) (15, 6, 1, 3) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(3,5,'-',perp=1); g # needs sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(3,5,'-',perp=1); g NO^-,perp(3, 5): Graph on 10 vertices - sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) (10, 3, 0, 1) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'+') # long time, needs sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # long time, needs sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'+') # long time + sage: g.is_strongly_regular(parameters=True) # long time (117, 36, 15, 9) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'-'); g # long time, needs sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'-'); g # long time NO^-(6, 3): Graph on 126 vertices - sage: g.is_strongly_regular(parameters=True) # long time, needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # long time (126, 45, 12, 18) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'-') # long time, needs sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # long time, needs sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'-') # long time + sage: g.is_strongly_regular(parameters=True) # long time (300, 104, 28, 40) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'+') # long time, needs sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # long time, needs sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'+') # long time + sage: g.is_strongly_regular(parameters=True) # long time (325, 144, 68, 60) sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,4,'+') Traceback (most recent call last): @@ -581,7 +575,7 @@ def _polar_graph(m, q, g, intersection_size=None): TESTS:: sage: from sage.graphs.generators.classical_geometries import _polar_graph - sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2)) # needs sage.libs.gap + sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2)) # needs sage.libs.gap Graph on 45 vertices sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2), intersection_size=1) # needs sage.libs.gap Graph on 27 vertices @@ -759,9 +753,9 @@ def UnitaryDualPolarGraph(m, q): The point graph of a generalized quadrangle (see :wikipedia:`Generalized_quadrangle`, [PT2009]_) of order (8,4):: - sage: G = graphs.UnitaryDualPolarGraph(5,2); G # long time, needs sage.libs.gap + sage: G = graphs.UnitaryDualPolarGraph(5,2); G # long time # needs sage.libs.gap Unitary Dual Polar Graph DU(5, 2); GQ(8, 4): Graph on 297 vertices - sage: G.is_strongly_regular(parameters=True) # long time, needs sage.libs.gap + sage: G.is_strongly_regular(parameters=True) # long time # needs sage.libs.gap (297, 40, 7, 5) Another way to get the generalized quadrangle of order (2,4):: @@ -865,13 +859,14 @@ def TaylorTwographDescendantSRG(q, clique_partition=False): EXAMPLES:: - sage: g = graphs.TaylorTwographDescendantSRG(3); g # needs sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: g = graphs.TaylorTwographDescendantSRG(3); g Taylor two-graph descendant SRG: Graph on 27 vertices - sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) (27, 10, 1, 5) sage: from sage.combinat.designs.twographs import taylor_twograph - sage: T = taylor_twograph(3) # long time, needs sage.rings.finite_rings - sage: g.is_isomorphic(T.descendant(T.ground_set()[1])) # long time, needs sage.rings.finite_rings + sage: T = taylor_twograph(3) # long time + sage: g.is_isomorphic(T.descendant(T.ground_set()[1])) # long time True sage: g = graphs.TaylorTwographDescendantSRG(5) # not tested (long time) sage: g.is_strongly_regular(parameters=True) # not tested (long time) @@ -879,8 +874,9 @@ def TaylorTwographDescendantSRG(q, clique_partition=False): TESTS:: - sage: g,l,_ = graphs.TaylorTwographDescendantSRG(3, clique_partition=True) # needs sage.rings.finite_rings - sage: all(g.is_clique(x) for x in l) # needs sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: g,l,_ = graphs.TaylorTwographDescendantSRG(3, clique_partition=True) + sage: all(g.is_clique(x) for x in l) True sage: graphs.TaylorTwographDescendantSRG(4) Traceback (most recent call last): @@ -1069,14 +1065,15 @@ def T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None, TESTS:: - sage: F = GF(4,'b') # repeating a point... # needs sage.libs.pari - sage: O = [vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] # needs sage.rings.finite_rings - sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F) # needs sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: F = GF(4,'b') # repeating a point... + sage: O = [vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] + sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F) Traceback (most recent call last): ... RuntimeError: incorrect hyperoval size - sage: O = [vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] # needs sage.rings.finite_rings - sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F) # needs sage.rings.finite_rings + sage: O = [vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] + sage: graphs.T2starGeneralizedQuadrangleGraph(4, hyperoval=O, field=F) Traceback (most recent call last): ... RuntimeError: incorrect hyperoval @@ -1183,21 +1180,21 @@ def HaemersGraph(q, hyperoval=None, hyperoval_matching=None, field=None, check_h TESTS:: sage: # needs sage.rings.finite_rings - sage: F=GF(4,'b') # repeating a point... - sage: O=[vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] + sage: F = GF(4,'b') # repeating a point... + sage: O = [vector(F,(0,1,0,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] sage: graphs.HaemersGraph(4, hyperoval=O, field=F) Traceback (most recent call last): ... RuntimeError: incorrect hyperoval size - sage: O=[vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] + sage: O = [vector(F,(0,1,1,0)),vector(F,(0,0,1,0))]+[vector(F, (0,1,x^2,x)) for x in F] sage: graphs.HaemersGraph(4, hyperoval=O, field=F) Traceback (most recent call last): ... RuntimeError: incorrect hyperoval - sage: g = graphs.HaemersGraph(8); g # not tested (long time), needs sage.rings.finite_rings + sage: g = graphs.HaemersGraph(8); g # not tested (long time) # needs sage.rings.finite_rings Haemers(8): Graph on 640 vertices - sage: g.is_strongly_regular(parameters=True) # not tested (long time), needs sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) # not tested (long time) # needs sage.rings.finite_rings (640, 71, 6, 8) """ @@ -1392,9 +1389,10 @@ def Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None, check_hyperov using the built-in construction:: - sage: g = graphs.Nowhere0WordsTwoWeightCodeGraph(8); g # needs sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: g = graphs.Nowhere0WordsTwoWeightCodeGraph(8); g Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices - sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings + sage: g.is_strongly_regular(parameters=True) (196, 60, 14, 20) sage: g = graphs.Nowhere0WordsTwoWeightCodeGraph(16) # not tested (long time) sage: g.is_strongly_regular(parameters=True) # not tested (long time) @@ -1413,14 +1411,15 @@ def Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None, check_hyperov TESTS:: - sage: F = GF(8) # repeating a point... # needs sage.rings.finite_rings - sage: O = [vector(F,(1,0,0)),vector(F,(0,1,0))]+[vector(F, (1,x^2,x)) for x in F] # needs sage.rings.finite_rings - sage: graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F) # needs sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: F = GF(8) # repeating a point... + sage: O = [vector(F,(1,0,0)),vector(F,(0,1,0))]+[vector(F, (1,x^2,x)) for x in F] + sage: graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F) Traceback (most recent call last): ... RuntimeError: incorrect hyperoval size - sage: O = [vector(F,(1,1,0)),vector(F,(0,1,0))]+[vector(F, (1,x^2,x)) for x in F] # needs sage.rings.finite_rings - sage: graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F) # optional - NameError: 'F' (with --distribution 'sagemath-graphs[modules]') + sage: O = [vector(F,(1,1,0)),vector(F,(0,1,0))]+[vector(F, (1,x^2,x)) for x in F] + sage: graphs.Nowhere0WordsTwoWeightCodeGraph(8,hyperoval=O,field=F) Traceback (most recent call last): ... RuntimeError: incorrect hyperoval From 9dc850b3425cbcd5dadfca1eed24bd29f885cb58 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 4 Jul 2023 19:51:06 -0700 Subject: [PATCH 73/87] ./sage -fixdoctests --probe all --distribution 'sagemath-graphs[modules]' src/sage/graphs/generators/smallgraphs.py; ./sage -fixdoctests src/sage/graphs/generators/smallgraphs.py --- src/sage/graphs/generators/smallgraphs.py | 613 ++++++++++++---------- 1 file changed, 330 insertions(+), 283 deletions(-) diff --git a/src/sage/graphs/generators/smallgraphs.py b/src/sage/graphs/generators/smallgraphs.py index 36275b2ce57..27d4fc300ab 100644 --- a/src/sage/graphs/generators/smallgraphs.py +++ b/src/sage/graphs/generators/smallgraphs.py @@ -139,21 +139,22 @@ def HarriesGraph(embedding=1): EXAMPLES:: - sage: g = graphs.HarriesGraph() # optional - networkx - sage: g.order() # optional - networkx + sage: # needs networkx + sage: g = graphs.HarriesGraph() + sage: g.order() 70 - sage: g.size() # optional - networkx + sage: g.size() 105 - sage: g.girth() # optional - networkx + sage: g.girth() 10 - sage: g.diameter() # optional - networkx + sage: g.diameter() 6 - sage: g.show(figsize=[10, 10]) # long time # optional - networkx sage.plot - sage: graphs.HarriesGraph(embedding=2).show(figsize=[10, 10]) # long time # optional - networkx sage.plot + sage: g.show(figsize=[10, 10]) # long time # needs sage.plot + sage: graphs.HarriesGraph(embedding=2).show(figsize=[10, 10]) # long time, needs sage.plot TESTS:: - sage: graphs.HarriesGraph(embedding=3) # optional - networkx + sage: graphs.HarriesGraph(embedding=3) # needs networkx Traceback (most recent call last): ... ValueError: the value of embedding must be 1 or 2 @@ -257,25 +258,26 @@ def HarriesWongGraph(embedding=1): EXAMPLES:: - sage: g = graphs.HarriesWongGraph() # optional - networkx - sage: g.order() # optional - networkx + sage: # needs networkx + sage: g = graphs.HarriesWongGraph() + sage: g.order() 70 - sage: g.size() # optional - networkx + sage: g.size() 105 - sage: g.girth() # optional - networkx + sage: g.girth() 10 - sage: g.diameter() # optional - networkx + sage: g.diameter() 6 - sage: orbits = g.automorphism_group(orbits=True)[-1] # long time # optional - networkx sage.groups - sage: g.show(figsize=[15, 15], partition=orbits) # long time # optional - networkx sage.groups sage.plot + sage: orbits = g.automorphism_group(orbits=True)[-1] # long time # needs sage.groups + sage: g.show(figsize=[15, 15], partition=orbits) # long time # needs sage.groups sage.plot Alternative embedding:: - sage: graphs.HarriesWongGraph(embedding=2).show() # long time # optional - networkx sage.plot + sage: graphs.HarriesWongGraph(embedding=2).show() # long time # needs networkx sage.plot TESTS:: - sage: graphs.HarriesWongGraph(embedding=3) # optional - networkx + sage: graphs.HarriesWongGraph(embedding=3) # needs networkx Traceback (most recent call last): ... ValueError: the value of embedding must be 1 or 2 @@ -453,12 +455,13 @@ def Cell600(embedding=1): EXAMPLES:: - sage: g = graphs.Cell600() # long time - sage: g.size() # long time + sage: # long time + sage: g = graphs.Cell600() + sage: g.size() 720 - sage: g.is_regular(12) # long time + sage: g.is_regular(12) True - sage: g.is_vertex_transitive() # long time + sage: g.is_vertex_transitive() True """ from sage.rings.polynomial.polynomial_ring import polygen @@ -528,12 +531,13 @@ def Cell120(): EXAMPLES:: - sage: g = graphs.Cell120() # long time - sage: g.size() # long time + sage: # long time + sage: g = graphs.Cell120() + sage: g.size() 1200 - sage: g.is_regular(4) # long time + sage: g.is_regular(4) True - sage: g.is_vertex_transitive() # long time + sage: g.is_vertex_transitive() True """ from sage.rings.polynomial.polynomial_ring import polygen @@ -679,7 +683,7 @@ def HallJankoGraph(from_string=True): sage: g = graphs.HallJankoGraph() sage: g.is_regular(36) True - sage: g.is_vertex_transitive() # optional - sage.groups + sage: g.is_vertex_transitive() # needs sage.groups True Is it really strongly regular with parameters 14, 12? :: @@ -702,7 +706,7 @@ def HallJankoGraph(from_string=True): 2 sage: g.girth() 3 - sage: factor(g.characteristic_polynomial()) + sage: factor(g.characteristic_polynomial()) # needs sage.libs.pari sage.modules (x - 36) * (x - 6)^36 * (x + 4)^63 TESTS:: @@ -804,20 +808,21 @@ def Balaban10Cage(embedding=1): EXAMPLES:: - sage: g = graphs.Balaban10Cage() # optional - networkx - sage: g.girth() # optional - networkx + sage: # needs networkx + sage: g = graphs.Balaban10Cage() + sage: g.girth() 10 - sage: g.chromatic_number() # optional - networkx + sage: g.chromatic_number() 2 - sage: g.diameter() # optional - networkx + sage: g.diameter() 6 - sage: g.is_hamiltonian() # optional - networkx + sage: g.is_hamiltonian() # needs sage.numerical.mip True - sage: g.show(figsize=[10,10]) # long time # optional - networkx sage.plot + sage: g.show(figsize=[10,10]) # long time # needs sage.plot TESTS:: - sage: graphs.Balaban10Cage(embedding='foo') # optional - networkx + sage: graphs.Balaban10Cage(embedding='foo') # needs networkx Traceback (most recent call last): ... ValueError: the value of embedding must be 1 or 2 @@ -897,21 +902,21 @@ def Balaban11Cage(embedding=1): 11 sage: g.diameter() 8 - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 64 Our many embeddings:: sage: g1 = graphs.Balaban11Cage(embedding=1) - sage: g2 = graphs.Balaban11Cage(embedding=2) - sage: g3 = graphs.Balaban11Cage(embedding=3) - sage: g1.show(figsize=[10,10]) # long time # optional - sage.plot - sage: g2.show(figsize=[10,10]) # long time # optional - sage.plot - sage: g3.show(figsize=[10,10]) # long time # optional - sage.plot + sage: g2 = graphs.Balaban11Cage(embedding=2) # needs networkx + sage: g3 = graphs.Balaban11Cage(embedding=3) # needs networkx + sage: g1.show(figsize=[10,10]) # long time # needs sage.plot + sage: g2.show(figsize=[10,10]) # long time # needs networkx sage.plot + sage: g3.show(figsize=[10,10]) # long time # needs sage.plot Proof that the embeddings are the same graph:: - sage: g1.is_isomorphic(g2) # g2 and g3 are obviously isomorphic + sage: g1.is_isomorphic(g2) # g2 and g3 are obviously isomorphic # needs networkx True TESTS:: @@ -1071,7 +1076,7 @@ def BidiakisCube(): It is a Hamiltonian graph with diameter 3 and girth 4:: - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True sage: g.diameter() 3 @@ -1084,11 +1089,11 @@ def BidiakisCube(): sage: g.is_planar() True - sage: char_poly = g.characteristic_polynomial() - sage: x = char_poly.parent()('x') - sage: char_poly == (x - 3) * (x - 2) * (x^4) * (x + 1) * (x + 2) * (x^2 + x - 4)^2 + sage: char_poly = g.characteristic_polynomial() # needs sage.modules + sage: x = char_poly.parent()('x') # needs sage.modules + sage: char_poly == (x - 3) * (x - 2) * (x^4) * (x + 1) * (x + 2) * (x^2 + x - 4)^2 # needs sage.modules True - sage: g.chromatic_number() + sage: g.chromatic_number() # needs sage.modules 3 """ edge_dict = { @@ -1114,26 +1119,27 @@ def BiggsSmithGraph(embedding=1): Basic properties:: - sage: g = graphs.BiggsSmithGraph() # optional - networkx - sage: g.order() # optional - networkx + sage: # needs networkx + sage: g = graphs.BiggsSmithGraph() + sage: g.order() 102 - sage: g.size() # optional - networkx + sage: g.size() 153 - sage: g.girth() # optional - networkx + sage: g.girth() 9 - sage: g.diameter() # optional - networkx + sage: g.diameter() 7 - sage: g.automorphism_group().cardinality() # long time # optional - networkx + sage: g.automorphism_group().cardinality() # long time 2448 - sage: g.show(figsize=[10, 10]) # long time # optional - networkx sage.plot + sage: g.show(figsize=[10, 10]) # long time # needs sage.plot The other embedding:: - sage: graphs.BiggsSmithGraph(embedding=2).show() # long time # optional - networkx + sage: graphs.BiggsSmithGraph(embedding=2).show() # long time # needs networkx TESTS:: - sage: graphs.BiggsSmithGraph(embedding='xyzzy') # optional - networkx + sage: graphs.BiggsSmithGraph(embedding='xyzzy') # needs networkx Traceback (most recent call last): ... ValueError: the value of embedding must be 1 or 2 @@ -1199,16 +1205,16 @@ def BlanusaFirstSnarkGraph(): EXAMPLES:: - sage: g = graphs.BlanusaFirstSnarkGraph() # optional - sage.groups - sage: g.order() # optional - sage.groups + sage: g = graphs.BlanusaFirstSnarkGraph() + sage: g.order() 18 - sage: g.size() # optional - sage.groups + sage: g.size() 27 - sage: g.diameter() # optional - sage.groups + sage: g.diameter() 4 - sage: g.girth() # optional - sage.groups + sage: g.girth() 5 - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 8 """ g = Graph({17: [4, 7, 1], 0: [5], 3: [8], 13: [9], 12: [16], @@ -1234,16 +1240,16 @@ def BlanusaSecondSnarkGraph(): EXAMPLES:: - sage: g = graphs.BlanusaSecondSnarkGraph() # optional - sage.groups - sage: g.order() # optional - sage.groups + sage: g = graphs.BlanusaSecondSnarkGraph() + sage: g.order() 18 - sage: g.size() # optional - sage.groups + sage: g.size() 27 - sage: g.diameter() # optional - sage.groups + sage: g.diameter() 4 - sage: g.girth() # optional - sage.groups + sage: g.girth() 5 - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 4 """ c0 = (-1, 0) @@ -1312,15 +1318,15 @@ def BrinkmannGraph(): The Brinkmann graph is also Hamiltonian with chromatic number 4:: - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip True sage: G.chromatic_number() 4 Its automorphism group is isomorphic to `D_7`:: - sage: ag = G.automorphism_group() - sage: ag.is_isomorphic(DihedralGroup(7)) + sage: ag = G.automorphism_group() # needs sage.groups + sage: ag.is_isomorphic(DihedralGroup(7)) # needs sage.groups True """ edge_dict = { @@ -1361,18 +1367,17 @@ def BrouwerHaemersGraph(): EXAMPLES:: - sage: g = graphs.BrouwerHaemersGraph() # optional - sage.modules - sage: g # optional - sage.modules + sage: g = graphs.BrouwerHaemersGraph(); g # needs sage.modules Brouwer-Haemers: Graph on 81 vertices It is indeed strongly regular with parameters `(81,20,1,6)`:: - sage: g.is_strongly_regular(parameters=True) # long time # optional - sage.modules + sage: g.is_strongly_regular(parameters=True) # long time # needs sage.modules sage.rings.finite_rings (81, 20, 1, 6) Its has as eigenvalues `20,2` and `-7`:: - sage: set(g.spectrum()) == {20,2,-7} # optional - sage.modules + sage: set(g.spectrum()) == {20,2,-7} # needs sage.modules sage.rings.finite_rings True """ from sage.rings.finite_rings.finite_field_constructor import FiniteField @@ -1419,16 +1424,17 @@ def BuckyBall(): The Bucky Ball can also be created by extracting the 1-skeleton of the Bucky Ball polyhedron, but this is much slower:: - sage: g = polytopes.buckyball().vertex_graph() # optional - sage.geometry.polyhedron - sage: g.remove_loops() # optional - sage.geometry.polyhedron + sage: # needs sage.geometry.polyhedron sage.rings.number_field + sage: g = polytopes.buckyball().vertex_graph() + sage: g.remove_loops() sage: h = graphs.BuckyBall() - sage: g.is_isomorphic(h) # optional - sage.geometry.polyhedron + sage: g.is_isomorphic(h) True The graph is returned along with an attractive embedding:: sage: g = graphs.BuckyBall() # long time - sage: g.plot(vertex_labels=False, vertex_size=10).show() # long time # optional - sage.plot + sage: g.plot(vertex_labels=False, vertex_size=10).show() # long time, needs sage.plot """ edges = [(0, 2), (0, 48), (0, 59), (1, 3), (1, 9), (1, 58), (2, 3), (2, 36), (3, 17), (4, 6), (4, 8), (4, 12), @@ -1573,11 +1579,11 @@ def DoubleStarSnark(): 45 sage: g.chromatic_number() 3 - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip False - sage: g.automorphism_group().cardinality() + sage: g.automorphism_group().cardinality() # needs sage.groups 80 - sage: g.show() # optional - sage.plot + sage: g.show() # needs sage.plot """ d = {0: [1, 14, 15], 1: [0, 2, 11], @@ -1641,7 +1647,7 @@ def MeredithGraph(): 4 sage: g.chromatic_number() 3 - sage: g.is_hamiltonian() # long time + sage: g.is_hamiltonian() # long time # needs sage.numerical.mip False """ g = Graph(name="Meredith Graph") @@ -1735,12 +1741,13 @@ def CameronGraph(): EXAMPLES:: - sage: g = graphs.CameronGraph() # optional - sage.groups - sage: g.order() # optional - sage.groups + sage: # needs sage.groups + sage: g = graphs.CameronGraph() + sage: g.order() 231 - sage: g.size() # optional - sage.groups + sage: g.size() 3465 - sage: g.is_strongly_regular(parameters=True) # long time # optional - sage.groups + sage: g.is_strongly_regular(parameters=True) # long time (231, 30, 9, 3) """ from sage.groups.perm_gps.permgroup_named import MathieuGroup @@ -1804,9 +1811,9 @@ def ChvatalGraph(): TESTS:: - sage: import networkx # optional - networkx + sage: import networkx # needs networkx sage: G = graphs.ChvatalGraph() - sage: G.is_isomorphic(Graph(networkx.chvatal_graph())) # optional - networkx + sage: G.is_isomorphic(Graph(networkx.chvatal_graph())) # needs networkx True """ edges = {0: [1, 4, 6, 9], 1: [2, 5, 7], 2: [3, 6, 8], 3: [4, 7, 9], @@ -1828,7 +1835,7 @@ def ClebschGraph(): EXAMPLES:: sage: g = graphs.ClebschGraph() - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 1920 sage: g.girth() 4 @@ -1836,7 +1843,7 @@ def ClebschGraph(): 4 sage: g.diameter() 2 - sage: g.show(figsize=[10, 10]) # long time # optional - sage.plot + sage: g.show(figsize=[10, 10]) # long time # needs sage.plot """ g = Graph(pos={}) x = 0 @@ -1865,7 +1872,7 @@ def CoxeterGraph(): EXAMPLES:: sage: g = graphs.CoxeterGraph() - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 336 sage: g.girth() 7 @@ -1873,7 +1880,7 @@ def CoxeterGraph(): 3 sage: g.diameter() 4 - sage: g.show(figsize=[10, 10]) # long time # optional - sage.plot + sage: g.show(figsize=[10, 10]) # long time # needs sage.plot """ g = Graph({ 27: [6, 22, 14], @@ -1904,11 +1911,11 @@ def DejterGraph(): EXAMPLES:: - sage: g = graphs.DejterGraph(); g # optional - sage.rings.finite_rings + sage: g = graphs.DejterGraph(); g # needs sage.rings.finite_rings Dejter Graph: Graph on 112 vertices - sage: g.is_regular(k=6) # optional - sage.rings.finite_rings + sage: g.is_regular(k=6) # needs sage.rings.finite_rings True - sage: g.girth() # optional - sage.rings.finite_rings + sage: g.girth() # needs sage.rings.finite_rings 4 """ from sage.graphs.generators.families import CubeGraph @@ -1931,10 +1938,10 @@ def DesarguesGraph(): EXAMPLES:: sage: D = graphs.DesarguesGraph() - sage: L = graphs.LCFGraph(20,[5,-5,9,-9],5) # optional - networkx - sage: D.is_isomorphic(L) # optional - networkx + sage: L = graphs.LCFGraph(20,[5,-5,9,-9],5) # needs networkx + sage: D.is_isomorphic(L) # needs networkx True - sage: D.show() # long time # optional - sage.plot + sage: D.show() # long time # needs sage.plot """ from sage.graphs.generators.families import GeneralizedPetersenGraph G = GeneralizedPetersenGraph(10, 3) @@ -1973,8 +1980,8 @@ def DurerGraph(): Its automorphism group is isomorphic to `D_6`:: - sage: ag = G.automorphism_group() - sage: ag.is_isomorphic(DihedralGroup(6)) + sage: ag = G.automorphism_group() # needs sage.groups + sage: ag.is_isomorphic(DihedralGroup(6)) # needs sage.groups True """ from sage.graphs.generators.families import GeneralizedPetersenGraph @@ -2012,7 +2019,7 @@ def DyckGraph(): sage: G.is_planar() False - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip True sage: G.is_bipartite() True @@ -2030,12 +2037,12 @@ def DyckGraph(): sage: G.chromatic_number() 2 - sage: G.automorphism_group().cardinality() + sage: G.automorphism_group().cardinality() # needs sage.groups 192 It is a non-integral graph as it has irrational eigenvalues:: - sage: G.characteristic_polynomial().factor() + sage: G.characteristic_polynomial().factor() # needs sage.libs.pari sage.modules (x - 3) * (x + 3) * (x - 1)^9 * (x + 1)^9 * (x^2 - 5)^6 It is a toroidal graph, and its embedding on a torus is dual to an embedding @@ -2085,22 +2092,23 @@ def HortonGraph(): EXAMPLES:: - sage: g = graphs.HortonGraph() # optional - networkx - sage: g.order() # optional - networkx + sage: # needs networkx + sage: g = graphs.HortonGraph() + sage: g.order() 96 - sage: g.size() # optional - networkx + sage: g.size() 144 - sage: g.radius() # optional - networkx + sage: g.radius() 10 - sage: g.diameter() # optional - networkx + sage: g.diameter() 10 - sage: g.girth() # optional - networkx + sage: g.girth() 6 - sage: g.automorphism_group().cardinality() # optional - networkx + sage: g.automorphism_group().cardinality() 96 - sage: g.chromatic_number() # optional - networkx + sage: g.chromatic_number() 2 - sage: g.is_hamiltonian() # not tested -- veeeery long # optional - networkx + sage: g.is_hamiltonian() # not tested # needs sage.numerical.mip False """ g = Graph(name="Horton Graph") @@ -2160,14 +2168,14 @@ def EllinghamHorton54Graph(): It is 3-connected and bipartite:: - sage: g.vertex_connectivity() # not tested - too long + sage: g.vertex_connectivity() # not tested - too long 3 sage: g.is_bipartite() True It is not Hamiltonian:: - sage: g.is_hamiltonian() # not tested - too long + sage: g.is_hamiltonian() # not tested (too long) # needs sage.numerical.mip False ... and it has a nice drawing :: @@ -2237,23 +2245,23 @@ def EllinghamHorton78Graph(): It is 3-connected and bipartite:: - sage: g.vertex_connectivity() # not tested - too long + sage: g.vertex_connectivity() # not tested (too long) 3 sage: g.is_bipartite() True It is not Hamiltonian:: - sage: g.is_hamiltonian() # not tested - too long + sage: g.is_hamiltonian() # not tested (too long) # needs sage.numerical.mip False ... and it has a nice drawing :: - sage: g.show(figsize=[10,10]) # not tested - too long + sage: g.show(figsize=[10,10]) # not tested (too long) TESTS:: - sage: g.show(figsize=[10, 10]) # not tested - too long + sage: g.show(figsize=[10, 10]) # not tested (too long) """ g = Graph({ 0: [1, 5, 60], 1: [2, 12], 2: [3, 7], 3: [4, 14], 4: [5, 9], @@ -2321,7 +2329,7 @@ def ErreraGraph(): The Errera graph is Hamiltonian with radius 3, diameter 4, girth 3, and chromatic number 4:: - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip True sage: G.radius() 3 @@ -2343,8 +2351,8 @@ def ErreraGraph(): The automorphism group of the Errera graph is isomorphic to the dihedral group of order 20:: - sage: ag = G.automorphism_group() - sage: ag.is_isomorphic(DihedralGroup(10)) + sage: ag = G.automorphism_group() # needs sage.groups + sage: ag.is_isomorphic(DihedralGroup(10)) # needs sage.groups True """ edge_dict = { @@ -2374,17 +2382,18 @@ def F26AGraph(): EXAMPLES:: - sage: g = graphs.F26AGraph(); g # optional - networkx + sage: # needs networkx + sage: g = graphs.F26AGraph(); g F26A Graph: Graph on 26 vertices - sage: g.order(), g.size() # optional - networkx + sage: g.order(), g.size() (26, 39) - sage: g.automorphism_group().cardinality() # optional - networkx + sage: g.automorphism_group().cardinality() 78 - sage: g.girth() # optional - networkx + sage: g.girth() 6 - sage: g.is_bipartite() # optional - networkx + sage: g.is_bipartite() True - sage: g.characteristic_polynomial().factor() # optional - networkx + sage: g.characteristic_polynomial().factor() (x - 3) * (x + 3) * (x^4 - 5*x^2 + 3)^6 """ from sage.graphs.generators.families import LCFGraph @@ -2435,26 +2444,27 @@ def FolkmanGraph(): EXAMPLES:: - sage: g = graphs.FolkmanGraph() # optional - networkx - sage: g.order() # optional - networkx + sage: # needs networkx + sage: g = graphs.FolkmanGraph() + sage: g.order() 20 - sage: g.size() # optional - networkx + sage: g.size() 40 - sage: g.diameter() # optional - networkx + sage: g.diameter() 4 - sage: g.girth() # optional - networkx + sage: g.girth() 4 - sage: g.charpoly().factor() # optional - networkx + sage: g.charpoly().factor() (x - 4) * (x + 4) * x^10 * (x^2 - 6)^4 - sage: g.chromatic_number() # optional - networkx + sage: g.chromatic_number() 2 - sage: g.is_eulerian() # optional - networkx + sage: g.is_eulerian() True - sage: g.is_hamiltonian() # optional - networkx + sage: g.is_hamiltonian() # needs sage.numerical_mip True - sage: g.is_vertex_transitive() # optional - networkx + sage: g.is_vertex_transitive() False - sage: g.is_bipartite() # optional - networkx + sage: g.is_bipartite() True """ from sage.graphs.generators.families import LCFGraph @@ -2471,18 +2481,19 @@ def FosterGraph(): EXAMPLES:: - sage: g = graphs.FosterGraph() # optional - networkx - sage: g.order() # optional - networkx + sage: # needs networkx + sage: g = graphs.FosterGraph() + sage: g.order() 90 - sage: g.size() # optional - networkx + sage: g.size() 135 - sage: g.diameter() # optional - networkx + sage: g.diameter() 8 - sage: g.girth() # optional - networkx + sage: g.girth() 10 - sage: g.automorphism_group().cardinality() # optional - networkx + sage: g.automorphism_group().cardinality() 4320 - sage: g.is_hamiltonian() # optional - networkx + sage: g.is_hamiltonian() # needs sage.numerical_mip True """ from sage.graphs.generators.families import LCFGraph @@ -2514,7 +2525,7 @@ def FranklinGraph(): The Franklin graph is a Hamiltonian, bipartite graph with radius 3, diameter 3, and girth 4:: - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical_mip True sage: G.is_bipartite() True @@ -2565,18 +2576,18 @@ def FruchtGraph(): EXAMPLES:: - sage: FRUCHT = graphs.FruchtGraph() # optional - networkx - sage: FRUCHT # optional - networkx + sage: FRUCHT = graphs.FruchtGraph() + sage: FRUCHT Frucht graph: Graph on 12 vertices - sage: FRUCHT.graph6_string() # optional - networkx + sage: FRUCHT.graph6_string() 'KhCKM?_EGK?L' - sage: (graphs.FruchtGraph()).show() # long time # optional - networkx + sage: (graphs.FruchtGraph()).show() # long time # needs networkx TESTS:: - sage: import networkx # optional - networkx - sage: G = graphs.FruchtGraph() # optional - networkx - sage: G.is_isomorphic(Graph(networkx.frucht_graph())) # optional - networkx + sage: import networkx # needs networkx + sage: G = graphs.FruchtGraph() + sage: G.is_isomorphic(Graph(networkx.frucht_graph())) # needs networkx True """ edges = {0: [1, 6, 7], 1: [2, 7], 2: [3, 8], 3: [4, 9], 4: [5, 9], @@ -2624,8 +2635,8 @@ def GoldnerHararyGraph(): sage: G.chromatic_number() 4 - sage: ag = G.automorphism_group() - sage: ag.is_isomorphic(DihedralGroup(6)) + sage: ag = G.automorphism_group() # needs sage.groups + sage: ag.is_isomorphic(DihedralGroup(6)) # needs sage.groups True """ edge_dict = { @@ -2668,12 +2679,12 @@ def GolombGraph(): and 18 edges. It has chromatic number 4, diameter 3, radius 2 and girth 3. It can be drawn in the plane as a unit distance graph:: - sage: G = graphs.GolombGraph(); G # optional - sage.symbolic + sage: G = graphs.GolombGraph(); G # needs sage.symbolic Golomb graph: Graph on 10 vertices - sage: pos = G.get_pos() # optional - sage.symbolic + sage: pos = G.get_pos() # needs sage.symbolic sage: def dist2(u, v): ....: return (u[0]-v[0])**2 + (u[1]-v[1])**2 - sage: all(dist2(pos[u], pos[v]) == 1 for u, v in G.edge_iterator(labels=None)) # optional - sage.symbolic + sage: all(dist2(pos[u], pos[v]) == 1 for u, v in G.edge_iterator(labels=None)) # needs sage.symbolic True """ edge_dict = { @@ -2713,6 +2724,7 @@ def GrayGraph(embedding=1): EXAMPLES:: + sage: # needs networkx sage: g = graphs.GrayGraph() sage: g.order() 54 @@ -2722,12 +2734,12 @@ def GrayGraph(embedding=1): 8 sage: g.diameter() 6 - sage: g.show(figsize=[10, 10]) # long time - sage: graphs.GrayGraph(embedding=2).show(figsize=[10, 10]) # long time + sage: g.show(figsize=[10, 10]) # long time, needs sage.plot + sage: graphs.GrayGraph(embedding=2).show(figsize=[10, 10]) # long time, needs sage.plot TESTS:: - sage: graphs.GrayGraph(embedding=3) + sage: graphs.GrayGraph(embedding=3) # needs networkx Traceback (most recent call last): ... ValueError: the value of embedding must be 1, 2, or 3 @@ -2762,7 +2774,7 @@ def GrotzschGraph(): sage: G = graphs.GrotzschGraph(); G Grotzsch graph: Graph on 11 vertices - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip True sage: G.order() 11 @@ -2786,8 +2798,8 @@ def GrotzschGraph(): sage: G.chromatic_number() 4 - sage: ag = G.automorphism_group() - sage: ag.is_isomorphic(DihedralGroup(5)) + sage: ag = G.automorphism_group() # needs sage.groups + sage: ag.is_isomorphic(DihedralGroup(5)) # needs sage.groups True """ edges = [(0, u) for u in range(1, 6)] @@ -2836,9 +2848,9 @@ def HeawoodGraph(): TESTS:: - sage: import networkx # optional - networkx + sage: import networkx # needs networkx sage: G = graphs.HeawoodGraph() - sage: G.is_isomorphic(Graph(networkx.heawood_graph())) # optional - networkx + sage: G.is_isomorphic(Graph(networkx.heawood_graph())) # needs networkx True """ edges = {0: [1, 5, 13], 1: [2, 10], 2: [3, 7], 3: [4, 12], 4: [5, 9], @@ -2888,8 +2900,8 @@ def HerschelGraph(): sage: G.chromatic_number() 2 - sage: ag = G.automorphism_group() # optional - sage.groups - sage: ag.is_isomorphic(DihedralGroup(6)) # optional - sage.groups + sage: ag = G.automorphism_group() # needs sage.groups + sage: ag.is_isomorphic(DihedralGroup(6)) # needs sage.groups True """ edge_dict = { @@ -2919,9 +2931,9 @@ def GritsenkoGraph(): EXAMPLES:: - sage: H = graphs.GritsenkoGraph(); H # optional - sage.groups + sage: H = graphs.GritsenkoGraph(); H # needs sage.groups Gritsenko strongly regular graph: Graph on 65 vertices - sage: H.is_strongly_regular(parameters=True) # optional - sage.groups + sage: H.is_strongly_regular(parameters=True) # needs sage.groups (65, 32, 15, 16) """ from sage.groups.perm_gps.permgroup import PermutationGroup @@ -3000,13 +3012,13 @@ def HigmanSimsGraph(relabel=True): which is of index 2 and is simple. It is known as the Higman-Sims group:: sage: H = graphs.HigmanSimsGraph() - sage: G = H.automorphism_group() # optional - sage.groups - sage: g = G.order(); g # optional - sage.groups + sage: G = H.automorphism_group() # needs sage.groups + sage: g = G.order(); g # needs sage.groups 88704000 - sage: K = G.normal_subgroups()[1] # optional - sage.groups - sage: K.is_simple() # optional - sage.groups + sage: K = G.normal_subgroups()[1] # needs sage.groups + sage: K.is_simple() # needs sage.groups True - sage: g//K.order() # optional - sage.groups + sage: g//K.order() # needs sage.groups 2 AUTHOR: @@ -3186,13 +3198,13 @@ def HoffmanGraph(): sage: g = graphs.HoffmanGraph() sage: g.is_bipartite() True - sage: g.is_hamiltonian() # long time + sage: g.is_hamiltonian() # long time # needs sage.numerical.mip True sage: g.radius() 3 sage: g.diameter() 4 - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 48 """ g = Graph({ @@ -3231,11 +3243,11 @@ def HoltGraph(): Holt graph: Graph on 27 vertices sage: g.is_regular() True - sage: g.is_vertex_transitive() # optional - sage.groups + sage: g.is_vertex_transitive() # needs sage.groups True sage: g.chromatic_number() 3 - sage: g.is_hamiltonian() # long time + sage: g.is_hamiltonian() # long time # needs sage.numerical.mip True sage: g.radius() 3 @@ -3243,7 +3255,7 @@ def HoltGraph(): 3 sage: g.girth() 5 - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 54 """ g = Graph(loops=False, name="Holt graph", pos={}) @@ -3295,9 +3307,9 @@ def KrackhardtKiteGraph(): TESTS:: - sage: import networkx # optional - networkx + sage: import networkx # needs networkx sage: G = graphs.KrackhardtKiteGraph() - sage: G.is_isomorphic(Graph(networkx.krackhardt_kite_graph())) # optional - networkx + sage: G.is_isomorphic(Graph(networkx.krackhardt_kite_graph())) # needs networkx True """ edges = {0: [1, 2, 3, 5], 1: [3, 4, 6], 2: [3, 5], 3: [4, 5, 6], @@ -3324,7 +3336,7 @@ def Klein3RegularGraph(): (56, 84) sage: g.girth() 7 - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 336 sage: g.chromatic_number() 3 @@ -3357,7 +3369,7 @@ def Klein7RegularGraph(): (24, 84) sage: g.girth() 3 - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 336 sage: g.chromatic_number() 4 @@ -3413,21 +3425,22 @@ def LjubljanaGraph(embedding=1): EXAMPLES:: - sage: g = graphs.LjubljanaGraph() # optional - networkx - sage: g.order() # optional - networkx + sage: # needs networkx + sage: g = graphs.LjubljanaGraph() + sage: g.order() 112 - sage: g.size() # optional - networkx + sage: g.size() 168 - sage: g.girth() # optional - networkx + sage: g.girth() 10 - sage: g.diameter() # optional - networkx + sage: g.diameter() 8 - sage: g.show(figsize=[10, 10]) # long time # optional - networkx sage.plot - sage: graphs.LjubljanaGraph(embedding=2).show(figsize=[10, 10]) # long time # optional - networkx sage.plot + sage: g.show(figsize=[10, 10]) # long time # needs sage.plot + sage: graphs.LjubljanaGraph(embedding=2).show(figsize=[10, 10]) # long time, needs sage.plot TESTS:: - sage: graphs.LjubljanaGraph(embedding=3) # optional - networkx + sage: graphs.LjubljanaGraph(embedding=3) # needs networkx Traceback (most recent call last): ... ValueError: the value of embedding must be 1 or 2 @@ -3486,16 +3499,17 @@ def LivingstoneGraph(): EXAMPLES:: - sage: g = graphs.LivingstoneGraph() # optional - internet - sage: g.order() # optional - internet + sage: # optional - internet + sage: g = graphs.LivingstoneGraph() + sage: g.order() 266 - sage: g.size() # optional - internet + sage: g.size() 1463 - sage: g.girth() # optional - internet + sage: g.girth() 5 - sage: g.is_vertex_transitive() # optional - internet + sage: g.is_vertex_transitive() True - sage: g.is_distance_regular() # optional - internet + sage: g.is_distance_regular() True """ from sage.groups.perm_gps.permgroup_named import JankoGroup @@ -3518,12 +3532,13 @@ def M22Graph(): EXAMPLES:: - sage: g = graphs.M22Graph() # optional - sage.groups - sage: g.order() # optional - sage.groups + sage: # needs sage.groups + sage: g = graphs.M22Graph() + sage: g.order() 77 - sage: g.size() # optional - sage.groups + sage: g.size() 616 - sage: g.is_strongly_regular(parameters=True) # optional - sage.groups + sage: g.is_strongly_regular(parameters=True) (77, 16, 0, 4) """ from sage.groups.perm_gps.permgroup_named import MathieuGroup @@ -3561,11 +3576,11 @@ def MarkstroemGraph(): True sage: g.is_regular(3) True - sage: g.subgraph_search(graphs.CycleGraph(4)) is None # optional - sage.modules + sage: g.subgraph_search(graphs.CycleGraph(4)) is None # needs sage.modules True - sage: g.subgraph_search(graphs.CycleGraph(8)) is None # optional - sage.modules + sage: g.subgraph_search(graphs.CycleGraph(8)) is None # needs sage.modules True - sage: g.subgraph_search(graphs.CycleGraph(16)) # optional - sage.modules + sage: g.subgraph_search(graphs.CycleGraph(16)) # needs sage.modules Subgraph of (Markstroem Graph): Graph on 16 vertices """ g = Graph(name="Markstroem Graph") @@ -3602,21 +3617,22 @@ def McGeeGraph(embedding=2): EXAMPLES:: - sage: g = graphs.McGeeGraph() # optional - networkx - sage: g.order() # optional - networkx + sage: # needs networkx + sage: g = graphs.McGeeGraph() + sage: g.order() 24 - sage: g.size() # optional - networkx + sage: g.size() 36 - sage: g.girth() # optional - networkx + sage: g.girth() 7 - sage: g.diameter() # optional - networkx + sage: g.diameter() 4 - sage: g.show() # optional - networkx sage.plot - sage: graphs.McGeeGraph(embedding=1).show() # long time # optional - networkx sage.plot + sage: g.show() # needs sage.plot + sage: graphs.McGeeGraph(embedding=1).show() # long time # needs sage.plot TESTS:: - sage: graphs.McGeeGraph(embedding=3) # optional - networkx + sage: graphs.McGeeGraph(embedding=3) # needs networkx Traceback (most recent call last): ... ValueError: the value of embedding must be 1 or 2 @@ -3726,7 +3742,7 @@ def MoebiusKantorGraph(): Moebius-Kantor Graph: Graph on 16 vertices sage: MK.graph6_string() 'OhCGKE?O@?ACAC@I?Q_AS' - sage: (graphs.MoebiusKantorGraph()).show() # long time # optional - sage.plot + sage: (graphs.MoebiusKantorGraph()).show() # long time # needs sage.plot """ from sage.graphs.generators.families import GeneralizedPetersenGraph G = GeneralizedPetersenGraph(8, 3) @@ -3744,38 +3760,41 @@ def MoserSpindle(): The Moser spindle is a planar graph having 7 vertices and 11 edges:: - sage: G = graphs.MoserSpindle(); G # optional - sage.symbolic + sage: # needs sage.symbolic + sage: G = graphs.MoserSpindle(); G Moser spindle: Graph on 7 vertices - sage: G.is_planar() # optional - sage.symbolic + sage: G.is_planar() True - sage: G.order() # optional - sage.symbolic + sage: G.order() 7 - sage: G.size() # optional - sage.symbolic + sage: G.size() 11 It is a Hamiltonian graph with radius 2, diameter 2, and girth 3:: - sage: G.is_hamiltonian() # optional - sage.symbolic + sage: # needs sage.symbolic + sage: G.is_hamiltonian() # needs sage.numerical.mip True - sage: G.radius() # optional - sage.symbolic + sage: G.radius() 2 - sage: G.diameter() # optional - sage.symbolic + sage: G.diameter() 2 - sage: G.girth() # optional - sage.symbolic + sage: G.girth() 3 The Moser spindle can be drawn in the plane as a unit distance graph, has chromatic number 4, and its automorphism group is isomorphic to the dihedral group `D_4`:: - sage: pos = G.get_pos() # optional - sage.symbolic - sage: all(sum((ui-vi)**2 for ui, vi in zip(pos[u], pos[v])) == 1 # optional - sage.symbolic + sage: # needs sage.symbolic + sage: pos = G.get_pos() + sage: all(sum((ui-vi)**2 for ui, vi in zip(pos[u], pos[v])) == 1 ....: for u, v in G.edge_iterator(labels=None)) True - sage: G.chromatic_number() # optional - sage.symbolic + sage: G.chromatic_number() 4 - sage: ag = G.automorphism_group() # optional - sage.symbolic - sage: ag.is_isomorphic(DihedralGroup(4)) # optional - sage.symbolic + sage: ag = G.automorphism_group() + sage: ag.is_isomorphic(DihedralGroup(4)) True """ edge_dict = { @@ -3821,8 +3840,8 @@ def NauruGraph(embedding=2): 6 sage: g.diameter() 4 - sage: g.show() # optional - sage.plot - sage: graphs.NauruGraph(embedding=1).show() # long time # optional - sage.plot + sage: g.show() # needs sage.plot + sage: graphs.NauruGraph(embedding=1).show() # long time # needs sage.plot TESTS:: @@ -3830,7 +3849,7 @@ def NauruGraph(embedding=2): Traceback (most recent call last): ... ValueError: the value of embedding must be 1 or 2 - sage: graphs.NauruGraph(embedding=1).is_isomorphic(g) # optional - networkx + sage: graphs.NauruGraph(embedding=1).is_isomorphic(g) # needs networkx True """ @@ -3857,10 +3876,10 @@ def PappusGraph(): EXAMPLES:: sage: G = graphs.PappusGraph() - sage: G.show() # long time # optional - sage.plot - sage: L = graphs.LCFGraph(18, [5,7,-7,7,-7,-5], 3) # optional - networkx - sage: L.show() # long time # optional - networkx sage.plot - sage: G.is_isomorphic(L) # optional - networkx + sage: G.show() # long time # needs sage.plot + sage: L = graphs.LCFGraph(18, [5,7,-7,7,-7,-5], 3) # needs networkx + sage: L.show() # long time # needs networkx sage.plot + sage: G.is_isomorphic(L) # needs networkx True """ edges = {0: [1, 5, 6], 1: [2, 7], 2: [3, 8], 3: [4, 9], 4: [5, 10], 5: [11], @@ -3923,9 +3942,9 @@ def PetersenGraph(): ....: 3:[2,4,8], 4:[0,3,9], 5:[0,7,8], ....: 6:[1,8,9], 7:[2,5,9], 8:[3,5,6], ....: 9:[4,6,7]}) - sage: petersen_spring.show() # long time # optional - sage.plot + sage: petersen_spring.show() # long time # needs sage.plot sage: petersen_database = graphs.PetersenGraph() - sage: petersen_database.show() # long time # optional - sage.plot + sage: petersen_database.show() # long time # needs sage.plot """ from sage.graphs.generators.families import GeneralizedPetersenGraph P = GeneralizedPetersenGraph(5, 2) @@ -3970,23 +3989,24 @@ def RobertsonGraph(): EXAMPLES:: - sage: g = graphs.RobertsonGraph() # optional - networkx - sage: g.order() # optional - networkx + sage: # needs networkx + sage: g = graphs.RobertsonGraph() + sage: g.order() 19 - sage: g.size() # optional - networkx + sage: g.size() 38 - sage: g.diameter() # optional - networkx + sage: g.diameter() 3 - sage: g.girth() # optional - networkx + sage: g.girth() 5 - sage: g.charpoly().factor() # optional - networkx + sage: g.charpoly().factor() (x - 4) * (x - 1)^2 * (x^2 + x - 5) * (x^2 + x - 1) * (x^2 - 3)^2 * (x^2 + x - 4)^2 * (x^2 + x - 3)^2 - sage: g.chromatic_number() # optional - networkx + sage: g.chromatic_number() 3 - sage: g.is_hamiltonian() # optional - networkx + sage: g.is_hamiltonian() # needs sage.numerical.mip True - sage: g.is_vertex_transitive() # optional - networkx + sage: g.is_vertex_transitive() False """ from sage.graphs.generators.families import LCFGraph @@ -4024,7 +4044,7 @@ def SchlaefliGraph(): The graph is vertex-transitive:: - sage: S.is_vertex_transitive() # optional - sage.groups + sage: S.is_vertex_transitive() # needs sage.groups True The neighborhood of each vertex is isomorphic to the complement of the @@ -4079,7 +4099,7 @@ def ShrikhandeGraph(): sage: G.is_planar() False - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip True sage: G.is_eulerian() True @@ -4097,12 +4117,12 @@ def ShrikhandeGraph(): sage: G.chromatic_number() 4 - sage: G.automorphism_group().cardinality() + sage: G.automorphism_group().cardinality() # needs sage.groups 192 It is an integral graph since it has only integral eigenvalues:: - sage: G.characteristic_polynomial().factor() + sage: G.characteristic_polynomial().factor() # needs sage.libs.pari sage.modules (x - 6) * (x - 2)^6 * (x + 2)^9 It is a toroidal graph, and its embedding on a torus is dual to an @@ -4236,12 +4256,12 @@ def SousselierGraph(): 2 sage: g.diameter() 3 - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 2 - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip False sage: g.delete_vertex(g.random_vertex()) - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True """ g = Graph(name="Sousselier Graph") @@ -4317,7 +4337,7 @@ def ThomsenGraph(): Thomsen graph: Graph on 6 vertices sage: T.graph6_string() 'EFz_' - sage: (graphs.ThomsenGraph()).show() # long time # optional - sage.plot + sage: (graphs.ThomsenGraph()).show() # long time # needs sage.plot """ from sage.graphs.generators.basic import CompleteBipartiteGraph G = CompleteBipartiteGraph(3, 3) @@ -4343,9 +4363,9 @@ def TietzeGraph(): 3 sage: g.girth() 3 - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 12 - sage: g.automorphism_group().is_isomorphic(groups.permutation.Dihedral(6)) # optional - sage.groups + sage: g.automorphism_group().is_isomorphic(groups.permutation.Dihedral(6)) # needs sage.groups True """ g = Graph([(0, 9), (3, 10), (6, 11), (1, 5), (2, 7), (4, 8)], @@ -4370,11 +4390,11 @@ def TruncatedIcosidodecahedralGraph(): Unfortunately, this graph can not be constructed currently, due to numerical issues:: - sage: g = graphs.TruncatedIcosidodecahedralGraph(); g + sage: g = graphs.TruncatedIcosidodecahedralGraph(); g # needs sage.geometry.polyhedron sage.groups sage.rings.number_field Traceback (most recent call last): ... ValueError: *Error: Numerical inconsistency is found. Use the GMP exact arithmetic. - sage: g.order(), g.size() # not tested + sage: g.order(), g.size() # not tested # needs sage.geometry.polyhedron sage.groups sage.rings.number_field (120, 180) """ from sage.geometry.polyhedron.library import polytopes @@ -4397,7 +4417,7 @@ def TruncatedTetrahedralGraph(): Truncated Tetrahedron: Graph on 12 vertices sage: g.order(), g.size() (12, 18) - sage: g.is_isomorphic(polytopes.simplex(3).truncation().graph()) # optional - sage.geometry.polyhedron + sage: g.is_isomorphic(polytopes.simplex(3).truncation().graph()) # needs sage.geometry.polyhedron True """ g = Graph(':K`ESwC_EOyDl\\MCi', loops=False, multiedges=False) @@ -4416,16 +4436,17 @@ def Tutte12Cage(): EXAMPLES:: - sage: g = graphs.Tutte12Cage() # optional - networkx - sage: g.order() # optional - networkx + sage: # needs networkx + sage: g = graphs.Tutte12Cage() + sage: g.order() 126 - sage: g.size() # optional - networkx + sage: g.size() 189 - sage: g.girth() # optional - networkx + sage: g.girth() 12 - sage: g.diameter() # optional - networkx + sage: g.diameter() 6 - sage: g.show() # optional - networkx sage.plot + sage: g.show() # needs sage.plot """ L = [17, 27, -13, -59, -35, 35, -11, 13, -53, 53, -27, 21, 57, 11, -21, -57, 59, -17] @@ -4449,21 +4470,22 @@ def TutteCoxeterGraph(embedding=2): EXAMPLES:: - sage: g = graphs.TutteCoxeterGraph() # optional - networkx - sage: g.order() # optional - networkx + sage: # needs networkx + sage: g = graphs.TutteCoxeterGraph() + sage: g.order() 30 - sage: g.size() # optional - networkx + sage: g.size() 45 - sage: g.girth() # optional - networkx + sage: g.girth() 8 - sage: g.diameter() # optional - networkx + sage: g.diameter() 4 - sage: g.show() # optional - networkx sage.plot - sage: graphs.TutteCoxeterGraph(embedding=1).show() # long time # optional - networkx sage.plot + sage: g.show() # needs sage.plot + sage: graphs.TutteCoxeterGraph(embedding=1).show() # long time # needs sage.plot TESTS:: - sage: graphs.TutteCoxeterGraph(embedding=3) # optional - networkx + sage: graphs.TutteCoxeterGraph(embedding=3) # needs networkx Traceback (most recent call last): ... ValueError: the value of embedding must be 1 or 2 @@ -4516,9 +4538,13 @@ def TutteGraph(): 3 sage: g.girth() 4 - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 3 +<<<<<<< HEAD sage: g.is_hamiltonian() +======= + sage: g.is_hamiltonian() # needs sage.numerical.mip +>>>>>>> 85d4a8d443 (./sage -fixdoctests --probe all --distribution 'sagemath-graphs[modules]' src/sage/graphs/generators/smallgraphs.py; ./sage -fixdoctests src/sage/graphs/generators/smallgraphs.py) False """ g = Graph(name="Tutte Graph") @@ -4562,16 +4588,17 @@ def WagnerGraph(): EXAMPLES:: - sage: g = graphs.WagnerGraph() # optional - networkx - sage: g.order() # optional - networkx + sage: # needs networkx + sage: g = graphs.WagnerGraph() + sage: g.order() 8 - sage: g.size() # optional - networkx + sage: g.size() 12 - sage: g.girth() # optional - networkx + sage: g.girth() 4 - sage: g.diameter() # optional - networkx + sage: g.diameter() 2 - sage: g.show() # optional - networkx sage.plot + sage: g.show() # needs sage.plot """ from sage.graphs.generators.families import LCFGraph g = LCFGraph(8, [4], 8) @@ -4637,10 +4664,17 @@ def WienerArayaGraph(): 4 sage: g.is_planar() True +<<<<<<< HEAD sage: g.is_hamiltonian() # not tested -- around 30s long False sage: g.delete_vertex(g.random_vertex()) sage: g.is_hamiltonian() +======= + sage: g.is_hamiltonian() # not tested (30s) # needs sage.numerical.mip + False + sage: g.delete_vertex(g.random_vertex()) + sage: g.is_hamiltonian() # needs sage.numerical.mip +>>>>>>> 85d4a8d443 (./sage -fixdoctests --probe all --distribution 'sagemath-graphs[modules]' src/sage/graphs/generators/smallgraphs.py; ./sage -fixdoctests src/sage/graphs/generators/smallgraphs.py) True """ g = Graph(name="Wiener-Araya Graph") @@ -4695,7 +4729,11 @@ def _EllipticLinesProjectivePlaneScheme(k): TESTS:: sage: from sage.graphs.generators.smallgraphs import _EllipticLinesProjectivePlaneScheme +<<<<<<< HEAD sage: _EllipticLinesProjectivePlaneScheme(2) +======= + sage: _EllipticLinesProjectivePlaneScheme(2) # needs sage.libs.gap +>>>>>>> 85d4a8d443 (./sage -fixdoctests --probe all --distribution 'sagemath-graphs[modules]' src/sage/graphs/generators/smallgraphs.py; ./sage -fixdoctests src/sage/graphs/generators/smallgraphs.py) [ [1 0 0 0 0 0] [0 1 1 1 1 0] [0 0 0 0 0 1] [0 1 0 0 0 0] [1 0 1 1 0 1] [0 0 0 0 1 0] @@ -4738,11 +4776,12 @@ def MathonStronglyRegularGraph(t): TESTS:: - sage: G = graphs.MathonStronglyRegularGraph(1) # long time - sage: G.is_strongly_regular(parameters=True) # long time + sage: # long time + sage: G = graphs.MathonStronglyRegularGraph(1) + sage: G.is_strongly_regular(parameters=True) (784, 270, 98, 90) - sage: G = graphs.MathonStronglyRegularGraph(2) # long time - sage: G.is_strongly_regular(parameters=True) # long time + sage: G = graphs.MathonStronglyRegularGraph(2) + sage: G.is_strongly_regular(parameters=True) (784, 297, 116, 110) """ @@ -5009,12 +5048,20 @@ def IoninKharaghani765Graph(): EXAMPLES:: +<<<<<<< HEAD sage: g = graphs.IoninKharaghani765Graph(); g +======= + sage: g = graphs.IoninKharaghani765Graph(); g # needs sage.modules sage.rings.finite_rings +>>>>>>> 85d4a8d443 (./sage -fixdoctests --probe all --distribution 'sagemath-graphs[modules]' src/sage/graphs/generators/smallgraphs.py; ./sage -fixdoctests src/sage/graphs/generators/smallgraphs.py) Ionin-Kharaghani: Graph on 765 vertices TESTS:: +<<<<<<< HEAD sage: graphs.strongly_regular_graph(765, 192, 48, 48) +======= + sage: graphs.strongly_regular_graph(765, 192, 48, 48) # needs sage.modules sage.rings.finite_rings +>>>>>>> 85d4a8d443 (./sage -fixdoctests --probe all --distribution 'sagemath-graphs[modules]' src/sage/graphs/generators/smallgraphs.py; ./sage -fixdoctests src/sage/graphs/generators/smallgraphs.py) Ionin-Kharaghani: Graph on 765 vertices .. TODO:: From cd752ffa3a9806e349a34bc36290b60082398619 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 8 Jul 2023 10:53:43 -0700 Subject: [PATCH 74/87] './sage -fixdoctests --only-tags' for files conflicting with #35749 --- src/sage/graphs/generic_graph.py | 629 ++++++++++++++++--------------- 1 file changed, 323 insertions(+), 306 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index a083ed43e5e..06bee055514 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -4964,15 +4964,15 @@ def spanning_trees_count(self, root_vertex=None): EXAMPLES:: sage: G = graphs.PetersenGraph() - sage: G.spanning_trees_count() + sage: G.spanning_trees_count() # needs sage.modules 2000 :: sage: n = 11 sage: G = graphs.CompleteGraph(n) - sage: ST = G.spanning_trees_count() - sage: ST == n ^ (n - 2) + sage: ST = G.spanning_trees_count() # needs sage.modules + sage: ST == n ^ (n - 2) # needs sage.modules True :: @@ -6860,14 +6860,14 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None The Petersen Graph does have a spanning tree (it is connected):: sage: g = graphs.PetersenGraph() - sage: [T] = g.edge_disjoint_spanning_trees(1) - sage: T.is_tree() + sage: [T] = g.edge_disjoint_spanning_trees(1) # needs sage.numerical.mip + sage: T.is_tree() # needs sage.numerical.mip True Though, it does not have 2 edge-disjoint trees (as it has less than `2(|V|-1)` edges):: - sage: g.edge_disjoint_spanning_trees(2) + sage: g.edge_disjoint_spanning_trees(2) # needs sage.numerical.mip Traceback (most recent call last): ... EmptySetError: this graph does not contain the required number of trees/arborescences @@ -6877,38 +6877,38 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None sage: g = digraphs.RandomDirectedGNP(11, .3) # reduced from 30 to 11, cf. #32169 sage: k = Integer(g.edge_connectivity()) - sage: while not k: + sage: while not k: # needs sage.numerical.mip ....: g = digraphs.RandomDirectedGNP(11, .3) ....: k = Integer(g.edge_connectivity()) - sage: arborescences = g.edge_disjoint_spanning_trees(k) # long time (up to 15s on sage.math, 2011) - sage: all(a.is_directed_acyclic() for a in arborescences) # long time + sage: arborescences = g.edge_disjoint_spanning_trees(k) # long time (up to 15s on sage.math, 2011), needs sage.numerical.mip + sage: all(a.is_directed_acyclic() for a in arborescences) # long time, needs sage.numerical.mip True - sage: all(a.is_connected() for a in arborescences) # long time + sage: all(a.is_connected() for a in arborescences) # long time # needs sage.numerical.mip True In the undirected case, we can only ensure half of it:: sage: g = graphs.RandomGNP(14, .3) # reduced from 30 to 14, see #32169 - sage: while not g.is_biconnected(): + sage: while not g.is_biconnected(): # needs sage.numerical.mip ....: g = graphs.RandomGNP(14, .3) - sage: k = Integer(g.edge_connectivity()) // 2 - sage: trees = g.edge_disjoint_spanning_trees(k) - sage: all(t.is_tree() for t in trees) + sage: k = Integer(g.edge_connectivity()) // 2 # needs sage.numerical.mip + sage: trees = g.edge_disjoint_spanning_trees(k) # needs sage.numerical.mip + sage: all(t.is_tree() for t in trees) # needs sage.numerical.mip True Check the validity of the algorithms for undirected graphs:: sage: g = graphs.RandomGNP(12, .7) sage: k = Integer(g.edge_connectivity()) // 2 - sage: trees = g.edge_disjoint_spanning_trees(k, algorithm="MILP") - sage: all(t.is_tree() for t in trees) + sage: trees = g.edge_disjoint_spanning_trees(k, algorithm="MILP") # needs sage.numerical.mip + sage: all(t.is_tree() for t in trees) # needs sage.numerical.mip True - sage: all(g.order() == t.size() + 1 for t in trees) + sage: all(g.order() == t.size() + 1 for t in trees) # needs sage.numerical.mip True - sage: trees = g.edge_disjoint_spanning_trees(k, algorithm="Roskind-Tarjan") - sage: all(t.is_tree() for t in trees) + sage: trees = g.edge_disjoint_spanning_trees(k, algorithm="Roskind-Tarjan") # needs sage.numerical.mip + sage: all(t.is_tree() for t in trees) # needs sage.numerical.mip True - sage: all(g.order() == t.size() + 1 for t in trees) + sage: all(g.order() == t.size() + 1 for t in trees) # needs sage.numerical.mip True Example of :trac:`32169`:: @@ -6919,7 +6919,7 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None sage: G = DiGraph(d6, format='dig6') sage: G.edge_connectivity() 5 - sage: G.edge_disjoint_spanning_trees(5) # long time + sage: G.edge_disjoint_spanning_trees(5) # long time # needs sage.numerical.mip [Digraph on 28 vertices, Digraph on 28 vertices, Digraph on 28 vertices, @@ -6928,6 +6928,7 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None Small cases:: + sage: # needs sage.numerical.mip sage: Graph().edge_disjoint_spanning_trees(0) [] sage: Graph(1).edge_disjoint_spanning_trees(0) @@ -6947,11 +6948,11 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None Choice of the algorithm:: - sage: Graph().edge_disjoint_spanning_trees(0, algorithm=None) + sage: Graph().edge_disjoint_spanning_trees(0, algorithm=None) # needs sage.numerical.mip [] sage: Graph().edge_disjoint_spanning_trees(0, algorithm="Roskind-Tarjan") [] - sage: Graph().edge_disjoint_spanning_trees(0, algorithm="MILP") + sage: Graph().edge_disjoint_spanning_trees(0, algorithm="MILP") # needs sage.numerical.mip [] sage: Graph().edge_disjoint_spanning_trees(0, algorithm="foo") Traceback (most recent call last): @@ -6959,7 +6960,7 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None ValueError: algorithm must be None, "Rosking-Tarjan" or "MILP" for undirected graphs sage: DiGraph().edge_disjoint_spanning_trees(0, algorithm=None) [] - sage: DiGraph().edge_disjoint_spanning_trees(0, algorithm="MILP") + sage: DiGraph().edge_disjoint_spanning_trees(0, algorithm="MILP") # needs sage.numerical.mip [] sage: DiGraph().edge_disjoint_spanning_trees(0, algorithm="foo") Traceback (most recent call last): @@ -7370,25 +7371,25 @@ def vertex_cut(self, s, t, value_only=True, vertices=False, solver=None, verbose A basic application in the Pappus graph:: sage: g = graphs.PappusGraph() - sage: g.vertex_cut(1, 16, value_only=True) + sage: g.vertex_cut(1, 16, value_only=True) # needs sage.numerical.mip 3 In the bipartite complete graph `K_{2,8}`, a cut between the two vertices in the size `2` part consists of the other `8` vertices:: sage: g = graphs.CompleteBipartiteGraph(2, 8) - sage: [value, vertices] = g.vertex_cut(0, 1, value_only=False) - sage: print(value) + sage: [value, vertices] = g.vertex_cut(0, 1, value_only=False) # needs sage.numerical.mip + sage: print(value) # needs sage.numerical.mip 8 - sage: vertices == list(range(2, 10)) + sage: vertices == list(range(2, 10)) # needs sage.numerical.mip True Clearly, in this case the two sides of the cut are singletons:: - sage: [value, vertices, [set1, set2]] = g.vertex_cut(0, 1, vertices=True) - sage: len(set1) == 1 + sage: [value, vertices, [set1, set2]] = g.vertex_cut(0, 1, vertices=True) # needs sage.numerical.mip + sage: len(set1) == 1 # needs sage.numerical.mip True - sage: len(set2) == 1 + sage: len(set2) == 1 # needs sage.numerical.mip True """ from sage.numerical.mip import MixedIntegerLinearProgram @@ -7495,35 +7496,35 @@ def multiway_cut(self, vertices, value_only=False, use_edge_labels=False, edge cut:: sage: g = graphs.PetersenGraph() - sage: g.edge_cut(0,3) == g.multiway_cut([0,3], value_only = True) + sage: g.edge_cut(0,3) == g.multiway_cut([0,3], value_only=True) # needs sage.numerical.mip True As Petersen's graph is `3`-regular, a minimum multiway cut between three vertices contains at most `2\times 3` edges (which could correspond to the neighborhood of 2 vertices):: - sage: g.multiway_cut([0,3,9], value_only = True) == 2*3 + sage: g.multiway_cut([0,3,9], value_only=True) == 2*3 # needs sage.numerical.mip True In this case, though, the vertices are an independent set. If we pick instead vertices `0,9,` and `7`, we can save `4` edges in the multiway cut:: - sage: g.multiway_cut([0,7,9], value_only = True) == 2*3 - 1 + sage: g.multiway_cut([0,7,9], value_only=True) == 2*3 - 1 # needs sage.numerical.mip True This example, though, does not work in the directed case anymore, as it is not possible in Petersen's graph to mutualise edges:: sage: g = DiGraph(g) - sage: g.multiway_cut([0,7,9], value_only = True) == 3*3 + sage: g.multiway_cut([0,7,9], value_only=True) == 3*3 # needs sage.numerical.mip True Of course, a multiway cut between the whole vertex set contains all the edges of the graph:: - sage: C = g.multiway_cut(g.vertices(sort=False)) - sage: set(C) == set(g.edges(sort=False)) + sage: C = g.multiway_cut(g.vertices(sort=False)) # needs sage.numerical.mip + sage: set(C) == set(g.edges(sort=False)) # needs sage.numerical.mip True """ self._scream_if_not_simple(allow_loops=True) @@ -7634,17 +7635,18 @@ def max_cut(self, value_only=True, use_edge_labels=False, vertices=False, edges, and the two sets of vertices are the two sides:: sage: g = graphs.CompleteBipartiteGraph(5,6) - sage: [ value, edges, [ setA, setB ]] = g.max_cut(vertices=True) - sage: value == 5*6 + sage: [ value, edges, [ setA, setB ]] = g.max_cut(vertices=True) # needs sage.numerical.mip + sage: value == 5*6 # needs sage.numerical.mip True - sage: bsetA, bsetB = map(list,g.bipartite_sets()) - sage: (bsetA == setA and bsetB == setB ) or ((bsetA == setB and bsetB == setA )) + sage: bsetA, bsetB = map(list, g.bipartite_sets()) # needs sage.numerical.mip + sage: ((bsetA == setA and bsetB == setB) # needs sage.numerical.mip + ....: or (bsetA == setB and bsetB == setA)) True The max cut of a Petersen graph:: - sage: g=graphs.PetersenGraph() - sage: g.max_cut() + sage: g = graphs.PetersenGraph() + sage: g.max_cut() # needs sage.numerical.mip 12 TESTS:: @@ -7809,8 +7811,8 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", `n - 2`:: sage: g = graphs.PetersenGraph() - sage: lp = g.longest_path() - sage: lp.order() >= g.order() - 2 + sage: lp = g.longest_path() # needs sage.numerical.mip + sage: lp.order() >= g.order() - 2 # needs sage.numerical.mip True The heuristic totally agrees:: @@ -7831,8 +7833,8 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", sage: g = graphs.RandomGNP(15, 0.3) sage: for u, v in g.edge_iterator(labels=False): ....: g.set_edge_label(u, v, random()) - sage: lp = g.longest_path() - sage: (not lp.is_forest() or not max(lp.degree()) <= 2 + sage: lp = g.longest_path() # needs sage.numerical.mip + sage: (not lp.is_forest() or not max(lp.degree()) <= 2 # needs sage.numerical.mip ....: or not lp.is_connected()) False @@ -7850,9 +7852,9 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", sage: g1 = graphs.PetersenGraph() sage: g2 = 2 * g1 - sage: lp1 = g1.longest_path() - sage: lp2 = g2.longest_path() - sage: len(lp1) == len(lp2) + sage: lp1 = g1.longest_path() # needs sage.numerical.mip + sage: lp2 = g2.longest_path() # needs sage.numerical.mip + sage: len(lp1) == len(lp2) # needs sage.numerical.mip True Disconnected graphs weighted:: @@ -7861,13 +7863,14 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", sage: for u,v in g.edge_iterator(labels=False): ....: g.set_edge_label(u, v, random()) sage: g2 = 2 * g1 - sage: lp1 = g1.longest_path(use_edge_labels=True) - sage: lp2 = g2.longest_path(use_edge_labels=True) - sage: lp1[0] == lp2[0] + sage: lp1 = g1.longest_path(use_edge_labels=True) # needs sage.numerical.mip + sage: lp2 = g2.longest_path(use_edge_labels=True) # needs sage.numerical.mip + sage: lp1[0] == lp2[0] # needs sage.numerical.mip True Empty graphs:: + sage: # needs sage.numerical.mip sage: Graph().longest_path() Graph on 0 vertices sage: Graph().longest_path(use_edge_labels=True) @@ -7881,13 +7884,13 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", sage: G = Graph() sage: G.add_vertex(0) - sage: G.longest_path() + sage: G.longest_path() # needs sage.numerical.mip Graph on 0 vertices - sage: G.longest_path(use_edge_labels=True) + sage: G.longest_path(use_edge_labels=True) # needs sage.numerical.mip [0, Graph on 0 vertices] - sage: graphs.CompleteGraph(1).longest_path() + sage: graphs.CompleteGraph(1).longest_path() # needs sage.numerical.mip Graph on 0 vertices - sage: graphs.CompleteGraph(1).longest_path(use_edge_labels=True) + sage: graphs.CompleteGraph(1).longest_path(use_edge_labels=True) # needs sage.numerical.mip [0, Graph on 0 vertices] Random test for digraphs:: @@ -7895,8 +7898,8 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", sage: g = digraphs.RandomDirectedGNP(15, 0.3) sage: for u, v in g.edge_iterator(labels=False): ....: g.set_edge_label(u, v, random()) - sage: lp = g.longest_path() - sage: (not lp.is_directed_acyclic() or + sage: lp = g.longest_path() # needs sage.numerical.mip + sage: (not lp.is_directed_acyclic() or # needs sage.numerical.mip ....: not max(lp.out_degree()) <= 1 or ....: not max(lp.in_degree()) <= 1 or ....: not lp.is_connected()) @@ -7905,7 +7908,7 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", :trac:`13019`:: sage: g = graphs.CompleteGraph(5).to_directed() - sage: g.longest_path(s=1, t=2) + sage: g.longest_path(s=1, t=2) # needs sage.numerical.mip Subgraph of (Complete graph): Digraph on 5 vertices :trac:`14412`:: @@ -7913,7 +7916,7 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", sage: l = [(0, 1), (0, 3), (2, 0), (3, 4)] sage: G = DiGraph(l) sage: H = {(0, 3), (2, 0), (3, 4)} - sage: H == {x for x in G.longest_path().edge_iterator(labels=False)} + sage: H == {x for x in G.longest_path().edge_iterator(labels=False)} # needs sage.numerical.mip True """ self._scream_if_not_simple() @@ -8190,15 +8193,15 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, Hamiltonian path starting from `(0, 0)` and ending at `(0, 1)`:: sage: g = graphs.Grid2dGraph(3, 3) - sage: g.hamiltonian_path() + sage: g.hamiltonian_path() # needs sage.numerical.mip Hamiltonian path from 2D Grid Graph for [3, 3]: Graph on 9 vertices - sage: g.hamiltonian_path(s=(0, 0), t=(2, 2)) + sage: g.hamiltonian_path(s=(0, 0), t=(2, 2)) # needs sage.numerical.mip Hamiltonian path from 2D Grid Graph for [3, 3]: Graph on 9 vertices - sage: g.hamiltonian_path(s=(0, 0), t=(2, 2), use_edge_labels=True) + sage: g.hamiltonian_path(s=(0, 0), t=(2, 2), use_edge_labels=True) # needs sage.numerical.mip (8, Hamiltonian path from 2D Grid Graph for [3, 3]: Graph on 9 vertices) - sage: g.hamiltonian_path(s=(0, 0), t=(0, 1)) is None + sage: g.hamiltonian_path(s=(0, 0), t=(0, 1)) is None # needs sage.numerical.mip True - sage: g.hamiltonian_path(s=(0, 0), t=(0, 1), use_edge_labels=True) + sage: g.hamiltonian_path(s=(0, 0), t=(0, 1), use_edge_labels=True) # needs sage.numerical.mip (0, None) TESTS: @@ -8206,13 +8209,13 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, Empty and one-element graphs:: sage: g = Graph() - sage: g.hamiltonian_path() + sage: g.hamiltonian_path() # needs sage.numerical.mip Traceback (most recent call last): ... ValueError: the Hamiltonian path problem is not well defined for empty and one-element (di)graphs sage: g = Graph(1) - sage: g.hamiltonian_path() + sage: g.hamiltonian_path() # needs sage.numerical.mip Traceback (most recent call last): ... ValueError: the Hamiltonian path problem is not well defined @@ -8221,20 +8224,22 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, A non-connected (di)graph has no hamiltonian path:: sage: g = Graph(2) - sage: g.hamiltonian_path() is None + sage: g.hamiltonian_path() is None # needs sage.numerical.mip True - sage: g.hamiltonian_path(use_edge_labels=True) + sage: g.hamiltonian_path(use_edge_labels=True) # needs sage.numerical.mip (0, None) sage: g = DiGraph(2) - sage: g.hamiltonian_path() is None + sage: g.hamiltonian_path() is None # needs sage.numerical.mip True Asking for a minimum (resp., maximum) weight Hamiltonian path:: sage: G = Graph([(0, 1, 1), (0, 2, 2), (0, 3, 1), (1, 2, 1), (1, 3, 2), (2, 3, 1)]) - sage: print(G.hamiltonian_path(s=0, t=1, use_edge_labels=True, maximize=False)[0]) + sage: print(G.hamiltonian_path(s=0, t=1, use_edge_labels=True, # needs sage.numerical.mip + ....: maximize=False)[0]) 3 - sage: print(G.hamiltonian_path(s=0, t=1, use_edge_labels=True, maximize=True)[0]) + sage: print(G.hamiltonian_path(s=0, t=1, use_edge_labels=True, # needs sage.numerical.mip + ....: maximize=True)[0]) 5 Parameter ``algorithm`` must be either ``'backtrack'`` or ``'MILP'``:: @@ -8444,29 +8449,28 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, The Heawood graph is known to be Hamiltonian:: sage: g = graphs.HeawoodGraph() - sage: tsp = g.traveling_salesman_problem() - sage: tsp + sage: tsp = g.traveling_salesman_problem(); tsp # needs sage.numerical.mip TSP from Heawood graph: Graph on 14 vertices The solution to the TSP has to be connected:: - sage: tsp.is_connected() + sage: tsp.is_connected() # needs sage.numerical.mip True It must also be a `2`-regular graph:: - sage: tsp.is_regular(k=2) + sage: tsp.is_regular(k=2) # needs sage.numerical.mip True And obviously it is a subgraph of the Heawood graph:: - sage: tsp.is_subgraph(g, induced=False) + sage: tsp.is_subgraph(g, induced=False) # needs sage.numerical.mip True On the other hand, the Petersen Graph is known not to be Hamiltonian:: sage: g = graphs.PetersenGraph() - sage: tsp = g.traveling_salesman_problem() + sage: tsp = g.traveling_salesman_problem() # needs sage.numerical.mip Traceback (most recent call last): ... EmptySetError: the given graph is not Hamiltonian @@ -8485,8 +8489,8 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, ....: g.add_edge(u, v) ....: g.set_edge_label(u, v, 2) - sage: tsp = g.traveling_salesman_problem(use_edge_labels=True) - sage: sum( tsp.edge_labels() ) < 2 * 10 + sage: tsp = g.traveling_salesman_problem(use_edge_labels=True) # needs sage.numerical.mip + sage: sum( tsp.edge_labels() ) < 2 * 10 # needs sage.numerical.mip True If we pick `1/2` instead of `2` as a cost for these new edges, they @@ -8495,18 +8499,20 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, sage: for u, v in cycle.edges(labels=None, sort=False): ....: g.set_edge_label(u,v,1/2) - sage: tsp = g.traveling_salesman_problem(use_edge_labels=True) - sage: sum(tsp.edge_labels()) == (1/2) * 10 + sage: tsp = g.traveling_salesman_problem(use_edge_labels=True) # needs sage.numerical.mip + sage: sum(tsp.edge_labels()) == (1/2) * 10 # needs sage.numerical.mip True Search for a minimum and a maximum weight Hamiltonian cycle:: sage: G = Graph([(0, 1, 1), (0, 2, 2), (0, 3, 1), (1, 2, 1), (1, 3, 2), (2, 3, 1)]) - sage: tsp = G.traveling_salesman_problem(use_edge_labels=True, maximize=False) - sage: print(sum(tsp.edge_labels())) + sage: tsp = G.traveling_salesman_problem(use_edge_labels=True, # needs sage.numerical.mip + ....: maximize=False) + sage: print(sum(tsp.edge_labels())) # needs sage.numerical.mip 4 - sage: tsp = G.traveling_salesman_problem(use_edge_labels=True, maximize=True) - sage: print(sum(tsp.edge_labels())) + sage: tsp = G.traveling_salesman_problem(use_edge_labels=True, # needs sage.numerical.mip + ....: maximize=True) + sage: print(sum(tsp.edge_labels())) # needs sage.numerical.mip 6 TESTS: @@ -8523,9 +8529,10 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, sage: for u, v in graphs.CycleGraph(n).edges(labels=False, sort=False): ....: if not g.has_edge(u, v): ....: g.add_edge(u, v, ZZ.random_element(1,100000)) - sage: v1 = g.traveling_salesman_problem(constraint_generation=False, use_edge_labels=True) - sage: v2 = g.traveling_salesman_problem(use_edge_labels=True) - sage: sum(v1.edge_labels()) == sum(v2.edge_labels()) + sage: v1 = g.traveling_salesman_problem(constraint_generation=False, # needs sage.numerical.mip + ....: use_edge_labels=True) + sage: v2 = g.traveling_salesman_problem(use_edge_labels=True) # needs sage.numerical.mip + sage: sum(v1.edge_labels()) == sum(v2.edge_labels()) # needs sage.numerical.mip True Then for digraphs:: @@ -8539,61 +8546,62 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, sage: for u, v in digraphs.Circuit(n).edges(labels=False, sort=False): ....: if not g.has_edge(u, v): ....: g.add_edge(u, v, ZZ.random_element(1,100000)) - sage: v2 = g.traveling_salesman_problem(use_edge_labels=True) - sage: v1 = g.traveling_salesman_problem(constraint_generation=False, use_edge_labels=True) - sage: sum(v1.edge_labels()) == sum(v2.edge_labels()) + sage: v2 = g.traveling_salesman_problem(use_edge_labels=True) # needs sage.numerical.mip + sage: v1 = g.traveling_salesman_problem(constraint_generation=False, # needs sage.numerical.mip + ....: use_edge_labels=True) + sage: sum(v1.edge_labels()) == sum(v2.edge_labels()) # needs sage.numerical.mip True Simple tests for multiple edges and loops:: sage: G = DiGraph(multiedges=True, loops=True) - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip False sage: G.add_vertex(0) - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip False sage: G.add_edge(0, 0, 1) sage: G.add_edge(0, 0, 2) - sage: tsp = G.traveling_salesman_problem(use_edge_labels=True) + sage: tsp = G.traveling_salesman_problem(use_edge_labels=True) # needs sage.numerical.mip Traceback (most recent call last): ... EmptySetError: the given graph is not Hamiltonian sage: G.add_vertex(1) - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip False sage: G.add_edge(0, 1, 2) sage: G.add_edge(0, 1, 3) sage: G.add_edge(1, 1, 1) sage: G.add_edge(1, 0, 2) - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip True - sage: tsp = G.traveling_salesman_problem(use_edge_labels=True) - sage: sum(tsp.edge_labels()) + sage: tsp = G.traveling_salesman_problem(use_edge_labels=True) # needs sage.numerical.mip + sage: sum(tsp.edge_labels()) # needs sage.numerical.mip 4 Graphs on 2 vertices:: - sage: Graph([(0, 1), (0, 1)], multiedges=True).is_hamiltonian() + sage: Graph([(0, 1), (0, 1)], multiedges=True).is_hamiltonian() # needs sage.numerical.mip True - sage: DiGraph([(0, 1), (0, 1)], multiedges=True).is_hamiltonian() + sage: DiGraph([(0, 1), (0, 1)], multiedges=True).is_hamiltonian() # needs sage.numerical.mip False - sage: DiGraph([(0, 1), (1, 0)], multiedges=True).is_hamiltonian() + sage: DiGraph([(0, 1), (1, 0)], multiedges=True).is_hamiltonian() # needs sage.numerical.mip True sage: G = digraphs.Complete(2, loops=True) - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip True sage: G.remove_loops() - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip True sage: G.allow_loops(False) - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip True Check that weight 0 edges are handled correctly (see :trac:`16214`):: sage: G = Graph([(0, 1, 1), (0, 2, 0), (0, 3, 1), (1, 2, 1), (1, 3, 0), (2, 3, 1)]) - sage: tsp = G.traveling_salesman_problem(use_edge_labels=True) - sage: sum(tsp.edge_labels()) + sage: tsp = G.traveling_salesman_problem(use_edge_labels=True) # needs sage.numerical.mip + sage: sum(tsp.edge_labels()) # needs sage.numerical.mip 2 """ from sage.categories.sets_cat import EmptySetError @@ -8953,13 +8961,13 @@ def hamiltonian_cycle(self, algorithm='tsp', solver=None, constraint_generation= The Heawood Graph is known to be Hamiltonian :: sage: g = graphs.HeawoodGraph() - sage: g.hamiltonian_cycle() + sage: g.hamiltonian_cycle() # needs sage.numerical.mip TSP from Heawood graph: Graph on 14 vertices The Petersen Graph, though, is not :: sage: g = graphs.PetersenGraph() - sage: g.hamiltonian_cycle() + sage: g.hamiltonian_cycle() # needs sage.numerical.mip Traceback (most recent call last): ... EmptySetError: the given graph is not Hamiltonian @@ -9093,11 +9101,11 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, The necessary example:: sage: g = graphs.PetersenGraph() - sage: fvs = g.feedback_vertex_set() - sage: len(fvs) + sage: fvs = g.feedback_vertex_set() # needs sage.numerical.mip + sage: len(fvs) # needs sage.numerical.mip 3 - sage: g.delete_vertices(fvs) - sage: g.is_forest() + sage: g.delete_vertices(fvs) # needs sage.numerical.mip + sage: g.is_forest() # needs sage.numerical.mip True In a digraph built from a graph, any edge is replaced by arcs going in @@ -9108,19 +9116,19 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, sage: cycle = graphs.CycleGraph(5) sage: dcycle = DiGraph(cycle) - sage: cycle.vertex_cover(value_only=True) + sage: cycle.vertex_cover(value_only=True) # needs sage.numerical.mip 3 - sage: feedback = dcycle.feedback_vertex_set() - sage: len(feedback) + sage: feedback = dcycle.feedback_vertex_set() # needs sage.numerical.mip + sage: len(feedback) # needs sage.numerical.mip 3 - sage: u,v = next(cycle.edge_iterator(labels=None)) - sage: u in feedback or v in feedback + sage: u,v = next(cycle.edge_iterator(labels=None)) # needs sage.numerical.mip + sage: u in feedback or v in feedback # needs sage.numerical.mip True For a circuit, the minimum feedback arc set is clearly `1`:: sage: circuit = digraphs.Circuit(5) - sage: circuit.feedback_vertex_set(value_only=True) == 1 + sage: circuit.feedback_vertex_set(value_only=True) == 1 # needs sage.numerical.mip True TESTS: @@ -9128,16 +9136,16 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, Comparing with/without constraint generation:: sage: g = digraphs.RandomDirectedGNP(10, .3) - sage: x = g.feedback_vertex_set(value_only=True) - sage: y = g.feedback_vertex_set(value_only=True, - ....: constraint_generation=False) - sage: x == y + sage: x = g.feedback_vertex_set(value_only=True) # needs sage.numerical.mip + sage: y = g.feedback_vertex_set(value_only=True, # needs sage.numerical.mip + ....: constraint_generation=False) + sage: x == y # needs sage.numerical.mip True Bad algorithm:: sage: g = graphs.PetersenGraph() - sage: g.feedback_vertex_set(constraint_generation=False) + sage: g.feedback_vertex_set(constraint_generation=False) # needs sage.numerical.mip Traceback (most recent call last): ... ValueError: the only implementation available for undirected graphs is with constraint_generation set to True @@ -9621,19 +9629,19 @@ def nowhere_zero_flow(self, k=None, solver=None, verbose=0, *, integrality_toler 4-nowhere zero flow:: sage: g = graphs.PetersenGraph() - sage: h = g.nowhere_zero_flow(k=5) - sage: sorted(set(h.edge_labels())) + sage: h = g.nowhere_zero_flow(k=5) # needs sage.numerical.mip + sage: sorted(set(h.edge_labels())) # needs sage.numerical.mip [1, 2, 3, 4] - sage: h = g.nowhere_zero_flow(k=3) + sage: h = g.nowhere_zero_flow(k=3) # needs sage.numerical.mip Traceback (most recent call last): ... EmptySetError: the problem has no feasible solution The de Bruijn digraph admits a 2-nowhere zero flow:: - sage: g = digraphs.DeBruijn(2, 3) - sage: h = g.nowhere_zero_flow(k=2) - sage: sorted(set(h.edge_labels())) + sage: g = digraphs.DeBruijn(2, 3) # needs sage.combinat + sage: h = g.nowhere_zero_flow(k=2) # needs sage.combinat sage.numerical.mip + sage: sorted(set(h.edge_labels())) # needs sage.combinat sage.numerical.mip [-1, 1] TESTS: @@ -9641,7 +9649,7 @@ def nowhere_zero_flow(self, k=None, solver=None, verbose=0, *, integrality_toler Empty graph:: sage: G = Graph() - sage: G.nowhere_zero_flow() + sage: G.nowhere_zero_flow() # needs sage.numerical.mip Digraph on 0 vertices Graph with one vertex:: @@ -9649,47 +9657,47 @@ def nowhere_zero_flow(self, k=None, solver=None, verbose=0, *, integrality_toler sage: G = Graph([[1], []]) sage: G Graph on 1 vertex - sage: G.nowhere_zero_flow() + sage: G.nowhere_zero_flow() # needs sage.numerical.mip Digraph on 1 vertex Loops and multiple edges:: sage: g = Graph([(0, 0), (0, 0)], loops=True, multiedges=True) - sage: g.nowhere_zero_flow().edges(sort=True) + sage: g.nowhere_zero_flow().edges(sort=True) # needs sage.numerical.mip [(0, 0, 1), (0, 0, 1)] sage: g = Graph([(0, 0), (0, 1), (0, 1)], loops=True, multiedges=True) - sage: g.nowhere_zero_flow(k=2).edges(sort=True) + sage: g.nowhere_zero_flow(k=2).edges(sort=True) # needs sage.numerical.mip [(0, 0, 1), (0, 1, 1), (1, 0, 1)] sage: g = DiGraph([(0, 0), (0, 0)], loops=True, multiedges=True) - sage: g.nowhere_zero_flow().edges(sort=True) + sage: g.nowhere_zero_flow().edges(sort=True) # needs sage.numerical.mip [(0, 0, 1), (0, 0, 1)] sage: g = DiGraph([(0, 0), (0, 1), (0, 1)], loops=True, multiedges=True) - sage: g.nowhere_zero_flow(k=2).edges(sort=True) + sage: g.nowhere_zero_flow(k=2).edges(sort=True) # needs sage.numerical.mip [(0, 0, 1), (0, 1, -1), (0, 1, 1)] Multiple connected components:: sage: g = graphs.CycleGraph(3) * 2 - sage: h = g.nowhere_zero_flow() - sage: h.connected_components_sizes() + sage: h = g.nowhere_zero_flow() # needs sage.numerical.mip + sage: h.connected_components_sizes() # needs sage.numerical.mip [3, 3] (Di)Graphs with bridges:: sage: g = graphs.PathGraph(2) - sage: g.nowhere_zero_flow() + sage: g.nowhere_zero_flow() # needs sage.numerical.mip Traceback (most recent call last): ... EmptySetError: (di)graphs with bridges have no feasible solution sage: g = digraphs.Path(2) - sage: g.nowhere_zero_flow() + sage: g.nowhere_zero_flow() # needs sage.numerical.mip Traceback (most recent call last): ... EmptySetError: (di)graphs with bridges have no feasible solution Too small value of ``k``:: - sage: Graph().nowhere_zero_flow(k=1) + sage: Graph().nowhere_zero_flow(k=1) # needs sage.numerical.mip Traceback (most recent call last): ... ValueError: parameter 'k' must be at least 2 @@ -10010,22 +10018,22 @@ def multicommodity_flow(self, terminals, integer=True, use_edge_labels=False, matching in a graph, and to consider the paired vertices as terminals :: sage: g = graphs.PetersenGraph() - sage: matching = [(u,v) for u,v,_ in g.matching()] - sage: h = g.multicommodity_flow(matching) - sage: len(h) + sage: matching = [(u,v) for u,v,_ in g.matching()] # needs networkx + sage: h = g.multicommodity_flow(matching) # needs networkx + sage: len(h) # needs networkx 5 We could also have considered ``g`` as symmetric and computed the multicommodity flow in this version instead. In this case, however edges can be used in both directions at the same time:: - sage: h = DiGraph(g).multicommodity_flow(matching) - sage: len(h) + sage: h = DiGraph(g).multicommodity_flow(matching) # needs networkx + sage: len(h) # needs networkx 5 An exception is raised when the problem has no solution :: - sage: h = g.multicommodity_flow([(u,v,3) for u,v in matching]) + sage: h = g.multicommodity_flow([(u,v,3) for u,v in matching]) # needs networkx Traceback (most recent call last): ... EmptySetError: the multicommodity flow problem has no solution @@ -10182,7 +10190,7 @@ def _build_flow_graph(self, flow, integer): Isolated zero-cost flow cycles are also removed:: - sage: g = digraphs.DeBruijn(2, 3) + sage: g = digraphs.DeBruijn(2, 3) # needs sage.combinat sage: flow = {('000', '001'): 1, ('010', '101'): 1, ('101', '010'): 1} sage: flow_graph = g._build_flow_graph(flow, True) sage: flow_graph.edges(sort=True) @@ -10258,13 +10266,13 @@ def disjoint_routed_paths(self, pairs, solver=None, verbose=0, top-right corner to the bottom-right corner is easy:: sage: g = graphs.Grid2dGraph(5, 5) - sage: p1,p2 = g.disjoint_routed_paths([((0, 0), (0, 4)), ((4, 4), (4, 0))]) + sage: p1,p2 = g.disjoint_routed_paths([((0, 0), (0, 4)), ((4, 4), (4, 0))]) # needs sage.numerical.mip Though there is obviously no solution to the problem in which each corner is sending information to the opposite one:: sage: g = graphs.Grid2dGraph(5, 5) - sage: p1,p2 = g.disjoint_routed_paths([((0, 0), (4, 4)), ((0, 4), (4, 0))]) + sage: p1,p2 = g.disjoint_routed_paths([((0, 0), (4, 4)), ((0, 4), (4, 0))]) # needs sage.numerical.mip Traceback (most recent call last): ... EmptySetError: the disjoint routed paths do not exist @@ -10384,7 +10392,7 @@ def vertex_disjoint_paths(self, s, t, solver=None, verbose=0, In a complete bipartite graph :: sage: g = graphs.CompleteBipartiteGraph(2, 3) - sage: g.vertex_disjoint_paths(0, 1) + sage: g.vertex_disjoint_paths(0, 1) # needs sage.numerical.mip [[0, 2, 1], [0, 3, 1], [0, 4, 1]] TESTS: @@ -10392,9 +10400,9 @@ def vertex_disjoint_paths(self, s, t, solver=None, verbose=0, Fix issues reported in :trac:`22990`:: sage: g = digraphs.Path(2) - sage: g.vertex_disjoint_paths(0, 1) + sage: g.vertex_disjoint_paths(0, 1) # needs sage.numerical.mip [[0, 1]] - sage: g.vertex_disjoint_paths(1, 0) + sage: g.vertex_disjoint_paths(1, 0) # needs sage.numerical.mip [] """ obj, flow_graph = self.flow(s, t, value_only=False, integer=True, use_edge_labels=False, @@ -10507,14 +10515,14 @@ def pagerank(self, alpha=0.85, personalization=None, by_weight=False, 4: 0.3063198690713853, 5: 0.1700057609707141, 6: 0.05390084497706962} - sage: G.pagerank(algorithm="Scipy") # abs tol 1e-9 # needs scipy + sage: G.pagerank(algorithm="Scipy") # abs tol 1e-9 # needs networkx scipy {1: 0.16112205885619563, 2: 0.1619531043247219, 3: 0.16112205885619563, 4: 0.2374999999999999, 5: 0.17775588228760858, 6: 0.100546895675278} - sage: G.pagerank(algorithm="Scipy", by_weight=True) # abs tol 1e-9 # needs scipy + sage: G.pagerank(algorithm="Scipy", by_weight=True) # abs tol 1e-9 # needs networkx scipy {1: 0.16459583718588994, 2: 0.13977928595154515, 3: 0.16539840184339605, @@ -10528,14 +10536,14 @@ def pagerank(self, alpha=0.85, personalization=None, by_weight=False, 4: 0.23749999999999993, 5: 0.17775603392041744, 6: 0.10054631441617742} - sage: G.pagerank() # abs tol 1e-9 + sage: G.pagerank() # abs tol 1e-9 # needs networkx {1: 0.16112205885619563, 2: 0.1619531043247219, 3: 0.16112205885619563, 4: 0.2374999999999999, 5: 0.17775588228760858, 6: 0.100546895675278} - sage: G.pagerank(by_weight=True) # abs tol 1e-9 + sage: G.pagerank(by_weight=True) # abs tol 1e-9 # needs networkx {1: 0.16459583718588994, 2: 0.13977928595154515, 3: 0.16539840184339605, @@ -11395,11 +11403,11 @@ def vertices(self, sort=None, key=None, degree=None, vertex_property=None): sage: t = polygen(QQ, 't') sage: K = Graph({5*t: [t^2], t^2: [t^2+2], t^2+2: [4*t^2-6], 4*t^2-6: [5*t]}) - sage: dsc = sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint.discriminant - sage: verts = K.vertices(sort=True, key=dsc) - sage: verts + sage: from sage.rings.polynomial.polynomial_rational_flint import Polynomial_rational_flint # needs sage.libs.flint + sage: dsc = Polynomial_rational_flint.discriminant # needs sage.libs.flint + sage: verts = K.vertices(sort=True, key=dsc); verts # needs sage.libs.flint [t^2 + 2, t^2, 5*t, 4*t^2 - 6] - sage: [x.discriminant() for x in verts] + sage: [x.discriminant() for x in verts] # needs sage.libs.flint [-8, 0, 1, 96] TESTS: @@ -13924,7 +13932,7 @@ def subgraph_search_count(self, G, induced=False): sage: T3 = digraphs.TransitiveTournament(3) sage: T5.subgraph_search_count(T3) # needs sage.modules 10 - sage: binomial(5,3) + sage: binomial(5,3) # needs sage.symbolic 10 sage: T3.is_isomorphic(T5.subgraph(vertices=[0, 1, 2])) # needs sage.modules True @@ -15275,9 +15283,9 @@ def clustering_average(self, implementation=None): The result is the same with all implementations:: + sage: # needs networkx sage: G = graphs.RandomGNM(10,20) - sage: impls = ['boost','sparse_copy','dense_copy'] - sage: impls += ['networkx'] # needs networkx + sage: impls = ['boost', 'sparse_copy', 'dense_copy', 'networkx'] sage: coeffs = [G.clustering_average(implementation=impl) ....: for impl in impls] sage: max(coeffs) - min(coeffs) # tol abs 1e-12 @@ -15355,7 +15363,7 @@ def clustering_coeff(self, {0: 1/3, 1: 1/3, 2: 0, 3: 1/3, 4: 1/3, 5: 1/3, 6: 1/3, 7: 1/3, 8: 0, 9: 1/3, 10: 1/3, 11: 0} - sage: (graphs.FruchtGraph()).clustering_coeff(weight=True) + sage: (graphs.FruchtGraph()).clustering_coeff(weight=True) # needs networkx {0: 0.3333333333333333, 1: 0.3333333333333333, 2: 0, 3: 0.3333333333333333, 4: 0.3333333333333333, 5: 0.3333333333333333, 6: 0.3333333333333333, @@ -15365,8 +15373,8 @@ def clustering_coeff(self, sage: (graphs.FruchtGraph()).clustering_coeff(nodes=[0,1,2]) {0: 0.3333333333333333, 1: 0.3333333333333333, 2: 0.0} - sage: (graphs.FruchtGraph()).clustering_coeff(nodes=[0,1,2], - ....: weight=True) + sage: (graphs.FruchtGraph()).clustering_coeff(nodes=[0,1,2], # needs networkx + ....: weight=True) {0: 0.3333333333333333, 1: 0.3333333333333333, 2: 0} sage: (graphs.GridGraph([5,5])).clustering_coeff(nodes=[(0,0),(0,1),(2,2)]) @@ -15390,6 +15398,7 @@ def clustering_coeff(self, Check that the result is the same with all implementations:: + sage: # needs networkx sage: G = graphs.RandomGNM(10, 20) sage: G.relabel(list("abcdefghik")) sage: coeffs = [G.clustering_coeff(implementation=impl) @@ -15774,8 +15783,8 @@ def odd_girth(self, algorithm="bfs", certificate=False): Bipartite graphs have no odd cycle and consequently have infinite odd girth:: - sage: G = graphs.RandomBipartite(6, 6, .5) - sage: G.odd_girth() + sage: G = graphs.RandomBipartite(6, 6, .5) # needs numpy + sage: G.odd_girth() # needs numpy +Infinity sage: G = graphs.Grid2dGraph(3, 4) sage: G.odd_girth() @@ -16186,17 +16195,17 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, sage: import itertools sage: n = random.randint(2,20) sage: m = random.randint(0, n*(n-1)/2) - sage: g = graphs.RandomGNM(n,m) - sage: c1 = g.centrality_closeness(algorithm='BFS') - sage: c2 = g.centrality_closeness(algorithm='NetworkX') - sage: c3 = g.centrality_closeness(algorithm='Dijkstra_Boost') - sage: c4 = g.centrality_closeness(algorithm='Floyd-Warshall-Cython') - sage: c5 = g.centrality_closeness(algorithm='Floyd-Warshall-Python') - sage: c6 = g.centrality_closeness(algorithm='Johnson_Boost') - sage: len(c1)==len(c2)==len(c3)==len(c4)==len(c5)==len(c6) - True - sage: c = [c1,c2,c3,c4,c5,c6] - sage: all( sum(abs(ci[v] - cj[v]) for v in g if g.degree(v)) < 1e-12 + sage: g = graphs.RandomGNM(n,m) # needs networkx + sage: c1 = g.centrality_closeness(algorithm='BFS') # needs networkx + sage: c2 = g.centrality_closeness(algorithm='NetworkX') # needs networkx + sage: c3 = g.centrality_closeness(algorithm='Dijkstra_Boost') # needs networkx + sage: c4 = g.centrality_closeness(algorithm='Floyd-Warshall-Cython') # needs networkx + sage: c5 = g.centrality_closeness(algorithm='Floyd-Warshall-Python') # needs networkx + sage: c6 = g.centrality_closeness(algorithm='Johnson_Boost') # needs networkx + sage: len(c1)==len(c2)==len(c3)==len(c4)==len(c5)==len(c6) # needs networkx + True + sage: c = [c1,c2,c3,c4,c5,c6] # needs networkx + sage: all( sum(abs(ci[v] - cj[v]) for v in g if g.degree(v)) < 1e-12 # needs networkx ....: for ci, cj in itertools.combinations(c, 2) ) True @@ -16208,15 +16217,15 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, sage: m = random.randint(0, n*(n-1)/2) sage: g = digraphs.RandomDirectedGNM(n,m) sage: c1 = g.centrality_closeness(algorithm='BFS') - sage: c2 = g.centrality_closeness(algorithm='NetworkX') + sage: c2 = g.centrality_closeness(algorithm='NetworkX') # needs networkx sage: c3 = g.centrality_closeness(algorithm='Dijkstra_Boost') sage: c4 = g.centrality_closeness(algorithm='Floyd-Warshall-Cython') sage: c5 = g.centrality_closeness(algorithm='Floyd-Warshall-Python') sage: c6 = g.centrality_closeness(algorithm='Johnson_Boost') - sage: len(c1)==len(c2)==len(c3)==len(c4)==len(c5)==len(c6) + sage: len(c1)==len(c2)==len(c3)==len(c4)==len(c5)==len(c6) # needs networkx True - sage: c = [c1,c2,c3,c4,c5,c6] - sage: all( sum(abs(ci[v] - cj[v]) for v in g if g.out_degree(v)) < 1e-12 + sage: c = [c1,c2,c3,c4,c5,c6] # needs networkx + sage: all( sum(abs(ci[v] - cj[v]) for v in g if g.out_degree(v)) < 1e-12 # needs networkx ....: for ci, cj in itertools.combinations(c, 2) ) True @@ -16226,17 +16235,17 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, sage: import itertools sage: n = random.randint(2,20) sage: m = random.randint(0, n*(n-1)/2) - sage: g = graphs.RandomGNM(n,m) - sage: for v,w in g.edges(sort=True, labels=False): + sage: g = graphs.RandomGNM(n,m) # needs networkx + sage: for v,w in g.edges(sort=True, labels=False): # needs networkx ....: g.set_edge_label(v,w,float(random.uniform(1,100))) - sage: c1 = g.centrality_closeness(by_weight=True, algorithm='NetworkX') - sage: c2 = g.centrality_closeness(by_weight=True, algorithm='Dijkstra_Boost') - sage: c3 = g.centrality_closeness(by_weight=True, algorithm='Floyd-Warshall-Python') - sage: c4 = g.centrality_closeness(by_weight=True, algorithm='Johnson_Boost') - sage: len(c1)==len(c2)==len(c3)==len(c4) - True - sage: c = [c1,c2,c3,c4] - sage: all( sum(abs(ci[v] - cj[v]) for v in g if g.degree(v)) < 1e-12 + sage: c1 = g.centrality_closeness(by_weight=True, algorithm='NetworkX') # needs networkx + sage: c2 = g.centrality_closeness(by_weight=True, algorithm='Dijkstra_Boost') # needs networkx + sage: c3 = g.centrality_closeness(by_weight=True, algorithm='Floyd-Warshall-Python') # needs networkx + sage: c4 = g.centrality_closeness(by_weight=True, algorithm='Johnson_Boost') # needs networkx + sage: len(c1)==len(c2)==len(c3)==len(c4) # needs networkx + True + sage: c = [c1,c2,c3,c4] # needs networkx + sage: all( sum(abs(ci[v] - cj[v]) for v in g if g.degree(v)) < 1e-12 # needs networkx ....: for ci, cj in itertools.combinations(c, 2) ) True @@ -16370,29 +16379,29 @@ def triangles_count(self, algorithm=None): have:: sage: G = graphs.CompleteGraph(15) - sage: G.triangles_count() == binomial(15, 3) + sage: G.triangles_count() == binomial(15, 3) # needs sage.symbolic True The 2-dimensional DeBruijn graph of 2 symbols has 2 directed `C_3`:: - sage: G = digraphs.DeBruijn(2,2) - sage: G.triangles_count() + sage: G = digraphs.DeBruijn(2,2) # needs sage.combinat + sage: G.triangles_count() # needs sage.combinat 2 The directed `n`-cycle is trivially triangle free for `n > 3`:: sage: G = digraphs.Circuit(10) - sage: G.triangles_count() + sage: G.triangles_count() # needs sage.modules 0 TESTS: Comparison of algorithms:: - sage: G = graphs.RandomBarabasiAlbert(50,2) + sage: G = graphs.RandomBarabasiAlbert(50,2) # needs networkx sage: results = [] sage: results.append(G.triangles_count(algorithm='matrix')) - sage: results.append(G.triangles_count(algorithm='iter')) + sage: results.append(G.triangles_count(algorithm='iter')) # needs sage.modules sage: results.append(G.triangles_count(algorithm='sparse_copy')) sage: results.append(G.triangles_count(algorithm='dense_copy')) sage: any(x != results[0] for x in results) @@ -17050,7 +17059,8 @@ def shortest_paths(self, u, by_weight=False, algorithm=None, However, if ``check_weight`` is set to ``False``, unexpected behavior may occur:: - sage: D.shortest_paths(0, algorithm='Dijkstra_NetworkX', weight_function=lambda e:e[2], check_weight=False) + sage: D.shortest_paths(0, algorithm='Dijkstra_NetworkX', # needs networkx + ....: weight_function=lambda e:e[2], check_weight=False) Traceback (most recent call last): ... TypeError: unsupported operand type(s) for +: 'int' and 'dict' @@ -17093,7 +17103,7 @@ def shortest_paths(self, u, by_weight=False, algorithm=None, Traceback (most recent call last): ... RuntimeError: Dijkstra algorithm does not work with negative weights, use Bellman-Ford instead - sage: D.shortest_paths(0, algorithm='Dijkstra_NetworkX', by_weight=True) + sage: D.shortest_paths(0, algorithm='Dijkstra_NetworkX', by_weight=True) # needs networkx Traceback (most recent call last): ... ValueError: ('Contradictory paths found:', 'negative weights?') @@ -17500,12 +17510,12 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, sage: d1, _ = g.shortest_path_all_pairs(algorithm="BFS") sage: d2, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Cython") sage: d3, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Python") - sage: d4, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX") + sage: d4, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX") # needs networkx sage: d5, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_Boost") sage: d6, _ = g.shortest_path_all_pairs(algorithm="Johnson_Boost") sage: d7, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_Boost") - sage: d8, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy") - sage: d1 == d2 == d3 == d4 == d5 == d6 == d7 == d8 + sage: d8, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy") # needs scipy + sage: d1 == d2 == d3 == d4 == d5 == d6 == d7 == d8 # needs networkx scipy True Checking that distances are equal regardless of the algorithm used:: @@ -17514,12 +17524,12 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, sage: d1, _ = g.shortest_path_all_pairs(algorithm="BFS") sage: d2, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Cython") sage: d3, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Python") - sage: d4, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX") + sage: d4, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX") # needs networkx sage: d5, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_Boost") sage: d6, _ = g.shortest_path_all_pairs(algorithm="Johnson_Boost") sage: d7, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_Boost") - sage: d8, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy") - sage: d1 == d2 == d3 == d4 == d5 == d6 == d7 == d8 + sage: d8, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy") # needs scipy + sage: d1 == d2 == d3 == d4 == d5 == d6 == d7 == d8 # needs networkx scipy True Checking that weighted distances are equal regardless of the algorithm @@ -17530,12 +17540,12 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, sage: for v, w in g.edges(labels=False, sort=False): ....: g.add_edge(v, w, random.uniform(1, 10)) sage: d1, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall-Python") - sage: d2, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX") + sage: d2, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_NetworkX") # needs networkx sage: d3, _ = g.shortest_path_all_pairs(algorithm="Dijkstra_Boost") sage: d4, _ = g.shortest_path_all_pairs(algorithm="Johnson_Boost") sage: d5, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_Boost") - sage: d6, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy") - sage: d1 == d2 == d3 == d4 == d5 == d6 + sage: d6, _ = g.shortest_path_all_pairs(algorithm="Floyd-Warshall_SciPy") # needs scipy + sage: d1 == d2 == d3 == d4 == d5 == d6 # needs networkx scipy True Checking a random path is valid:: @@ -17562,7 +17572,7 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, sage: g.shortest_path_all_pairs(algorithm='BFS') ({0: {0: 0, 1: 1, 2: 2}, 1: {1: 0, 2: 1}, 2: {2: 0}}, {0: {0: None, 1: 0, 2: 1}, 1: {1: None, 2: 1}, 2: {2: None}}) - sage: g.shortest_path_all_pairs(algorithm='Dijkstra_NetworkX') + sage: g.shortest_path_all_pairs(algorithm='Dijkstra_NetworkX') # needs networkx ({0: {0: 0, 1: 1, 2: 2}, 1: {1: 0, 2: 1}, 2: {2: 0}}, {0: {0: None, 1: 1, 2: 1}, 1: {1: None, 2: 2}, 2: {2: None}}) sage: g.shortest_path_all_pairs(algorithm='Dijkstra_Boost') @@ -17574,7 +17584,7 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, sage: g.shortest_path_all_pairs(algorithm='Floyd-Warshall-Cython') ({0: {0: 0, 1: 1, 2: 2}, 1: {1: 0, 2: 1}, 2: {2: 0}}, {0: {0: None, 1: 0, 2: 1}, 1: {1: None, 2: 1}, 2: {2: None}}) - sage: g.shortest_path_all_pairs(algorithm='Floyd-Warshall_SciPy') + sage: g.shortest_path_all_pairs(algorithm='Floyd-Warshall_SciPy') # needs scipy ({0: {0: 0.0, 1: 1.0, 2: 2.0}, 1: {1: 0.0, 2: 1.0}, 2: {2: 0.0}}, {0: {0: None, 1: 0, 2: 1}, 1: {1: None, 2: 1}, 2: {2: None}}) @@ -17846,7 +17856,7 @@ def wiener_index(self, by_weight=False, algorithm=None, 15 sage: G.wiener_index(algorithm='Johnson_Boost') 15 - sage: G.wiener_index(algorithm='Dijkstra_NetworkX') + sage: G.wiener_index(algorithm='Dijkstra_NetworkX') # needs networkx 15 Wiener index of complete (di)graphs:: @@ -19000,6 +19010,7 @@ def tensor_product(self, other): The tensor product of two DeBruijn digraphs of same diameter is a DeBruijn digraph:: + sage: # needs sage.combinat sage: B1 = digraphs.DeBruijn(2, 3) sage: B2 = digraphs.DeBruijn(3, 3) sage: T = B1.tensor_product(B2) @@ -20277,13 +20288,14 @@ def layout_graphviz(self, dim=2, prog='dot', **options): Make sure that :trac:`12364` is fixed:: + sage: # needs sage.combinat sage: m = WordMorphism('a->abb,b->ba') sage: w = m.fixed_point('a') - sage: prefix = Word(list(w[:100])) - sage: pals = prefix.palindromes() - sage: poset = Poset((pals, lambda x,y: x.is_factor(y))) - sage: H = poset.hasse_diagram() - sage: d = H.layout_graphviz() # optional - dot2tex graphviz + sage: prefix = Word(list(w[:100])) # needs sage.modules + sage: pals = prefix.palindromes() # needs sage.modules + sage: poset = Poset((pals, lambda x,y: x.is_factor(y))) # needs sage.modules + sage: H = poset.hasse_diagram() # needs sage.modules + sage: d = H.layout_graphviz() # optional - dot2tex graphviz # needs sage.modules """ assert_have_dot2tex() assert dim == 2, "3D graphviz layout not implemented" @@ -20750,11 +20762,11 @@ def plot(self, **options): :: - sage: from sage.plot.colors import rainbow + sage: from sage.plot.colors import rainbow # needs sage.plot sage: C = graphs.CubeGraph(5) - sage: R = rainbow(5) - sage: edge_colors = {R[i]: [] for i in range(5)} - sage: for u, v, l in C.edges(sort=False): + sage: R = rainbow(5) # needs sage.plot + sage: edge_colors = {R[i]: [] for i in range(5)} # needs sage.plot + sage: for u, v, l in C.edges(sort=False): # needs sage.plot ....: for i in range(5): ....: if u[i] != v[i]: ....: edge_colors[R[i]].append((u, v, l)) @@ -20887,6 +20899,7 @@ def plot(self, **options): :: + sage: # needs sage.modular sage: S = SupersingularModule(389) sage: H = S.hecke_matrix(2) sage: D = DiGraph(H, sparse=True) @@ -21074,9 +21087,9 @@ def plot3d(self, bgcolor=(1, 1, 1), :: sage: P = graphs.PetersenGraph().to_directed() - sage: from sage.plot.colors import rainbow - sage: R = rainbow(P.size(), 'rgbtuple') - sage: edge_colors = {R[i]: [e] for i, e in enumerate(P.edge_iterator())} + sage: from sage.plot.colors import rainbow # needs sage.plot + sage: R = rainbow(P.size(), 'rgbtuple') # needs sage.plot + sage: edge_colors = {R[i]: [e] for i, e in enumerate(P.edge_iterator())} # needs sage.plot sage: P.plot3d(engine='tachyon', edge_colors=edge_colors).show() # long time, needs sage.plot @@ -21816,12 +21829,12 @@ def graphviz_string(self, **options): Check that :trac:`25121` is fixed:: sage: G = Graph([(0, 1)]) - sage: G.graphviz_string(edge_colors={(0.25, 0.5, 1.0): [(0, 1)]}) + sage: G.graphviz_string(edge_colors={(0.25, 0.5, 1.0): [(0, 1)]}) # needs sage.plot 'graph {\n node_0 [label="0"];\n node_1 [label="1"];\n\n node_0 -- node_1 [color = "#4080ff"];\n}' sage: G = Graph([(0, 1)]) - sage: G.set_latex_options(edge_colors={(0, 1): (0.25, 0.5, 1.0)}) - sage: print(G.latex_options().dot2tex_picture()) # optional - dot2tex graphviz + sage: G.set_latex_options(edge_colors={(0, 1): (0.25, 0.5, 1.0)}) # needs sage.plot + sage: print(G.latex_options().dot2tex_picture()) # optional - dot2tex graphviz, needs sage.plot \begin{tikzpicture}[>=latex,line join=bevel,] ... \definecolor{strokecolor}{rgb}{0.25,0.5,1.0}; @@ -22069,26 +22082,26 @@ def spectrum(self, laplacian=False): EXAMPLES:: sage: P = graphs.PetersenGraph() - sage: P.spectrum() # needs sage.modules + sage: P.spectrum() # needs sage.modules sage.rings.number_field [3, 1, 1, 1, 1, 1, -2, -2, -2, -2] - sage: P.spectrum(laplacian=True) # needs sage.modules + sage: P.spectrum(laplacian=True) # needs sage.modules sage.rings.number_field [5, 5, 5, 5, 2, 2, 2, 2, 2, 0] sage: D = P.to_directed() sage: D.delete_edge(7, 9) - sage: D.spectrum() # needs sage.modules + sage: D.spectrum() # needs sage.modules sage.rings.number_field [2.9032119259..., 1, 1, 1, 1, 0.8060634335..., -1.7092753594..., -2, -2, -2] :: sage: C = graphs.CycleGraph(8) - sage: C.spectrum() # needs sage.modules + sage: C.spectrum() # needs sage.modules sage.rings.number_field [2, 1.4142135623..., 1.4142135623..., 0, 0, -1.4142135623..., -1.4142135623..., -2] A digraph may have complex eigenvalues. Previously, the complex parts of graph eigenvalues were being dropped. For a 3-cycle, we have:: sage: T = DiGraph({0: [1], 1: [2], 2: [0]}) - sage: T.spectrum() # needs sage.modules + sage: T.spectrum() # needs sage.modules sage.rings.number_field [1, -0.5000000000... + 0.8660254037...*I, -0.5000000000... - 0.8660254037...*I] TESTS: @@ -22102,10 +22115,10 @@ def spectrum(self, laplacian=False): eigenvalues. :: sage: H = graphs.HoffmanSingletonGraph() - sage: evals = H.spectrum() # needs sage.modules - sage: lap = [7 - x for x in evals] # needs sage.modules - sage: lap.sort(reverse=True) # needs sage.modules - sage: lap == H.spectrum(laplacian=True) # needs sage.modules + sage: evals = H.spectrum() # needs sage.modules sage.rings.number_field + sage: lap = [7 - x for x in evals] # needs sage.modules sage.rings.number_field + sage: lap.sort(reverse=True) # needs sage.modules sage.rings.number_field + sage: lap == H.spectrum(laplacian=True) # needs sage.modules sage.rings.number_field True """ # Ideally the spectrum should return something like a Factorization object @@ -22191,7 +22204,7 @@ def eigenvectors(self, laplacian=False): EXAMPLES:: sage: P = graphs.PetersenGraph() - sage: P.eigenvectors() # needs sage.modules + sage: P.eigenvectors() # needs sage.modules sage.rings.number_field [(3, [ (1, 1, 1, 1, 1, 1, 1, 1, 1, 1) ], 1), (-2, [ @@ -22211,7 +22224,7 @@ def eigenvectors(self, laplacian=False): graph is regular. However, since the output also contains the eigenvalues, the two outputs are slightly different:: - sage: P.eigenvectors(laplacian=True) # needs sage.modules + sage: P.eigenvectors(laplacian=True) # needs sage.modules sage.rings.number_field [(0, [ (1, 1, 1, 1, 1, 1, 1, 1, 1, 1) ], 1), (5, [ @@ -22230,7 +22243,7 @@ def eigenvectors(self, laplacian=False): :: sage: C = graphs.CycleGraph(8) - sage: C.eigenvectors() # needs sage.modules + sage: C.eigenvectors() # needs sage.modules sage.rings.number_field [(2, [ (1, 1, 1, 1, 1, 1, 1, 1) @@ -22260,7 +22273,7 @@ def eigenvectors(self, laplacian=False): graph eigenvalues were being dropped. For a 3-cycle, we have:: sage: T = DiGraph({0:[1], 1:[2], 2:[0]}) - sage: T.eigenvectors() # needs sage.modules + sage: T.eigenvectors() # needs sage.modules sage.rings.number_field [(1, [ (1, 1, 1) @@ -22301,7 +22314,7 @@ def eigenspaces(self, laplacian=False): EXAMPLES:: sage: P = graphs.PetersenGraph() - sage: P.eigenspaces() # needs sage.modules + sage: P.eigenspaces() # needs sage.modules sage.rings.number_field [ (3, Vector space of degree 10 and dimension 1 over Rational Field User basis matrix: @@ -22325,7 +22338,7 @@ def eigenspaces(self, laplacian=False): graph is regular. However, since the output also contains the eigenvalues, the two outputs are slightly different:: - sage: P.eigenspaces(laplacian=True) # needs sage.modules + sage: P.eigenspaces(laplacian=True) # needs sage.modules sage.rings.number_field [ (0, Vector space of degree 10 and dimension 1 over Rational Field User basis matrix: @@ -22350,7 +22363,7 @@ def eigenspaces(self, laplacian=False): corresponding eigenspace:: sage: C = graphs.CycleGraph(8) - sage: C.eigenspaces() # needs sage.modules + sage: C.eigenspaces() # needs sage.modules sage.rings.number_field [ (2, Vector space of degree 8 and dimension 1 over Rational Field User basis matrix: @@ -22373,7 +22386,7 @@ def eigenspaces(self, laplacian=False): we have:: sage: T = DiGraph({0: [1], 1: [2], 2: [0]}) - sage: T.eigenspaces() # needs sage.modules + sage: T.eigenspaces() # needs sage.modules sage.rings.number_field [ (1, Vector space of degree 3 and dimension 1 over Rational Field User basis matrix: @@ -22980,7 +22993,7 @@ def automorphism_group(self, partition=None, verbosity=0, (4, ((2,3), (0,1))) (24, ((2,3), (1,2), (0,1))) sage: C = graphs.CubeGraph(4) - sage: G = C.automorphism_group() + sage: G = C.automorphism_group() # needs sage.groups sage: M = G.character_table() # random order of rows, thus abs() below sage: QQ(M.determinant()).abs() 712483534798848 @@ -22990,7 +23003,7 @@ def automorphism_group(self, partition=None, verbosity=0, :: sage: D = graphs.DodecahedralGraph() - sage: G = D.automorphism_group() + sage: G = D.automorphism_group() # needs sage.groups sage: A5 = AlternatingGroup(5) sage: Z2 = CyclicPermutationGroup(2) sage: H = A5.direct_product(Z2)[0] #see documentation for direct_product to explain the [0] @@ -23003,49 +23016,49 @@ def automorphism_group(self, partition=None, verbosity=0, sage: G.add_edge(('a', 'b')) sage: G.add_edge(('a', 'b')) sage: G.add_edge(('a', 'b')) - sage: G.automorphism_group() + sage: G.automorphism_group() # needs sage.groups Permutation Group with generators [('a','b')] Digraphs:: sage: D = DiGraph( { 0:[1], 1:[2], 2:[3], 3:[4], 4:[0] } ) - sage: D.automorphism_group() + sage: D.automorphism_group() # needs sage.groups Permutation Group with generators [(0,1,2,3,4)] Edge labeled graphs:: sage: G = Graph(sparse=True) sage: G.add_edges( [(0,1,'a'),(1,2,'b'),(2,3,'c'),(3,4,'b'),(4,0,'a')] ) - sage: G.automorphism_group(edge_labels=True) + sage: G.automorphism_group(edge_labels=True) # needs sage.groups Permutation Group with generators [(1,4)(2,3)] sage: G.automorphism_group(edge_labels=True, algorithm="bliss") # optional - bliss Permutation Group with generators [(1,4)(2,3)] - sage: G.automorphism_group(edge_labels=True, algorithm="sage") + sage: G.automorphism_group(edge_labels=True, algorithm="sage") # needs sage.groups Permutation Group with generators [(1,4)(2,3)] :: sage: G = Graph({0 : {1 : 7}}) - sage: G.automorphism_group(edge_labels=True) + sage: G.automorphism_group(edge_labels=True) # needs sage.groups Permutation Group with generators [(0,1)] sage: foo = Graph(sparse=True) sage: bar = Graph(sparse=True) sage: foo.add_edges([(0,1,1),(1,2,2), (2,3,3)]) sage: bar.add_edges([(0,1,1),(1,2,2), (2,3,3)]) - sage: foo.automorphism_group(edge_labels=True) + sage: foo.automorphism_group(edge_labels=True) # needs sage.groups Permutation Group with generators [()] - sage: foo.automorphism_group() + sage: foo.automorphism_group() # needs sage.groups Permutation Group with generators [(0,3)(1,2)] - sage: bar.automorphism_group(edge_labels=True) + sage: bar.automorphism_group(edge_labels=True) # needs sage.groups Permutation Group with generators [()] You can also ask for just the order of the group:: sage: G = graphs.PetersenGraph() - sage: G.automorphism_group(return_group=False, order=True) + sage: G.automorphism_group(return_group=False, order=True) # needs sage.groups 120 Or, just the orbits (note that each graph here is vertex transitive) @@ -23053,15 +23066,15 @@ def automorphism_group(self, partition=None, verbosity=0, :: sage: G = graphs.PetersenGraph() - sage: G.automorphism_group(return_group=False, orbits=True, algorithm='sage') + sage: G.automorphism_group(return_group=False, orbits=True, algorithm='sage') # needs sage.groups [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]] - sage: orb = G.automorphism_group(partition=[[0],list(range(1,10))], + sage: orb = G.automorphism_group(partition=[[0],list(range(1,10))], # needs sage.groups ....: return_group=False, orbits=True, algorithm='sage') - sage: sorted([sorted(o) for o in orb], key=len) + sage: sorted([sorted(o) for o in orb], key=len) # needs sage.groups [[0], [1, 4, 5], [2, 3, 6, 7, 8, 9]] sage: C = graphs.CubeGraph(3) - sage: orb = C.automorphism_group(orbits=True, return_group=False, algorithm='sage') - sage: [sorted(o) for o in orb] + sage: orb = C.automorphism_group(orbits=True, return_group=False, algorithm='sage') # needs sage.groups + sage: [sorted(o) for o in orb] # needs sage.groups [['000', '001', '010', '011', '100', '101', '110', '111']] One can also use the faster algorithm for computing the automorphism @@ -23069,9 +23082,9 @@ def automorphism_group(self, partition=None, verbosity=0, sage: # optional - bliss sage: G = graphs.HallJankoGraph() - sage: A1 = G.automorphism_group() + sage: A1 = G.automorphism_group() # needs sage.groups sage: A2 = G.automorphism_group(algorithm='bliss') - sage: A1.is_isomorphic(A2) + sage: A1.is_isomorphic(A2) # needs sage.groups True TESTS: @@ -23080,47 +23093,47 @@ def automorphism_group(self, partition=None, verbosity=0, sage: g=graphs.CubeGraph(3) sage: g.relabel() - sage: g.automorphism_group(partition=[[0,1,2],[3,4,5]],algorithm='sage') + sage: g.automorphism_group(partition=[[0,1,2],[3,4,5]],algorithm='sage') # needs sage.groups Traceback (most recent call last): ... KeyError: ... Labeled automorphism group:: - sage: d = digraphs.DeBruijn(3,2) - sage: A = d.automorphism_group(algorithm='sage') + sage: d = digraphs.DeBruijn(3,2) # needs sage.combinat + sage: A = d.automorphism_group(algorithm='sage') # needs sage.combinat sage: A_target = PermutationGroup(["('02','10','21')('00','11','22')('01','12','20')", ....: "('02','01')('10','20')('21','12')('22','11')"]) - sage: A.is_isomorphic(A_target) + sage: A.is_isomorphic(A_target) # needs sage.combinat True - sage: d.allow_multiple_edges(True) - sage: d.add_edge(('00', '00', '0')) - sage: A = d.automorphism_group(algorithm='sage') + sage: d.allow_multiple_edges(True) # needs sage.combinat + sage: d.add_edge(('00', '00', '0')) # needs sage.combinat + sage: A = d.automorphism_group(algorithm='sage') # needs sage.combinat sage: A_target = PermutationGroup(["('01','02')('10','20')('11','22')('12','21')"]) - sage: A.is_isomorphic(A_target) + sage: A.is_isomorphic(A_target) # needs sage.combinat True The labeling is correct:: sage: g = graphs.PetersenGraph() - sage: ag = g.automorphism_group() - sage: all(len(ag.orbit(e, action="OnPairs")) == 30 + sage: ag = g.automorphism_group() # needs sage.groups + sage: all(len(ag.orbit(e, action="OnPairs")) == 30 # needs sage.groups ....: for e in g.edge_iterator(labels=False)) True Empty group, correct domain:: - sage: ag = Graph({'a':['a'], 'b':[]}).automorphism_group() - sage: ag + sage: ag = Graph({'a':['a'], 'b':[]}).automorphism_group() # needs sage.groups + sage: ag # needs sage.groups Permutation Group with generators [()] - sage: sorted(ag.domain()) + sage: sorted(ag.domain()) # needs sage.groups ['a', 'b'] We can check that the subgroups are labelled correctly (:trac:`15656`):: sage: G1 = Graph(':H`ECw@HGXGAGUG`e') - sage: G = G1.automorphism_group() + sage: G = G1.automorphism_group() # needs sage.groups sage: G.subgroups() [Subgroup generated by [()] of (Permutation Group with generators [(0,7)(1,4)(2,3)(6,8)]), Subgroup generated by [(0,7)(1,4)(2,3)(6,8)] of (Permutation Group with generators [(0,7)(1,4)(2,3)(6,8)])] @@ -23128,19 +23141,19 @@ def automorphism_group(self, partition=None, verbosity=0, We check that the representations of the groups returned with ``'sage'`` and ``'bliss'`` are the same (:trac:`27571`):: - sage: G = graphs.PaleyGraph(9) - sage: a1 = G.automorphism_group(algorithm='sage') + sage: G = graphs.PaleyGraph(9) # needs sage.libs.pari + sage: a1 = G.automorphism_group(algorithm='sage') # needs sage.groups sage: V = sorted(G, reverse=True) - sage: a2 = G.automorphism_group(algorithm='sage', partition=[V]) - sage: a1.is_isomorphic(a2) + sage: a2 = G.automorphism_group(algorithm='sage', partition=[V]) # needs sage.groups + sage: a1.is_isomorphic(a2) # needs sage.groups True - sage: str(a1) == str(a2) + sage: str(a1) == str(a2) # needs sage.groups False sage: b1 = G.automorphism_group(algorithm='bliss') # optional - bliss - sage: str(a1) == str(b1) # optional - bliss + sage: str(a1) == str(b1) # optional - bliss, needs sage.groups True sage: b2 = G.automorphism_group(algorithm='bliss', partition=[V]) # optional - bliss - sage: str(a2) == str(b2) # optional - bliss + sage: str(a2) == str(b2) # optional - bliss, needs sage.groups True """ from sage.features.bliss import Bliss @@ -23387,19 +23400,19 @@ def is_hamiltonian(self, solver=None, constraint_generation=None, The Heawood Graph is known to be Hamiltonian :: sage: g = graphs.HeawoodGraph() - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True The Petergraph, though, is not :: sage: g = graphs.PetersenGraph() - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip False TESTS:: sage: g = graphs.ChvatalGraph() - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True :trac:`16210`:: @@ -23407,7 +23420,7 @@ def is_hamiltonian(self, solver=None, constraint_generation=None, sage: g = graphs.CycleGraph(10) sage: g.allow_loops(True) sage: g.add_edge(0,0) - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True """ from sage.categories.sets_cat import EmptySetError @@ -23904,7 +23917,7 @@ class by some canonization function `c`. If `G` and `H` are graphs, sage: algos = ['sage'] sage: algos.append('bliss') # optional - bliss sage: S = Set([0,1,2]) - sage: for (algo, edges) in product(algos, edges_list): + sage: for (algo, edges) in product(algos, edges_list): # needs sage.combinat ....: L = cartesian_product([S] * len(edges)) ....: O = OrderedSetPartitions([0,1,2,3]) ....: P = Permutations([0,1,2,3]) @@ -24058,11 +24071,12 @@ def is_cayley(self, return_group=False, mapping=False, Graphs with loops and multiedges will have identity and repeated elements, respectively, among the generators:: + sage: # needs sage.rings.finite_rings sage: g = Graph(graphs.PaleyGraph(9), loops=True, multiedges=True) sage: g.add_edges([(u, u) for u in g]) sage: g.add_edges([(u, u+1) for u in g]) - sage: _, S = g.is_cayley(generators=True) - sage: S # random + sage: _, S = g.is_cayley(generators=True) # needs sage.groups + sage: S # random # needs sage.groups [(), (0,2,1)(a,a + 2,a + 1)(2*a,2*a + 2,2*a + 1), (0,2,1)(a,a + 2,a + 1)(2*a,2*a + 2,2*a + 1), @@ -24075,24 +24089,27 @@ def is_cayley(self, return_group=False, mapping=False, Cayley graphs can be reconstructed from the group and generating set:: - sage: g = graphs.PaleyGraph(9) - sage: _, G, S = g.is_cayley(return_group=True, generators=True) - sage: Graph(G.cayley_graph(generators=S)).is_isomorphic(g) + sage: g = graphs.PaleyGraph(9) # needs sage.rings.finite_rings + sage: _, G, S = g.is_cayley(return_group=True, generators=True) # needs sage.groups sage.rings.finite_rings + sage: Graph(G.cayley_graph(generators=S)).is_isomorphic(g) # needs sage.groups sage.rings.finite_rings True A disconnected graphs may also be a Cayley graph:: + sage: # needs sage.rings.finite_rings sage: g = graphs.PaleyGraph(9) sage: h = g.disjoint_union(g) sage: h = h.disjoint_union(h) sage: h = h.disjoint_union(g) - sage: _, G, d, S = h.is_cayley(return_group=True, mapping=True, generators=True, allow_disconnected=True) - sage: all(set(d[u] for u in h.neighbors(v)) == set(d[v]*x for x in S) for v in h) + sage: _, G, d, S = h.is_cayley(return_group=True, mapping=True, # needs sage.groups + ....: generators=True, allow_disconnected=True) + sage: all(set(d[u] for u in h.neighbors(v)) == set(d[v]*x for x in S) # needs sage.groups + ....: for v in h) True The method also works efficiently with dense simple graphs:: - sage: graphs.CompleteBipartiteGraph(50, 50).is_cayley() + sage: graphs.CompleteBipartiteGraph(50, 50).is_cayley() # needs sage.groups True TESTS:: @@ -24198,8 +24215,8 @@ def is_self_complementary(self): Every Paley graph is self-complementary:: - sage: G = graphs.PaleyGraph(9) - sage: G.is_self_complementary() + sage: G = graphs.PaleyGraph(9) # needs sage.libs.pari + sage: G.is_self_complementary() # needs sage.libs.pari True TESTS: @@ -24327,7 +24344,7 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None): We find the Katz matrix of an undirected 4-cycle. :: sage: G = graphs.CycleGraph(4) - sage: G.katz_matrix(1/20) # needs sage.modules + sage: G.katz_matrix(1/20) # needs sage.modules sage.rings.number_field [1/198 5/99 1/198 5/99] [ 5/99 1/198 5/99 1/198] [1/198 5/99 1/198 5/99] @@ -24336,7 +24353,7 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None): We find the Katz matrix of an undirected 4-cycle with all entries other than those which correspond to non-edges zeroed out. :: - sage: G.katz_matrix(1/20, True) # needs sage.modules + sage: G.katz_matrix(1/20, True) # needs sage.modules sage.rings.number_field [ 0 0 1/198 0] [ 0 0 0 1/198] [1/198 0 0 0] @@ -24348,7 +24365,7 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None): We find the Katz matrix in a fan on 6 vertices. :: sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)]) - sage: H.katz_matrix(1/10) # needs sage.modules + sage: H.katz_matrix(1/10) # needs sage.modules sage.rings.number_field [ 169/2256 545/4512 25/188 605/4512 25/188 545/4512 485/4512] [ 545/4512 7081/297792 4355/37224 229/9024 595/37224 4073/297792 109/9024] [ 25/188 4355/37224 172/4653 45/376 125/4653 595/37224 5/376] @@ -24364,7 +24381,7 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None): TESTS:: - sage: # needs sage.modules + sage: # needs sage.modules sage.rings.number_field sage: (graphs.CompleteGraph(4)).katz_matrix(1/4) [3/5 4/5 4/5 4/5] [4/5 3/5 4/5 4/5] @@ -24683,7 +24700,7 @@ def symmetric_edge_polytope(self, backend=None): ....: break ....: else: ....: polys.append(P) - sage: len(polys) + sage: len(polys) # needs sage.geometry.polyhedron 25 A non-trivial example of two graphs with isomorphic SEPs:: From 0d94e55c356a8d533ff855a67ab99e020d4edc43 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 2 Aug 2023 15:35:46 -0700 Subject: [PATCH 75/87] ./sage -fixdoctests --only-tags src/sage/graphs --- src/sage/graphs/base/boost_graph.pyx | 6 +- src/sage/graphs/base/c_graph.pyx | 30 +- .../graphs/base/static_sparse_backend.pyx | 17 +- src/sage/graphs/base/static_sparse_graph.pyx | 18 +- src/sage/graphs/bipartite_graph.py | 195 +++-- src/sage/graphs/bliss.pyx | 109 +-- src/sage/graphs/centrality.pyx | 35 +- src/sage/graphs/cliquer.pyx | 4 +- src/sage/graphs/comparability.pyx | 26 +- src/sage/graphs/connectivity.pyx | 80 +- src/sage/graphs/digraph.py | 187 ++-- src/sage/graphs/digraph_generators.py | 118 +-- src/sage/graphs/distances_all_pairs.pyx | 49 +- src/sage/graphs/domination.py | 44 +- src/sage/graphs/dot2tex_utils.py | 6 +- src/sage/graphs/edge_connectivity.pyx | 19 +- src/sage/graphs/generators/basic.py | 147 ++-- src/sage/graphs/generators/chessboard.py | 2 +- .../graphs/generators/classical_geometries.py | 30 +- src/sage/graphs/generators/degree_sequence.py | 49 +- .../graphs/generators/distance_regular.pyx | 255 +++--- src/sage/graphs/generators/families.py | 315 +++---- src/sage/graphs/generators/intersection.py | 37 +- src/sage/graphs/generators/platonic_solids.py | 36 +- src/sage/graphs/generators/random.py | 185 ++-- src/sage/graphs/generators/smallgraphs.py | 12 +- src/sage/graphs/generic_graph.py | 7 +- src/sage/graphs/generic_graph_pyx.pyx | 36 +- src/sage/graphs/graph.py | 819 +++++++++--------- src/sage/graphs/graph_coloring.pyx | 122 +-- src/sage/graphs/graph_database.py | 2 +- .../graphs/graph_decompositions/bandwidth.pyx | 4 +- .../graphs/graph_decompositions/cutwidth.pyx | 20 +- .../graph_decompositions/fast_digraph.pyx | 10 +- .../graph_decompositions/graph_products.pyx | 4 +- .../modular_decomposition.py | 2 +- .../graphs/graph_decompositions/tdlib.pyx | 11 +- .../vertex_separation.pyx | 52 +- src/sage/graphs/graph_generators.py | 40 +- src/sage/graphs/graph_generators_pyx.pyx | 4 +- src/sage/graphs/graph_input.py | 142 +-- src/sage/graphs/graph_latex.py | 10 +- src/sage/graphs/graph_list.py | 16 +- src/sage/graphs/graph_plot_js.py | 17 +- src/sage/graphs/hypergraph_generators.py | 19 +- src/sage/graphs/independent_sets.pyx | 2 +- .../graphs/isoperimetric_inequalities.pyx | 4 +- src/sage/graphs/line_graph.pyx | 21 +- src/sage/graphs/matchpoly.pyx | 6 +- src/sage/graphs/partial_cube.py | 10 +- src/sage/graphs/path_enumeration.pyx | 22 +- src/sage/graphs/planarity.pyx | 13 +- src/sage/graphs/schnyder.py | 2 +- src/sage/graphs/spanning_tree.pyx | 37 +- src/sage/graphs/strongly_regular_db.pyx | 328 +++---- src/sage/graphs/traversals.pyx | 46 +- src/sage/graphs/tutte_polynomial.py | 6 +- src/sage/graphs/views.pyx | 6 +- 58 files changed, 1980 insertions(+), 1871 deletions(-) diff --git a/src/sage/graphs/base/boost_graph.pyx b/src/sage/graphs/base/boost_graph.pyx index d6508f172f8..ff222837117 100644 --- a/src/sage/graphs/base/boost_graph.pyx +++ b/src/sage/graphs/base/boost_graph.pyx @@ -572,7 +572,7 @@ cpdef bandwidth_heuristics(g, algorithm='cuthill_mckee'): from sage.graphs.base.boost_graph import bandwidth_heuristics sage: bandwidth_heuristics(Graph()) (0, []) - sage: bandwidth_heuristics(graphs.RandomGNM(10,0)) # optional - networkx + sage: bandwidth_heuristics(graphs.RandomGNM(10,0)) # needs networkx (0, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) """ @@ -1964,8 +1964,8 @@ cpdef diameter_DHV(g, weight_function=None, check_weight=True): TESTS:: - sage: G = graphs.RandomBarabasiAlbert(17,6) # optional - networkx - sage: diameter_DHV(G) == G.diameter(algorithm = 'Dijkstra_Boost') # optional - networkx + sage: G = graphs.RandomBarabasiAlbert(17,6) # needs networkx + sage: diameter_DHV(G) == G.diameter(algorithm = 'Dijkstra_Boost') # needs networkx True sage: G = Graph([(0,1,-1)], weighted=True) sage: diameter_DHV(G) diff --git a/src/sage/graphs/base/c_graph.pyx b/src/sage/graphs/base/c_graph.pyx index a4f2efd6060..0f5c09aa12f 100644 --- a/src/sage/graphs/base/c_graph.pyx +++ b/src/sage/graphs/base/c_graph.pyx @@ -1577,11 +1577,11 @@ cdef class CGraphBackend(GenericGraphBackend): We check that the bug described in :trac:`8406` is gone:: sage: G = Graph() - sage: R. = GF(3**3) # optional - sage.rings.finite_rings - sage: S. = R[] # optional - sage.rings.finite_rings - sage: G.add_vertex(a**2) # optional - sage.rings.finite_rings - sage: G.add_vertex(x) # optional - sage.rings.finite_rings - sage: G.vertices(sort=True) # optional - sage.rings.finite_rings + sage: R. = GF(3**3) # needs sage.rings.finite_rings + sage: S. = R[] # needs sage.rings.finite_rings + sage: G.add_vertex(a**2) # needs sage.rings.finite_rings + sage: G.add_vertex(x) # needs sage.rings.finite_rings + sage: G.vertices(sort=True) # needs sage.rings.finite_rings [a^2, x] And that the bug described in :trac:`9610` is gone:: @@ -2107,9 +2107,9 @@ cdef class CGraphBackend(GenericGraphBackend): Ensure that :trac:`13664` is fixed :: - sage: W = WeylGroup(["A",1]) # optional - sage.combinat sage.groups - sage: G = W.cayley_graph() # optional - sage.combinat sage.groups - sage: Graph(G).degree() # optional - sage.combinat sage.groups + sage: W = WeylGroup(["A",1]) # needs sage.combinat sage.groups + sage: G = W.cayley_graph() # needs sage.combinat sage.groups + sage: Graph(G).degree() # needs sage.combinat sage.groups [1, 1] sage: h = Graph() sage: h.add_edge(1,2,"a") @@ -4406,9 +4406,9 @@ cdef class CGraphBackend(GenericGraphBackend): TESTS:: - sage: P = posets.PentagonPoset() # optional - sage.modules - sage: H = P._hasse_diagram # optional - sage.modules - sage: H._backend.is_connected() # optional - sage.modules + sage: P = posets.PentagonPoset() # needs sage.modules + sage: H = P._hasse_diagram # needs sage.modules + sage: H._backend.is_connected() # needs sage.modules True """ cdef int v_int @@ -4548,7 +4548,7 @@ cdef class CGraphBackend(GenericGraphBackend): At first, the following graph is acyclic:: sage: D = DiGraph({ 0:[1,2,3], 4:[2,5], 1:[8], 2:[7], 3:[7], 5:[6,7], 7:[8], 6:[9], 8:[10], 9:[10] }) - sage: D.plot(layout='circular').show() # optional - sage.plot + sage: D.plot(layout='circular').show() # needs sage.plot sage: D.is_directed_acyclic() True @@ -4589,9 +4589,9 @@ cdef class CGraphBackend(GenericGraphBackend): TESTS:: - sage: m = Matrix(3,[0, 1, 1, 0, 0, 0, 0, 1, 0]) # optional - sage.modules - sage: g = DiGraph(m) # optional - sage.modules - sage: g.is_directed_acyclic(certificate=True) # optional - sage.modules + sage: m = Matrix(3,[0, 1, 1, 0, 0, 0, 0, 1, 0]) # needs sage.modules + sage: g = DiGraph(m) # needs sage.modules + sage: g.is_directed_acyclic(certificate=True) # needs sage.modules (True, [0, 2, 1]) """ if not self._directed: diff --git a/src/sage/graphs/base/static_sparse_backend.pyx b/src/sage/graphs/base/static_sparse_backend.pyx index a8de583d4db..2eecc1a69d0 100644 --- a/src/sage/graphs/base/static_sparse_backend.pyx +++ b/src/sage/graphs/base/static_sparse_backend.pyx @@ -446,17 +446,18 @@ cdef class StaticSparseBackend(CGraphBackend): :: - sage: g = DiGraph(digraphs.DeBruijn(4, 3), data_structure="static_sparse") # optional - sage.combinat - sage: gi = DiGraph(g, data_structure="static_sparse") # optional - sage.combinat - sage: gi.edges(sort=True)[0] # optional - sage.combinat + sage: # needs sage.combinat + sage: g = DiGraph(digraphs.DeBruijn(4, 3), data_structure="static_sparse") + sage: gi = DiGraph(g, data_structure="static_sparse") + sage: gi.edges(sort=True)[0] ('000', '000', '0') - sage: sorted(gi.edges_incident('111')) # optional - sage.combinat + sage: sorted(gi.edges_incident('111')) [('111', '110', '0'), ('111', '111', '1'), ('111', '112', '2'), ('111', '113', '3')] - sage: set(g.edges(sort=False)) == set(gi.edges(sort=False)) # optional - sage.combinat + sage: set(g.edges(sort=False)) == set(gi.edges(sort=False)) # needs sage.combinat True :: @@ -671,10 +672,10 @@ cdef class StaticSparseBackend(CGraphBackend): :: sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend - sage: g = StaticSparseBackend(digraphs.DeBruijn(3, 2)) # optional - sage.combinat - sage: g.has_edge('00', '01', '1') # optional - sage.combinat + sage: g = StaticSparseBackend(digraphs.DeBruijn(3, 2)) # needs sage.combinat + sage: g.has_edge('00', '01', '1') # needs sage.combinat True - sage: g.has_edge('00', '01', '0') # optional - sage.combinat + sage: g.has_edge('00', '01', '0') # needs sage.combinat False """ try: diff --git a/src/sage/graphs/base/static_sparse_graph.pyx b/src/sage/graphs/base/static_sparse_graph.pyx index cfaff95ccde..6fd78510c94 100644 --- a/src/sage/graphs/base/static_sparse_graph.pyx +++ b/src/sage/graphs/base/static_sparse_graph.pyx @@ -731,8 +731,8 @@ def tarjan_strongly_connected_components(G): Checking against NetworkX:: - sage: import networkx # optional - networkx - sage: for i in range(10): # long time # optional - networkx + sage: import networkx # needs networkx + sage: for i in range(10): # long time # needs networkx ....: g = digraphs.RandomDirectedGNP(100,.05) ....: h = g.networkx_graph() ....: scc1 = g.strongly_connected_components() @@ -1023,8 +1023,8 @@ def spectral_radius(G, prec=1e-10): sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(2,4),(3,4)]) sage: e_min, e_max = spectral_radius(G, 1e-14) - sage: e = max(G.adjacency_matrix().charpoly().roots(AA, multiplicities=False)) - sage: e_min < e < e_max + sage: e = max(G.adjacency_matrix().charpoly().roots(AA, multiplicities=False)) # needs sage.modules + sage: e_min < e < e_max # needs sage.modules True sage: G.spectral_radius() # abs tol 1e-9 @@ -1037,10 +1037,10 @@ def spectral_radius(G, prec=1e-10): sage: G.add_edge(200,0) sage: G.add_edge(1,0) sage: e_min, e_max = spectral_radius(G, 0.00001) - sage: p = G.adjacency_matrix(sparse=True).charpoly() - sage: p + sage: p = G.adjacency_matrix(sparse=True).charpoly() # needs sage.modules + sage: p # needs sage.modules x^201 - x^199 - 1 - sage: r = p.roots(AA, multiplicities=False)[0] + sage: r = p.roots(AA, multiplicities=False)[0] # needs sage.modules sage: e_min < r < e_max True @@ -1060,7 +1060,7 @@ def spectral_radius(G, prec=1e-10): sage: G.add_edges([(0,0),(0,0),(0,1),(1,0)]) sage: spectral_radius(G, 1e-14) # abs tol 1e-14 (2.414213562373094, 2.414213562373095) - sage: max(G.adjacency_matrix().eigenvalues(AA)) + sage: max(G.adjacency_matrix().eigenvalues(AA)) # needs sage.modules 2.414213562373095? Some bipartite graphs:: @@ -1091,7 +1091,7 @@ def spectral_radius(G, prec=1e-10): ... ValueError: precision (=1.00000000000000e-20) is too small - sage: for _ in range(100): + sage: for _ in range(100): # needs sage.modules ....: G = digraphs.RandomDirectedGNM(10,35) ....: if not G.is_strongly_connected(): ....: continue diff --git a/src/sage/graphs/bipartite_graph.py b/src/sage/graphs/bipartite_graph.py index 635d5554329..0aaae8e1551 100644 --- a/src/sage/graphs/bipartite_graph.py +++ b/src/sage/graphs/bipartite_graph.py @@ -161,7 +161,7 @@ class BipartiteGraph(Graph): sage: B = BipartiteGraph(P, partition, check=False) sage: B.left {0, 1, 2, 3, 4} - sage: B.show() # optional - sage.plot + sage: B.show() # needs sage.plot :: @@ -198,16 +198,16 @@ class BipartiteGraph(Graph): #. From a reduced adjacency matrix:: - sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), # optional - sage.modules + sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), # needs sage.modules ....: (0,1,0,1,0,1,0), (1,1,0,1,0,0,1)]) - sage: M # optional - sage.modules + sage: M # needs sage.modules [1 1 1 0 0 0 0] [1 0 0 1 1 0 0] [0 1 0 1 0 1 0] [1 1 0 1 0 0 1] - sage: H = BipartiteGraph(M); H # optional - sage.modules + sage: H = BipartiteGraph(M); H # needs sage.modules Bipartite graph on 11 vertices - sage: H.edges(sort=True) # optional - sage.modules + sage: H.edges(sort=True) # needs sage.modules [(0, 7, None), (0, 8, None), (0, 10, None), @@ -224,9 +224,9 @@ class BipartiteGraph(Graph): :: - sage: M = Matrix([(1, 1, 2, 0, 0), (0, 2, 1, 1, 1), (0, 1, 2, 1, 1)]) # optional - sage.modules - sage: B = BipartiteGraph(M, multiedges=True, sparse=True) # optional - sage.modules - sage: B.edges(sort=True) # optional - sage.modules + sage: M = Matrix([(1, 1, 2, 0, 0), (0, 2, 1, 1, 1), (0, 1, 2, 1, 1)]) # needs sage.modules + sage: B = BipartiteGraph(M, multiedges=True, sparse=True) # needs sage.modules + sage: B.edges(sort=True) # needs sage.modules [(0, 5, None), (1, 5, None), (1, 6, None), @@ -244,13 +244,13 @@ class BipartiteGraph(Graph): :: - sage: F. = GF(4) # optional - sage.modules sage.rings.finite_rings - sage: MS = MatrixSpace(F, 2, 3) # optional - sage.modules sage.rings.finite_rings - sage: M = MS.matrix([[0, 1, a + 1], [a, 1, 1]]) # optional - sage.modules sage.rings.finite_rings - sage: B = BipartiteGraph(M, weighted=True, sparse=True) # optional - sage.modules sage.rings.finite_rings - sage: B.edges(sort=True) # optional - sage.modules sage.rings.finite_rings + sage: F. = GF(4) # needs sage.modules sage.rings.finite_rings + sage: MS = MatrixSpace(F, 2, 3) # needs sage.modules sage.rings.finite_rings + sage: M = MS.matrix([[0, 1, a + 1], [a, 1, 1]]) # needs sage.modules sage.rings.finite_rings + sage: B = BipartiteGraph(M, weighted=True, sparse=True) # needs sage.modules sage.rings.finite_rings + sage: B.edges(sort=True) # needs sage.modules sage.rings.finite_rings [(0, 4, a), (1, 3, 1), (1, 4, 1), (2, 3, a + 1), (2, 4, 1)] - sage: B.weighted() # optional - sage.modules sage.rings.finite_rings + sage: B.weighted() # needs sage.modules sage.rings.finite_rings True #. From an alist file:: @@ -264,7 +264,7 @@ class BipartiteGraph(Graph): ....: 1 2 4 7 \n") ....: f.flush() ....: B = BipartiteGraph(f.name) - sage: B.is_isomorphic(H) # optional - sage.modules + sage: B.is_isomorphic(H) # needs sage.modules True #. From a ``graph6`` string:: @@ -307,14 +307,14 @@ class BipartiteGraph(Graph): sage: B = BipartiteGraph('F?^T_\n', partition=[[0, 1, 2], [3, 4, 5, 6]], check=False) sage: B.left {0, 1, 2} - sage: B.show() # optional - sage.plot + sage: B.show() # needs sage.plot #. From a NetworkX bipartite graph:: - sage: import networkx # optional - networkx - sage: G = graphs.OctahedralGraph() # optional - networkx - sage: N = networkx.make_clique_bipartite(G.networkx_graph()) # optional - networkx - sage: B = BipartiteGraph(N) # optional - networkx + sage: import networkx # needs networkx + sage: G = graphs.OctahedralGraph() # needs networkx + sage: N = networkx.make_clique_bipartite(G.networkx_graph()) # needs networkx + sage: B = BipartiteGraph(N) # needs networkx TESTS: @@ -328,15 +328,15 @@ class BipartiteGraph(Graph): Ensure that we can construct a ``BipartiteGraph`` with isolated vertices via the reduced adjacency matrix (:trac:`10356`):: - sage: a = BipartiteGraph(matrix(2, 2, [1, 0, 1, 0])) # optional - sage.modules - sage: a # optional - sage.modules + sage: a = BipartiteGraph(matrix(2, 2, [1, 0, 1, 0])) # needs sage.modules + sage: a # needs sage.modules Bipartite graph on 4 vertices - sage: a.vertices(sort=True) # optional - sage.modules + sage: a.vertices(sort=True) # needs sage.modules [0, 1, 2, 3] - sage: g = BipartiteGraph(matrix(4, 4, [1] * 4 + [0] * 12)) # optional - sage.modules - sage: g.vertices(sort=True) # optional - sage.modules + sage: g = BipartiteGraph(matrix(4, 4, [1] * 4 + [0] * 12)) # needs sage.modules + sage: g.vertices(sort=True) # needs sage.modules [0, 1, 2, 3, 4, 5, 6, 7] - sage: sorted(g.left.union(g.right)) # optional - sage.modules + sage: sorted(g.left.union(g.right)) # needs sage.modules [0, 1, 2, 3, 4, 5, 6, 7] Make sure that loops are not allowed (:trac:`23275`):: @@ -1291,10 +1291,10 @@ def is_bipartite(self, certificate=False): EXAMPLES:: - sage: g = BipartiteGraph(graphs.RandomBipartite(3, 3, .5)) # optional - numpy - sage: g.is_bipartite() # optional - numpy + sage: g = BipartiteGraph(graphs.RandomBipartite(3, 3, .5)) # needs numpy + sage: g.is_bipartite() # needs numpy True - sage: g.is_bipartite(certificate=True) # random # optional - numpy + sage: g.is_bipartite(certificate=True) # random # needs numpy (True, {(0, 0): 0, (0, 1): 0, (0, 2): 0, (1, 0): 1, (1, 1): 1, (1, 2): 1}) TESTS:: @@ -1466,7 +1466,7 @@ def plot(self, *args, **kwds): EXAMPLES:: sage: B = BipartiteGraph(graphs.CycleGraph(20)) - sage: B.plot() # optional - sage.plot + sage: B.plot() # needs sage.plot Graphics object consisting of 41 graphics primitives """ if "pos" not in kwds: @@ -1511,14 +1511,16 @@ def matching_polynomial(self, algorithm="Godsil", name=None): sage: x = polygen(QQ) sage: g = BipartiteGraph(graphs.CompleteBipartiteGraph(16, 16)) - sage: bool(factorial(16) * laguerre(16, x^2) == g.matching_polynomial(algorithm='rook')) # optional - sage.symbolic + sage: bool(factorial(16) * laguerre(16, x^2) # needs sage.symbolic + ....: == g.matching_polynomial(algorithm='rook')) True Compute the matching polynomial of a line with `60` vertices:: - sage: from sage.functions.orthogonal_polys import chebyshev_U # optional - sage.symbolic + sage: from sage.functions.orthogonal_polys import chebyshev_U # needs sage.symbolic sage: g = next(graphs.trees(60)) - sage: chebyshev_U(60, x/2) == BipartiteGraph(g).matching_polynomial(algorithm='rook') # optional - sage.symbolic + sage: (chebyshev_U(60, x/2) # needs sage.symbolic + ....: == BipartiteGraph(g).matching_polynomial(algorithm='rook')) True The matching polynomial of a tree is equal to its characteristic @@ -1627,7 +1629,7 @@ def perfect_matchings(self, labels=False): sage: B = BipartiteGraph(graphs.CompleteBipartiteGraph(4, 4)) sage: len(list(B.perfect_matchings())) 24 - sage: B.matching_polynomial(algorithm='rook')(0) # optional - sage.modules + sage: B.matching_polynomial(algorithm='rook')(0) # needs sage.modules 24 TESTS:: @@ -1804,26 +1806,26 @@ def save_afile(self, fname): EXAMPLES:: - sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), # optional - sage.modules + sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), # needs sage.modules ....: (0,1,0,1,0,1,0), (1,1,0,1,0,0,1)]) - sage: M # optional - sage.modules + sage: M # needs sage.modules [1 1 1 0 0 0 0] [1 0 0 1 1 0 0] [0 1 0 1 0 1 0] [1 1 0 1 0 0 1] - sage: b = BipartiteGraph(M) # optional - sage.modules - sage: import tempfile # optional - sage.modules - sage: with tempfile.NamedTemporaryFile() as f: # optional - sage.modules + sage: b = BipartiteGraph(M) # needs sage.modules + sage: import tempfile # needs sage.modules + sage: with tempfile.NamedTemporaryFile() as f: # needs sage.modules ....: b.save_afile(f.name) ....: b2 = BipartiteGraph(f.name) - sage: b.is_isomorphic(b2) # optional - sage.modules + sage: b.is_isomorphic(b2) # needs sage.modules True TESTS:: sage: import tempfile sage: f = tempfile.NamedTemporaryFile() - sage: for order in range(3, 13, 3): # optional - sage.combinat + sage: for order in range(3, 13, 3): # needs sage.combinat ....: num_chks = int(order / 3) ....: num_vars = order - num_chks ....: partition = (list(range(num_vars)), list(range(num_vars, num_vars+num_chks))) @@ -1921,78 +1923,77 @@ def reduced_adjacency_matrix(self, sparse=True, *, base_ring=None, **kwds): Bipartite graphs that are not weighted will return a matrix over ZZ, unless a base ring is specified:: - sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), # optional - sage.modules + sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), # needs sage.modules ....: (0,1,0,1,0,1,0), (1,1,0,1,0,0,1)]) - sage: B = BipartiteGraph(M) # optional - sage.modules - sage: N = B.reduced_adjacency_matrix() # optional - sage.modules - sage: N # optional - sage.modules + sage: B = BipartiteGraph(M) # needs sage.modules + sage: N = B.reduced_adjacency_matrix(); N # needs sage.modules [1 1 1 0 0 0 0] [1 0 0 1 1 0 0] [0 1 0 1 0 1 0] [1 1 0 1 0 0 1] - sage: N == M # optional - sage.modules + sage: N == M # needs sage.modules True - sage: N[0,0].parent() # optional - sage.modules + sage: N[0,0].parent() # needs sage.modules Integer Ring - sage: N2 = B.reduced_adjacency_matrix(base_ring=RDF); N2 # optional - sage.modules + sage: N2 = B.reduced_adjacency_matrix(base_ring=RDF); N2 # needs sage.modules [1.0 1.0 1.0 0.0 0.0 0.0 0.0] [1.0 0.0 0.0 1.0 1.0 0.0 0.0] [0.0 1.0 0.0 1.0 0.0 1.0 0.0] [1.0 1.0 0.0 1.0 0.0 0.0 1.0] - sage: N2[0, 0].parent() # optional - sage.modules + sage: N2[0, 0].parent() # needs sage.modules Real Double Field Multi-edge graphs also return a matrix over ZZ, unless a base ring is specified:: - sage: M = Matrix([(1,1,2,0,0), (0,2,1,1,1), (0,1,2,1,1)]) # optional - sage.modules - sage: B = BipartiteGraph(M, multiedges=True, sparse=True) # optional - sage.modules - sage: N = B.reduced_adjacency_matrix() # optional - sage.modules - sage: N == M # optional - sage.modules + sage: M = Matrix([(1,1,2,0,0), (0,2,1,1,1), (0,1,2,1,1)]) # needs sage.modules + sage: B = BipartiteGraph(M, multiedges=True, sparse=True) # needs sage.modules + sage: N = B.reduced_adjacency_matrix() # needs sage.modules + sage: N == M # needs sage.modules True - sage: N[0,0].parent() # optional - sage.modules + sage: N[0,0].parent() # needs sage.modules Integer Ring - sage: N2 = B.reduced_adjacency_matrix(base_ring=RDF) # optional - sage.modules - sage: N2[0, 0].parent() # optional - sage.modules + sage: N2 = B.reduced_adjacency_matrix(base_ring=RDF) # needs sage.modules + sage: N2[0, 0].parent() # needs sage.modules Real Double Field Weighted graphs will return a matrix over the ring given by their (first) weights, unless a base ring is specified:: - sage: F. = GF(4) # optional - sage.modules sage.rings.finite_rings - sage: MS = MatrixSpace(F, 2, 3) # optional - sage.modules sage.rings.finite_rings - sage: M = MS.matrix([[0, 1, a+1], [a, 1, 1]]) # optional - sage.modules sage.rings.finite_rings - sage: B = BipartiteGraph(M, weighted=True, sparse=True) # optional - sage.modules sage.rings.finite_rings - sage: N = B.reduced_adjacency_matrix(sparse=False) # optional - sage.modules sage.rings.finite_rings - sage: N == M # optional - sage.modules sage.rings.finite_rings + sage: F. = GF(4) # needs sage.modules sage.rings.finite_rings + sage: MS = MatrixSpace(F, 2, 3) # needs sage.modules sage.rings.finite_rings + sage: M = MS.matrix([[0, 1, a+1], [a, 1, 1]]) # needs sage.modules sage.rings.finite_rings + sage: B = BipartiteGraph(M, weighted=True, sparse=True) # needs sage.modules sage.rings.finite_rings + sage: N = B.reduced_adjacency_matrix(sparse=False) # needs sage.modules sage.rings.finite_rings + sage: N == M # needs sage.modules sage.rings.finite_rings True - sage: N[0,0].parent() # optional - sage.modules sage.rings.finite_rings + sage: N[0,0].parent() # needs sage.modules sage.rings.finite_rings Finite Field in a of size 2^2 - sage: N2 = B.reduced_adjacency_matrix(base_ring=F) # optional - sage.modules sage.rings.finite_rings - sage: N2[0, 0].parent() # optional - sage.modules sage.rings.finite_rings + sage: N2 = B.reduced_adjacency_matrix(base_ring=F) # needs sage.modules sage.rings.finite_rings + sage: N2[0, 0].parent() # needs sage.modules sage.rings.finite_rings Finite Field in a of size 2^2 TESTS:: sage: B = BipartiteGraph() - sage: B.reduced_adjacency_matrix() # optional - sage.modules + sage: B.reduced_adjacency_matrix() # needs sage.modules [] - sage: M = Matrix([[0,0], [0,0]]) # optional - sage.modules - sage: BipartiteGraph(M).reduced_adjacency_matrix() == M # optional - sage.modules + sage: M = Matrix([[0,0], [0,0]]) # needs sage.modules + sage: BipartiteGraph(M).reduced_adjacency_matrix() == M # needs sage.modules True - sage: M = Matrix([[10,2/3], [0,0]]) # optional - sage.modules - sage: B = BipartiteGraph(M, weighted=True, sparse=True) # optional - sage.modules - sage: M == B.reduced_adjacency_matrix() # optional - sage.modules + sage: M = Matrix([[10,2/3], [0,0]]) # needs sage.modules + sage: B = BipartiteGraph(M, weighted=True, sparse=True) # needs sage.modules + sage: M == B.reduced_adjacency_matrix() # needs sage.modules True An error is raised if the specified base ring is not compatible with the type of the weights of the bipartite graph:: - sage: F. = GF(4) # optional - sage.modules sage.rings.finite_rings - sage: MS = MatrixSpace(F, 2, 3) # optional - sage.modules sage.rings.finite_rings - sage: M = MS.matrix([[0, 1, a+1], [a, 1, 1]]) # optional - sage.modules sage.rings.finite_rings - sage: B = BipartiteGraph(M, weighted=True, sparse=True) # optional - sage.modules sage.rings.finite_rings - sage: B.reduced_adjacency_matrix(base_ring=RDF) # optional - sage.modules sage.rings.finite_rings + sage: F. = GF(4) # needs sage.modules sage.rings.finite_rings + sage: MS = MatrixSpace(F, 2, 3) # needs sage.modules sage.rings.finite_rings + sage: M = MS.matrix([[0, 1, a+1], [a, 1, 1]]) # needs sage.modules sage.rings.finite_rings + sage: B = BipartiteGraph(M, weighted=True, sparse=True) # needs sage.modules sage.rings.finite_rings + sage: B.reduced_adjacency_matrix(base_ring=RDF) # needs sage.modules sage.rings.finite_rings Traceback (most recent call last): ... TypeError: float() argument must be a string or a ...number, not 'sage.rings.finite_rings.element_givaro.FiniteField_givaroElement' @@ -2098,14 +2099,14 @@ class :class:`MixedIntegerLinearProgram Maximum matching in a cycle graph:: sage: G = BipartiteGraph(graphs.CycleGraph(10)) - sage: G.matching() # optional - networkx + sage: G.matching() # needs networkx [(0, 1, None), (2, 3, None), (4, 5, None), (6, 7, None), (8, 9, None)] The size of a maximum matching in a complete bipartite graph using Eppstein:: sage: G = BipartiteGraph(graphs.CompleteBipartiteGraph(4,5)) - sage: G.matching(algorithm="Eppstein", value_only=True) + sage: G.matching(algorithm="Eppstein", value_only=True) # needs networkx 4 TESTS: @@ -2123,11 +2124,11 @@ class :class:`MixedIntegerLinearProgram sage: G = graphs.CycleGraph(4) sage: B = BipartiteGraph([(u,v,2) for u,v in G.edges(sort=True, labels=0)]) - sage: sorted(B.matching(use_edge_labels=True)) + sage: sorted(B.matching(use_edge_labels=True)) # needs networkx [(0, 3, 2), (1, 2, 2)] - sage: B.matching(use_edge_labels=True, value_only=True) # optional - networkx + sage: B.matching(use_edge_labels=True, value_only=True) # needs networkx 4 - sage: B.matching(use_edge_labels=True, value_only=True, algorithm='Edmonds') + sage: B.matching(use_edge_labels=True, value_only=True, algorithm='Edmonds') # needs networkx 4 sage: B.matching(use_edge_labels=True, value_only=True, algorithm='LP') 4 @@ -2139,11 +2140,13 @@ class :class:`MixedIntegerLinearProgram Traceback (most recent call last): ... ValueError: use_edge_labels cannot be used with "Hopcroft-Karp" or "Eppstein" - sage: B.matching(use_edge_labels=False, value_only=True, algorithm='Hopcroft-Karp') # optional - networkx + sage: B.matching(use_edge_labels=False, value_only=True, # needs networkx + ....: algorithm='Hopcroft-Karp') 2 - sage: B.matching(use_edge_labels=False, value_only=True, algorithm='Eppstein') # optional - networkx + sage: B.matching(use_edge_labels=False, value_only=True, # needs networkx + ....: algorithm='Eppstein') 2 - sage: B.matching(use_edge_labels=False, value_only=True, algorithm='Edmonds') + sage: B.matching(use_edge_labels=False, value_only=True, algorithm='Edmonds') # needs networkx 2 sage: B.matching(use_edge_labels=False, value_only=True, algorithm='LP') 2 @@ -2154,23 +2157,23 @@ class :class:`MixedIntegerLinearProgram sage: for e in G.edges(sort=True): ....: G.set_edge_label(e[0], e[1], int(e[0]) + int(e[1])) sage: G.allow_multiple_edges(True) - sage: G.matching(use_edge_labels=True, value_only=True) + sage: G.matching(use_edge_labels=True, value_only=True) # needs networkx 444 Empty bipartite graph and bipartite graphs without edges:: sage: B = BipartiteGraph() sage: algorithms = ["Hopcroft-Karp", "Eppstein", "Edmonds", "LP"] - sage: not any(B.matching(algorithm=algo) for algo in algorithms) + sage: not any(B.matching(algorithm=algo) for algo in algorithms) # needs networkx True - sage: all(B.matching(algorithm=algo, value_only=True) == 0 for algo in algorithms) + sage: all(B.matching(algorithm=algo, value_only=True) == 0 for algo in algorithms) # needs networkx True sage: B.add_vertex(1, left=True) sage: B.add_vertex(2, left=True) sage: B.add_vertex(3, right=True) - sage: not any(B.matching(algorithm=algo) for algo in algorithms) + sage: not any(B.matching(algorithm=algo) for algo in algorithms) # needs networkx True - sage: all(B.matching(algorithm=algo, value_only=True) == 0 for algo in algorithms) + sage: all(B.matching(algorithm=algo, value_only=True) == 0 for algo in algorithms) # needs networkx True """ if algorithm is None: @@ -2285,17 +2288,17 @@ def vertex_cover(self, algorithm="Konig", value_only=False, On the Cycle Graph:: sage: B = BipartiteGraph(graphs.CycleGraph(6)) - sage: len(B.vertex_cover()) # optional - networkx + sage: len(B.vertex_cover()) # needs networkx 3 - sage: B.vertex_cover(value_only=True) # optional - networkx + sage: B.vertex_cover(value_only=True) # needs networkx 3 The two algorithms should return the same result:: - sage: g = BipartiteGraph(graphs.RandomBipartite(10, 10, .5)) - sage: vc1 = g.vertex_cover(algorithm="Konig") - sage: vc2 = g.vertex_cover(algorithm="Cliquer") - sage: len(vc1) == len(vc2) + sage: g = BipartiteGraph(graphs.RandomBipartite(10, 10, .5)) # needs numpy + sage: vc1 = g.vertex_cover(algorithm="Konig") # needs numpy + sage: vc2 = g.vertex_cover(algorithm="Cliquer") # needs numpy + sage: len(vc1) == len(vc2) # needs numpy True TESTS: @@ -2303,7 +2306,7 @@ def vertex_cover(self, algorithm="Konig", value_only=False, Giving a non connected bipartite graph:: sage: B = BipartiteGraph(graphs.CycleGraph(4) * 2) - sage: len(B.vertex_cover()) + sage: len(B.vertex_cover()) # needs networkx 4 Empty bipartite graph and bipartite graphs without edges:: diff --git a/src/sage/graphs/bliss.pyx b/src/sage/graphs/bliss.pyx index d8c50f220e3..5911778953c 100644 --- a/src/sage/graphs/bliss.pyx +++ b/src/sage/graphs/bliss.pyx @@ -437,12 +437,13 @@ cpdef canonical_form(G, partition=None, return_graph=False, use_edge_labels=True sage: g.is_isomorphic(canonical_form(g, return_graph=True)) # optional - bliss True - sage: g1 = graphs.RandomGNP(100, .4) # optional - bliss - sage: r = Permutations(range(100)).random_element() # optional - bliss - sage: g2 = Graph([(r[u],r[v]) for u,v in g1.edges(sort=True, labels=False)]) # optional - bliss - sage: g1 = canonical_form(g1, return_graph=True) # optional - bliss - sage: g2 = canonical_form(g2, return_graph=True) # optional - bliss - sage: g2 == g2 # optional - bliss + sage: # optional - bliss + sage: g1 = graphs.RandomGNP(100, .4) + sage: r = Permutations(range(100)).random_element() + sage: g2 = Graph([(r[u],r[v]) for u,v in g1.edges(sort=True, labels=False)]) + sage: g1 = canonical_form(g1, return_graph=True) + sage: g2 = canonical_form(g2, return_graph=True) + sage: g2 == g2 True sage: g = Graph({1: [2]}) @@ -476,11 +477,12 @@ cpdef canonical_form(G, partition=None, return_graph=False, use_edge_labels=True Check that it works with non hashable non sortable edge labels (relying on string representations of the labels):: - sage: g1 = Graph([(0, 1, matrix(ZZ, 2)), (0, 2, RDF.pi()), (1, 2, 'a')]) # optional - sage.modules - sage: g2 = Graph([(1, 2, matrix(ZZ, 2)), (2, 0, RDF.pi()), (0, 1, 'a')]) # optional - sage.modules - sage: g1can = canonical_form(g1, use_edge_labels=True) # optional - bliss sage.modules - sage: g2can = canonical_form(g2, use_edge_labels=True) # optional - bliss sage.modules - sage: g1can == g2can # optional - bliss sage.modules + sage: # needs sage.modules + sage: g1 = Graph([(0, 1, matrix(ZZ, 2)), (0, 2, RDF.pi()), (1, 2, 'a')]) + sage: g2 = Graph([(1, 2, matrix(ZZ, 2)), (2, 0, RDF.pi()), (0, 1, 'a')]) + sage: g1can = canonical_form(g1, use_edge_labels=True) # optional - bliss + sage: g2can = canonical_form(g2, use_edge_labels=True) # optional - bliss + sage: g1can == g2can # optional - bliss True Check that :trac:`32395` is fixed:: @@ -677,11 +679,12 @@ cpdef automorphism_group(G, partition=None, use_edge_labels=True): Computing the automorphism group of a graph or digraph:: - sage: G = graphs.CompleteMultipartiteGraph([1, 1, 1, 2]) # optional - bliss - sage: automorphism_group(G).cardinality() # optional - bliss + sage: # optional - bliss + sage: G = graphs.CompleteMultipartiteGraph([1, 1, 1, 2]) + sage: automorphism_group(G).cardinality() 12 - sage: D = DiGraph(G.edges(sort=True)) # optional - bliss - sage: automorphism_group(D).cardinality() # optional - bliss + sage: D = DiGraph(G.edges(sort=True)) + sage: automorphism_group(D).cardinality() 2 Observe that the order 12 is given by permuting the first three vertices, or the last two @@ -690,12 +693,13 @@ cpdef automorphism_group(G, partition=None, use_edge_labels=True): Partitioning the vertices into classes:: - sage: G = graphs.CompleteMultipartiteGraph([3, 2]) # optional - bliss - sage: automorphism_group(G).cardinality() # optional - bliss + sage: # optional - bliss + sage: G = graphs.CompleteMultipartiteGraph([3, 2]) + sage: automorphism_group(G).cardinality() 12 - sage: automorphism_group(G,partition=[[0],[1],[2],[3,4]]).cardinality() # optional - bliss + sage: automorphism_group(G,partition=[[0],[1],[2],[3,4]]).cardinality() 2 - sage: automorphism_group(G,partition=[[0],[1,2],[3,4]]).cardinality() # optional - bliss + sage: automorphism_group(G,partition=[[0],[1,2],[3,4]]).cardinality() 4 sage: automorphism_group(G,partition=[[1,2],[0,3],[4]]).cardinality() # optional - bliss @@ -724,10 +728,11 @@ cpdef automorphism_group(G, partition=None, use_edge_labels=True): sage: automorphism_group(G).is_isomorphic(G.automorphism_group()) # optional - bliss True - sage: G = graphs.HeawoodGraph() # optional - bliss - sage: p = G.bipartite_sets() # optional - bliss - sage: A = G.automorphism_group(partition=[list(p[0]), list(p[1])]) # optional - bliss - sage: automorphism_group(G, partition=p).is_isomorphic(A) # optional - bliss + sage: # optional - bliss + sage: G = graphs.HeawoodGraph() + sage: p = G.bipartite_sets() + sage: A = G.automorphism_group(partition=[list(p[0]), list(p[1])]) + sage: automorphism_group(G, partition=p).is_isomorphic(A) True sage: G = graphs.CompleteMultipartiteGraph([5,7,11]) @@ -735,55 +740,59 @@ cpdef automorphism_group(G, partition=None, use_edge_labels=True): sage: B.cardinality() == prod(factorial(n) for n in [5,7,11]) # optional - bliss True - sage: G = Graph(graphs.CompleteMultipartiteGraph([8,8,8,5]),sparse=True)# optional - bliss - sage: for i,j in G.edges(labels=False, sort=False): # optional - bliss + sage: # optional - bliss + sage: G = Graph(graphs.CompleteMultipartiteGraph([8,8,8,5]),sparse=True) + sage: for i,j in G.edges(labels=False, sort=False): ....: if 0 <= i < 3: ....: G.set_edge_label(i, j, "A") ....: if 3 <= i < 6: ....: G.set_edge_label(i, j, "B") ....: if 6 <= i < 8: ....: G.set_edge_label(i, j, "C") - sage: automorphism_group(G).cardinality() == prod( factorial(n) for n in [3,3,2,8,8,5,2] ) # optional - bliss + sage: automorphism_group(G).cardinality() == prod( factorial(n) for n in [3,3,2,8,8,5,2] ) True - sage: automorphism_group(G, use_edge_labels=False).cardinality() == prod( factorial(n) for n in [8,8,8,5,3] ) # optional - bliss + sage: automorphism_group(G, use_edge_labels=False).cardinality() == prod( factorial(n) for n in [8,8,8,5,3] ) True - sage: automorphism_group(G,[[0 .. 7],[8 .. 11],[12 .. 28]]).cardinality() == prod( factorial(n) for n in [3,3,2,4,4,8,5] ) # optional - bliss + sage: automorphism_group(G,[[0 .. 7],[8 .. 11],[12 .. 28]]).cardinality() == prod( factorial(n) for n in [3,3,2,4,4,8,5] ) True - sage: G = Graph() # optional - bliss - sage: G.add_edges((i,j,"A") for i in range(0, 2) for j in range(14,20)) # optional - bliss - sage: G.add_edges((i,j,"B") for i in range(2, 5) for j in range(14,20)) # optional - bliss - sage: G.add_edges((i,j,"C") for i in range(5, 9) for j in range(14,20)) # optional - bliss - sage: G.add_edges((i,j,"D") for i in range(9,14) for j in range(14,20)) # optional - bliss - sage: A = automorphism_group(G) # optional - bliss - sage: print(A.gens()) # random, optional - bliss + sage: # optional - bliss + sage: G = Graph() + sage: G.add_edges((i,j,"A") for i in range(0, 2) for j in range(14,20)) + sage: G.add_edges((i,j,"B") for i in range(2, 5) for j in range(14,20)) + sage: G.add_edges((i,j,"C") for i in range(5, 9) for j in range(14,20)) + sage: G.add_edges((i,j,"D") for i in range(9,14) for j in range(14,20)) + sage: A = automorphism_group(G) + sage: print(A.gens()) # random [(9,13), (18,19), (17,18), (16,17), (15,16), (14,15), (12,9), (11,12), (10,11), (7,8), (6,7), (5,6), (3,4), (2,3), (0,1)] - sage: A.cardinality() == prod(factorial(n) for n in [2,3,4,5,6]) # optional - bliss + sage: A.cardinality() == prod(factorial(n) for n in [2,3,4,5,6]) True sage: alpha = "abcdefghijklmnopqrstuvwxyz" - sage: G = Graph() # optional - bliss - sage: G.add_edges((alpha[i],alpha[j],"A") for i in range(0, 2) for j in range(14,20)) # optional - bliss - sage: G.add_edges((alpha[i],alpha[j],"B") for i in range(2, 5) for j in range(14,20)) # optional - bliss - sage: G.add_edges((alpha[i],alpha[j],"C") for i in range(5, 9) for j in range(14,20)) # optional - bliss - sage: G.add_edges((alpha[i],alpha[j],"D") for i in range(9,14) for j in range(14,20)) # optional - bliss - sage: A = automorphism_group(G) # optional - bliss - sage: print(A.gens()) # random, optional - bliss + sage: # optional - bliss + sage: G = Graph() + sage: G.add_edges((alpha[i],alpha[j],"A") for i in range(0, 2) for j in range(14,20)) + sage: G.add_edges((alpha[i],alpha[j],"B") for i in range(2, 5) for j in range(14,20)) + sage: G.add_edges((alpha[i],alpha[j],"C") for i in range(5, 9) for j in range(14,20)) + sage: G.add_edges((alpha[i],alpha[j],"D") for i in range(9,14) for j in range(14,20)) + sage: A = automorphism_group(G) + sage: print(A.gens()) [('r','t'), ('s','r'), ('p','s'), ('q','p'), ('o','q'), ('l','n'), ('m','l'), ('j','m'), ('k','j'), ('i','h'), ('f','i'), ('g','f'), ('e','d'), ('c','e'), ('a','b')] - sage: A.cardinality() == prod(factorial(n) for n in [2,3,4,5,6]) # optional - bliss + sage: A.cardinality() == prod(factorial(n) for n in [2,3,4,5,6]) True - sage: gg = graphs.CompleteGraph(5) # optional - bliss - sage: gg.allow_loops(True) # optional - bliss - sage: gg.add_edge(0,0) # optional - bliss - sage: gg.add_edge(1,1) # optional - bliss - sage: automorphism_group(gg).cardinality() # optional - bliss + sage: # optional - bliss + sage: gg = graphs.CompleteGraph(5) + sage: gg.allow_loops(True) + sage: gg.add_edge(0,0) + sage: gg.add_edge(1,1) + sage: automorphism_group(gg).cardinality() 12 - sage: automorphism_group(gg,[[0],[1,2,3,4]]).cardinality() # optional - bliss + sage: automorphism_group(gg,[[0],[1,2,3,4]]).cardinality() 6 """ # We need this to convert the numbers from to diff --git a/src/sage/graphs/centrality.pyx b/src/sage/graphs/centrality.pyx index 9de214115f9..fa659c13d94 100755 --- a/src/sage/graphs/centrality.pyx +++ b/src/sage/graphs/centrality.pyx @@ -99,11 +99,12 @@ def centrality_betweenness(G, bint exact=False, bint normalize=True): Compare with NetworkX:: - sage: import networkx # optional - networkx - sage: g = graphs.RandomGNP(100, .2) # optional - networkx - sage: nw = networkx.betweenness_centrality(g.networkx_graph()) # optional - networkx - sage: sg = centrality_betweenness(g) # optional - networkx - sage: max(abs(nw[x] - sg[x]) for x in g) # abs tol 1e-10 # optional - networkx + sage: # needs networkx + sage: import networkx + sage: g = graphs.RandomGNP(100, .2) + sage: nw = networkx.betweenness_centrality(g.networkx_graph()) + sage: sg = centrality_betweenness(g) + sage: max(abs(nw[x] - sg[x]) for x in g) # abs tol 1e-10 0 Stupid cases:: @@ -642,13 +643,13 @@ def centrality_closeness_top_k(G, int k=1, int verbose=0): sage: n = 20 sage: m = random.randint(1, n * (n - 1) / 2) sage: k = random.randint(1, n) - sage: g = graphs.RandomGNM(n, m) # optional - networkx - sage: topk = centrality_closeness_top_k(g, k) # optional - networkx - sage: centr = g.centrality_closeness(algorithm='BFS') # optional - networkx - sage: sorted_centr = sorted(centr.values(), reverse=True) # optional - networkx - sage: len(topk) == min(k, len(sorted_centr)) # optional - networkx + sage: g = graphs.RandomGNM(n, m) # needs networkx + sage: topk = centrality_closeness_top_k(g, k) # needs networkx + sage: centr = g.centrality_closeness(algorithm='BFS') # needs networkx + sage: sorted_centr = sorted(centr.values(), reverse=True) # needs networkx + sage: len(topk) == min(k, len(sorted_centr)) # needs networkx True - sage: all(abs(topk[i][0] - sorted_centr[i]) < 1e-12 for i in range(len(topk))) # optional - networkx + sage: all(abs(topk[i][0] - sorted_centr[i]) < 1e-12 for i in range(len(topk))) # needs networkx True Directed case:: @@ -658,13 +659,13 @@ def centrality_closeness_top_k(G, int k=1, int verbose=0): sage: n = 20 sage: m = random.randint(1, n * (n - 1)) sage: k = random.randint(1, n) - sage: g = digraphs.RandomDirectedGNM(n, m) # optional - networkx - sage: topk = centrality_closeness_top_k(g, k) # optional - networkx - sage: centr = g.centrality_closeness(algorithm='BFS') # optional - networkx - sage: sorted_centr = sorted(centr.values(), reverse=True) # optional - networkx - sage: len(topk) == min(k, len(sorted_centr)) # optional - networkx + sage: g = digraphs.RandomDirectedGNM(n, m) # needs networkx + sage: topk = centrality_closeness_top_k(g, k) # needs networkx + sage: centr = g.centrality_closeness(algorithm='BFS') # needs networkx + sage: sorted_centr = sorted(centr.values(), reverse=True) # needs networkx + sage: len(topk) == min(k, len(sorted_centr)) # needs networkx True - sage: all(abs(topk[i][0] - sorted_centr[i]) < 1e-12 for i in range(len(topk))) # optional - networkx + sage: all(abs(topk[i][0] - sorted_centr[i]) < 1e-12 for i in range(len(topk))) # needs networkx True """ cdef list res diff --git a/src/sage/graphs/cliquer.pyx b/src/sage/graphs/cliquer.pyx index 9ff02b8572e..6f232d97e16 100644 --- a/src/sage/graphs/cliquer.pyx +++ b/src/sage/graphs/cliquer.pyx @@ -115,7 +115,7 @@ def all_max_clique(graph): [2, 6], [2, 8], [3, 4], [3, 7], [3, 9], [4, 5], [4, 8], [5, 10], [5, 11], [6, 10], [6, 11], [7, 8], [7, 11], [8, 10], [9, 10], [9, 11]] sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2,2]) # optional - sage.plot + sage: G.show(figsize=[2,2]) # needs sage.plot sage: G.cliques_maximum() [[0, 1, 2], [0, 1, 3]] sage: C = graphs.PetersenGraph() @@ -302,7 +302,7 @@ def clique_number(graph): sage: C.clique_number() 4 sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2,2]) # optional - sage.plot + sage: G.show(figsize=[2,2]) # needs sage.plot sage: G.clique_number() 3 diff --git a/src/sage/graphs/comparability.pyx b/src/sage/graphs/comparability.pyx index b694b552ee8..119cd892265 100644 --- a/src/sage/graphs/comparability.pyx +++ b/src/sage/graphs/comparability.pyx @@ -417,20 +417,20 @@ def is_comparability_MILP(g, certificate=False, solver=None, verbose=0): The 5-cycle or the Petersen Graph are not transitively orientable:: sage: from sage.graphs.comparability import is_comparability_MILP as is_comparability - sage: is_comparability(graphs.CycleGraph(5), certificate = True) + sage: is_comparability(graphs.CycleGraph(5), certificate=True) # needs sage.numerical.mip (False, None) sage: g = graphs.PetersenGraph() - sage: is_comparability(g, certificate = True) + sage: is_comparability(g, certificate=True) # needs sage.numerical.mip (False, None) But the Bull graph is:: sage: g = graphs.BullGraph() - sage: is_comparability(g) + sage: is_comparability(g) # needs sage.numerical.mip True - sage: is_comparability(g, certificate = True) + sage: is_comparability(g, certificate=True) # needs sage.numerical.mip (True, Digraph on 5 vertices) - sage: is_comparability(g, certificate = True)[1].is_transitive() + sage: is_comparability(g, certificate=True)[1].is_transitive() # needs sage.numerical.mip True """ from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException @@ -642,7 +642,7 @@ def is_permutation(g, algorithm="greedy", certificate=False, check=True, sage: p1 = Permutation([nn+1 for nn in perm[0]]) sage: p2 = Permutation([nn+1 for nn in perm[1]]) sage: p = p2 * p1.inverse() - sage: p.show(representation="braid") # optional - sage.plot + sage: p.show(representation="braid") # needs sage.plot TESTS: @@ -664,7 +664,7 @@ def is_permutation(g, algorithm="greedy", certificate=False, check=True, Then with MILP:: sage: from sage.graphs.comparability import is_permutation - sage: for i in range(20): + sage: for i in range(20): # needs sage.numerical.mip ....: p = Permutations(10).random_element() ....: g1 = graphs.PermutationGraph(p) ....: isit, certif = is_permutation(g1, algorithm="MILP", certificate=True) @@ -745,15 +745,15 @@ def is_transitive(g, certificate=False): (0, 2) sage: digraphs.RandomDirectedGNP(30,.2).is_transitive() False - sage: D = digraphs.DeBruijn(5, 2) # optional - sage.combinat - sage: D.is_transitive() # optional - sage.combinat + sage: D = digraphs.DeBruijn(5, 2) # needs sage.combinat + sage: D.is_transitive() # needs sage.combinat False - sage: cert = D.is_transitive(certificate=True) # optional - sage.combinat - sage: D.has_edge(*cert) # optional - sage.combinat + sage: cert = D.is_transitive(certificate=True) # needs sage.combinat + sage: D.has_edge(*cert) # needs sage.combinat False - sage: bool(D.shortest_path(*cert)) # optional - sage.combinat + sage: bool(D.shortest_path(*cert)) # needs sage.combinat True - sage: digraphs.RandomDirectedGNP(20,.2).transitive_closure().is_transitive() # optional - networkx + sage: digraphs.RandomDirectedGNP(20,.2).transitive_closure().is_transitive() # needs networkx True """ cdef int n = g.order() diff --git a/src/sage/graphs/connectivity.pyx b/src/sage/graphs/connectivity.pyx index c2100141f30..ff0cabb8f37 100644 --- a/src/sage/graphs/connectivity.pyx +++ b/src/sage/graphs/connectivity.pyx @@ -258,12 +258,12 @@ def connected_components_subgraphs(G): sage: from sage.graphs.connectivity import connected_components_subgraphs sage: G = Graph({0: [1, 3], 1: [2], 2: [3], 4: [5, 6], 5: [6]}) sage: L = connected_components_subgraphs(G) - sage: graphs_list.show_graphs(L) # optional - sage.plot + sage: graphs_list.show_graphs(L) # needs sage.plot sage: D = DiGraph({0: [1, 3], 1: [2], 2: [3], 4: [5, 6], 5: [6]}) sage: L = connected_components_subgraphs(D) - sage: graphs_list.show_graphs(L) # optional - sage.plot + sage: graphs_list.show_graphs(L) # needs sage.plot sage: L = D.connected_components_subgraphs() - sage: graphs_list.show_graphs(L) # optional - sage.plot + sage: graphs_list.show_graphs(L) # needs sage.plot TESTS: @@ -1361,25 +1361,25 @@ def vertex_connectivity(G, value_only=True, sets=False, k=None, solver=None, ver A basic application on a ``PappusGraph``:: sage: from sage.graphs.connectivity import vertex_connectivity - sage: g=graphs.PappusGraph() - sage: vertex_connectivity(g) + sage: g = graphs.PappusGraph() + sage: vertex_connectivity(g) # needs sage.numerical.mip 3 - sage: g.vertex_connectivity() + sage: g.vertex_connectivity() # needs sage.numerical.mip 3 In a grid, the vertex connectivity is equal to the minimum degree, in which case one of the two sets is of cardinality `1`:: sage: g = graphs.GridGraph([ 3,3 ]) - sage: [value, cut, [ setA, setB ]] = vertex_connectivity(g, sets=True) - sage: len(setA) == 1 or len(setB) == 1 + sage: [value, cut, [ setA, setB ]] = vertex_connectivity(g, sets=True) # needs sage.numerical.mip + sage: len(setA) == 1 or len(setB) == 1 # needs sage.numerical.mip True A vertex cut in a tree is any internal vertex:: sage: tree = graphs.RandomTree(15) - sage: val, [cut_vertex] = vertex_connectivity(tree, value_only=False) - sage: tree.degree(cut_vertex) > 1 + sage: val, [cut_vertex] = vertex_connectivity(tree, value_only=False) # needs sage.numerical.mip + sage: tree.degree(cut_vertex) > 1 # needs sage.numerical.mip True When ``value_only = True``, this function is optimized for small @@ -1388,41 +1388,41 @@ def vertex_connectivity(G, value_only=True, sets=False, k=None, solver=None, ver It is the case for connected graphs which are not connected:: sage: g = 2 * graphs.PetersenGraph() - sage: vertex_connectivity(g) + sage: vertex_connectivity(g) # needs sage.numerical.mip 0 Or if they are just 1-connected:: sage: g = graphs.PathGraph(10) - sage: vertex_connectivity(g) + sage: vertex_connectivity(g) # needs sage.numerical.mip 1 For directed graphs, the strong connectivity is tested through the dedicated function:: sage: g = digraphs.ButterflyGraph(3) - sage: vertex_connectivity(g) + sage: vertex_connectivity(g) # needs sage.numerical.mip 0 A complete graph on `10` vertices is `9`-connected:: sage: g = graphs.CompleteGraph(10) - sage: vertex_connectivity(g) + sage: vertex_connectivity(g) # needs sage.numerical.mip 9 A complete digraph on `10` vertices is `9`-connected:: sage: g = DiGraph(graphs.CompleteGraph(10)) - sage: vertex_connectivity(g) + sage: vertex_connectivity(g) # needs sage.numerical.mip 9 When parameter ``k`` is set, we only check for the existence of a vertex cut of order at least ``k``:: sage: g = graphs.PappusGraph() - sage: vertex_connectivity(g, k=3) + sage: vertex_connectivity(g, k=3) # needs sage.numerical.mip True - sage: vertex_connectivity(g, k=4) + sage: vertex_connectivity(g, k=4) # needs sage.numerical.mip False TESTS: @@ -1441,13 +1441,13 @@ def vertex_connectivity(G, value_only=True, sets=False, k=None, solver=None, ver sage: from sage.graphs.connectivity import is_strongly_connected sage: from sage.graphs.connectivity import is_connected sage: empty = Graph() - sage: vertex_connectivity(empty) + sage: vertex_connectivity(empty) # needs sage.numerical.mip 0 - sage: vertex_connectivity(empty, k=1) == is_connected(empty) + sage: vertex_connectivity(empty, k=1) == is_connected(empty) # needs sage.numerical.mip True - sage: vertex_connectivity(Graph(), k=2) == empty.is_biconnected() + sage: vertex_connectivity(Graph(), k=2) == empty.is_biconnected() # needs sage.numerical.mip True - sage: vertex_connectivity(DiGraph(), k=1) == is_strongly_connected(DiGraph()) + sage: vertex_connectivity(DiGraph(), k=1) == is_strongly_connected(DiGraph()) # needs sage.numerical.mip True If ``G`` is not a Sage (Di)Graph, an error is raised:: @@ -1460,16 +1460,16 @@ def vertex_connectivity(G, value_only=True, sets=False, k=None, solver=None, ver Complete Graph with loops or multiple edges (:trac:`25589`):: sage: G = Graph([(0, 1), (0, 1)], multiedges=True) - sage: G.vertex_connectivity() + sage: G.vertex_connectivity() # needs sage.numerical.mip 1 sage: G = graphs.CompleteGraph(4) sage: G.allow_loops(True) sage: G.add_edge(0, 0) - sage: G.vertex_connectivity(value_only=False, verbose=1) + sage: G.vertex_connectivity(value_only=False, verbose=1) # needs sage.numerical.mip (3, []) sage: G.allow_multiple_edges(True) sage: G.add_edge(0, 1) - sage: G.vertex_connectivity(value_only=False, verbose=1) + sage: G.vertex_connectivity(value_only=False, verbose=1) # needs sage.numerical.mip (3, []) """ from sage.graphs.generic_graph import GenericGraph @@ -2379,21 +2379,21 @@ def spqr_tree(G, algorithm="Hopcroft_Tarjan", solver=None, verbose=0, sage: T = spqr_tree(G, algorithm="Hopcroft_Tarjan") sage: G.is_isomorphic(spqr_tree_to_graph(T)) True - sage: T2 = spqr_tree(G, algorithm='cleave') - sage: G.is_isomorphic(spqr_tree_to_graph(T2)) + sage: T2 = spqr_tree(G, algorithm='cleave') # needs sage.numerical.mip + sage: G.is_isomorphic(spqr_tree_to_graph(T2)) # needs sage.numerical.mip True sage: G = Graph([(0, 1)], multiedges=True) - sage: T = spqr_tree(G, algorithm='cleave') - sage: T.vertices(sort=True) + sage: T = spqr_tree(G, algorithm='cleave') # needs sage.numerical.mip + sage: T.vertices(sort=True) # needs sage.numerical.mip [('Q', Multi-graph on 2 vertices)] - sage: G.is_isomorphic(spqr_tree_to_graph(T)) + sage: G.is_isomorphic(spqr_tree_to_graph(T)) # needs sage.numerical.mip True sage: T = spqr_tree(G, algorithm='Hopcroft_Tarjan') sage: T.vertices(sort=True) [('Q', Multi-graph on 2 vertices)] sage: G.add_edge(0, 1) - sage: spqr_tree(G, algorithm='cleave').vertices(sort=True) + sage: spqr_tree(G, algorithm='cleave').vertices(sort=True) # needs sage.numerical.mip [('P', Multi-graph on 2 vertices)] sage: from collections import Counter @@ -2401,24 +2401,24 @@ def spqr_tree(G, algorithm="Hopcroft_Tarjan", solver=None, verbose=0, sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan") sage: Counter(u[0] for u in T) Counter({'R': 1}) - sage: T = G.spqr_tree(algorithm="cleave") - sage: Counter(u[0] for u in T) + sage: T = G.spqr_tree(algorithm="cleave") # needs sage.numerical.mip + sage: Counter(u[0] for u in T) # needs sage.numerical.mip Counter({'R': 1}) sage: for u,v in list(G.edges(labels=False, sort=False)): ....: G.add_path([u, G.add_vertex(), G.add_vertex(), v]) sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan") sage: sorted(Counter(u[0] for u in T).items()) [('P', 15), ('R', 1), ('S', 15)] - sage: T = G.spqr_tree(algorithm="cleave") - sage: sorted(Counter(u[0] for u in T).items()) + sage: T = G.spqr_tree(algorithm="cleave") # needs sage.numerical.mip + sage: sorted(Counter(u[0] for u in T).items()) # needs sage.numerical.mip [('P', 15), ('R', 1), ('S', 15)] sage: for u,v in list(G.edges(labels=False, sort=False)): ....: G.add_path([u, G.add_vertex(), G.add_vertex(), v]) sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan") sage: sorted(Counter(u[0] for u in T).items()) [('P', 60), ('R', 1), ('S', 75)] - sage: T = G.spqr_tree(algorithm="cleave") # long time - sage: sorted(Counter(u[0] for u in T).items()) # long time + sage: T = G.spqr_tree(algorithm="cleave") # long time # needs sage.numerical.mip + sage: sorted(Counter(u[0] for u in T).items()) # long time # needs sage.numerical.mip [('P', 60), ('R', 1), ('S', 75)] TESTS:: @@ -2814,7 +2814,7 @@ cdef class _Component: ....: 'comp.add_edge(3)', ....: 'comp.finish_tric_or_poly(4)', ....: 'print(comp)'] - sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython + sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython Polygon: 2 3 4 """ self.mem = MemoryAllocator() @@ -2861,7 +2861,7 @@ cdef class _Component: ....: 'comp.add_edge(3)', ....: 'comp.finish_tric_or_poly(4)', ....: 'print(comp)'] - sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython + sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython Polygon: 2 3 4 """ if self.component_type == 0: @@ -4344,8 +4344,8 @@ def is_triconnected(G): Comparing different methods on random graphs that are not always triconnected:: - sage: G = graphs.RandomBarabasiAlbert(50, 3) # optional - networkx - sage: G.is_triconnected() == G.vertex_connectivity(k=3) # optional - networkx + sage: G = graphs.RandomBarabasiAlbert(50, 3) # needs networkx + sage: G.is_triconnected() == G.vertex_connectivity(k=3) # needs networkx True .. SEEALSO:: diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index b1d046ee25d..1017f8490eb 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -357,7 +357,7 @@ class DiGraph(GenericGraph): sage: g = DiGraph([[1..12], lambda i,j: i != j and i.divides(j)]) sage: g.vertices(sort=True) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] - sage: g.adjacency_matrix() # optional - sage.modules + sage: g.adjacency_matrix() # needs sage.modules [0 1 1 1 1 1 1 1 1 1 1 1] [0 0 0 1 0 1 0 1 0 1 0 1] [0 0 0 0 0 1 0 0 1 0 0 1] @@ -377,28 +377,28 @@ class DiGraph(GenericGraph): - an adjacency matrix:: - sage: M = Matrix([[0, 1, 1, 1, 0], [0, 0, 0, 0, 0], # optional - sage.modules + sage: M = Matrix([[0, 1, 1, 1, 0], [0, 0, 0, 0, 0], # needs sage.modules ....: [0, 0, 0, 0, 1], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]); M [0 1 1 1 0] [0 0 0 0 0] [0 0 0 0 1] [0 0 0 0 0] [0 0 0 0 0] - sage: DiGraph(M) # optional - sage.modules + sage: DiGraph(M) # needs sage.modules Digraph on 5 vertices - sage: M = Matrix([[0,1,-1], [-1,0,-1/2], [1,1/2,0]]); M # optional - sage.modules + sage: M = Matrix([[0,1,-1], [-1,0,-1/2], [1,1/2,0]]); M # needs sage.modules [ 0 1 -1] [ -1 0 -1/2] [ 1 1/2 0] - sage: G = DiGraph(M, sparse=True, weighted=True); G # optional - sage.modules + sage: G = DiGraph(M, sparse=True, weighted=True); G # needs sage.modules Digraph on 3 vertices - sage: G.weighted() # optional - sage.modules + sage: G.weighted() # needs sage.modules True - an incidence matrix:: - sage: M = Matrix(6, [-1,0,0,0,1, 1,-1,0,0,0, 0,1,-1,0,0, # optional - sage.modules + sage: M = Matrix(6, [-1,0,0,0,1, 1,-1,0,0,0, 0,1,-1,0,0, # needs sage.modules ....: 0,0,1,-1,0, 0,0,0,1,-1, 0,0,0,0,0]); M [-1 0 0 0 1] [ 1 -1 0 0 0] @@ -406,7 +406,7 @@ class DiGraph(GenericGraph): [ 0 0 1 -1 0] [ 0 0 0 1 -1] [ 0 0 0 0 0] - sage: DiGraph(M) # optional - sage.modules + sage: DiGraph(M) # needs sage.modules Digraph on 6 vertices #. A ``dig6`` string: Sage automatically recognizes whether a string is in @@ -429,17 +429,17 @@ class DiGraph(GenericGraph): #. A NetworkX MultiDiGraph:: - sage: import networkx # optional - networkx - sage: g = networkx.MultiDiGraph({0: [1, 2, 3], 2: [4]}) # optional - networkx - sage: DiGraph(g) # optional - networkx + sage: import networkx # needs networkx + sage: g = networkx.MultiDiGraph({0: [1, 2, 3], 2: [4]}) # needs networkx + sage: DiGraph(g) # needs networkx Multi-digraph on 5 vertices #. A NetworkX digraph:: - sage: import networkx # optional - networkx - sage: g = networkx.DiGraph({0: [1, 2, 3], 2: [4]}) # optional - networkx - sage: DiGraph(g) # optional - networkx + sage: import networkx # needs networkx + sage: g = networkx.DiGraph({0: [1, 2, 3], 2: [4]}) # needs networkx + sage: DiGraph(g) # needs networkx Digraph on 5 vertices #. An igraph directed Graph (see also @@ -453,11 +453,12 @@ class DiGraph(GenericGraph): If ``vertex_labels`` is ``True``, the names of the vertices are given by the vertex attribute ``'name'``, if available:: - sage: g = igraph.Graph([(0,1),(0,2)], directed=True, vertex_attrs={'name':['a','b','c']}) # optional - python_igraph - sage: DiGraph(g).vertices(sort=True) # optional - python_igraph + sage: # optional - python_igraph + sage: g = igraph.Graph([(0,1),(0,2)], directed=True, vertex_attrs={'name':['a','b','c']}) + sage: DiGraph(g).vertices(sort=True) ['a', 'b', 'c'] - sage: g = igraph.Graph([(0,1),(0,2)], directed=True, vertex_attrs={'label':['a','b','c']}) # optional - python_igraph - sage: DiGraph(g).vertices(sort=True) # optional - python_igraph + sage: g = igraph.Graph([(0,1),(0,2)], directed=True, vertex_attrs={'label':['a','b','c']}) + sage: DiGraph(g).vertices(sort=True) [0, 1, 2] If the igraph Graph has edge attributes, they are used as edge labels:: @@ -479,18 +480,19 @@ class DiGraph(GenericGraph): Demonstrate that digraphs using the static backend are equal to mutable graphs but can be used as dictionary keys:: - sage: import networkx # optional - networkx - sage: g = networkx.DiGraph({0:[1,2,3], 2:[4]}) # optional - networkx - sage: G = DiGraph(g) # optional - networkx - sage: G_imm = DiGraph(G, data_structure="static_sparse") # optional - networkx - sage: H_imm = DiGraph(G, data_structure="static_sparse") # optional - networkx - sage: H_imm is G_imm # optional - networkx + sage: # needs networkx + sage: import networkx + sage: g = networkx.DiGraph({0:[1,2,3], 2:[4]}) + sage: G = DiGraph(g) + sage: G_imm = DiGraph(G, data_structure="static_sparse") + sage: H_imm = DiGraph(G, data_structure="static_sparse") + sage: H_imm is G_imm False - sage: H_imm == G_imm == G # optional - networkx + sage: H_imm == G_imm == G True - sage: {G_imm:1}[H_imm] # optional - networkx + sage: {G_imm:1}[H_imm] 1 - sage: {G_imm:1}[G] # optional - networkx + sage: {G_imm:1}[G] Traceback (most recent call last): ... TypeError: This graph is mutable, and thus not hashable. Create an @@ -500,10 +502,10 @@ class DiGraph(GenericGraph): specifying the ``immutable`` optional argument (not only by ``data_structure='static_sparse'`` as above):: - sage: J_imm = DiGraph(G, immutable=True) # optional - networkx - sage: J_imm == G_imm # optional - networkx + sage: J_imm = DiGraph(G, immutable=True) # needs networkx + sage: J_imm == G_imm # needs networkx True - sage: type(J_imm._backend) == type(G_imm._backend) # optional - networkx + sage: type(J_imm._backend) == type(G_imm._backend) # needs networkx True From a list of vertices and a list of edges:: @@ -515,7 +517,7 @@ class DiGraph(GenericGraph): Check that :trac:`27505` is fixed:: - sage: DiGraph(DiGraph().networkx_graph(), weighted=None, format='NX') # optional - networkx + sage: DiGraph(DiGraph().networkx_graph(), weighted=None, format='NX') # needs networkx Digraph on 0 vertices """ _directed = True @@ -532,12 +534,12 @@ def __init__(self, data=None, pos=None, loops=None, format=None, sage: loads(dumps(D)) == D True - sage: a = matrix(2,2,[1,2,0,1]) # optional - sage.modules - sage: DiGraph(a, sparse=True).adjacency_matrix() == a # optional - sage.modules + sage: a = matrix(2,2,[1,2,0,1]) # needs sage.modules + sage: DiGraph(a, sparse=True).adjacency_matrix() == a # needs sage.modules True - sage: a = matrix(2,2,[3,2,0,1]) # optional - sage.modules - sage: DiGraph(a, sparse=True).adjacency_matrix() == a # optional - sage.modules + sage: a = matrix(2,2,[3,2,0,1]) # needs sage.modules + sage: DiGraph(a, sparse=True).adjacency_matrix() == a # needs sage.modules True The positions are copied when the DiGraph is built from another DiGraph @@ -580,9 +582,9 @@ def __init__(self, data=None, pos=None, loops=None, format=None, sage: B = {0:{1:2,2:5,3:4},1:{2:2,4:7},2:{3:1,4:4,5:3}, ....: 3:{5:4},4:{5:1,6:5},5:{4:1,6:7,5:1}} sage: grafo3 = DiGraph(B, weighted=True) - sage: matad = grafo3.weighted_adjacency_matrix() # optional - sage.modules - sage: grafo4 = DiGraph(matad, format="adjacency_matrix", weighted=True) # optional - sage.modules - sage: grafo4.shortest_path(0, 6, by_weight=True) # optional - sage.modules + sage: matad = grafo3.weighted_adjacency_matrix() # needs sage.modules + sage: grafo4 = DiGraph(matad, format="adjacency_matrix", weighted=True) # needs sage.modules + sage: grafo4.shortest_path(0, 6, by_weight=True) # needs sage.modules [0, 1, 2, 5, 4, 6] Building a DiGraph with ``immutable=False`` returns a mutable graph:: @@ -954,7 +956,7 @@ def is_directed_acyclic(self, certificate=False): At first, the following graph is acyclic:: sage: D = DiGraph({0:[1, 2, 3], 4:[2, 5], 1:[8], 2:[7], 3:[7], 5:[6,7], 7:[8], 6:[9], 8:[10], 9:[10]}) - sage: D.plot(layout='circular').show() # optional - sage.plot + sage: D.plot(layout='circular').show() # needs sage.plot sage: D.is_directed_acyclic() True @@ -1457,12 +1459,12 @@ def degree_polynomial(self): EXAMPLES:: - sage: G = posets.PentagonPoset().hasse_diagram() # optional - sage.matrix - sage: G.degree_polynomial() # optional - sage.matrix + sage: G = posets.PentagonPoset().hasse_diagram() # needs sage.modules + sage: G.degree_polynomial() # needs sage.modules x^2 + 3*x*y + y^2 sage: G = posets.BooleanLattice(4).hasse_diagram() - sage: G.degree_polynomial().factor() + sage: G.degree_polynomial().factor() # needs sage.libs.pari (x + y)^4 """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -1563,7 +1565,7 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, sage: dcycle=DiGraph(cycle) sage: cycle.size() 5 - sage: dcycle.feedback_edge_set(value_only=True) + sage: dcycle.feedback_edge_set(value_only=True) # needs sage.numerical.mip 5 And in this situation, for any edge `uv` of the first graph, `uv` of @@ -1573,9 +1575,9 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, sage: while not g.num_edges(): ....: g = graphs.RandomGNP(5,.3) sage: dg = DiGraph(g) - sage: feedback = dg.feedback_edge_set() + sage: feedback = dg.feedback_edge_set() # needs sage.numerical.mip sage: u,v,l = next(g.edge_iterator()) - sage: (u,v) in feedback or (v,u) in feedback + sage: (u,v) in feedback or (v,u) in feedback # needs sage.numerical.mip True TESTS: @@ -1583,7 +1585,7 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, Comparing with/without constraint generation. Also double-checks issue :trac:`12833`:: - sage: for i in range(20): + sage: for i in range(20): # needs sage.numerical.mip ....: g = digraphs.RandomDirectedGNP(10, .3) ....: x = g.feedback_edge_set(value_only=True) ....: y = g.feedback_edge_set(value_only=True, @@ -1594,34 +1596,37 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, Loops are part of the feedback edge set (:trac:`23989`):: + sage: # needs sage.combinat sage: D = digraphs.DeBruijn(2, 2) sage: sorted(D.loops(labels=None)) [('00', '00'), ('11', '11')] - sage: FAS = D.feedback_edge_set(value_only=False) - sage: all(l in FAS for l in D.loops(labels=None)) + sage: FAS = D.feedback_edge_set(value_only=False) # needs sage.numerical.mip + sage: all(l in FAS for l in D.loops(labels=None)) # needs sage.numerical.mip True - sage: FAS2 = D.feedback_edge_set(value_only=False, constraint_generation=False) - sage: len(FAS) == len(FAS2) + sage: FAS2 = D.feedback_edge_set(value_only=False, # needs sage.numerical.mip + ....: constraint_generation=False) + sage: len(FAS) == len(FAS2) # needs sage.numerical.mip True Check that multi-edges are properly taken into account:: sage: cycle = graphs.CycleGraph(5) sage: dcycle = DiGraph(cycle) - sage: dcycle.feedback_edge_set(value_only=True) + sage: dcycle.feedback_edge_set(value_only=True) # needs sage.numerical.mip 5 sage: dcycle.allow_multiple_edges(True) sage: dcycle.add_edges(dcycle.edges(sort=True)) - sage: dcycle.feedback_edge_set(value_only=True) + sage: dcycle.feedback_edge_set(value_only=True) # needs sage.numerical.mip 10 - sage: dcycle.feedback_edge_set(value_only=True, constraint_generation=False) + sage: dcycle.feedback_edge_set(value_only=True, # needs sage.numerical.mip + ....: constraint_generation=False) 10 Strongly connected components are well handled (:trac:`23989`):: sage: g = digraphs.Circuit(3) * 2 sage: g.add_edge(0, 3) - sage: g.feedback_edge_set(value_only=True) + sage: g.feedback_edge_set(value_only=True) # needs sage.numerical.mip 2 """ # It would be a pity to start a LP if the digraph is already acyclic @@ -2071,10 +2076,10 @@ def reverse_edges(self, edges, inplace=True, multiedges=None): [(0, 5, None), (1, 0, None), (2, 1, None), (3, 2, None), (4, 3, None), (5, 4, None)] - sage: D = digraphs.Kautz(2, 3) # optional - sage.combinat - sage: Dr = D.reverse_edges(D.edges(sort=True), inplace=False, # optional - sage.combinat + sage: D = digraphs.Kautz(2, 3) # needs sage.combinat + sage: Dr = D.reverse_edges(D.edges(sort=True), inplace=False, # needs sage.combinat ....: multiedges=True) - sage: Dr.edges(sort=True) == D.reverse().edges(sort=True) # optional - sage.combinat + sage: Dr.edges(sort=True) == D.reverse().edges(sort=True) # needs sage.combinat True """ tempG = self if inplace else copy(self) @@ -2181,7 +2186,7 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None, [2, 2, 2] sage: G.eccentricity(algorithm='Floyd-Warshall-Cython') [2, 2, 2] - sage: G.eccentricity(by_weight=True, algorithm='Dijkstra_NetworkX') # optional - networkx + sage: G.eccentricity(by_weight=True, algorithm='Dijkstra_NetworkX') # needs networkx [5, 5, 4] sage: G.eccentricity(by_weight=True, algorithm='Dijkstra_Boost') [5, 5, 4] @@ -2446,11 +2451,12 @@ def diameter(self, by_weight=False, algorithm=None, weight_function=None, EXAMPLES:: - sage: G = digraphs.DeBruijn(5,4) # optional - sage.combinat - sage: G.diameter() # optional - sage.combinat + sage: # needs sage.combinat + sage: G = digraphs.DeBruijn(5,4) + sage: G.diameter() 4 - sage: G = digraphs.GeneralizedDeBruijn(9, 3) # optional - sage.combinat - sage: G.diameter() # optional - sage.combinat + sage: G = digraphs.GeneralizedDeBruijn(9, 3) + sage: G.diameter() 2 TESTS:: @@ -3144,7 +3150,7 @@ def topological_sort(self, implementation="default"): sage: D = DiGraph({0: [1, 2, 3], 4: [2, 5], 1: [8], 2: [7], 3: [7], ....: 5: [6, 7], 7: [8], 6: [9], 8: [10], 9: [10]}) - sage: D.plot(layout='circular').show() # optional - sage.plot + sage: D.plot(layout='circular').show() # needs sage.plot sage: D.topological_sort() [4, 5, 6, 9, 0, 1, 2, 3, 7, 8, 10] @@ -3156,9 +3162,9 @@ def topological_sort(self, implementation="default"): Using the NetworkX implementation :: - sage: s = list(D.topological_sort(implementation="NetworkX")); s # random # optional - networkx + sage: s = list(D.topological_sort(implementation="NetworkX")); s # random # needs networkx [0, 4, 1, 3, 2, 5, 6, 9, 7, 8, 10] - sage: all(s.index(u) < s.index(v) # optional - networkx + sage: all(s.index(u) < s.index(v) # needs networkx ....: for u, v in D.edges(sort=False, labels=False)) True @@ -3225,14 +3231,14 @@ def topological_sort_generator(self): EXAMPLES:: sage: D = DiGraph({0: [1, 2], 1: [3], 2: [3, 4]}) - sage: D.plot(layout='circular').show() # optional - sage.plot - sage: list(D.topological_sort_generator()) # optional - sage.modules sage.rings.finite_rings + sage: D.plot(layout='circular').show() # needs sage.plot + sage: list(D.topological_sort_generator()) # needs sage.modules sage.rings.finite_rings [[0, 1, 2, 3, 4], [0, 2, 1, 3, 4], [0, 2, 1, 4, 3], [0, 2, 4, 1, 3], [0, 1, 2, 4, 3]] :: - sage: for sort in D.topological_sort_generator(): + sage: for sort in D.topological_sort_generator(): # needs sage.modules sage.rings.finite_rings ....: for u, v in D.edge_iterator(labels=False): ....: if sort.index(u) > sort.index(v): ....: print("this should never happen") @@ -3592,7 +3598,7 @@ def flow_polytope(self, edges=None, ends=None, backend=None): Flow polytopes can also be built through the ``polytopes.`` object:: - sage: polytopes.flow_polytope(digraphs.Path(5)) # optional - sage.geometry.polyhedron + sage: polytopes.flow_polytope(digraphs.Path(5)) # needs sage.geometry.polyhedron A 0-dimensional polyhedron in QQ^4 defined as the convex hull of 1 vertex EXAMPLES: @@ -3600,26 +3606,26 @@ def flow_polytope(self, edges=None, ends=None, backend=None): A commutative square:: sage: G = DiGraph({1: [2, 3], 2: [4], 3: [4]}) - sage: fl = G.flow_polytope(); fl # optional - sage.geometry.polyhedron + sage: fl = G.flow_polytope(); fl # needs sage.geometry.polyhedron A 1-dimensional polyhedron in QQ^4 defined as the convex hull of 2 vertices - sage: fl.vertices() # optional - sage.geometry.polyhedron + sage: fl.vertices() # needs sage.geometry.polyhedron (A vertex at (0, 1, 0, 1), A vertex at (1, 0, 1, 0)) Using a different order for the edges of the graph:: - sage: fl = G.flow_polytope(edges=G.edges(key=lambda x: x[0] - x[1])); fl # optional - sage.geometry.polyhedron + sage: fl = G.flow_polytope(edges=G.edges(key=lambda x: x[0] - x[1])); fl # needs sage.geometry.polyhedron A 1-dimensional polyhedron in QQ^4 defined as the convex hull of 2 vertices - sage: fl.vertices() # optional - sage.geometry.polyhedron + sage: fl.vertices() # needs sage.geometry.polyhedron (A vertex at (0, 1, 1, 0), A vertex at (1, 0, 0, 1)) A tournament on 4 vertices:: sage: H = digraphs.TransitiveTournament(4) - sage: fl = H.flow_polytope(); fl # optional - sage.geometry.polyhedron + sage: fl = H.flow_polytope(); fl # needs sage.geometry.polyhedron A 3-dimensional polyhedron in QQ^6 defined as the convex hull of 4 vertices - sage: fl.vertices() # optional - sage.geometry.polyhedron + sage: fl.vertices() # needs sage.geometry.polyhedron (A vertex at (0, 0, 1, 0, 0, 0), A vertex at (0, 1, 0, 0, 0, 1), A vertex at (1, 0, 0, 0, 1, 0), @@ -3627,40 +3633,41 @@ def flow_polytope(self, edges=None, ends=None, backend=None): Restricting to a subset of the edges:: - sage: fl = H.flow_polytope(edges=[(0, 1, None), (1, 2, None), # optional - sage.geometry.polyhedron + sage: fl = H.flow_polytope(edges=[(0, 1, None), (1, 2, None), # needs sage.geometry.polyhedron ....: (2, 3, None), (0, 3, None)]); fl A 1-dimensional polyhedron in QQ^4 defined as the convex hull of 2 vertices - sage: fl.vertices() # optional - sage.geometry.polyhedron + sage: fl.vertices() # needs sage.geometry.polyhedron (A vertex at (0, 0, 0, 1), A vertex at (1, 1, 1, 0)) Using a different choice of sources and sinks:: - sage: fl = H.flow_polytope(ends=([1], [3])); fl # optional - sage.geometry.polyhedron + sage: # needs sage.geometry.polyhedron + sage: fl = H.flow_polytope(ends=([1], [3])); fl A 1-dimensional polyhedron in QQ^6 defined as the convex hull of 2 vertices - sage: fl.vertices() # optional - sage.geometry.polyhedron + sage: fl.vertices() (A vertex at (0, 0, 0, 1, 0, 1), A vertex at (0, 0, 0, 0, 1, 0)) - sage: fl = H.flow_polytope(ends=([0, 1], [3])); fl # optional - sage.geometry.polyhedron + sage: fl = H.flow_polytope(ends=([0, 1], [3])); fl The empty polyhedron in QQ^6 - sage: fl = H.flow_polytope(ends=([3], [0])); fl # optional - sage.geometry.polyhedron + sage: fl = H.flow_polytope(ends=([3], [0])); fl The empty polyhedron in QQ^6 - sage: fl = H.flow_polytope(ends=([0, 1], [2, 3])); fl # optional - sage.geometry.polyhedron + sage: fl = H.flow_polytope(ends=([0, 1], [2, 3])); fl A 3-dimensional polyhedron in QQ^6 defined as the convex hull of 5 vertices - sage: fl.vertices() # optional - sage.geometry.polyhedron + sage: fl.vertices() (A vertex at (0, 0, 1, 1, 0, 0), A vertex at (0, 1, 0, 0, 1, 0), A vertex at (1, 0, 0, 2, 0, 1), A vertex at (1, 0, 0, 1, 1, 0), A vertex at (0, 1, 0, 1, 0, 1)) - sage: fl = H.flow_polytope(edges=[(0, 1, None), (1, 2, None), # optional - sage.geometry.polyhedron + sage: fl = H.flow_polytope(edges=[(0, 1, None), (1, 2, None), ....: (2, 3, None), (0, 2, None), ....: (1, 3, None)], ....: ends=([0, 1], [2, 3])); fl A 2-dimensional polyhedron in QQ^5 defined as the convex hull of 4 vertices - sage: fl.vertices() # optional - sage.geometry.polyhedron + sage: fl.vertices() (A vertex at (0, 0, 0, 1, 1), A vertex at (1, 2, 1, 0, 0), A vertex at (1, 1, 0, 0, 1), @@ -3669,13 +3676,13 @@ def flow_polytope(self, edges=None, ends=None, backend=None): A digraph with one source and two sinks:: sage: Y = DiGraph({1: [2], 2: [3, 4]}) - sage: Y.flow_polytope() # optional - sage.geometry.polyhedron + sage: Y.flow_polytope() # needs sage.geometry.polyhedron The empty polyhedron in QQ^3 A digraph with one vertex and no edge:: sage: Z = DiGraph({1: []}) - sage: Z.flow_polytope() # optional - sage.geometry.polyhedron + sage: Z.flow_polytope() # needs sage.geometry.polyhedron A 0-dimensional polyhedron in QQ^0 defined as the convex hull of 1 vertex @@ -3683,11 +3690,11 @@ def flow_polytope(self, edges=None, ends=None, backend=None): sage: G = DiGraph([(0, 1), (0,1)], multiedges=True); G Multi-digraph on 2 vertices - sage: P = G.flow_polytope(); P # optional - sage.geometry.polyhedron + sage: P = G.flow_polytope(); P # needs sage.geometry.polyhedron A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices - sage: P.vertices() # optional - sage.geometry.polyhedron + sage: P.vertices() # needs sage.geometry.polyhedron (A vertex at (1, 0), A vertex at (0, 1)) - sage: P.lines() # optional - sage.geometry.polyhedron + sage: P.lines() # needs sage.geometry.polyhedron () """ from sage.geometry.polyhedron.constructor import Polyhedron diff --git a/src/sage/graphs/digraph_generators.py b/src/sage/graphs/digraph_generators.py index b9a87601a47..3070cb2f37f 100644 --- a/src/sage/graphs/digraph_generators.py +++ b/src/sage/graphs/digraph_generators.py @@ -226,22 +226,23 @@ def ButterflyGraph(self, n, vertices='strings'): sage: digraphs.ButterflyGraph(2).edges(sort=True, labels=False) [(('00', 0), ('00', 1)), - (('00', 0), ('10', 1)), - (('00', 1), ('00', 2)), - (('00', 1), ('01', 2)), - (('01', 0), ('01', 1)), - (('01', 0), ('11', 1)), - (('01', 1), ('00', 2)), - (('01', 1), ('01', 2)), - (('10', 0), ('00', 1)), - (('10', 0), ('10', 1)), - (('10', 1), ('10', 2)), - (('10', 1), ('11', 2)), - (('11', 0), ('01', 1)), - (('11', 0), ('11', 1)), - (('11', 1), ('10', 2)), - (('11', 1), ('11', 2))] - sage: digraphs.ButterflyGraph(2,vertices='vectors').edges(sort=True, labels=False) + (('00', 0), ('10', 1)), + (('00', 1), ('00', 2)), + (('00', 1), ('01', 2)), + (('01', 0), ('01', 1)), + (('01', 0), ('11', 1)), + (('01', 1), ('00', 2)), + (('01', 1), ('01', 2)), + (('10', 0), ('00', 1)), + (('10', 0), ('10', 1)), + (('10', 1), ('10', 2)), + (('10', 1), ('11', 2)), + (('11', 0), ('01', 1)), + (('11', 0), ('11', 1)), + (('11', 1), ('10', 2)), + (('11', 1), ('11', 2))] + sage: digraphs.ButterflyGraph(2, vertices='vectors').edges(sort=True, # needs sage.modules sage.rings.finite_rings + ....: labels=False) [(((0, 0), 0), ((0, 0), 1)), (((0, 0), 0), ((1, 0), 1)), (((0, 0), 1), ((0, 0), 2)), @@ -338,7 +339,7 @@ def Path(self, n): [0, 1, 2, 3, 4] sage: g.size() 4 - sage: g.automorphism_group().cardinality() + sage: g.automorphism_group().cardinality() # needs sage.groups 1 """ g = DiGraph(n, name="Path") @@ -370,9 +371,11 @@ def StronglyRegular(self, n): A Strongly Regular digraph satisfies the condition `AJ = JA = kJ` where `A` is the adjacency matrix:: + sage: # needs sage.modules sage: g = digraphs.StronglyRegular(7); g Strongly regular digraph: Digraph on 7 vertices - sage: A = g.adjacency_matrix()*ones_matrix(7); B = ones_matrix(7)*g.adjacency_matrix() + sage: A = g.adjacency_matrix()*ones_matrix(7) + sage: B = ones_matrix(7)*g.adjacency_matrix() sage: A == B == A[0, 0]*ones_matrix(7) True @@ -380,7 +383,7 @@ def StronglyRegular(self, n): Wrong parameter:: - sage: digraphs.StronglyRegular(73) + sage: digraphs.StronglyRegular(73) # needs sage.modules Traceback (most recent call last): ... ValueError: strongly regular digraph with 73 vertices not yet implemented @@ -413,16 +416,16 @@ def Paley(self, q): A Paley digraph has `n * (n-1) / 2` edges, its underlying graph is a clique, and so it is a tournament:: - sage: g = digraphs.Paley(7); g + sage: g = digraphs.Paley(7); g # needs sage.rings.finite_rings Paley digraph with parameter 7: Digraph on 7 vertices - sage: g.size() == g.order() * (g.order() - 1) / 2 + sage: g.size() == g.order() * (g.order() - 1) / 2 # needs sage.rings.finite_rings True - sage: g.to_undirected().is_clique() + sage: g.to_undirected().is_clique() # needs sage.rings.finite_rings True A Paley digraph is always self-complementary:: - sage: g.complement().is_isomorphic(g) + sage: g.complement().is_isomorphic(g) # needs sage.rings.finite_rings True TESTS: @@ -470,7 +473,7 @@ def TransitiveTournament(self, n): [0, 1, 2, 3, 4] sage: g.size() 10 - sage: g.automorphism_group().cardinality() + sage: g.automorphism_group().cardinality() # needs sage.groups 1 .. SEEALSO:: @@ -890,15 +893,16 @@ def DeBruijn(self, k, n, vertices='strings'): de Bruijn digraph of degree 2 and diameter 2:: - sage: db = digraphs.DeBruijn(2, 2); db + sage: db = digraphs.DeBruijn(2, 2); db # needs sage.combinat De Bruijn digraph (k=2, n=2): Looped digraph on 4 vertices - sage: db.order(), db.size() + sage: db.order(), db.size() # needs sage.combinat (4, 8) - sage: db.diameter() + sage: db.diameter() # needs sage.combinat 2 Building a de Bruijn digraph on a different alphabet:: + sage: # needs sage.combinat sage: g = digraphs.DeBruijn(['a', 'b'], 2) sage: g.vertices(sort=True) ['aa', 'ab', 'ba', 'bb'] @@ -914,20 +918,20 @@ def DeBruijn(self, k, n, vertices='strings'): Alphabet of null size or words of length zero:: - sage: digraphs.DeBruijn(5, 0) + sage: digraphs.DeBruijn(5, 0) # needs sage.combinat De Bruijn digraph (k=5, n=0): Looped multi-digraph on 1 vertex - sage: digraphs.DeBruijn(0, 0) + sage: digraphs.DeBruijn(0, 0) # needs sage.combinat De Bruijn digraph (k=0, n=0): Looped multi-digraph on 0 vertices :trac:`22355`:: - sage: db = digraphs.DeBruijn(2, 2, vertices='strings') - sage: db.vertices(sort=True) + sage: db = digraphs.DeBruijn(2, 2, vertices='strings') # needs sage.combinat + sage: db.vertices(sort=True) # needs sage.combinat ['00', '01', '10', '11'] sage: h = digraphs.DeBruijn(2, 2, vertices='integers') sage: h.vertices(sort=True) [0, 1, 2, 3] - sage: db.is_isomorphic(h) + sage: db.is_isomorphic(h) # needs sage.combinat True sage: digraphs.DeBruijn(0, 0, vertices='integers') De Bruijn digraph (k=0, n=0): Looped multi-digraph on 0 vertices @@ -998,8 +1002,9 @@ def GeneralizedDeBruijn(self, n, d): EXAMPLES:: sage: GB = digraphs.GeneralizedDeBruijn(8, 2) - sage: GB.is_isomorphic(digraphs.DeBruijn(2, 3), certificate = True) - (True, {0: '000', 1: '001', 2: '010', 3: '011', 4: '100', 5: '101', 6: '110', 7: '111'}) + sage: GB.is_isomorphic(digraphs.DeBruijn(2, 3), certificate=True) # needs sage.combinat + (True, {0: '000', 1: '001', 2: '010', 3: '011', + 4: '100', 5: '101', 6: '110', 7: '111'}) TESTS: @@ -1054,14 +1059,15 @@ def ImaseItoh(self, n, d): EXAMPLES:: sage: II = digraphs.ImaseItoh(8, 2) - sage: II.is_isomorphic(digraphs.DeBruijn(2, 3), certificate = True) - (True, {0: '010', 1: '011', 2: '000', 3: '001', 4: '110', 5: '111', 6: '100', 7: '101'}) + sage: II.is_isomorphic(digraphs.DeBruijn(2, 3), certificate=True) # needs sage.combinat + (True, {0: '010', 1: '011', 2: '000', 3: '001', + 4: '110', 5: '111', 6: '100', 7: '101'}) sage: II = digraphs.ImaseItoh(12, 2) - sage: b,D = II.is_isomorphic(digraphs.Kautz(2, 3), certificate=True) - sage: b + sage: b,D = II.is_isomorphic(digraphs.Kautz(2, 3), certificate=True) # needs sage.combinat + sage: b # needs sage.combinat True - sage: D # random isomorphism + sage: D # random isomorphism # needs sage.combinat {0: '202', 1: '201', 2: '210', 3: '212', 4: '121', 5: '120', 6: '102', 7: '101', 8: '010', 9: '012', 10: '021', 11: '020'} @@ -1132,23 +1138,24 @@ def Kautz(self, k, D, vertices='strings'): EXAMPLES:: + sage: # needs sage.combinat sage: K = digraphs.Kautz(2, 3) - sage: b,D = K.is_isomorphic(digraphs.ImaseItoh(12, 2), certificate=True) + sage: b, D = K.is_isomorphic(digraphs.ImaseItoh(12, 2), certificate=True) sage: b True sage: D # random isomorphism {'010': 8, '012': 9, '020': 11, '021': 10, '101': 7, '102': 6, '120': 5, '121': 4, '201': 1, '202': 0, '210': 2, '212': 3} - sage: K = digraphs.Kautz([1,'a','B'], 2) - sage: K.edges(sort=True) + sage: K = digraphs.Kautz([1,'a','B'], 2) # needs sage.combinat + sage: K.edges(sort=True) # needs sage.combinat [('1B', 'B1', '1'), ('1B', 'Ba', 'a'), ('1a', 'a1', '1'), ('1a', 'aB', 'B'), ('B1', '1B', 'B'), ('B1', '1a', 'a'), ('Ba', 'a1', '1'), ('Ba', 'aB', 'B'), ('a1', '1B', 'B'), ('a1', '1a', 'a'), ('aB', 'B1', '1'), ('aB', 'Ba', 'a')] - sage: K = digraphs.Kautz([1,'aA','BB'], 2) - sage: K.edges(sort=True) + sage: K = digraphs.Kautz([1,'aA','BB'], 2) # needs sage.combinat + sage: K.edges(sort=True) # needs sage.combinat [('1,BB', 'BB,1', '1'), ('1,BB', 'BB,aA', 'aA'), ('1,aA', 'aA,1', '1'), ('1,aA', 'aA,BB', 'BB'), ('BB,1', '1,BB', 'BB'), ('BB,1', '1,aA', 'aA'), @@ -1160,12 +1167,12 @@ def Kautz(self, k, D, vertices='strings'): An exception is raised when the degree is less than one:: - sage: G = digraphs.Kautz(0, 2) + sage: G = digraphs.Kautz(0, 2) # needs sage.combinat Traceback (most recent call last): ... ValueError: degree must be greater than or equal to one - sage: G = digraphs.Kautz(['a'], 2) + sage: G = digraphs.Kautz(['a'], 2) # needs sage.combinat Traceback (most recent call last): ... ValueError: degree must be greater than or equal to one @@ -1173,23 +1180,23 @@ def Kautz(self, k, D, vertices='strings'): An exception is raised when the diameter of the graph is less than one:: - sage: G = digraphs.Kautz(2, 0) + sage: G = digraphs.Kautz(2, 0) # needs sage.combinat Traceback (most recent call last): ... ValueError: diameter must be greater than or equal to one :trac:`22355`:: - sage: K = digraphs.Kautz(2, 2, vertices='strings') - sage: K.vertices(sort=True) + sage: K = digraphs.Kautz(2, 2, vertices='strings') # needs sage.combinat + sage: K.vertices(sort=True) # needs sage.combinat ['01', '02', '10', '12', '20', '21'] sage: h = digraphs.Kautz(2, 2, vertices='integers') sage: h.vertices(sort=True) [0, 1, 2, 3, 4, 5] - sage: h.is_isomorphic(K) + sage: h.is_isomorphic(K) # needs sage.combinat True sage: h = digraphs.Kautz([1,'aA','BB'], 2, vertices='integers') - sage: h.is_isomorphic(K) + sage: h.is_isomorphic(K) # needs sage.combinat True sage: h.vertices(sort=True) [0, 1, 2, 3, 4, 5] @@ -1346,6 +1353,7 @@ def RandomDirectedGN(self, n, kernel=lambda x: x, seed=None): EXAMPLES:: + sage: # needs networkx sage: D = digraphs.RandomDirectedGN(25) sage: D.num_verts() 25 @@ -1355,7 +1363,7 @@ def RandomDirectedGN(self, n, kernel=lambda x: x, seed=None): True sage: D.parent() is DiGraph True - sage: D.show() # long time + sage: D.show() # long time """ if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) @@ -1382,12 +1390,13 @@ def RandomDirectedGNC(self, n, seed=None): EXAMPLES:: + sage: # needs networkx sage: D = digraphs.RandomDirectedGNC(25) sage: D.is_directed_acyclic() True sage: D.topological_sort() [24, 23, ..., 1, 0] - sage: D.show() # long time + sage: D.show() # long time """ if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) @@ -1583,12 +1592,13 @@ def RandomDirectedGNR(self, n, p, seed=None): EXAMPLES:: + sage: # needs networkx sage: D = digraphs.RandomDirectedGNR(25, .2) sage: D.is_directed_acyclic() True sage: D.to_undirected().is_tree() True - sage: D.show() # long time + sage: D.show() # long time # needs sage.plot """ if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) diff --git a/src/sage/graphs/distances_all_pairs.pyx b/src/sage/graphs/distances_all_pairs.pyx index 46baaf8ca73..a5a90cc0c0c 100644 --- a/src/sage/graphs/distances_all_pairs.pyx +++ b/src/sage/graphs/distances_all_pairs.pyx @@ -545,7 +545,7 @@ def is_distance_regular(G, parameters=False): sage: graphs.PathGraph(2).is_distance_regular(parameters=True) ([1, None], [None, 1]) - sage: graphs.Tutte12Cage().is_distance_regular(parameters=True) # optional - networkx + sage: graphs.Tutte12Cage().is_distance_regular(parameters=True) # needs networkx ([3, 2, 2, 2, 2, 2, None], [None, 1, 1, 1, 1, 1, 3]) """ @@ -843,8 +843,8 @@ cdef uint32_t * c_eccentricity_DHV(short_digraph sd) except NULL: TESTS: - sage: G = graphs.RandomBarabasiAlbert(50, 2) # optional - networkx - sage: eccentricity(G, algorithm='bounds') == eccentricity(G, algorithm='DHV') # optional - networkx + sage: G = graphs.RandomBarabasiAlbert(50, 2) # needs networkx + sage: eccentricity(G, algorithm='bounds') == eccentricity(G, algorithm='DHV') # needs networkx True """ cdef uint32_t n = sd.n @@ -1777,26 +1777,28 @@ def diameter(G, algorithm=None, source=None): Comparison of exact algorithms for graphs:: - sage: G = graphs.RandomBarabasiAlbert(100, 2) # optional - networkx - sage: d1 = diameter(G, algorithm='standard') # optional - networkx - sage: d2 = diameter(G, algorithm='iFUB') # optional - networkx - sage: d3 = diameter(G, algorithm='iFUB', source=G.random_vertex()) # optional - networkx - sage: d4 = diameter(G, algorithm='DHV') # optional - networkx - sage: if d1 != d2 or d1 != d3 or d1 != d4: print("Something goes wrong!") # optional - networkx + sage: # needs networkx + sage: G = graphs.RandomBarabasiAlbert(100, 2) + sage: d1 = diameter(G, algorithm='standard') + sage: d2 = diameter(G, algorithm='iFUB') + sage: d3 = diameter(G, algorithm='iFUB', source=G.random_vertex()) + sage: d4 = diameter(G, algorithm='DHV') + sage: if d1 != d2 or d1 != d3 or d1 != d4: print("Something goes wrong!") Comparison of lower bound algorithms:: - sage: lb2 = diameter(G, algorithm='2sweep') # optional - networkx - sage: lbm = diameter(G, algorithm='multi-sweep') # optional - networkx - sage: if not (lb2 <= lbm and lbm <= d3): print("Something goes wrong!") # optional - networkx + sage: lb2 = diameter(G, algorithm='2sweep') # needs networkx + sage: lbm = diameter(G, algorithm='multi-sweep') # needs networkx + sage: if not (lb2 <= lbm and lbm <= d3): print("Something goes wrong!") # needs networkx Comparison of exact algorithms for digraphs:: - sage: D = DiGraph(graphs.RandomBarabasiAlbert(50, 2)) # optional - networkx - sage: d1 = diameter(D, algorithm='standard') # optional - networkx - sage: d2 = diameter(D, algorithm='DiFUB') # optional - networkx - sage: d3 = diameter(D, algorithm='DiFUB', source=D.random_vertex()) # optional - networkx - sage: d1 == d2 and d1 == d3 # optional - networkx + sage: # needs networkx + sage: D = DiGraph(graphs.RandomBarabasiAlbert(50, 2)) + sage: d1 = diameter(D, algorithm='standard') + sage: d2 = diameter(D, algorithm='DiFUB') + sage: d3 = diameter(D, algorithm='DiFUB', source=D.random_vertex()) + sage: d1 == d2 and d1 == d3 True TESTS: @@ -2294,10 +2296,11 @@ def szeged_index(G, algorithm=None): Check that both algorithms return same value:: - sage: G = graphs.RandomBarabasiAlbert(100, 2) # long time - sage: a = szeged_index(G, algorithm='low') # long time - sage: b = szeged_index(G, algorithm='high') # long time - sage: a == b # long time + sage: # long time + sage: G = graphs.RandomBarabasiAlbert(100, 2) + sage: a = szeged_index(G, algorithm='low') + sage: b = szeged_index(G, algorithm='high') + sage: a == b True The Szeged index of a directed circuit of order `n` is `(n-1)^2`:: @@ -2438,8 +2441,8 @@ def distances_distribution(G): The de Bruijn digraph dB(2,3):: - sage: D = digraphs.DeBruijn(2,3) # optional - sage.combinat - sage: D.distances_distribution() # optional - sage.combinat + sage: D = digraphs.DeBruijn(2,3) # needs sage.combinat + sage: D.distances_distribution() # needs sage.combinat {1: 1/4, 2: 11/28, 3: 5/14} """ cdef size_t n = G.order() diff --git a/src/sage/graphs/domination.py b/src/sage/graphs/domination.py index ed2fdd17183..a92c814c7fa 100644 --- a/src/sage/graphs/domination.py +++ b/src/sage/graphs/domination.py @@ -24,7 +24,7 @@ We compute the size of a minimum dominating set of the Petersen graph:: sage: g = graphs.PetersenGraph() - sage: g.dominating_set(value_only=True) + sage: g.dominating_set(value_only=True) # needs sage.numerical.mip 3 We enumerate the minimal dominating sets of the 5-star graph:: @@ -281,7 +281,7 @@ def dominating_sets(g, k=1, independent=False, total=False, Number of distance-`k` dominating sets of a Path graph of order 10:: sage: g = graphs.PathGraph(10) - sage: [sum(1 for _ in g.dominating_sets(k=k)) for k in range(11)] + sage: [sum(1 for _ in g.dominating_sets(k=k)) for k in range(11)] # needs sage.numerical.mip [1, 13, 1, 13, 25, 2, 4, 6, 8, 10, 10] If we build a graph from two disjoint stars, then link their centers we will @@ -290,15 +290,15 @@ def dominating_sets(g, k=1, independent=False, total=False, sage: g = 2 * graphs.StarGraph(5) sage: g.add_edge(0, 6) - sage: [sum(1 for _ in g.dominating_sets(k=k)) for k in range(11)] + sage: [sum(1 for _ in g.dominating_sets(k=k)) for k in range(11)] # needs sage.numerical.mip [1, 1, 2, 12, 12, 12, 12, 12, 12, 12, 12] The total dominating set of the Petersen graph has cardinality 4:: sage: G = graphs.PetersenGraph() - sage: G.dominating_set(total=True, value_only=True) + sage: G.dominating_set(total=True, value_only=True) # needs sage.numerical.mip 4 - sage: sorted(G.dominating_sets(k=1)) + sage: sorted(G.dominating_sets(k=1)) # needs sage.numerical.mip [[0, 2, 6], [0, 3, 9], [0, 7, 8], @@ -313,33 +313,33 @@ def dominating_sets(g, k=1, independent=False, total=False, Independent distance-`k` dominating sets of a Path graph:: sage: G = graphs.PathGraph(6) - sage: sorted(G.dominating_sets(k=1, independent=True)) + sage: sorted(G.dominating_sets(k=1, independent=True)) # needs sage.numerical.mip [[1, 4]] - sage: sorted(G.dominating_sets(k=2, independent=True)) + sage: sorted(G.dominating_sets(k=2, independent=True)) # needs sage.numerical.mip [[0, 3], [0, 4], [0, 5], [1, 3], [1, 4], [1, 5], [2, 4], [2, 5]] - sage: sorted(G.dominating_sets(k=3, independent=True)) + sage: sorted(G.dominating_sets(k=3, independent=True)) # needs sage.numerical.mip [[2], [3]] The dominating set is calculated for both the directed and undirected graphs (modification introduced in :trac:`17905`):: sage: g = digraphs.Path(3) - sage: g.dominating_set(value_only=True) + sage: g.dominating_set(value_only=True) # needs sage.numerical.mip 2 - sage: list(g.dominating_sets()) + sage: list(g.dominating_sets()) # needs sage.numerical.mip [[0, 1], [0, 2]] - sage: list(g.dominating_sets(k=2)) + sage: list(g.dominating_sets(k=2)) # needs sage.numerical.mip [[0]] sage: g = graphs.PathGraph(3) - sage: g.dominating_set(value_only=True) + sage: g.dominating_set(value_only=True) # needs sage.numerical.mip 1 - sage: next(g.dominating_sets()) + sage: next(g.dominating_sets()) # needs sage.numerical.mip [1] TESTS:: sage: g = Graph([(0, 1)]) - sage: next(g.dominating_sets(k=-1)) + sage: next(g.dominating_sets(k=-1)) # needs sage.numerical.mip Traceback (most recent call last): ... ValueError: the domination distance must be a non-negative integer @@ -468,7 +468,7 @@ def dominating_set(g, k=1, independent=False, total=False, value_only=False, A basic illustration on a ``PappusGraph``:: sage: g = graphs.PappusGraph() - sage: g.dominating_set(value_only=True) + sage: g.dominating_set(value_only=True) # needs sage.numerical.mip 5 If we build a graph from two disjoint stars, then link their centers we will @@ -477,34 +477,34 @@ def dominating_set(g, k=1, independent=False, total=False, value_only=False, sage: g = 2 * graphs.StarGraph(5) sage: g.add_edge(0, 6) - sage: len(g.dominating_set()) + sage: len(g.dominating_set()) # needs sage.numerical.mip 2 - sage: len(g.dominating_set(independent=True)) + sage: len(g.dominating_set(independent=True)) # needs sage.numerical.mip 6 The total dominating set of the Petersen graph has cardinality 4:: sage: G = graphs.PetersenGraph() - sage: G.dominating_set(total=True, value_only=True) + sage: G.dominating_set(total=True, value_only=True) # needs sage.numerical.mip 4 The dominating set is calculated for both the directed and undirected graphs (modification introduced in :trac:`17905`):: sage: g = digraphs.Path(3) - sage: g.dominating_set(value_only=True) + sage: g.dominating_set(value_only=True) # needs sage.numerical.mip 2 sage: g = graphs.PathGraph(3) - sage: g.dominating_set(value_only=True) + sage: g.dominating_set(value_only=True) # needs sage.numerical.mip 1 Cardinality of distance-`k` dominating sets:: sage: G = graphs.PetersenGraph() - sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)] + sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)] # needs sage.numerical.mip [10, 3, 1] sage: G = graphs.PathGraph(5) - sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)] + sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)] # needs sage.numerical.mip [5, 2, 1] """ dom = next(dominating_sets(g, k=k, independent=independent, total=total, diff --git a/src/sage/graphs/dot2tex_utils.py b/src/sage/graphs/dot2tex_utils.py index 95850012885..ce2cd873c8b 100644 --- a/src/sage/graphs/dot2tex_utils.py +++ b/src/sage/graphs/dot2tex_utils.py @@ -74,7 +74,7 @@ def quoted_latex(x): EXAMPLES:: - sage: sage.graphs.dot2tex_utils.quoted_latex(matrix([[1,1],[0,1],[0,0]])) # optional - sage.modules + sage: sage.graphs.dot2tex_utils.quoted_latex(matrix([[1,1],[0,1],[0,0]])) # needs sage.modules '\\left(\\begin{array}{rr}1 & 1 \\\\0 & 1 \\\\0 & 0\\end{array}\\right)' """ return re.sub("\"|\r|(%[^\n]*)?\n", "", latex(x)) @@ -89,9 +89,9 @@ def quoted_str(x): EXAMPLES:: - sage: sage.graphs.dot2tex_utils.quoted_str(matrix([[1,1],[0,1],[0,0]])) # optional - sage.modules + sage: sage.graphs.dot2tex_utils.quoted_str(matrix([[1,1],[0,1],[0,0]])) # needs sage.modules '[1 1]\\n\\\n[0 1]\\n\\\n[0 0]' - sage: print(sage.graphs.dot2tex_utils.quoted_str(matrix([[1,1],[0,1],[0,0]]))) # optional - sage.modules + sage: print(sage.graphs.dot2tex_utils.quoted_str(matrix([[1,1],[0,1],[0,0]]))) # needs sage.modules [1 1]\n\ [0 1]\n\ [0 0] diff --git a/src/sage/graphs/edge_connectivity.pyx b/src/sage/graphs/edge_connectivity.pyx index c4cf6a4f81b..02326437a54 100644 --- a/src/sage/graphs/edge_connectivity.pyx +++ b/src/sage/graphs/edge_connectivity.pyx @@ -56,10 +56,10 @@ cdef class GabowEdgeConnectivity: A random `d`-regular digraph is `d`-edge-connected:: sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity - sage: D = DiGraph(graphs.RandomRegular(6, 50)) # optional - networkx - sage: while not D.is_strongly_connected(): # optional - networkx + sage: D = DiGraph(graphs.RandomRegular(6, 50)) # needs networkx + sage: while not D.is_strongly_connected(): # needs networkx ....: D = DiGraph(graphs.RandomRegular(6, 50)) - sage: GabowEdgeConnectivity(D).edge_connectivity() # optional - networkx + sage: GabowEdgeConnectivity(D).edge_connectivity() # needs networkx 6 A complete digraph with `n` vertices is `n-1`-edge-connected:: @@ -72,15 +72,16 @@ cdef class GabowEdgeConnectivity: Check that we get the same result when with and without the DFS-based speed-up initialization proposed in [GKLP2021]_:: - sage: G = graphs.RandomBarabasiAlbert(100, 2) # optional - networkx - sage: D = DiGraph(G) # optional - networkx - sage: ec1 = GabowEdgeConnectivity(D, # optional - networkx + sage: # needs networkx + sage: G = graphs.RandomBarabasiAlbert(100, 2) + sage: D = DiGraph(G) + sage: ec1 = GabowEdgeConnectivity(D, ....: dfs_preprocessing=False).edge_connectivity() - sage: ec2 = GabowEdgeConnectivity(D, # optional - networkx + sage: ec2 = GabowEdgeConnectivity(D, ....: dfs_preprocessing=True).edge_connectivity() - sage: ec3 = GabowEdgeConnectivity(D, dfs_preprocessing=True, # optional - networkx + sage: ec3 = GabowEdgeConnectivity(D, dfs_preprocessing=True, ....: use_rec=True).edge_connectivity() - sage: ec1 == ec2 and ec2 == ec3 # optional - networkx + sage: ec1 == ec2 and ec2 == ec3 True TESTS: diff --git a/src/sage/graphs/generators/basic.py b/src/sage/graphs/generators/basic.py index 43e0b683703..89555fec008 100644 --- a/src/sage/graphs/generators/basic.py +++ b/src/sage/graphs/generators/basic.py @@ -179,13 +179,13 @@ def CircularLadderGraph(n): sage: for i in range(9): ....: k = graphs.CircularLadderGraph(i+3) ....: g.append(k) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): # needs sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) # needs sage.plot + sage: G.show() # long time # needs sage.plot """ G = Graph(2 * n, name="Circular Ladder graph") G._circle_embedding(list(range(n)), radius=1, angle=pi/2) @@ -248,12 +248,13 @@ def CycleGraph(n): Compare plotting using the predefined layout and networkx:: - sage: import networkx # optional - networkx - sage: n = networkx.cycle_graph(23) # optional - networkx - sage: spring23 = Graph(n) # optional - networkx - sage: posdict23 = graphs.CycleGraph(23) # optional - networkx - sage: spring23.show() # long time # optional - networkx - sage: posdict23.show() # long time # optional - networkx + sage: # needs networkx + sage: import networkx + sage: n = networkx.cycle_graph(23) + sage: spring23 = Graph(n) + sage: posdict23 = graphs.CycleGraph(23) + sage: spring23.show() # long time + sage: posdict23.show() # long time We next view many cycle graphs as a Sage graphics array. First we use the ``CycleGraph`` constructor, which fills in the position dictionary:: @@ -263,29 +264,29 @@ def CycleGraph(n): sage: for i in range(9): ....: k = graphs.CycleGraph(i+3) ....: g.append(k) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): # needs sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) # needs sage.plot + sage: G.show() # long time # needs sage.plot Compare to plotting with the spring-layout algorithm:: sage: g = [] sage: j = [] - sage: for i in range(9): # optional - networkx + sage: for i in range(9): # needs networkx ....: spr = networkx.cycle_graph(i+3) ....: k = Graph(spr) ....: g.append(k) - sage: for i in range(3): # optional - networkx sage.plot + sage: for i in range(3): # needs networkx sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - networkx sage.plot - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphics_array(j) # needs networkx sage.plot + sage: G.show() # long time # needs networkx sage.plot TESTS: @@ -339,37 +340,37 @@ def CompleteGraph(n): sage: for i in range(9): ....: k = graphs.CompleteGraph(i+3) ....: g.append(k) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): # needs sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) # needs sage.plot + sage: G.show() # long time # needs sage.plot We compare to plotting with the spring-layout algorithm:: - sage: import networkx # optional - networkx + sage: import networkx # needs networkx sage: g = [] sage: j = [] - sage: for i in range(9): # optional - networkx + sage: for i in range(9): # needs networkx ....: spr = networkx.complete_graph(i+3) ....: k = Graph(spr) ....: g.append(k) - sage: for i in range(3): # optional - networkx sage.plot + sage: for i in range(3): # needs networkx sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - networkx sage.plot - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphics_array(j) # needs networkx sage.plot + sage: G.show() # long time # needs networkx sage.plot Compare the constructors (results will vary):: - sage: import networkx # optional - networkx - sage: t = cputime() # optional - networkx - sage: n = networkx.complete_graph(389); spring389 = Graph(n) # optional - networkx - sage: cputime(t) # random # optional - networkx + sage: import networkx # needs networkx + sage: t = cputime() # needs networkx + sage: n = networkx.complete_graph(389); spring389 = Graph(n) # needs networkx + sage: cputime(t) # random # needs networkx 0.59203700000000126 sage: t = cputime() sage: posdict389 = graphs.CompleteGraph(389) @@ -378,12 +379,12 @@ def CompleteGraph(n): We compare plotting:: - sage: import networkx # optional - networkx - sage: n = networkx.complete_graph(23) # optional - networkx - sage: spring23 = Graph(n) # optional - networkx + sage: import networkx # needs networkx + sage: n = networkx.complete_graph(23) # needs networkx + sage: spring23 = Graph(n) # needs networkx sage: posdict23 = graphs.CompleteGraph(23) - sage: spring23.show() # long time # optional - networkx sage.plot - sage: posdict23.show() # long time # optional - sage.plot + sage: spring23.show() # long time # needs networkx sage.plot + sage: posdict23.show() # long time # needs sage.plot """ G = Graph(n, name="Complete graph") if n == 1: @@ -405,14 +406,14 @@ def CorrelationGraph(seqs, alpha, include_anticorrelation): sage: from sage.graphs.generators.basic import CorrelationGraph sage: data = [[1,2,3], [4,5,6], [7,8,9999]] - sage: CG1 = CorrelationGraph(data, 0.9, False) # optional - numpy - sage: CG2 = CorrelationGraph(data, 0.9, True) # optional - numpy - sage: CG3 = CorrelationGraph(data, 0.1, True) # optional - numpy - sage: CG1.edges(sort=False) # optional - numpy + sage: CG1 = CorrelationGraph(data, 0.9, False) # needs numpy + sage: CG2 = CorrelationGraph(data, 0.9, True) # needs numpy + sage: CG3 = CorrelationGraph(data, 0.1, True) # needs numpy + sage: CG1.edges(sort=False) # needs numpy [(0, 0, None), (0, 1, None), (1, 1, None), (2, 2, None)] - sage: CG2.edges(sort=False) # optional - numpy + sage: CG2.edges(sort=False) # needs numpy [(0, 0, None), (0, 1, None), (1, 1, None), (2, 2, None)] - sage: CG3.edges(sort=False) # optional - numpy + sage: CG3.edges(sort=False) # needs numpy [(0, 0, None), (0, 1, None), (0, 2, None), (1, 1, None), (1, 2, None), (2, 2, None)] """ @@ -477,20 +478,20 @@ def CompleteBipartiteGraph(p, q, set_position=True): Two ways of constructing the complete bipartite graph, using different layout algorithms:: - sage: import networkx # optional - networkx - sage: n = networkx.complete_bipartite_graph(389, 157) # long time # optional - networkx - sage: spring_big = Graph(n) # long time # optional - networkx + sage: import networkx # needs networkx + sage: n = networkx.complete_bipartite_graph(389, 157) # long time # needs networkx + sage: spring_big = Graph(n) # long time # needs networkx sage: posdict_big = graphs.CompleteBipartiteGraph(389, 157) # long time Compare the plotting:: - sage: n = networkx.complete_bipartite_graph(11, 17) # optional - networkx - sage: spring_med = Graph(n) # optional - networkx + sage: n = networkx.complete_bipartite_graph(11, 17) # needs networkx + sage: spring_med = Graph(n) # needs networkx sage: posdict_med = graphs.CompleteBipartiteGraph(11, 17) Notice here how the spring-layout tends to center the nodes of `n1`:: - sage: spring_med.show() # long time # optional - networkx + sage: spring_med.show() # long time # needs networkx sage: posdict_med.show() # long time View many complete bipartite graphs with a Sage Graphics Array, with this @@ -501,29 +502,29 @@ def CompleteBipartiteGraph(p, q, set_position=True): sage: for i in range(9): ....: k = graphs.CompleteBipartiteGraph(i+1,4) ....: g.append(k) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): # needs sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) # needs sage.plot + sage: G.show() # long time # needs sage.plot We compare to plotting with the spring-layout algorithm:: sage: g = [] sage: j = [] - sage: for i in range(9): # optional - networkx + sage: for i in range(9): # needs networkx ....: spr = networkx.complete_bipartite_graph(i+1,4) ....: k = Graph(spr) ....: g.append(k) - sage: for i in range(3): # optional - networkx sage.plot + sage: for i in range(3): # needs networkx sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - networkx sage.plot - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphics_array(j) # needs networkx sage.plot + sage: G.show() # long time # needs networkx sage.plot :trac:`12155`:: @@ -825,13 +826,13 @@ def Toroidal6RegularGrid2dGraph(p, q): sage: g = graphs.Toroidal6RegularGrid2dGraph(5,5) sage: g.is_regular(k=6) True - sage: g.is_vertex_transitive() # optional - sage.groups + sage: g.is_vertex_transitive() # needs sage.groups True - sage: g.line_graph().is_vertex_transitive() # optional - sage.groups + sage: g.line_graph().is_vertex_transitive() # needs sage.groups True - sage: g.automorphism_group().cardinality() # optional - sage.groups + sage: g.automorphism_group().cardinality() # needs sage.groups 300 - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True TESTS: @@ -973,9 +974,9 @@ def GridGraph(dim_list): sage: dim = [randint(1,4) for i in range(4)] sage: g = graphs.GridGraph(dim) - sage: import networkx # optional - networkx - sage: h = Graph(networkx.grid_graph(list(dim))) # optional - networkx - sage: g.is_isomorphic(h) # optional - networkx + sage: import networkx # needs networkx + sage: h = Graph(networkx.grid_graph(list(dim))) # needs networkx + sage: g.is_isomorphic(h) # needs networkx True Trivial cases:: @@ -1115,13 +1116,13 @@ def LadderGraph(n): sage: for i in range(9): ....: k = graphs.LadderGraph(i+2) ....: g.append(k) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): # needs sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) # needs sage.plot + sage: G.show() # long time # needs sage.plot """ pos_dict = {} for i in range(n): @@ -1263,14 +1264,14 @@ def StarGraph(n): EXAMPLES:: - sage: import networkx # optional - networkx + sage: import networkx # needs networkx Compare the plots:: - sage: n = networkx.star_graph(23) # optional - networkx - sage: spring23 = Graph(n) # optional - networkx + sage: n = networkx.star_graph(23) # needs networkx + sage: spring23 = Graph(n) # needs networkx sage: posdict23 = graphs.StarGraph(23) - sage: spring23.show() # long time # optional - networkx + sage: spring23.show() # long time # needs networkx sage: posdict23.show() # long time View many star graphs as a Sage Graphics Array @@ -1284,13 +1285,13 @@ def StarGraph(n): sage: for i in range(9): ....: k = graphs.StarGraph(i+3) ....: g.append(k) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): # needs sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) # needs sage.plot + sage: G.show() # long time # needs sage.plot Compared to plotting with the spring-layout algorithm @@ -1298,17 +1299,17 @@ def StarGraph(n): sage: g = [] sage: j = [] - sage: for i in range(9): # optional - networkx + sage: for i in range(9): # needs networkx ....: spr = networkx.star_graph(i+3) ....: k = Graph(spr) ....: g.append(k) - sage: for i in range(3): # optional - networkx sage.plot + sage: for i in range(3): # needs networkx sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - networkx sage.plot - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphics_array(j) # needs networkx sage.plot + sage: G.show() # long time # needs networkx sage.plot """ G = Graph({0: list(range(1, n + 1))}, name="Star graph", format="dict_of_lists") G.set_pos({0: (0, 0)}) diff --git a/src/sage/graphs/generators/chessboard.py b/src/sage/graphs/generators/chessboard.py index 2835fbe987f..59517d128bb 100644 --- a/src/sage/graphs/generators/chessboard.py +++ b/src/sage/graphs/generators/chessboard.py @@ -414,7 +414,7 @@ def KnightGraph(dim_list, one=1, two=2, relabel=False): The `(6,6)`-Knight Graph is Hamiltonian:: sage: G = graphs.KnightGraph( [6, 6] ) - sage: G.is_hamiltonian() + sage: G.is_hamiltonian() # needs sage.numerical.mip True """ G, dimstr = ChessboardGraphGenerator(dim_list, diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index 7ef70020a14..48481b3b240 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -67,8 +67,14 @@ def SymplecticPolarGraph(d, q, algorithm=None): (40, 12, 2, 4) sage: O.is_isomorphic(G) False - sage: S = graphs.SymplecticPolarGraph(6, 4, algorithm="gap") # not tested (long time) - sage: S.is_strongly_regular(parameters=True) # not tested (long time) + sage: O.is_isomorphic(G) # optional - GOT (with --distribution 'sagemath-graphs[modules]') + Traceback (most recent call last): + ... + File "", line 1, in + O.is_isomorphic(G) + AttributeError: 'function' object has no attribute 'is_isomorphic' + sage: S = graphs.SymplecticPolarGraph(6,4,algorithm="gap") # not tested (long time), needs sage.libs.gap + sage: S.is_strongly_regular(parameters=True) # not tested (long time) # needs sage.libs.gap (1365, 340, 83, 85) TESTS:: @@ -481,18 +487,18 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): NO^-,perp(3, 5): Graph on 10 vertices sage: g.is_strongly_regular(parameters=True) (10, 3, 0, 1) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'+') # long time - sage: g.is_strongly_regular(parameters=True) # long time + sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'+') # long time, needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # long time # needs sage.libs.gap (117, 36, 15, 9) sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'-'); g # long time NO^-(6, 3): Graph on 126 vertices - sage: g.is_strongly_regular(parameters=True) # long time + sage: g.is_strongly_regular(parameters=True) # long time # needs sage.libs.gap (126, 45, 12, 18) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'-') # long time - sage: g.is_strongly_regular(parameters=True) # long time + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'-') # long time, needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # long time # needs sage.libs.gap (300, 104, 28, 40) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'+') # long time - sage: g.is_strongly_regular(parameters=True) # long time + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'+') # long time, needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # long time # needs sage.libs.gap (325, 144, 68, 60) sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,4,'+') Traceback (most recent call last): @@ -865,8 +871,8 @@ def TaylorTwographDescendantSRG(q, clique_partition=False): sage: g.is_strongly_regular(parameters=True) (27, 10, 1, 5) sage: from sage.combinat.designs.twographs import taylor_twograph - sage: T = taylor_twograph(3) # long time - sage: g.is_isomorphic(T.descendant(T.ground_set()[1])) # long time + sage: T = taylor_twograph(3) # long time # needs sage.rings.finite_rings + sage: g.is_isomorphic(T.descendant(T.ground_set()[1])) # long time # needs sage.rings.finite_rings True sage: g = graphs.TaylorTwographDescendantSRG(5) # not tested (long time) sage: g.is_strongly_regular(parameters=True) # not tested (long time) @@ -1192,7 +1198,7 @@ def HaemersGraph(q, hyperoval=None, hyperoval_matching=None, field=None, check_h ... RuntimeError: incorrect hyperoval - sage: g = graphs.HaemersGraph(8); g # not tested (long time) # needs sage.rings.finite_rings + sage: g = graphs.HaemersGraph(8); g # not tested (long time) # needs sage.rings.finite_rings Haemers(8): Graph on 640 vertices sage: g.is_strongly_regular(parameters=True) # not tested (long time) # needs sage.rings.finite_rings (640, 71, 6, 8) diff --git a/src/sage/graphs/generators/degree_sequence.py b/src/sage/graphs/generators/degree_sequence.py index 071878d124e..ed89ce43abc 100644 --- a/src/sage/graphs/generators/degree_sequence.py +++ b/src/sage/graphs/generators/degree_sequence.py @@ -41,25 +41,25 @@ def DegreeSequence(deg_sequence): EXAMPLES:: - sage: G = graphs.DegreeSequence([3,3,3,3]) # optional - networkx - sage: G.edges(sort=True, labels=False) # optional - networkx + sage: G = graphs.DegreeSequence([3,3,3,3]) # needs networkx + sage: G.edges(sort=True, labels=False) # needs networkx [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] - sage: G.show() # long time # optional - networkx sage.plot + sage: G.show() # long time # needs networkx sage.plot :: - sage: G = graphs.DegreeSequence([3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]) # optional - networkx - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphs.DegreeSequence([3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]) # needs networkx + sage: G.show() # long time # needs networkx sage.plot :: - sage: G = graphs.DegreeSequence([4,4,4,4,4,4,4,4]) # optional - networkx - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphs.DegreeSequence([4,4,4,4,4,4,4,4]) # needs networkx + sage: G.show() # long time # needs networkx sage.plot :: - sage: G = graphs.DegreeSequence([1,2,3,4,3,4,3,2,3,2,1]) # optional - networkx - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphs.DegreeSequence([1,2,3,4,3,4,3,2,3,2,1]) # needs networkx + sage: G.show() # long time # needs networkx sage.plot """ import networkx return Graph(networkx.havel_hakimi_graph([int(i) for i in deg_sequence])) @@ -93,15 +93,15 @@ def DegreeSequenceBipartite(s1, s2): If we are given as sequences ``[2,2,2,2,2]`` and ``[5,5]`` we are given as expected the complete bipartite graph `K_{2,5}`:: - sage: g = graphs.DegreeSequenceBipartite([2,2,2,2,2],[5,5]) # optional - sage.modules - sage: g.is_isomorphic(graphs.CompleteBipartiteGraph(5,2)) # optional - sage.modules + sage: g = graphs.DegreeSequenceBipartite([2,2,2,2,2],[5,5]) # needs sage.modules + sage: g.is_isomorphic(graphs.CompleteBipartiteGraph(5,2)) # needs sage.modules True Some sequences being incompatible if, for example, their sums are different, the functions raises a ``ValueError`` when no graph corresponding to the degree sequences exists:: - sage: g = graphs.DegreeSequenceBipartite([2,2,2,2,1],[5,5]) # optional - sage.modules + sage: g = graphs.DegreeSequenceBipartite([2,2,2,2,1],[5,5]) # needs sage.modules Traceback (most recent call last): ... ValueError: there exists no bipartite graph corresponding to the given degree sequences @@ -110,7 +110,7 @@ def DegreeSequenceBipartite(s1, s2): :trac:`12155`:: - sage: graphs.DegreeSequenceBipartite([2,2,2,2,2],[5,5]).complement() # optional - sage.modules + sage: graphs.DegreeSequenceBipartite([2,2,2,2,2],[5,5]).complement() # needs sage.modules Graph on 7 vertices """ from sage.combinat.integer_vector import gale_ryser_theorem @@ -147,20 +147,21 @@ def DegreeSequenceConfigurationModel(deg_sequence, seed=None): EXAMPLES:: - sage: G = graphs.DegreeSequenceConfigurationModel([1,1]) # optional - networkx - sage: G.adjacency_matrix() # optional - networkx sage.modules + sage: G = graphs.DegreeSequenceConfigurationModel([1,1]) # needs networkx + sage: G.adjacency_matrix() # needs networkx sage.modules [0 1] [1 0] The output is allowed to contain both loops and multiple edges:: - sage: deg_sequence = [3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3] # optional - networkx - sage: G = graphs.DegreeSequenceConfigurationModel(deg_sequence) # optional - networkx - sage: G.order(), G.size() # optional - networkx + sage: # needs networkx + sage: deg_sequence = [3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3] + sage: G = graphs.DegreeSequenceConfigurationModel(deg_sequence) + sage: G.order(), G.size() (20, 30) - sage: G.has_loops() or G.has_multiple_edges() # random # optional - networkx + sage: G.has_loops() or G.has_multiple_edges() # random True - sage: G.show() # long time # optional - networkx sage.plot + sage: G.show() # long time # needs sage.plot REFERENCE: @@ -191,9 +192,9 @@ def DegreeSequenceTree(deg_sequence): EXAMPLES:: - sage: G = graphs.DegreeSequenceTree([3,1,3,3,1,1,1,2,1]); G # optional - networkx + sage: G = graphs.DegreeSequenceTree([3,1,3,3,1,1,1,2,1]); G # needs networkx Graph on 9 vertices - sage: G.show() # long time # optional - networkx sage.plot + sage: G.show() # long time # needs networkx sage.plot """ import networkx return Graph(networkx.degree_sequence_tree([int(i) for i in deg_sequence])) @@ -219,9 +220,9 @@ def DegreeSequenceExpected(deg_sequence, seed=None): EXAMPLES:: - sage: G = graphs.DegreeSequenceExpected([1,2,3,2,3]); G # optional - networkx + sage: G = graphs.DegreeSequenceExpected([1,2,3,2,3]); G # needs networkx Looped graph on 5 vertices - sage: G.show() # long time # optional - networkx sage.plot + sage: G.show() # long time # needs networkx sage.plot REFERENCE: diff --git a/src/sage/graphs/generators/distance_regular.pyx b/src/sage/graphs/generators/distance_regular.pyx index dd809a835af..edcb9ad4cfa 100644 --- a/src/sage/graphs/generators/distance_regular.pyx +++ b/src/sage/graphs/generators/distance_regular.pyx @@ -132,8 +132,8 @@ def ConwaySmith_for_3S7(): EXAMPLES:: - sage: G = graphs.ConwaySmith_for_3S7() - sage: G.is_distance_regular(True) + sage: G = graphs.ConwaySmith_for_3S7() # needs sage.modules sage.rings.finite_rings sage.rings.number_field + sage: G.is_distance_regular(True) # needs sage.modules sage.rings.finite_rings sage.rings.number_field ([10, 6, 4, 1, None], [None, 1, 2, 6, 10]) REFERENCES: @@ -243,8 +243,8 @@ def FosterGraph3S6(): EXAMPLES:: - sage: G = graphs.FosterGraph3S6() - sage: G.is_distance_regular(True) + sage: G = graphs.FosterGraph3S6() # needs sage.libs.gap + sage: G.is_distance_regular(True) # needs sage.libs.gap ([6, 4, 2, 1, None], [None, 1, 1, 4, 6]) REFERENCES: @@ -321,8 +321,8 @@ def LargeWittGraph(): EXAMPLES:: - sage: g = graphs.LargeWittGraph() - sage: g.is_distance_regular(True) + sage: g = graphs.LargeWittGraph() # needs sage.modules + sage: g.is_distance_regular(True) # needs sage.modules ([30, 28, 24, None], [None, 1, 3, 15]) REFERENCES: @@ -359,8 +359,8 @@ def TruncatedWittGraph(): EXAMPLES:: - sage: G = graphs.TruncatedWittGraph() # long time - sage: G.is_distance_regular(True) # long time (due to above) + sage: G = graphs.TruncatedWittGraph() # long time # needs sage.modules + sage: G.is_distance_regular(True) # long time (due to above) # needs sage.modules ([15, 14, 12, None], [None, 1, 1, 9]) REFERENCES: @@ -388,8 +388,8 @@ def DoublyTruncatedWittGraph(): EXAMPLES:: - sage: G = graphs.DoublyTruncatedWittGraph() - sage: G.is_distance_regular(True) + sage: G = graphs.DoublyTruncatedWittGraph() # needs sage.modules + sage: G.is_distance_regular(True) # needs sage.modules ([7, 6, 4, 4, None], [None, 1, 1, 1, 6]) REFERENCES: @@ -411,8 +411,8 @@ def distance_3_doubly_truncated_Golay_code_graph(): EXAMPLES:: - sage: G = graphs.distance_3_doubly_truncated_Golay_code_graph() # long time - sage: G.is_distance_regular(True) # long time (due to above) + sage: G = graphs.distance_3_doubly_truncated_Golay_code_graph() # long time, needs sage.modules sage.rings.finite_rings + sage: G.is_distance_regular(True) # long time (due to above) # needs sage.modules sage.rings.finite_rings ([9, 8, 6, 3, None], [None, 1, 1, 3, 8]) ALGORITHM: @@ -446,8 +446,8 @@ def shortened_00_11_binary_Golay_code_graph(): EXAMPLES:: - sage: G = graphs.shortened_00_11_binary_Golay_code_graph() # long time (9 s) - sage: G.is_distance_regular(True) # long time + sage: G = graphs.shortened_00_11_binary_Golay_code_graph() # long time (9 s), needs sage.modules sage.rings.finite_rings + sage: G.is_distance_regular(True) # long time # needs sage.modules sage.rings.finite_rings ([21, 20, 16, 6, 2, 1, None], [None, 1, 2, 6, 16, 20, 21]) ALGORITHM: @@ -485,8 +485,8 @@ def shortened_000_111_extended_binary_Golay_code_graph(): EXAMPLES:: - sage: G = graphs.shortened_000_111_extended_binary_Golay_code_graph() # long time (25 s) - sage: G.is_distance_regular(True) # long time + sage: G = graphs.shortened_000_111_extended_binary_Golay_code_graph() # long time (25 s), needs sage.modules sage.rings.finite_rings + sage: G.is_distance_regular(True) # long time # needs sage.modules sage.rings.finite_rings ([21, 20, 16, 9, 2, 1, None], [None, 1, 2, 3, 16, 20, 21]) ALGORITHM: @@ -526,8 +526,8 @@ def vanLintSchrijverGraph(): EXAMPLES:: - sage: G = graphs.vanLintSchrijverGraph() - sage: G.is_distance_regular(True) + sage: G = graphs.vanLintSchrijverGraph() # needs sage.modules + sage: G.is_distance_regular(True) # needs sage.modules ([6, 5, 5, 4, None], [None, 1, 1, 2, 6]) REFERENCES: @@ -557,8 +557,8 @@ def LeonardGraph(): EXAMPLES:: - sage: G = graphs.LeonardGraph() - sage: G.is_distance_regular(True) + sage: G = graphs.LeonardGraph() # needs sage.combinat sage.modules + sage: G.is_distance_regular(True) # needs sage.combinat sage.modules ([12, 11, 10, 7, None], [None, 1, 2, 5, 12]) REFERENCES: @@ -597,8 +597,8 @@ def UstimenkoGraph(const int m, const int q): EXAMPLES:: - sage: G = graphs.UstimenkoGraph(4, 2) - sage: G.is_distance_regular(True) + sage: G = graphs.UstimenkoGraph(4, 2) # needs sage.libs.gap + sage: G.is_distance_regular(True) # needs sage.libs.gap ([70, 32, None], [None, 1, 35]) REFERENCES: @@ -607,13 +607,14 @@ def UstimenkoGraph(const int m, const int q): TESTS:: - sage: G = graphs.UstimenkoGraph(5, 2) # long time - sage: G.order() # long time + sage: # long time, needs sage.libs.gap + sage: G = graphs.UstimenkoGraph(5, 2) + sage: G.order() 2295 - sage: G.is_distance_regular(True) # long time + sage: G.is_distance_regular(True) ([310, 224, None], [None, 1, 35]) - sage: G = graphs.UstimenkoGraph(4,3) # long time - sage: G.is_distance_regular(True) # long time + sage: G = graphs.UstimenkoGraph(4,3) + sage: G.is_distance_regular(True) ([390, 243, None], [None, 1, 130]) """ from sage.graphs.graph_generators import graphs @@ -652,14 +653,15 @@ def BilinearFormsGraph(const int d, const int e, const int q): EXAMPLES:: + sage: # needs sage.modules sage: G = graphs.BilinearFormsGraph(3, 3, 2) sage: G.is_distance_regular(True) ([49, 36, 16, None], [None, 1, 6, 28]) - sage: G = graphs.BilinearFormsGraph(3,3,3) # not tested (20 s) - sage: G.order() # not tested (due to above) + sage: G = graphs.BilinearFormsGraph(3,3,3) # not tested (20 s) # needs sage.rings.finite_rings + sage: G.order() # not tested (due to above) # needs sage.rings.finite_rings 19683 - sage: G = graphs.BilinearFormsGraph(3, 4, 2) # long time - sage: G.is_distance_regular(True) # long time + sage: G = graphs.BilinearFormsGraph(3, 4, 2) # long time # needs sage.rings.finite_rings + sage: G.is_distance_regular(True) # long time # needs sage.rings.finite_rings ([105, 84, 48, None], [None, 1, 6, 28]) REFERENCES: @@ -669,6 +671,7 @@ def BilinearFormsGraph(const int d, const int e, const int q): TESTS:: + sage: # needs sage.modules sage: G = graphs.BilinearFormsGraph(2,3,2) sage: G.is_distance_regular(True) ([21, 12, None], [None, 1, 6]) @@ -754,10 +757,11 @@ def AlternatingFormsGraph(const int n, const int q): TESTS:: - sage: G = graphs.AlternatingFormsGraph(6,2) # not tested (2 min) - sage: G.order() # not tested (because of above) + sage: # needs sage.modules + sage: G = graphs.AlternatingFormsGraph(6,2) # not tested (2 min) # needs sage.rings.finite_rings + sage: G.order() # not tested (because of above) # needs sage.rings.finite_rings 32768 - sage: G.is_distance_regular(True) # not tested (33 min) + sage: G.is_distance_regular(True) # not tested (33 min) # needs sage.rings.finite_rings ([651, 560, 256, None], [None, 1, 20, 336]) sage: G = graphs.AlternatingFormsGraph(4, 3) sage: G.is_distance_regular(True) @@ -840,11 +844,12 @@ def HermitianFormsGraph(const int n, const int r): EXAMPLES:: + sage: # needs sage.modules sage.rings.finite_rings sage: G = graphs.HermitianFormsGraph(2, 2) sage: G.is_distance_regular(True) ([5, 4, None], [None, 1, 2]) - sage: G = graphs.HermitianFormsGraph(3, 3) # not tested (2 min) - sage: G.order() # not tested (bacuase of the above) + sage: G = graphs.HermitianFormsGraph(3, 3) # not tested (2 min) + sage: G.order() # not tested (bacuase of the above) 19683 REFERENCES: @@ -853,6 +858,7 @@ def HermitianFormsGraph(const int n, const int r): TESTS:: + sage: # needs sage.modules sage.rings.finite_rings sage: G = graphs.HermitianFormsGraph(3, 2) sage: G.is_distance_regular(True) ([21, 20, 16, None], [None, 1, 2, 12]) @@ -1079,8 +1085,8 @@ def GrassmannGraph(const int q, const int n, const int input_e): EXAMPLES:: - sage: G = graphs.GrassmannGraph(2, 4, 2) - sage: G.is_distance_regular(True) + sage: G = graphs.GrassmannGraph(2, 4, 2) # needs sage.modules sage.rings.finite_rings + sage: G.is_distance_regular(True) # needs sage.modules sage.rings.finite_rings ([18, 8, None], [None, 1, 9]) REFERENCES: @@ -1089,8 +1095,9 @@ def GrassmannGraph(const int q, const int n, const int input_e): TESTS:: - sage: G = graphs.GrassmannGraph(2, 6, 3) # long time - sage: G.is_distance_regular(True) # long time + sage: # needs sage.modules sage.rings.finite_rings + sage: G = graphs.GrassmannGraph(2, 6, 3) # long time + sage: G.is_distance_regular(True) # long time ([98, 72, 32, None], [None, 1, 9, 49]) sage: G = graphs.GrassmannGraph(3, 4, 2) sage: G.is_distance_regular(True) @@ -1132,10 +1139,10 @@ def DoubleGrassmannGraph(const int q, const int e): EXAMPLES:: - sage: G = graphs.DoubleGrassmannGraph(2,1) - sage: G.diameter() + sage: G = graphs.DoubleGrassmannGraph(2,1) # needs sage.modules + sage: G.diameter() # needs sage.modules 3 - sage: G.is_distance_regular(True) + sage: G.is_distance_regular(True) # needs sage.modules ([3, 2, 2, None], [None, 1, 1, 3]) @@ -1145,15 +1152,16 @@ def DoubleGrassmannGraph(const int q, const int e): TESTS:: + sage: # needs sage.modules sage: G = graphs.DoubleGrassmannGraph(5,1) sage: G.order() 62 sage: G.is_distance_regular(True) ([6, 5, 5, None], [None, 1, 1, 6]) - sage: G = graphs.DoubleGrassmannGraph(3, 2) # long time - sage: G.order() # long time + sage: G = graphs.DoubleGrassmannGraph(3, 2) # long time # needs sage.rings.finite_rings + sage: G.order() # long time # needs sage.rings.finite_rings 2420 - sage: G.is_distance_regular(True) # long time + sage: G.is_distance_regular(True) # long time # needs sage.rings.finite_rings ([13, 12, 12, 9, 9, None], [None, 1, 1, 4, 4, 13]) """ n = 2*e + 1 @@ -1187,10 +1195,10 @@ def is_from_GQ_spread(list arr): sage: from sage.graphs.generators.distance_regular import \ ....: is_from_GQ_spread, graph_from_GQ_spread - sage: is_from_GQ_spread([125, 120, 1, 1, 24, 125]) + sage: is_from_GQ_spread([125, 120, 1, 1, 24, 125]) # needs sage.libs.pari (5, 25) - sage: G = graph_from_GQ_spread(5, 25) - sage: G.is_distance_regular(True) + sage: G = graph_from_GQ_spread(5, 25) # needs sage.libs.pari + sage: G.is_distance_regular(True) # needs sage.libs.pari ([125, 120, 1, None], [None, 1, 24, 125]) REFERENCES: @@ -1202,9 +1210,9 @@ def is_from_GQ_spread(list arr): sage: from sage.graphs.generators.distance_regular import \ ....: is_from_GQ_spread - sage: is_from_GQ_spread([343, 336, 1, 1, 48, 343]) + sage: is_from_GQ_spread([343, 336, 1, 1, 48, 343]) # needs sage.libs.pari (7, 49) - sage: is_from_GQ_spread([343, 336, 1, 2, 48, 343]) + sage: is_from_GQ_spread([343, 336, 1, 2, 48, 343]) # needs sage.libs.pari False Check that we don't get ``True`` for inexisting GQs:: @@ -1215,7 +1223,7 @@ def is_from_GQ_spread(list arr): sage: t = 6 sage: [s * t, s * (t-1), 1, 1, t - 1, s * t] [30, 25, 1, 1, 5, 30] - sage: is_from_GQ_spread([30, 25, 1, 1, 5, 30]) + sage: is_from_GQ_spread([30, 25, 1, 1, 5, 30]) # needs sage.libs.pari False """ from sage.combinat.designs import design_catalog as designs @@ -1258,8 +1266,8 @@ def graph_from_GQ_spread(const int s, const int t): sage: from sage.graphs.generators.distance_regular import \ ....: graph_from_GQ_spread - sage: G = graph_from_GQ_spread(4, 16) - sage: G.is_distance_regular(True) + sage: G = graph_from_GQ_spread(4, 16) # needs sage.libs.pari + sage: G.is_distance_regular(True) # needs sage.libs.pari ([64, 60, 1, None], [None, 1, 15, 64]) REFERENCES: @@ -1270,11 +1278,11 @@ def graph_from_GQ_spread(const int s, const int t): sage: from sage.graphs.generators.distance_regular import \ ....: graph_from_GQ_spread, is_from_GQ_spread - sage: is_from_GQ_spread([64, 60, 1, 1, 15, 64]) + sage: is_from_GQ_spread([64, 60, 1, 1, 15, 64]) # needs sage.libs.pari (4, 16) - sage: graph_from_GQ_spread(*is_from_GQ_spread([27, 24, 1, 1, 8, 27])) + sage: graph_from_GQ_spread(*is_from_GQ_spread([27, 24, 1, 1, 8, 27])) # needs sage.libs.pari Graph on 112 vertices - sage: _.is_distance_regular(True) + sage: _.is_distance_regular(True) # needs sage.libs.pari ([27, 24, 1, None], [None, 1, 8, 27]) """ from sage.combinat.designs import design_catalog as designs @@ -1302,13 +1310,14 @@ def GeneralisedDodecagonGraph(const int s, const int t): EXAMPLES:: - sage: G = graphs.GeneralisedDodecagonGraph(1, 5) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: # optional - gap_packages internet + sage: G = graphs.GeneralisedDodecagonGraph(1, 5) + sage: G.is_distance_regular(True) ([6, 5, 5, 5, 5, 5, None], [None, 1, 1, 1, 1, 1, 6]) - sage: H = graphs.GeneralisedDodecagonGraph(5, 1) # optional - gap_packages internet - sage: H.order() # optional - gap_packages internet + sage: H = graphs.GeneralisedDodecagonGraph(5, 1) + sage: H.order() 23436 - sage: H.is_distance_regular(True) # not tested (6 min); optional - gap_packages internet + sage: H.is_distance_regular(True) # not tested (6 min) ([10, 5, 5, 5, 5, 5, None], [None, 1, 1, 1, 1, 1, 2]) .. NOTE:: @@ -1326,29 +1335,31 @@ def GeneralisedDodecagonGraph(const int s, const int t): Test all graphs of order `(1, q)`:: - sage: G = graphs.GeneralisedDodecagonGraph(1, 4) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: # optional - gap_packages internet + sage: G = graphs.GeneralisedDodecagonGraph(1, 4) + sage: G.is_distance_regular(True) ([5, 4, 4, 4, 4, 4, None], [None, 1, 1, 1, 1, 1, 5]) - sage: G = graphs.GeneralisedDodecagonGraph(1, 3) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: G = graphs.GeneralisedDodecagonGraph(1, 3) + sage: G.is_distance_regular(True) ([4, 3, 3, 3, 3, 3, None], [None, 1, 1, 1, 1, 1, 4]) - sage: G = graphs.GeneralisedDodecagonGraph(1, 2) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: G = graphs.GeneralisedDodecagonGraph(1, 2) + sage: G.is_distance_regular(True) ([3, 2, 2, 2, 2, 2, None], [None, 1, 1, 1, 1, 1, 3]) - sage: G = graphs.GeneralisedDodecagonGraph(1, 1) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: G = graphs.GeneralisedDodecagonGraph(1, 1) + sage: G.is_distance_regular(True) ([2, 1, 1, 1, 1, 1, None], [None, 1, 1, 1, 1, 1, 2]) Now test all graphs of order `(q, 1)`:: - sage: G = graphs.GeneralisedDodecagonGraph(4, 1) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: # optional - gap_packages internet + sage: G = graphs.GeneralisedDodecagonGraph(4, 1) + sage: G.is_distance_regular(True) ([8, 4, 4, 4, 4, 4, None], [None, 1, 1, 1, 1, 1, 2]) - sage: G = graphs.GeneralisedDodecagonGraph(3, 1) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: G = graphs.GeneralisedDodecagonGraph(3, 1) + sage: G.is_distance_regular(True) ([6, 3, 3, 3, 3, 3, None], [None, 1, 1, 1, 1, 1, 2]) - sage: G = graphs.GeneralisedDodecagonGraph(2, 1) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: G = graphs.GeneralisedDodecagonGraph(2, 1) + sage: G.is_distance_regular(True) ([4, 2, 2, 2, 2, 2, None], [None, 1, 1, 1, 1, 1, 2]) """ from sage.arith.misc import is_prime_power @@ -1407,14 +1418,14 @@ def GeneralisedOctagonGraph(const int s, const int t): EXAMPLES:: - sage: G = graphs.GeneralisedOctagonGraph(1, 4) - sage: G.is_distance_regular(True) + sage: G = graphs.GeneralisedOctagonGraph(1, 4) # needs sage.libs.gap + sage: G.is_distance_regular(True) # needs sage.libs.gap ([5, 4, 4, 4, None], [None, 1, 1, 1, 5]) sage: G = graphs.GeneralisedOctagonGraph(2, 4) # optional - gap_packages internet sage: G.is_distance_regular(True) # optional - gap_packages internet ([10, 8, 8, 8, None], [None, 1, 1, 1, 5]) - sage: G = graphs.GeneralisedOctagonGraph(5, 1) - sage: G.is_distance_regular(True) + sage: G = graphs.GeneralisedOctagonGraph(5, 1) # needs sage.libs.gap + sage: G.is_distance_regular(True) # needs sage.libs.gap ([10, 5, 5, 5, None], [None, 1, 1, 1, 2]) .. NOTE:: @@ -1430,11 +1441,11 @@ def GeneralisedOctagonGraph(const int s, const int t): TESTS:: - sage: G = graphs.GeneralisedOctagonGraph(8, 64) + sage: G = graphs.GeneralisedOctagonGraph(8, 64) # needs sage.libs.gap Traceback (most recent call last): ... NotImplementedError: Graph would be too big - sage: G = graphs.GeneralisedOctagonGraph(4, 16) + sage: G = graphs.GeneralisedOctagonGraph(4, 16) # needs sage.libs.gap Traceback (most recent call last): ... ValueError: generalised octagons of order (q, q^2) are known only for odd powers q of 2 @@ -1520,10 +1531,10 @@ def GeneralisedHexagonGraph(const int s, const int t): sage: G = graphs.GeneralisedHexagonGraph(5, 5) # optional - gap_packages internet sage: G.is_distance_regular(True) # optional - gap_packages internet ([30, 25, 25, None], [None, 1, 1, 6]) - sage: G = graphs.GeneralisedHexagonGraph(7, 1) - sage: G.is_distance_regular(True) + sage: G = graphs.GeneralisedHexagonGraph(7, 1) # needs sage.libs.gap + sage: G.is_distance_regular(True) # needs sage.libs.gap ([14, 7, 7, None], [None, 1, 1, 2]) - sage: graphs.GeneralisedHexagonGraph(1, 1) + sage: graphs.GeneralisedHexagonGraph(1, 1) # needs sage.libs.gap Cycle graph: Graph on 6 vertices .. NOTE:: @@ -1539,17 +1550,18 @@ def GeneralisedHexagonGraph(const int s, const int t): TESTS:: - sage: G = graphs.GeneralisedHexagonGraph(4, 4) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: # optional - gap_packages internet + sage: G = graphs.GeneralisedHexagonGraph(4, 4) + sage: G.is_distance_regular(True) ([20, 16, 16, None], [None, 1, 1, 5]) - sage: G = graphs.GeneralisedHexagonGraph(3, 3) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: G = graphs.GeneralisedHexagonGraph(3, 3) + sage: G.is_distance_regular(True) ([12, 9, 9, None], [None, 1, 1, 4]) - sage: G = graphs.GeneralisedHexagonGraph(2, 2) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: G = graphs.GeneralisedHexagonGraph(2, 2) + sage: G.is_distance_regular(True) ([6, 4, 4, None], [None, 1, 1, 3]) - sage: G = graphs.GeneralisedHexagonGraph(2, 8) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet + sage: G = graphs.GeneralisedHexagonGraph(2, 8) + sage: G.is_distance_regular(True) ([18, 16, 16, None], [None, 1, 1, 9]) """ from sage.arith.misc import is_prime_power @@ -1672,6 +1684,7 @@ def _extract_lines(G): EXAMPLES:: + sage: # needs sage.libs.gap sage: from sage.graphs.generators.distance_regular import _extract_lines sage: G = graphs.GeneralisedHexagonGraph(1, 8) sage: lines = _extract_lines(G) @@ -1741,9 +1754,9 @@ def _line_graph_generalised_polygon(H): sage: from sage.graphs.generators.distance_regular import \ ....: _line_graph_generalised_polygon - sage: G = graphs.GeneralisedHexagonGraph(1, 8) - sage: H = _line_graph_generalised_polygon(G) - sage: H.is_distance_regular(True) + sage: G = graphs.GeneralisedHexagonGraph(1, 8) # needs sage.libs.gap + sage: H = _line_graph_generalised_polygon(G) # needs sage.libs.gap + sage: H.is_distance_regular(True) # needs sage.libs.gap ([16, 8, 8, None], [None, 1, 1, 2]) sage: G = graphs.GeneralisedHexagonGraph(3, 3) # optional - gap_packages internet sage: H = _line_graph_generalised_polygon(G) # optional - gap_packages internet @@ -1792,9 +1805,9 @@ def _intersection_array_from_graph(G): sage: from sage.graphs.generators.distance_regular import \ ....: _intersection_array_from_graph - sage: _intersection_array_from_graph(graphs.FosterGraph()) + sage: _intersection_array_from_graph(graphs.FosterGraph()) # needs networkx [3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3] - sage: graphs.FosterGraph().is_distance_regular(True) + sage: graphs.FosterGraph().is_distance_regular(True) # needs networkx ([3, 2, 2, 2, 2, 1, 1, 1, None], [None, 1, 1, 1, 1, 2, 2, 2, 3]) sage: graphs.DartGraph().is_distance_regular() False @@ -1877,7 +1890,7 @@ def is_classical_parameters_graph(list array): sage: G = graphs.HammingGraph(5, 4) sage: G.is_distance_regular(True) ([15, 12, 9, 6, 3, None], [None, 1, 2, 3, 4, 5]) - sage: is_classical_parameters_graph([15, 12, 9, 6, 3, 1, 2, 3, 4, 5]) + sage: is_classical_parameters_graph([15, 12, 9, 6, 3, 1, 2, 3, 4, 5]) # needs sage.combinat (5, 1, 0, 3, 2) REFERENCES: @@ -1890,12 +1903,12 @@ def is_classical_parameters_graph(list array): sage: from sage.graphs.generators.distance_regular import \ ....: is_classical_parameters_graph - sage: is_classical_parameters_graph([68, 64, 1, 17]) # srg not drg + sage: is_classical_parameters_graph([68, 64, 1, 17]) # srg not drg # needs sage.combinat False sage: G = graphs.GossetGraph() # sporadic classical parameters graph sage: G.is_distance_regular(True) ([27, 10, 1, None], [None, 1, 10, 27]) - sage: is_classical_parameters_graph([27, 10, 1, 1, 10, 27]) + sage: is_classical_parameters_graph([27, 10, 1, 1, 10, 27]) # needs sage.combinat False """ from sage.misc.functional import log @@ -2101,7 +2114,7 @@ def graph_with_classical_parameters(int d, int b, alpha_in, beta_in, int gamma): Hamming Graph with parameters 3,4: Graph on 64 vertices sage: G = _; G.is_distance_regular(True) ([9, 6, 3, None], [None, 1, 2, 3]) - sage: is_classical_parameters_graph([9, 6, 3, 1, 2, 3]) + sage: is_classical_parameters_graph([9, 6, 3, 1, 2, 3]) # needs sage.combinat (3, 1, 0, 3, 2) Two families of graphs are not implemented yet:: @@ -2125,7 +2138,7 @@ def graph_with_classical_parameters(int d, int b, alpha_in, beta_in, int gamma): sage: graph_with_classical_parameters(3, 1, 2, 3, 3) Half 4 Cube: Graph on 8 vertices - sage: graph_with_classical_parameters(3, 2, 0, 2, 9) + sage: graph_with_classical_parameters(3, 2, 0, 2, 9) # needs sage.libs.gap Symplectic Dual Polar Graph DSp(6, 2): Graph on 135 vertices sage: graph_with_classical_parameters(3, 2, 2, 14, 7) # long time Grassmann graph J_2(6, 3): Graph on 1395 vertices @@ -2389,7 +2402,7 @@ def is_near_polygon(array): sage: from sage.graphs.generators.distance_regular import ( ....: is_near_polygon, near_polygon_graph) - sage: is_near_polygon([7, 6, 6, 5, 5, 4, 1, 1, 2, 2, 3, 3]) + sage: is_near_polygon([7, 6, 6, 5, 5, 4, 1, 1, 2, 2, 3, 3]) # needs sage.combinat (2, 7) sage: near_polygon_graph(2, 7) Odd Graph with parameter 7: Graph on 1716 vertices @@ -2405,17 +2418,17 @@ def is_near_polygon(array): sage: from sage.graphs.generators.distance_regular import ( ....: is_near_polygon, near_polygon_graph) - sage: is_near_polygon([7, 6, 6, 4, 4, 1, 1, 3, 3, 7]) + sage: is_near_polygon([7, 6, 6, 4, 4, 1, 1, 3, 3, 7]) # needs sage.combinat sage.libs.pari (4, (2, 2)) sage: near_polygon_graph(4, (2, 2)) Double Grassmann graph (5, 2, 2): Graph on 310 vertices - sage: near_polygon_graph(*is_near_polygon([3, 2, 2, 1, 1, 3])) + sage: near_polygon_graph(*is_near_polygon([3, 2, 2, 1, 1, 3])) # needs sage.combinat sage.rings.finite_rings Generalised hexagon of order (1, 2): Graph on 14 vertices - sage: is_near_polygon([16, 12, 8, 4, 1, 2, 3, 4]) + sage: is_near_polygon([16, 12, 8, 4, 1, 2, 3, 4]) # needs sage.combinat sage.libs.pari (6, (4, 5)) - sage: is_near_polygon([]) + sage: is_near_polygon([]) # needs sage.combinat sage.libs.pari False - sage: is_near_polygon([25, 16, 9, 4, 1, 1, 4, 9, 16, 25]) # JohnsonGraph + sage: is_near_polygon([25, 16, 9, 4, 1, 1, 4, 9, 16, 25]) # JohnsonGraph # needs sage.combinat sage.libs.pari False """ from sage.arith.misc import is_prime_power @@ -2525,12 +2538,11 @@ def near_polygon_graph(family, params): EXAMPLES:: - sage: from sage.graphs.generators.distance_regular import ( - ....: is_near_polygon, near_polygon_graph) - sage: near_polygon_graph(*is_near_polygon([6, 5, 5, 4, 4, 3, 3, 2, 2, \ - ....: 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6])) + sage: from sage.graphs.generators.distance_regular import is_near_polygon, near_polygon_graph + sage: near_polygon_graph(*is_near_polygon( # needs sage.combinat + ....: [6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6])) Bipartite double of Odd graph on a set of 11 elements: Graph on 924 vertices - sage: G=_; G.is_distance_regular(True) + sage: G=_; G.is_distance_regular(True) # needs sage.combinat ([6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, None], [None, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6]) @@ -2541,6 +2553,7 @@ def near_polygon_graph(family, params): TESTS:: + sage: # needs sage.combinat sage: near_polygon_graph(12, 9) Traceback (most recent call last): ... @@ -2695,8 +2708,8 @@ def distance_regular_graph(list arr, existence=False, check=True): sage: graphs.distance_regular_graph([21,20,16,1,2,12], existence=True) True - sage: G = graphs.distance_regular_graph([12,11,10,7,1,2,5,12], check=False) - sage: G.is_distance_regular(True) + sage: G = graphs.distance_regular_graph([12,11,10,7,1,2,5,12], check=False) # needs sage.combinat sage.modules + sage: G.is_distance_regular(True) # needs sage.combinat sage.modules ([12, 11, 10, 7, None], [None, 1, 2, 5, 12]) REFERENCES: @@ -2705,7 +2718,7 @@ def distance_regular_graph(list arr, existence=False, check=True): TESTS:: - sage: graphs.distance_regular_graph([3, 2, 2, 1, 1, 1, 1, 2, 2, 3], + sage: graphs.distance_regular_graph([3, 2, 2, 1, 1, 1, 1, 2, 2, 3], # needs sage.combinat ....: existence=True) True sage: graphs.distance_regular_graph([3, 2, 2, 1, 2, 1, 1, 2, 2, 3], @@ -2713,14 +2726,14 @@ def distance_regular_graph(list arr, existence=False, check=True): False sage: graphs.distance_regular_graph([18, 16, 16, 1, 1, 9]) # optional - internet gap_packages Generalised hexagon of order (2, 8): Graph on 819 vertices - sage: graphs.distance_regular_graph([14, 12, 10, 8, 6, 4, 2, + sage: graphs.distance_regular_graph([14, 12, 10, 8, 6, 4, 2, # needs sage.combinat ....: 1, 2, 3, 4, 5, 6, 7]) Hamming Graph with parameters 7,3: Graph on 2187 vertices - sage: graphs.distance_regular_graph([66, 45, 28, 1, 6, 30]) + sage: graphs.distance_regular_graph([66, 45, 28, 1, 6, 30]) # needs sage.combinat Graph on 1024 vertices - sage: graphs.distance_regular_graph([6,5,5,5,1,1,1,6]) + sage: graphs.distance_regular_graph([6,5,5,5,1,1,1,6]) # needs sage.combinat Generalised octagon of order (1, 5): Graph on 312 vertices - sage: graphs.distance_regular_graph([64, 60, 1, 1, 15, 64], check=True) + sage: graphs.distance_regular_graph([64, 60, 1, 1, 15, 64], check=True) # needs sage.combinat Graph on 325 vertices """ from sage.misc.unknown import Unknown diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index 30396e1ab9e..dba8ec3d5c9 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -40,13 +40,13 @@ def JohnsonGraph(n, k): The Johnson graph is a Hamiltonian graph:: sage: g = graphs.JohnsonGraph(7, 3) - sage: g.is_hamiltonian() + sage: g.is_hamiltonian() # needs sage.numerical.mip True Every Johnson graph is vertex transitive:: sage: g = graphs.JohnsonGraph(6, 4) - sage: g.is_vertex_transitive() + sage: g.is_vertex_transitive() # needs sage.groups True The complement of the Johnson graph `J(n,2)` is isomorphic to the Kneser @@ -452,7 +452,7 @@ def HammingGraph(n, q, X=None): True sage: g.is_regular() True - sage: g.is_vertex_transitive() # optional - sage.groups + sage: g.is_vertex_transitive() # needs sage.groups True A Hamming graph with parameters (1,q) is isomorphic to the @@ -526,9 +526,9 @@ def BalancedTree(r, h): A balanced tree whose root node has degree `r = 2`, and of height `h = 1`, has order 3 and size 2:: - sage: G = graphs.BalancedTree(2, 1); G # optional - networkx + sage: G = graphs.BalancedTree(2, 1); G # needs networkx Balanced tree: Graph on 3 vertices - sage: G.order(); G.size() # optional - networkx + sage: G.order(); G.size() # needs networkx 3 2 sage: r = 2; h = 1 @@ -539,21 +539,21 @@ def BalancedTree(r, h): Plot a balanced tree of height 5, whose root node has degree `r = 3`:: - sage: G = graphs.BalancedTree(3, 5) # optional - networkx - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphs.BalancedTree(3, 5) # needs networkx + sage: G.show() # long time # needs networkx sage.plot A tree is bipartite. If its vertex set is finite, then it is planar. :: sage: r = randint(2, 5); h = randint(1, 7) - sage: T = graphs.BalancedTree(r, h) # optional - networkx - sage: T.is_bipartite() # optional - networkx + sage: T = graphs.BalancedTree(r, h) # needs networkx + sage: T.is_bipartite() # needs networkx True - sage: T.is_planar() # optional - networkx + sage: T.is_planar() # needs networkx True - sage: v = (r^(h + 1) - 1) / (r - 1) # optional - networkx - sage: T.order() == v # optional - networkx + sage: v = (r^(h + 1) - 1) / (r - 1) # needs networkx + sage: T.order() == v # needs networkx True - sage: T.size() == v - 1 # optional - networkx + sage: T.size() == v - 1 # needs networkx True TESTS: @@ -562,13 +562,13 @@ def BalancedTree(r, h): has degree `r \geq 2`, but the construction degenerates gracefully:: - sage: graphs.BalancedTree(1, 10) # optional - networkx + sage: graphs.BalancedTree(1, 10) # needs networkx Balanced tree: Graph on 11 vertices Similarly, we usually want the tree must have height `h \geq 1` but the algorithm also degenerates gracefully here:: - sage: graphs.BalancedTree(3, 0) # optional - networkx + sage: graphs.BalancedTree(3, 0) # needs networkx Balanced tree: Graph on 1 vertex """ import networkx @@ -627,11 +627,11 @@ def BarbellGraph(n1, n2): True sage: K_n1 = graphs.CompleteGraph(n1) sage: P_n2 = graphs.PathGraph(n2) - sage: s_K = g.subgraph_search(K_n1, induced=True) # optional - sage.modules - sage: s_P = g.subgraph_search(P_n2, induced=True) # optional - sage.modules - sage: K_n1.is_isomorphic(s_K) # optional - sage.modules + sage: s_K = g.subgraph_search(K_n1, induced=True) # needs sage.modules + sage: s_P = g.subgraph_search(P_n2, induced=True) # needs sage.modules + sage: K_n1.is_isomorphic(s_K) # needs sage.modules True - sage: P_n2.is_isomorphic(s_P) # optional - sage.modules + sage: P_n2.is_isomorphic(s_P) # needs sage.modules True TESTS:: @@ -640,7 +640,7 @@ def BarbellGraph(n1, n2): sage: g = graphs.BarbellGraph(n1, n2) sage: g.num_verts() == 2 * n1 + n2 True - sage: g.num_edges() == 2 * binomial(n1, 2) + n2 + 1 + sage: g.num_edges() == 2 * binomial(n1, 2) + n2 + 1 # needs sage.symbolic True sage: g.is_connected() True @@ -717,7 +717,7 @@ def LollipopGraph(n1, n2): sage: g = graphs.LollipopGraph(n1, n2) sage: g.num_verts() == n1 + n2 True - sage: g.num_edges() == binomial(n1, 2) + n2 + sage: g.num_edges() == binomial(n1, 2) + n2 # needs sage.symbolic True sage: g.is_connected() True @@ -1027,10 +1027,10 @@ def chang_graphs(): sage: c3c5 = graphs.CycleGraph(3).disjoint_union(graphs.CycleGraph(5)) sage: c8 = graphs.CycleGraph(8) - sage: s = [K8.subgraph_search(c8).edges(sort=False), # optional - sage.modules + sage: s = [K8.subgraph_search(c8).edges(sort=False), # needs sage.modules ....: [(0,1,None),(2,3,None),(4,5,None),(6,7,None)], ....: K8.subgraph_search(c3c5).edges(sort=False)] - sage: [T8.seidel_switching(x, inplace=False).is_isomorphic(G) # optional - sage.modules + sage: [T8.seidel_switching(x, inplace=False).is_isomorphic(G) # needs sage.modules ....: for x, G in zip(s, chang_graphs)] [True, True, True] @@ -1076,11 +1076,11 @@ def CirculantGraph(n, adjacency): EXAMPLES: Compare plotting using the predefined layout and networkx:: - sage: import networkx # optional - networkx - sage: n = networkx.cycle_graph(23) # optional - networkx - sage: spring23 = Graph(n) # optional - networkx + sage: import networkx # needs networkx + sage: n = networkx.cycle_graph(23) # needs networkx + sage: spring23 = Graph(n) # needs networkx sage: posdict23 = graphs.CirculantGraph(23,2) - sage: spring23.show() # long time # optional - networkx + sage: spring23.show() # long time # needs networkx sage: posdict23.show() # long time We next view many cycle graphs as a Sage graphics array. First we @@ -1092,29 +1092,29 @@ def CirculantGraph(n, adjacency): sage: for i in range(9): ....: k = graphs.CirculantGraph(i+4, i+1) ....: g.append(k) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): # needs sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) # needs sage.plot + sage: G.show() # long time # needs sage.plot Compare to plotting with the spring-layout algorithm:: sage: g = [] sage: j = [] - sage: for i in range(9): # optional - networkx + sage: for i in range(9): # needs networkx ....: spr = networkx.cycle_graph(i+3) ....: k = Graph(spr) ....: g.append(k) - sage: for i in range(3): # optional - networkx sage.plot + sage: for i in range(3): # needs networkx sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - networkx sage.plot - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphics_array(j) # needs networkx sage.plot + sage: G.show() # long time # needs networkx sage.plot Passing a 1 into adjacency should give the cycle. @@ -1193,21 +1193,21 @@ def CubeGraph(n, embedding=1): ....: k = graphs.CubeGraph(i+1) ....: g.append(k) ... - sage: for i in range(2): # optional - sage.plot + sage: for i in range(2): # needs sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) ... - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show(figsize=[6,4]) # long time # optional - sage.plot + sage: G = graphics_array(j) # needs sage.plot + sage: G.show(figsize=[6,4]) # long time # needs sage.plot Use the plot options to display larger `n`-cubes:: sage: g = graphs.CubeGraph(9, embedding=1) - sage: g.show(figsize=[12,12],vertex_labels=False, vertex_size=20) # long time # optional - sage.plot + sage: g.show(figsize=[12,12],vertex_labels=False, vertex_size=20) # long time, needs sage.plot sage: g = graphs.CubeGraph(9, embedding=2) - sage: g.show(figsize=[12,12],vertex_labels=False, vertex_size=20) # long time # optional - sage.plot + sage: g.show(figsize=[12,12],vertex_labels=False, vertex_size=20) # long time, needs sage.plot AUTHORS: @@ -1306,9 +1306,9 @@ def GoethalsSeidelGraph(k, r): EXAMPLES:: - sage: graphs.GoethalsSeidelGraph(3,3) + sage: graphs.GoethalsSeidelGraph(3,3) # needs sage.modules Graph on 28 vertices - sage: graphs.GoethalsSeidelGraph(3,3).is_strongly_regular(parameters=True) + sage: graphs.GoethalsSeidelGraph(3,3).is_strongly_regular(parameters=True) # needs sage.modules (28, 15, 6, 10) """ from sage.combinat.designs.bibd import balanced_incomplete_block_design @@ -1353,8 +1353,8 @@ def DorogovtsevGoltsevMendesGraph(n): EXAMPLES:: - sage: G = graphs.DorogovtsevGoltsevMendesGraph(8) # optional - networkx - sage: G.size() # optional - networkx + sage: G = graphs.DorogovtsevGoltsevMendesGraph(8) # needs networkx + sage: G.size() # needs networkx 6561 REFERENCE: @@ -1442,20 +1442,20 @@ def FriendshipGraph(n): sage: for i in range(9): ....: g = graphs.FriendshipGraph(i + 1) ....: A.append(g) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): # needs sage.plot ....: n = [] ....: for j in range(3): ....: n.append(A[3*i + j].plot(vertex_size=20, vertex_labels=False)) ....: B.append(n) - sage: G = graphics_array(B) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(B) # needs sage.plot + sage: G.show() # long time # needs sage.plot For `n = 1`, the friendship graph `F_1` is isomorphic to the cycle graph `C_3`, whose visual representation is a triangle. :: sage: G = graphs.FriendshipGraph(1); G Friendship graph: Graph on 3 vertices - sage: G.show() # long time # optional - sage.plot + sage: G.show() # long time # needs sage.plot sage: G.is_isomorphic(graphs.CycleGraph(3)) True @@ -1538,7 +1538,7 @@ def FuzzyBallGraph(partition, q): EXAMPLES:: sage: F = graphs.FuzzyBallGraph([3,1],2) - sage: F.adjacency_matrix(vertices=list(F)) # optional - sage.modules + sage: F.adjacency_matrix(vertices=list(F)) # needs sage.modules [0 0 1 1 1 0 0 0] [0 0 0 0 0 1 0 0] [1 0 0 1 1 1 1 1] @@ -1554,9 +1554,9 @@ def FuzzyBallGraph(partition, q): Laplacian:: sage: m = 4; q = 2; k = 2 - sage: g_list = [graphs.FuzzyBallGraph(p,q) # optional - sage.combinat sage.modules + sage: g_list = [graphs.FuzzyBallGraph(p,q) # needs sage.combinat sage.modules ....: for p in Partitions(m, length=k)] - sage: set(g.laplacian_matrix(normalized=True, # long time (7s on sage.math, 2011), optional - sage.combinat sage.modules + sage: set(g.laplacian_matrix(normalized=True, # long time (7s on sage.math, 2011), needs sage.combinat sage.modules ....: vertices=list(g)).charpoly() ....: for g in g_list) {x^8 - 8*x^7 + 4079/150*x^6 - 68689/1350*x^5 + 610783/10800*x^4 @@ -1588,15 +1588,15 @@ def FibonacciTree(n): EXAMPLES:: - sage: g = graphs.FibonacciTree(3) - sage: g.is_tree() + sage: g = graphs.FibonacciTree(3) # needs sage.libs.pari + sage: g.is_tree() # needs sage.libs.pari True :: - sage: l1 = [ len(graphs.FibonacciTree(_)) + 1 for _ in range(6) ] - sage: l2 = list(fibonacci_sequence(2,8)) - sage: l1 == l2 + sage: l1 = [ len(graphs.FibonacciTree(_)) + 1 for _ in range(6) ] # needs sage.libs.pari + sage: l2 = list(fibonacci_sequence(2,8)) # needs sage.libs.pari + sage: l1 == l2 # needs sage.libs.pari True AUTHORS: @@ -2074,15 +2074,15 @@ def HararyGraph(k, n): 9 sage: h.size() 23 - sage: h.vertex_connectivity() + sage: h.vertex_connectivity() # needs sage.numerical.mip 5 TESTS: Connectivity of some Harary graphs:: - sage: n=10 - sage: for k in range(2,n): + sage: n = 10 + sage: for k in range(2,n): # needs sage.numerical.mip ....: g = graphs.HararyGraph(k,n) ....: if k != g.vertex_connectivity(): ....: print("Connectivity of Harary graphs not satisfied.") @@ -2207,31 +2207,31 @@ def LCFGraph(n, shift_list, repeats): EXAMPLES:: - sage: G = graphs.LCFGraph(4, [2,-2], 2) # optional - networkx - sage: G.is_isomorphic(graphs.TetrahedralGraph()) # optional - networkx + sage: G = graphs.LCFGraph(4, [2,-2], 2) # needs networkx + sage: G.is_isomorphic(graphs.TetrahedralGraph()) # needs networkx True :: - sage: G = graphs.LCFGraph(20, [10,7,4,-4,-7,10,-4,7,-7,4], 2) # optional - networkx - sage: G.is_isomorphic(graphs.DodecahedralGraph()) # optional - networkx + sage: G = graphs.LCFGraph(20, [10,7,4,-4,-7,10,-4,7,-7,4], 2) # needs networkx + sage: G.is_isomorphic(graphs.DodecahedralGraph()) # needs networkx True :: - sage: G = graphs.LCFGraph(14, [5,-5], 7) # optional - networkx - sage: G.is_isomorphic(graphs.HeawoodGraph()) # optional - networkx + sage: G = graphs.LCFGraph(14, [5,-5], 7) # needs networkx + sage: G.is_isomorphic(graphs.HeawoodGraph()) # needs networkx True The largest cubic nonplanar graph of diameter three:: - sage: G = graphs.LCFGraph(20, [-10,-7,-5,4,7,-10,-7,-4,5,7, # optional - networkx + sage: G = graphs.LCFGraph(20, [-10,-7,-5,4,7,-10,-7,-4,5,7, # needs networkx ....: -10,-7,6,-5,7,-10,-7,5,-6,7], 1) - sage: G.degree() # optional - networkx + sage: G.degree() # needs networkx [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] - sage: G.diameter() # optional - networkx + sage: G.diameter() # needs networkx 3 - sage: G.show() # long time # optional - networkx sage.plot + sage: G.show() # long time # needs networkx sage.plot PLOTTING: LCF Graphs are plotted as an n-cycle with edges in the middle, as described above. @@ -2538,14 +2538,14 @@ def PaleyGraph(q): EXAMPLES:: - sage: G = graphs.PaleyGraph(9); G + sage: G = graphs.PaleyGraph(9); G # needs sage.rings.finite_rings Paley graph with parameter 9: Graph on 9 vertices - sage: G.is_regular() + sage: G.is_regular() # needs sage.rings.finite_rings True A Paley graph is always self-complementary:: - sage: G.is_self_complementary() + sage: G.is_self_complementary() # needs sage.rings.finite_rings True TESTS: @@ -2588,9 +2588,9 @@ def PasechnikGraph(n): EXAMPLES:: - sage: graphs.PasechnikGraph(4).is_strongly_regular(parameters=True) # optional - sage.combinat sage.modules + sage: graphs.PasechnikGraph(4).is_strongly_regular(parameters=True) # needs sage.combinat sage.modules (225, 98, 43, 42) - sage: graphs.PasechnikGraph(5).is_strongly_regular(parameters=True) # long time, optional - sage.combinat sage.modules + sage: graphs.PasechnikGraph(5).is_strongly_regular(parameters=True) # long time, needs sage.combinat sage.modules (361, 162, 73, 72) sage: graphs.PasechnikGraph(9).is_strongly_regular(parameters=True) # not tested (1225, 578, 273, 272) @@ -2630,11 +2630,14 @@ def SquaredSkewHadamardMatrixGraph(n): EXAMPLES:: - sage: graphs.SquaredSkewHadamardMatrixGraph(4).is_strongly_regular(parameters=True) + sage: G = graphs.SquaredSkewHadamardMatrixGraph(4) # needs sage.modules + sage: G.is_strongly_regular(parameters=True) # needs sage.modules (225, 112, 55, 56) - sage: graphs.SquaredSkewHadamardMatrixGraph(5).is_strongly_regular(parameters=True) # long time + sage: G = graphs.SquaredSkewHadamardMatrixGraph(5) # needs sage.modules + sage: G.is_strongly_regular(parameters=True) # long time # needs sage.modules (361, 180, 89, 90) - sage: graphs.SquaredSkewHadamardMatrixGraph(9).is_strongly_regular(parameters=True) # not tested + sage: G = graphs.SquaredSkewHadamardMatrixGraph(9) # needs sage.modules + sage: G.is_strongly_regular(parameters=True) # not tested # needs sage.modules (1225, 612, 305, 306) TESTS:: @@ -2680,13 +2683,14 @@ def SwitchedSquaredSkewHadamardMatrixGraph(n): EXAMPLES:: - sage: g=graphs.SwitchedSquaredSkewHadamardMatrixGraph(4) - sage: g.is_strongly_regular(parameters=True) + sage: g = graphs.SwitchedSquaredSkewHadamardMatrixGraph(4) # needs sage.modules + sage: g.is_strongly_regular(parameters=True) # needs sage.modules (226, 105, 48, 49) sage: from sage.combinat.designs.twographs import twograph_descendant - sage: twograph_descendant(g,0).is_strongly_regular(parameters=True) + sage: twograph_descendant(g, 0).is_strongly_regular(parameters=True) # needs sage.modules (225, 112, 55, 56) - sage: twograph_descendant(g.complement(),0).is_strongly_regular(parameters=True) + sage: gc = g.complement() # needs sage.modules + sage: twograph_descendant(gc, 0).is_strongly_regular(parameters=True) # needs sage.modules (225, 112, 55, 56) TESTS:: @@ -2817,7 +2821,7 @@ def HanoiTowerGraph(pegs, disks, labels=True, positions=True): :: sage: H = graphs.HanoiTowerGraph(3, 4, labels=False, positions=False) - sage: H.automorphism_group().is_isomorphic(SymmetricGroup(3)) # optional - sage.groups + sage: H.automorphism_group().is_isomorphic(SymmetricGroup(3)) # needs sage.groups True sage: H.chromatic_number() 3 @@ -3065,10 +3069,10 @@ def petersen_family(generate=False): The two different inputs generate the same graphs:: sage: F1 = graphs.petersen_family(generate=False) - sage: F2 = graphs.petersen_family(generate=True) + sage: F2 = graphs.petersen_family(generate=True) # needs sage.modules sage: F1 = [g.canonical_label().graph6_string() for g in F1] - sage: F2 = [g.canonical_label().graph6_string() for g in F2] - sage: set(F1) == set(F2) + sage: F2 = [g.canonical_label().graph6_string() for g in F2] # needs sage.modules + sage: set(F1) == set(F2) # needs sage.modules True """ from sage.graphs.generators.smallgraphs import PetersenGraph @@ -3183,13 +3187,13 @@ def SierpinskiGasketGraph(n): EXAMPLES:: - sage: s4 = graphs.SierpinskiGasketGraph(4); s4 + sage: s4 = graphs.SierpinskiGasketGraph(4); s4 # needs sage.modules Graph on 42 vertices - sage: s4.size() + sage: s4.size() # needs sage.modules 81 - sage: s4.degree_histogram() + sage: s4.degree_histogram() # needs sage.modules [0, 0, 3, 0, 39] - sage: s4.is_hamiltonian() + sage: s4.is_hamiltonian() # needs sage.modules True REFERENCES: @@ -3272,9 +3276,9 @@ def GeneralizedSierpinskiGraph(G, k, stretch=None): of `G` are isomorphic to Hanoi Tower graphs:: sage: k = randint(1, 5) - sage: S = graphs.GeneralizedSierpinskiGraph(graphs.CompleteGraph(3), k) + sage: S = graphs.GeneralizedSierpinskiGraph(graphs.CompleteGraph(3), k) # needs sage.modules sage: H = graphs.HanoiTowerGraph(3, k) - sage: S.is_isomorphic(H) + sage: S.is_isomorphic(H) # needs sage.modules True The generalized Sierpinski graph of dimension `k` of any graph `G` with `n` @@ -3284,16 +3288,16 @@ def GeneralizedSierpinskiGraph(G, k, stretch=None): sage: k = randint(1, 5) sage: G = graphs.RandomGNP(n, .5) sage: m = G.size() - sage: S = graphs.GeneralizedSierpinskiGraph(G, k) - sage: S.order() == n**k + sage: S = graphs.GeneralizedSierpinskiGraph(G, k) # needs sage.modules + sage: S.order() == n**k # needs sage.modules True - sage: S.size() == m*sum([n**i for i in range(k)]) + sage: S.size() == m*sum([n**i for i in range(k)]) # needs sage.modules True sage: G = graphs.CompleteGraph(n) - sage: S = graphs.GeneralizedSierpinskiGraph(G, k) - sage: S.order() == n**k + sage: S = graphs.GeneralizedSierpinskiGraph(G, k) # needs sage.modules + sage: S.order() == n**k # needs sage.modules True - sage: S.size() == (n*(n - 1)/2)*sum([n**i for i in range(k)]) + sage: S.size() == (n*(n - 1)/2)*sum([n**i for i in range(k)]) # needs sage.modules True The positions of the vertices of the output graph are determined from the @@ -3302,14 +3306,14 @@ def GeneralizedSierpinskiGraph(G, k, stretch=None): sage: G = graphs.HouseGraph() sage: G.get_pos() is not None True - sage: H = graphs.GeneralizedSierpinskiGraph(G, 2) # optional - sage.symbolic - sage: H.get_pos() is not None # optional - sage.symbolic + sage: H = graphs.GeneralizedSierpinskiGraph(G, 2) # needs sage.symbolic + sage: H.get_pos() is not None # needs sage.symbolic True sage: G = Graph([(0, 1)]) sage: G.get_pos() is not None False - sage: H = graphs.GeneralizedSierpinskiGraph(G, 2) # optional - sage.symbolic - sage: H.get_pos() is not None # optional - sage.symbolic + sage: H = graphs.GeneralizedSierpinskiGraph(G, 2) # needs sage.symbolic + sage: H.get_pos() is not None # needs sage.symbolic False .. PLOT:: @@ -3318,18 +3322,18 @@ def GeneralizedSierpinskiGraph(G, k, stretch=None): TESTS:: - sage: graphs.GeneralizedSierpinskiGraph(Graph(), 3) + sage: graphs.GeneralizedSierpinskiGraph(Graph(), 3) # needs sage.modules Generalized Sierpinski Graph of Graph on 0 vertices of dimension 3: Graph on 0 vertices - sage: graphs.GeneralizedSierpinskiGraph(Graph(1), 3).vertices(sort=False) + sage: graphs.GeneralizedSierpinskiGraph(Graph(1), 3).vertices(sort=False) # needs sage.modules [(0, 0, 0)] - sage: G = graphs.GeneralizedSierpinskiGraph(Graph(2), 3) - sage: G.order(), G.size() + sage: G = graphs.GeneralizedSierpinskiGraph(Graph(2), 3) # needs sage.modules + sage: G.order(), G.size() # needs sage.modules (8, 0) - sage: graphs.GeneralizedSierpinskiGraph("foo", 1) + sage: graphs.GeneralizedSierpinskiGraph("foo", 1) # needs sage.modules Traceback (most recent call last): ... ValueError: parameter G must be a Graph - sage: graphs.GeneralizedSierpinskiGraph(Graph(), 0) + sage: graphs.GeneralizedSierpinskiGraph(Graph(), 0) # needs sage.modules Traceback (most recent call last): ... ValueError: parameter k must be >= 1 @@ -3403,40 +3407,40 @@ def WheelGraph(n): ....: k = graphs.WheelGraph(i+3) ....: g.append(k) ... - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): # needs sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) ... - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) # needs sage.plot + sage: G.show() # long time # needs sage.plot Next, using the spring-layout algorithm:: - sage: import networkx # optional - networkx + sage: import networkx # needs networkx sage: g = [] sage: j = [] - sage: for i in range(9): # optional - networkx + sage: for i in range(9): # needs networkx ....: spr = networkx.wheel_graph(i+3) ....: k = Graph(spr) ....: g.append(k) ... - sage: for i in range(3): # optional - networkx sage.plot + sage: for i in range(3): # needs networkx sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) ... - sage: G = graphics_array(j) # optional - networkx sage.plot - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphics_array(j) # needs networkx sage.plot + sage: G.show() # long time # needs networkx sage.plot Compare the plotting:: - sage: n = networkx.wheel_graph(23) # optional - networkx - sage: spring23 = Graph(n) # optional - networkx + sage: n = networkx.wheel_graph(23) # needs networkx + sage: spring23 = Graph(n) # needs networkx sage: posdict23 = graphs.WheelGraph(23) - sage: spring23.show() # long time # optional - networkx + sage: spring23.show() # long time # needs networkx sage: posdict23.show() # long time """ from sage.graphs.generators.basic import CycleGraph @@ -3740,10 +3744,10 @@ def RingedTree(k, vertex_labels=True): EXAMPLES:: - sage: G = graphs.RingedTree(5) - sage: P = G.plot(vertex_labels=False, vertex_size=10) # optional - sage.plot - sage: P.show() # long time # optional - sage.plot - sage: G.vertices(sort=True) + sage: G = graphs.RingedTree(5) # needs networkx + sage: P = G.plot(vertex_labels=False, vertex_size=10) # needs networkx sage.plot + sage: P.show() # long time # needs networkx sage.plot + sage: G.vertices(sort=True) # needs networkx ['', '0', '00', '000', '0000', '0001', '001', '0010', '0011', '01', '010', '0100', '0101', '011', '0110', '0111', '1', '10', '100', '1000', '1001', '101', '1010', '1011', '11', '110', '1100', '1101', @@ -3755,8 +3759,8 @@ def RingedTree(k, vertex_labels=True): Traceback (most recent call last): ... ValueError: The number of levels must be >= 1. - sage: G = graphs.RingedTree(5, vertex_labels = False) - sage: G.vertices(sort=True) + sage: G = graphs.RingedTree(5, vertex_labels=False) # needs networkx + sage: G.vertices(sort=True) # needs networkx [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30] """ @@ -3828,13 +3832,13 @@ def MathonPseudocyclicMergingGraph(M, t): sage: G = mer(ES(3), 2) # long time sage: G.is_strongly_regular(parameters=True) # long time (784, 297, 116, 110) - sage: G = mer(ES(2), 2) + sage: G = mer(ES(2), 2) # needs sage.libs.gap Traceback (most recent call last): ... AssertionError... - sage: M = ES(3) - sage: M = [M[1],M[0],M[2],M[3]] - sage: G = mer(M, 2) + sage: M = ES(3) # needs sage.libs.gap + sage: M = [M[1],M[0],M[2],M[3]] # needs sage.libs.gap + sage: G = mer(M, 2) # needs sage.libs.gap Traceback (most recent call last): ... AssertionError... @@ -3889,22 +3893,22 @@ def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None): Using default ``G`` and ``L``. :: sage: from sage.graphs.generators.families import MathonPseudocyclicStronglyRegularGraph - sage: G=MathonPseudocyclicStronglyRegularGraph(1); G + sage: G = MathonPseudocyclicStronglyRegularGraph(1); G # needs sage.modules sage.rings.finite_rings Mathon's PC SRG on 45 vertices: Graph on 45 vertices - sage: G.is_strongly_regular(parameters=True) + sage: G.is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings (45, 22, 10, 11) Supplying ``G`` and ``L`` (constructed from the automorphism group of ``G``). :: - sage: G = graphs.PaleyGraph(9) - sage: a = G.automorphism_group(partition=[sorted(G)]) - sage: it = (x for x in a.normal_subgroups() if x.order() == 9) - sage: subg = next(iter(it)) - sage: r = [matrix(libgap.PermutationMat(libgap(z), 9).sage()) + sage: G = graphs.PaleyGraph(9) # needs sage.rings.finite_rings + sage: a = G.automorphism_group(partition=[sorted(G)]) # needs sage.groups sage.rings.finite_rings + sage: it = (x for x in a.normal_subgroups() if x.order() == 9) # needs sage.groups sage.rings.finite_rings + sage: subg = next(iter(it)) # needs sage.groups sage.rings.finite_rings + sage: r = [matrix(libgap.PermutationMat(libgap(z), 9).sage()) # needs sage.groups sage.libs.gap sage.rings.finite_rings ....: for z in subg] - sage: ff = list(map(lambda y: (y[0]-1,y[1]-1), + sage: ff = list(map(lambda y: (y[0]-1,y[1]-1), # needs sage.groups sage.libs.gap sage.rings.finite_rings ....: Permutation(map(lambda x: 1+r.index(x^-1), r)).cycle_tuples()[1:])) - sage: L = sum(i*(r[a]-r[b]) for i,(a,b) in zip(range(1,len(ff)+1), ff)); L + sage: L = sum(i*(r[a]-r[b]) for i,(a,b) in zip(range(1,len(ff)+1), ff)); L # needs sage.groups sage.libs.gap sage.rings.finite_rings [ 0 1 -1 -3 -2 -4 3 4 2] [-1 0 1 -4 -3 -2 2 3 4] [ 1 -1 0 -2 -4 -3 4 2 3] @@ -3915,21 +3919,21 @@ def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None): [-4 -3 -2 2 3 4 -1 0 1] [-2 -4 -3 4 2 3 1 -1 0] - sage: G.relabel(range(9)) - sage: G3x3=graphs.MathonPseudocyclicStronglyRegularGraph(2,G=G,L=L) - sage: G3x3.is_strongly_regular(parameters=True) + sage: G.relabel(range(9)) # needs sage.rings.finite_rings + sage: G3x3 = graphs.MathonPseudocyclicStronglyRegularGraph(2, G=G, L=L) # needs sage.modules sage.rings.finite_rings + sage: G3x3.is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings (441, 220, 109, 110) - sage: G3x3.automorphism_group(algorithm="bliss").order() # optional - bliss + sage: G3x3.automorphism_group(algorithm="bliss").order() # optional - bliss, needs sage.modules sage.rings.finite_rings 27 - sage: G9=graphs.MathonPseudocyclicStronglyRegularGraph(2) - sage: G9.is_strongly_regular(parameters=True) + sage: G9 = graphs.MathonPseudocyclicStronglyRegularGraph(2) # needs sage.modules sage.rings.finite_rings + sage: G9.is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings (441, 220, 109, 110) - sage: G9.automorphism_group(algorithm="bliss").order() # optional - bliss + sage: G9.automorphism_group(algorithm="bliss").order() # optional - bliss, needs sage.modules sage.rings.finite_rings 9 TESTS:: - sage: graphs.MathonPseudocyclicStronglyRegularGraph(5) + sage: graphs.MathonPseudocyclicStronglyRegularGraph(5) # needs sage.modules Traceback (most recent call last): ... ValueError: 21 must be a sum of two squares!... @@ -4123,36 +4127,37 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False): EXAMPLES:: - sage: graphs.MuzychukS6Graph(3, 3).is_strongly_regular(parameters=True) + sage: graphs.MuzychukS6Graph(3, 3).is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings (378, 116, 34, 36) - sage: phi={(2,(0,2)):0,(1,(1,3)):1,(0,(0,3)):1,(2,(1,2)):1,(1,(1, - ....: 2)):0,(0,(0,2)):0,(3,(0,3)):0,(3,(1,3)):1} - sage: graphs.MuzychukS6Graph(2,2,Phi=phi).is_strongly_regular(parameters=True) + sage: phi = {(2,(0,2)):0, (1,(1,3)):1, (0,(0,3)):1, (2,(1,2)):1, # needs sage.modules + ....: (1,(1,2)):0, (0,(0,2)):0, (3,(0,3)):0, (3,(1,3)):1} + sage: graphs.MuzychukS6Graph(2, 2, # needs sage.modules sage.rings.finite_rings + ....: Phi=phi).is_strongly_regular(parameters=True) (16, 5, 0, 2) TESTS:: - sage: graphs.MuzychukS6Graph(2,2,Phi='random',Sigma='random').is_strongly_regular(parameters=True) + sage: graphs.MuzychukS6Graph(2,2,Phi='random',Sigma='random').is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings (16, 5, 0, 2) - sage: graphs.MuzychukS6Graph(3,3,Phi='random',Sigma='random').is_strongly_regular(parameters=True) + sage: graphs.MuzychukS6Graph(3,3,Phi='random',Sigma='random').is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings (378, 116, 34, 36) - sage: graphs.MuzychukS6Graph(3,2) + sage: graphs.MuzychukS6Graph(3,2) # needs sage.modules Traceback (most recent call last): ... AssertionError: n must be even or d must be odd - sage: graphs.MuzychukS6Graph(6,2) + sage: graphs.MuzychukS6Graph(6,2) # needs sage.modules Traceback (most recent call last): ... AssertionError: n must be a prime power - sage: graphs.MuzychukS6Graph(3,1) + sage: graphs.MuzychukS6Graph(3,1) # needs sage.modules Traceback (most recent call last): ... AssertionError: d must be at least 2 - sage: graphs.MuzychukS6Graph(3,3,Phi=42) + sage: graphs.MuzychukS6Graph(3,3,Phi=42) # needs sage.modules sage.rings.finite_rings Traceback (most recent call last): ... AssertionError: Phi must be a dictionary or 'random' or 'fixed' - sage: graphs.MuzychukS6Graph(3,3,Sigma=42) + sage: graphs.MuzychukS6Graph(3,3,Sigma=42) # needs sage.modules sage.rings.finite_rings Traceback (most recent call last): ... ValueError: Sigma must be 'random' or 'fixed' diff --git a/src/sage/graphs/generators/intersection.py b/src/sage/graphs/generators/intersection.py index f2cd8b248ad..06368795029 100644 --- a/src/sage/graphs/generators/intersection.py +++ b/src/sage/graphs/generators/intersection.py @@ -417,9 +417,10 @@ def OrthogonalArrayBlockGraph(k, n, OA=None): EXAMPLES:: - sage: G = graphs.OrthogonalArrayBlockGraph(5,5); G + sage: # needs sage.modules + sage: G = graphs.OrthogonalArrayBlockGraph(5,5); G # needs sage.schemes OA(5,5): Graph on 25 vertices - sage: G.is_strongly_regular(parameters=True) + sage: G.is_strongly_regular(parameters=True) # needs sage.schemes (25, 20, 15, 20) sage: G = graphs.OrthogonalArrayBlockGraph(4,10); G OA(4,10): Graph on 100 vertices @@ -428,20 +429,20 @@ def OrthogonalArrayBlockGraph(k, n, OA=None): Two graphs built from different orthogonal arrays are also different:: - sage: k=4;n=10 - sage: OAa = designs.orthogonal_arrays.build(k,n) - sage: OAb = [[(x+1)%n for x in R] for R in OAa] - sage: set(map(tuple,OAa)) == set(map(tuple,OAb)) + sage: k = 4; n = 10 + sage: OAa = designs.orthogonal_arrays.build(k,n) # needs sage.modules + sage: OAb = [[(x+1)%n for x in R] for R in OAa] # needs sage.modules + sage: set(map(tuple,OAa)) == set(map(tuple,OAb)) # needs sage.modules False - sage: Ga = graphs.OrthogonalArrayBlockGraph(k,n,OAa) - sage: Gb = graphs.OrthogonalArrayBlockGraph(k,n,OAb) - sage: Ga == Gb + sage: Ga = graphs.OrthogonalArrayBlockGraph(k, n, OAa) # needs sage.modules + sage: Gb = graphs.OrthogonalArrayBlockGraph(k, n, OAb) # needs sage.modules + sage: Ga == Gb # needs sage.modules False As ``OAb`` was obtained from ``OAa`` by a relabelling the two graphs are isomorphic:: - sage: Ga.is_isomorphic(Gb) + sage: Ga.is_isomorphic(Gb) # needs sage.modules True But there are examples of `OA(k,n)` for which the resulting graphs are not @@ -455,31 +456,31 @@ def OrthogonalArrayBlockGraph(k, n, OA=None): ....: [1, 0, 3], [1, 1, 2], [1, 2, 0], [1, 3, 1], ....: [2, 0, 0], [2, 1, 1], [2, 2, 2], [2, 3, 3], ....: [3, 0, 2], [3, 1, 3], [3, 2, 1], [3, 3, 0]] - sage: g0 = graphs.OrthogonalArrayBlockGraph(3,4,oa0) - sage: g1 = graphs.OrthogonalArrayBlockGraph(3,4,oa1) - sage: g0.is_isomorphic(g1) + sage: g0 = graphs.OrthogonalArrayBlockGraph(3, 4, oa0) # needs sage.modules + sage: g1 = graphs.OrthogonalArrayBlockGraph(3, 4, oa1) # needs sage.modules + sage: g0.is_isomorphic(g1) # needs sage.modules False But nevertheless isospectral:: - sage: g0.spectrum() + sage: g0.spectrum() # needs sage.modules [9, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3] - sage: g1.spectrum() + sage: g1.spectrum() # needs sage.modules [9, 1, 1, 1, 1, 1, 1, 1, 1, 1, -3, -3, -3, -3, -3, -3] Note that the graph ``g0`` is actually isomorphic to the affine polar graph `VO^+(4,2)`:: - sage: graphs.AffineOrthogonalPolarGraph(4,2,'+').is_isomorphic(g0) + sage: graphs.AffineOrthogonalPolarGraph(4,2,'+').is_isomorphic(g0) # needs sage.modules True TESTS:: - sage: G = graphs.OrthogonalArrayBlockGraph(4,6) + sage: G = graphs.OrthogonalArrayBlockGraph(4,6) # needs sage.modules Traceback (most recent call last): ... NotImplementedError: I don't know how to build an OA(4,6)! - sage: G = graphs.OrthogonalArrayBlockGraph(8,2) + sage: G = graphs.OrthogonalArrayBlockGraph(8,2) # needs sage.modules Traceback (most recent call last): ... ValueError: There is no OA(8,2). Beware, Brouwer's website uses OA(n,k) instead of OA(k,n) ! diff --git a/src/sage/graphs/generators/platonic_solids.py b/src/sage/graphs/generators/platonic_solids.py index f36fa8ecf66..b0f97da83fa 100644 --- a/src/sage/graphs/generators/platonic_solids.py +++ b/src/sage/graphs/generators/platonic_solids.py @@ -43,24 +43,24 @@ def TetrahedralGraph(): The following example requires networkx:: - sage: import networkx as NX # optional - networkx + sage: import networkx as NX # needs networkx Compare this Tetrahedral, Wheel(4), Complete(4), and the Tetrahedral plotted with the spring-layout algorithm below in a Sage graphics array:: sage: tetra_pos = graphs.TetrahedralGraph() - sage: tetra_spring = Graph(NX.tetrahedral_graph()) # optional - networkx + sage: tetra_spring = Graph(NX.tetrahedral_graph()) # needs networkx sage: wheel = graphs.WheelGraph(4) sage: complete = graphs.CompleteGraph(4) - sage: g = [tetra_pos, tetra_spring, wheel, complete] # optional - networkx + sage: g = [tetra_pos, tetra_spring, wheel, complete] # needs networkx sage: j = [] - sage: for i in range(2): # optional - networkx sage.plot + sage: for i in range(2): # needs networkx sage.plot ....: n = [] ....: for m in range(2): ....: n.append(g[i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - networkx sage.plot - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphics_array(j) # needs networkx sage.plot + sage: G.show() # long time # needs networkx sage.plot """ edges = [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] pos = {0: (0, 0), @@ -98,13 +98,13 @@ def HexahedralGraph(): sage: for i in range(9): ....: k = graphs.HexahedralGraph() ....: g.append(k) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): # needs sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) # needs sage.plot + sage: G.show() # long time # needs sage.plot """ adj = {0: [1, 3, 4], 1: [2, 5], 2: [3, 6], 3: [7], 4: [5, 7], 5: [6], 6: [7]} pos = { @@ -150,13 +150,13 @@ def OctahedralGraph(): sage: for i in range(9): ....: k = graphs.OctahedralGraph() ....: g.append(k) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): # needs sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) # needs sage.plot + sage: G.show() # long time # needs sage.plot """ adj = {0: [1, 2, 3, 4], 1: [2, 3, 5], 2: [4, 5], 3: [4, 5], 4: [5]} G = Graph(adj, format='dict_of_lists', name="Octahedron") @@ -194,13 +194,13 @@ def IcosahedralGraph(): sage: for i in range(9): ....: k = graphs.IcosahedralGraph() ....: g.append(k) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): # needs sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) # needs sage.plot + sage: G.show() # long time # needs sage.plot """ adj = {0: [1, 5, 7, 8, 11], 1: [2, 5, 6, 8], 2: [3, 6, 8, 9], 3: [4, 6, 9, 10], 4: [5, 6, 10, 11], 5: [6, 11], @@ -238,13 +238,13 @@ def DodecahedralGraph(): sage: for i in range(9): ....: k = graphs.DodecahedralGraph() ....: g.append(k) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): # needs sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) # needs sage.plot + sage: G.show() # long time # needs sage.plot """ adj = {0: [1, 10, 19], 1: [2, 8], 2: [3, 6], 3: [4, 19], 4: [5, 17], 5: [6, 15], 6: [7], 7: [8, 14], 8: [9], 9: [10, 13], 10: [11], diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index 288515ac397..22459ca6930 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -78,13 +78,13 @@ def RandomGNP(n, p, seed=None, fast=True, algorithm='Sage'): sage: for i in range(9): ....: k = graphs.RandomGNP(i+3,.43) ....: g.append(k) - sage: for i in range(3): # optional - sage.plot + sage: for i in range(3): # needs sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - sage.plot - sage: G.show() # long time # optional - sage.plot + sage: G = graphics_array(j) # needs sage.plot + sage: G.show() # long time # needs sage.plot sage: graphs.RandomGNP(4,1) Complete graph: Graph on 4 vertices @@ -97,7 +97,7 @@ def RandomGNP(n, p, seed=None, fast=True, algorithm='Sage'): sage: set_random_seed(0) sage: graphs.RandomGNP(50,.2, algorithm="Sage").size() 243 - sage: graphs.RandomGNP(50,.2, algorithm="networkx").size() # optional - networkx + sage: graphs.RandomGNP(50,.2, algorithm="networkx").size() # needs networkx 279 # 32-bit 209 # 64-bit """ @@ -149,35 +149,35 @@ def RandomBarabasiAlbert(n, m, seed=None): We show the edge list of a random graph on 6 nodes with `m = 2`:: - sage: G = graphs.RandomBarabasiAlbert(6,2) # optional - networkx - sage: G.order(), G.size() # optional - networkx + sage: G = graphs.RandomBarabasiAlbert(6,2) # needs networkx + sage: G.order(), G.size() # needs networkx (6, 8) - sage: G.degree_sequence() # random # optional - networkx + sage: G.degree_sequence() # random # needs networkx [4, 3, 3, 2, 2, 2] We plot a random graph on 12 nodes with `m = 3`:: - sage: ba = graphs.RandomBarabasiAlbert(12,3) # optional - networkx - sage: ba.show() # long time # optional - networkx sage.plot + sage: ba = graphs.RandomBarabasiAlbert(12,3) # needs networkx + sage: ba.show() # long time # needs networkx sage.plot We view many random graphs using a graphics array:: sage: g = [] sage: j = [] - sage: for i in range(1,10): # optional - networkx + sage: for i in range(1,10): # needs networkx ....: k = graphs.RandomBarabasiAlbert(i+3, 3) ....: g.append(k) - sage: for i in range(3): # optional - networkx sage.plot + sage: for i in range(3): # needs networkx sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - networkx sage.plot - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphics_array(j) # needs networkx sage.plot + sage: G.show() # long time # needs networkx sage.plot When `m = 1`, the generated graph is a tree:: - sage: graphs.RandomBarabasiAlbert(6, 1).is_tree() # optional - networkx + sage: graphs.RandomBarabasiAlbert(6, 1).is_tree() # needs networkx True """ if seed is None: @@ -206,35 +206,36 @@ def RandomBipartite(n1, n2, p, set_position=False, seed=None): EXAMPLES:: - sage: g = graphs.RandomBipartite(5, 2, 0.5) # optional - numpy - sage: g.vertices(sort=True) # optional - numpy + sage: g = graphs.RandomBipartite(5, 2, 0.5) # needs numpy + sage: g.vertices(sort=True) # needs numpy [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1)] TESTS:: - sage: g = graphs.RandomBipartite(5, -3, 0.5) # optional - numpy + sage: g = graphs.RandomBipartite(5, -3, 0.5) # needs numpy Traceback (most recent call last): ... ValueError: n1 and n2 should be integers strictly greater than 0 - sage: g = graphs.RandomBipartite(5, 3, 1.5) # optional - numpy + sage: g = graphs.RandomBipartite(5, 3, 1.5) # needs numpy Traceback (most recent call last): ... ValueError: parameter p is a probability, and so should be a real value between 0 and 1 :trac:`12155`:: - sage: graphs.RandomBipartite(5, 6, .2).complement() # optional - numpy + sage: graphs.RandomBipartite(5, 6, .2).complement() # needs numpy complement(Random bipartite graph of order 5+6 with edge probability 0.200000000000000): Graph on 11 vertices Test assigned positions:: - sage: graphs.RandomBipartite(1, 2, .1, set_position=True).get_pos() # optional - numpy + sage: # needs numpy + sage: graphs.RandomBipartite(1, 2, .1, set_position=True).get_pos() {(0, 0): (1, 1.0), (1, 0): (0, 0), (1, 1): (2.0, 0.0)} - sage: graphs.RandomBipartite(2, 1, .1, set_position=True).get_pos() # optional - numpy + sage: graphs.RandomBipartite(2, 1, .1, set_position=True).get_pos() {(0, 0): (0, 1), (0, 1): (2.0, 1.0), (1, 0): (1, 0.0)} - sage: graphs.RandomBipartite(2, 2, .1, set_position=True).get_pos() # optional - numpy + sage: graphs.RandomBipartite(2, 2, .1, set_position=True).get_pos() {(0, 0): (0, 1), (0, 1): (2.0, 1.0), (1, 0): (0, 0), (1, 1): (2.0, 0.0)} - sage: graphs.RandomBipartite(2, 2, .1, set_position=False).get_pos() # optional - numpy + sage: graphs.RandomBipartite(2, 2, .1, set_position=False).get_pos() """ if not (p >= 0 and p <= 1): @@ -512,7 +513,7 @@ def RandomBlockGraph(m, k, kmax=None, incidence_structure=False, seed=None): sage: m, k = 6, 4 sage: IS = graphs.RandomBlockGraph(m, k, incidence_structure=True) sage: from sage.combinat.designs.incidence_structures import IncidenceStructure - sage: IncidenceStructure(IS) + sage: IncidenceStructure(IS) # needs sage.modules Incidence structure with 19 points and 6 blocks sage: m*(k-1)+1 19 @@ -679,28 +680,28 @@ def RandomGNM(n, m, dense=False, seed=None): We show the edge list of a random graph on 5 nodes with 10 edges:: - sage: graphs.RandomGNM(5, 10).edges(sort=True, labels=False) # optional - networkx + sage: graphs.RandomGNM(5, 10).edges(sort=True, labels=False) # needs networkx [(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] We plot a random graph on 12 nodes with m = 12:: - sage: gnm = graphs.RandomGNM(12, 12) # optional - networkx - sage: gnm.show() # long time # optional - networkx sage.plot + sage: gnm = graphs.RandomGNM(12, 12) # needs networkx + sage: gnm.show() # long time # needs networkx sage.plot We view many random graphs using a graphics array:: sage: g = [] sage: j = [] - sage: for i in range(9): # optional - networkx + sage: for i in range(9): # needs networkx ....: k = graphs.RandomGNM(i+3, i^2-i) ....: g.append(k) - sage: for i in range(3): # optional - networkx sage.plot + sage: for i in range(3): # needs networkx sage.plot ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # optional - networkx sage.plot - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphics_array(j) # needs networkx sage.plot + sage: G.show() # long time # needs networkx sage.plot """ if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) @@ -737,33 +738,34 @@ def RandomNewmanWattsStrogatz(n, k, p, seed=None): We check that the generated graph contains a cycle of order `n`:: - sage: G = graphs.RandomNewmanWattsStrogatz(7, 2, 0.2) # optional - networkx - sage: G.order() # optional - networkx + sage: # needs networkx + sage: G = graphs.RandomNewmanWattsStrogatz(7, 2, 0.2) + sage: G.order() 7 - sage: C7 = graphs.CycleGraph(7) # optional - networkx - sage: G.subgraph_search(C7) # optional - networkx + sage: C7 = graphs.CycleGraph(7) + sage: G.subgraph_search(C7) Subgraph of (): Graph on 7 vertices - sage: G.diameter() <= C7.diameter() # optional - networkx + sage: G.diameter() <= C7.diameter() True :: - sage: G = graphs.RandomNewmanWattsStrogatz(12, 2, .3) # optional - networkx - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphs.RandomNewmanWattsStrogatz(12, 2, .3) # needs networkx + sage: G.show() # long time # needs networkx sage.plot TESTS: We check that when `k = 2` and `p = 0`, the generated graph is a cycle:: - sage: G = graphs.RandomNewmanWattsStrogatz(7, 2, 0) # optional - networkx - sage: G.is_cycle() # optional - networkx + sage: G = graphs.RandomNewmanWattsStrogatz(7, 2, 0) # needs networkx + sage: G.is_cycle() # needs networkx True We check that when `k = 4` and `p = 0`, the generated graph is a circulant graph of parameters ``[1, 2]``:: - sage: G = graphs.RandomNewmanWattsStrogatz(7, 4, 0) # optional - networkx - sage: G.is_isomorphic(graphs.CirculantGraph(7, [1, 2])) # optional - networkx + sage: G = graphs.RandomNewmanWattsStrogatz(7, 4, 0) # needs networkx + sage: G.is_isomorphic(graphs.CirculantGraph(7, [1, 2])) # needs networkx True REFERENCE: @@ -807,8 +809,8 @@ def RandomHolmeKim(n, m, p, seed=None): EXAMPLES:: - sage: G = graphs.RandomHolmeKim(12, 3, .3) # optional - networkx - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphs.RandomHolmeKim(12, 3, .3) # needs networkx + sage: G.show() # long time # needs networkx sage.plot REFERENCE: @@ -952,8 +954,8 @@ def connecting_nodes(T, l): sage: from sage.graphs.generators.random import connecting_nodes sage: T = graphs.RandomTree(10) - sage: S = connecting_nodes(T, 5) # optional - numpy - sage: len(S) # optional - numpy + sage: S = connecting_nodes(T, 5) # needs numpy + sage: len(S) # needs numpy 10 """ from sage.combinat.permutation import Permutations @@ -1178,8 +1180,8 @@ def RandomChordalGraph(n, algorithm="growing", k=None, l=None, f=None, s=None, s sage: T = RandomChordalGraph(20, algorithm="growing", k=5) sage: T.is_chordal() True - sage: T = RandomChordalGraph(20, algorithm="connecting", l=3) # optional - numpy - sage: T.is_chordal() # optional - numpy + sage: T = RandomChordalGraph(20, algorithm="connecting", l=3) # needs numpy + sage: T.is_chordal() # needs numpy True sage: T = RandomChordalGraph(20, algorithm="pruned", f=1/3, s=.5) sage: T.is_chordal() @@ -1303,13 +1305,14 @@ def RandomLobster(n, p, q, seed=None): We check a random graph with 12 backbone nodes and probabilities `p = 0.7` and `q = 0.3`:: - sage: G = graphs.RandomLobster(12, 0.7, 0.3) # optional - networkx - sage: leaves = [v for v in G.vertices(sort=False) if G.degree(v) == 1] # optional - networkx - sage: G.delete_vertices(leaves) # caterpillar # optional - networkx - sage: leaves = [v for v in G.vertices(sort=False) if G.degree(v) == 1] # optional - networkx - sage: G.delete_vertices(leaves) # path # optional - networkx - sage: s = G.degree_sequence() # optional - networkx - sage: if G: # optional - networkx + sage: # needs networkx + sage: G = graphs.RandomLobster(12, 0.7, 0.3) + sage: leaves = [v for v in G.vertices(sort=False) if G.degree(v) == 1] + sage: G.delete_vertices(leaves) # caterpillar + sage: leaves = [v for v in G.vertices(sort=False) if G.degree(v) == 1] + sage: G.delete_vertices(leaves) # path + sage: s = G.degree_sequence() + sage: if G: ....: if G.num_verts() == 1: ....: assert s == [0] ....: else: @@ -1318,8 +1321,8 @@ def RandomLobster(n, p, q, seed=None): :: - sage: G = graphs.RandomLobster(9, .6, .3) # optional - networkx - sage: G.show() # long time # optional - networkx sage.plot + sage: G = graphs.RandomLobster(9, .6, .3) # needs networkx + sage: G.show() # long time # needs networkx sage.plot """ if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) @@ -1434,16 +1437,16 @@ def RandomTreePowerlaw(n, gamma=3, tries=1000, seed=None): We check that the generated graph is a tree:: - sage: G = graphs.RandomTreePowerlaw(10, 3) # optional - networkx - sage: G.is_tree() # optional - networkx + sage: G = graphs.RandomTreePowerlaw(10, 3) # needs networkx + sage: G.is_tree() # needs networkx True - sage: G.order(), G.size() # optional - networkx + sage: G.order(), G.size() # needs networkx (10, 9) :: - sage: G = graphs.RandomTreePowerlaw(15, 2) # optional - networkx - sage: if G: # random output, long time # optional - networkx sage.plot + sage: G = graphs.RandomTreePowerlaw(15, 2) # needs networkx + sage: if G: # random output # long time # needs networkx sage.plot ....: G.show() """ if seed is None: @@ -1474,16 +1477,16 @@ def RandomRegular(d, n, seed=None): We check that a random graph with 8 nodes each of degree 3 is 3-regular:: - sage: G = graphs.RandomRegular(3, 8) # optional - networkx - sage: G.is_regular(k=3) # optional - networkx + sage: G = graphs.RandomRegular(3, 8) # needs networkx + sage: G.is_regular(k=3) # needs networkx True - sage: G.degree_histogram() # optional - networkx + sage: G.degree_histogram() # needs networkx [0, 0, 0, 8] :: - sage: G = graphs.RandomRegular(3, 20) # optional - networkx - sage: if G: # random output, long time # optional - networkx sage.plot + sage: G = graphs.RandomRegular(3, 20) # needs networkx + sage: if G: # random output # long time # needs networkx sage.plot ....: G.show() REFERENCES: @@ -1524,10 +1527,10 @@ def RandomShell(constructor, seed=None): EXAMPLES:: - sage: G = graphs.RandomShell([(10,20,0.8),(20,40,0.8)]) # optional - networkx - sage: G.order(), G.size() # optional - networkx + sage: G = graphs.RandomShell([(10,20,0.8),(20,40,0.8)]) # needs networkx + sage: G.order(), G.size() # needs networkx (30, 52) - sage: G.show() # long time # optional - networkx sage.plot + sage: G.show() # long time # needs networkx sage.plot """ if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) @@ -1889,7 +1892,7 @@ def RandomTriangulation(n, set_position=False, k=3, seed=None): True sage: G.girth() 3 - sage: G.plot(vertex_size=0, vertex_labels=False) # optional - sage.plot + sage: G.plot(vertex_size=0, vertex_labels=False) # needs sage.plot Graphics object consisting of 13 graphics primitives sage: H = graphs.RandomTriangulation(7, k=5) @@ -2005,16 +2008,16 @@ def blossoming_contour(t, shift=0, seed=None): sage: print(blossoming_contour(BinaryTrees(1).an_element())) [('i', 0), ('xb',), ('i', 0), ('xb',), ('i', 0)] - sage: t = BinaryTrees(2).random_element() # optional - sage.combinat - sage: print(blossoming_contour(t)) # random # optional - sage.combinat + sage: t = BinaryTrees(2).random_element() # needs sage.combinat + sage: print(blossoming_contour(t)) # random # needs sage.combinat [('i', 0), ('xb',), ('i', 0), ('n', 2), ('i', 1), ('xb',), ('i', 1), ('xb',), ('i', 1), ('n', 2), ('x',), ('n', 2), ('i', 0)] - sage: w = blossoming_contour(BinaryTrees(3).random_element()); len(w) # optional - sage.combinat + sage: w = blossoming_contour(BinaryTrees(3).random_element()); len(w) # needs sage.combinat 21 - sage: w.count(('xb',)) # optional - sage.combinat + sage: w.count(('xb',)) # needs sage.combinat 4 - sage: w.count(('x',)) # optional - sage.combinat + sage: w.count(('x',)) # needs sage.combinat 2 TESTS:: @@ -2099,16 +2102,16 @@ def RandomBicubicPlanar(n, seed=None): EXAMPLES:: sage: n = randint(200, 300) - sage: G = graphs.RandomBicubicPlanar(n) # optional - sage.combinat - sage: G.order() == 2*n # optional - sage.combinat + sage: G = graphs.RandomBicubicPlanar(n) # needs sage.combinat + sage: G.order() == 2*n # needs sage.combinat True - sage: G.size() == 3*n # optional - sage.combinat + sage: G.size() == 3*n # needs sage.combinat True - sage: G.is_bipartite() and G.is_planar() and G.is_regular(3) # optional - sage.combinat + sage: G.is_bipartite() and G.is_planar() and G.is_regular(3) # needs sage.combinat True - sage: dic = {'red': [v for v in G.vertices(sort=False) if v[0] == 'n'], # optional - sage.combinat + sage: dic = {'red': [v for v in G.vertices(sort=False) if v[0] == 'n'], # needs sage.combinat ....: 'blue': [v for v in G.vertices(sort=False) if v[0] != 'n']} - sage: G.plot(vertex_labels=False, vertex_size=20, vertex_colors=dic) # optional - sage.combinat sage.plot + sage: G.plot(vertex_labels=False, vertex_size=20, vertex_colors=dic) # needs sage.combinat sage.plot Graphics object consisting of ... graphics primitives .. PLOT:: @@ -2212,21 +2215,21 @@ def RandomUnitDiskGraph(n, radius=.1, side=1, seed=None): sage: from sage.misc.randstate import current_randstate sage: seed = current_randstate().seed() - sage: G = graphs.RandomUnitDiskGraph(20, radius=.5, side=1, seed=seed) # optional - scipy - sage: H = graphs.RandomUnitDiskGraph(20, radius=.2, side=1, seed=seed) # optional - scipy - sage: H.is_subgraph(G, induced=False) # optional - scipy + sage: G = graphs.RandomUnitDiskGraph(20, radius=.5, side=1, seed=seed) # needs scipy + sage: H = graphs.RandomUnitDiskGraph(20, radius=.2, side=1, seed=seed) # needs scipy + sage: H.is_subgraph(G, induced=False) # needs scipy True - sage: H.size() <= G.size() # optional - scipy + sage: H.size() <= G.size() # needs scipy True - sage: Gpos = G.get_pos() # optional - scipy - sage: Hpos = H.get_pos() # optional - scipy - sage: all(Gpos[u] == Hpos[u] for u in G) # optional - scipy + sage: Gpos = G.get_pos() # needs scipy + sage: Hpos = H.get_pos() # needs scipy + sage: all(Gpos[u] == Hpos[u] for u in G) # needs scipy True When the radius is more than `\sqrt{2 \text{side}}`, the graph is a clique:: - sage: G = graphs.RandomUnitDiskGraph(10, radius=2, side=1) # optional - scipy - sage: G.is_clique() # optional - scipy + sage: G = graphs.RandomUnitDiskGraph(10, radius=2, side=1) # needs scipy + sage: G.is_clique() # needs scipy True """ if seed is not None: diff --git a/src/sage/graphs/generators/smallgraphs.py b/src/sage/graphs/generators/smallgraphs.py index 27d4fc300ab..e879b708aaf 100644 --- a/src/sage/graphs/generators/smallgraphs.py +++ b/src/sage/graphs/generators/smallgraphs.py @@ -2175,7 +2175,7 @@ def EllinghamHorton54Graph(): It is not Hamiltonian:: - sage: g.is_hamiltonian() # not tested (too long) # needs sage.numerical.mip + sage: g.is_hamiltonian() # not tested # needs sage.numerical.mip False ... and it has a nice drawing :: @@ -2252,7 +2252,7 @@ def EllinghamHorton78Graph(): It is not Hamiltonian:: - sage: g.is_hamiltonian() # not tested (too long) # needs sage.numerical.mip + sage: g.is_hamiltonian() # not tested # needs sage.numerical.mip False ... and it has a nice drawing :: @@ -2734,7 +2734,7 @@ def GrayGraph(embedding=1): 8 sage: g.diameter() 6 - sage: g.show(figsize=[10, 10]) # long time, needs sage.plot + sage: g.show(figsize=[10, 10]) # long time # needs sage.plot sage: graphs.GrayGraph(embedding=2).show(figsize=[10, 10]) # long time, needs sage.plot TESTS:: @@ -4664,12 +4664,6 @@ def WienerArayaGraph(): 4 sage: g.is_planar() True -<<<<<<< HEAD - sage: g.is_hamiltonian() # not tested -- around 30s long - False - sage: g.delete_vertex(g.random_vertex()) - sage: g.is_hamiltonian() -======= sage: g.is_hamiltonian() # not tested (30s) # needs sage.numerical.mip False sage: g.delete_vertex(g.random_vertex()) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 06bee055514..64cdd8dffcb 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -15285,7 +15285,8 @@ def clustering_average(self, implementation=None): sage: # needs networkx sage: G = graphs.RandomGNM(10,20) - sage: impls = ['boost', 'sparse_copy', 'dense_copy', 'networkx'] + sage: impls = ['boost', 'sparse_copy', 'dense_copy'] + sage: impls += ['networkx'] sage: coeffs = [G.clustering_average(implementation=impl) ....: for impl in impls] sage: max(coeffs) - min(coeffs) # tol abs 1e-12 @@ -23150,10 +23151,10 @@ def automorphism_group(self, partition=None, verbosity=0, sage: str(a1) == str(a2) # needs sage.groups False sage: b1 = G.automorphism_group(algorithm='bliss') # optional - bliss - sage: str(a1) == str(b1) # optional - bliss, needs sage.groups + sage: str(a1) == str(b1) # optional - bliss # needs sage.groups True sage: b2 = G.automorphism_group(algorithm='bliss', partition=[V]) # optional - bliss - sage: str(a2) == str(b2) # optional - bliss, needs sage.groups + sage: str(a2) == str(b2) # optional - bliss # needs sage.groups True """ from sage.features.bliss import Bliss diff --git a/src/sage/graphs/generic_graph_pyx.pyx b/src/sage/graphs/generic_graph_pyx.pyx index 45867176382..0e05f3a4ec9 100644 --- a/src/sage/graphs/generic_graph_pyx.pyx +++ b/src/sage/graphs/generic_graph_pyx.pyx @@ -400,7 +400,7 @@ cdef inline double sqrt_approx(double x, double y, double xx, double yy): ....: y = abs(y) ....: return max(x,y) + min(x,y)**2/(2*max(x,y)) - sage: polar_plot([1,lambda x:dist(cos(x),sin(x))], (0, 2*math.pi)) # optional - sage.plot + sage: polar_plot([1,lambda x:dist(cos(x),sin(x))], (0, 2*math.pi)) # needs sage.plot Graphics object consisting of 2 graphics primitives """ if xx < yy: @@ -651,7 +651,7 @@ cdef class SubgraphSearch: EXAMPLES:: sage: g = graphs.PetersenGraph() - sage: g.subgraph_search(graphs.CycleGraph(5)) # optional - sage.modules + sage: g.subgraph_search(graphs.CycleGraph(5)) # needs sage.modules Subgraph of (Petersen graph): Graph on 5 vertices TESTS: @@ -661,11 +661,11 @@ cdef class SubgraphSearch: computations with it:: sage: from sage.graphs.generic_graph_pyx import SubgraphSearch - sage: SubgraphSearch(Graph(5), Graph(1)) # optional - sage.modules + sage: SubgraphSearch(Graph(5), Graph(1)) # needs sage.modules Traceback (most recent call last): ... ValueError: searched graph should have at least 2 vertices - sage: SubgraphSearch(Graph(5), Graph(2)) # optional - sage.modules + sage: SubgraphSearch(Graph(5), Graph(2)) # needs sage.modules """ if H.order() <= 1: @@ -691,8 +691,8 @@ cdef class SubgraphSearch: sage: from sage.graphs.generic_graph_pyx import SubgraphSearch sage: g = graphs.PathGraph(5) sage: h = graphs.PathGraph(3) - sage: S = SubgraphSearch(g, h) # optional - sage.modules - sage: for p in S: # optional - sage.modules + sage: S = SubgraphSearch(g, h) # needs sage.modules + sage: for p in S: # needs sage.modules ....: print(p) [0, 1, 2] [1, 2, 3] @@ -722,8 +722,8 @@ cdef class SubgraphSearch: sage: from sage.graphs.generic_graph_pyx import SubgraphSearch sage: g = graphs.PathGraph(5) sage: h = graphs.PathGraph(3) - sage: S = SubgraphSearch(g, h) # optional - sage.modules - sage: S.cardinality() # optional - sage.modules + sage: S = SubgraphSearch(g, h) # needs sage.modules + sage: S.cardinality() # needs sage.modules 6 Check that the method is working even when vertices or edges are of @@ -734,8 +734,8 @@ cdef class SubgraphSearch: sage: G.add_cycle(['A', 1, 2, 3, ('a', 1)]) sage: H = Graph() sage: H.add_path("xyz") - sage: S = SubgraphSearch(G, H) # optional - sage.modules - sage: S.cardinality() # optional - sage.modules + sage: S = SubgraphSearch(G, H) # needs sage.modules + sage: S.cardinality() # needs sage.modules 10 """ if self.nh > self.ng: @@ -769,18 +769,18 @@ cdef class SubgraphSearch: sage: from sage.graphs.generic_graph_pyx import SubgraphSearch sage: g = graphs.PathGraph(5) sage: h = graphs.PathGraph(3) - sage: S = SubgraphSearch(g, h) # optional - sage.modules - sage: S.__next__() # optional - sage.modules + sage: S = SubgraphSearch(g, h) # needs sage.modules + sage: S.__next__() # needs sage.modules [0, 1, 2] - sage: S._initialization() # optional - sage.modules - sage: S.__next__() # optional - sage.modules + sage: S._initialization() # needs sage.modules + sage: S.__next__() # needs sage.modules [0, 1, 2] TESTS: Check that :trac:`21828` is fixed:: - sage: Poset().is_incomparable_chain_free(1,1) # indirect doctest # optional - sage.modules + sage: Poset().is_incomparable_chain_free(1,1) # indirect doctest # needs sage.modules True """ cdef int i @@ -815,7 +815,7 @@ cdef class SubgraphSearch: EXAMPLES:: sage: g = graphs.PetersenGraph() - sage: g.subgraph_search(graphs.CycleGraph(5)) # optional - sage.modules + sage: g.subgraph_search(graphs.CycleGraph(5)) # needs sage.modules Subgraph of (Petersen graph): Graph on 5 vertices """ self.mem = MemoryAllocator() @@ -904,8 +904,8 @@ cdef class SubgraphSearch: sage: from sage.graphs.generic_graph_pyx import SubgraphSearch sage: g = graphs.PathGraph(5) sage: h = graphs.PathGraph(3) - sage: S = SubgraphSearch(g, h) # optional - sage.modules - sage: S.__next__() # optional - sage.modules + sage: S = SubgraphSearch(g, h) # needs sage.modules + sage: S.__next__() # needs sage.modules [0, 1, 2] """ if not self.ng: diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index e2c86f69d40..c6a32319305 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -106,16 +106,16 @@ 5: [7, 8], 6: [8,9], 7: [9]} sage: G = Graph(d); G Graph on 10 vertices - sage: G.plot().show() # or G.show() # optional - sage.plot + sage: G.plot().show() # or G.show() # needs sage.plot - A NetworkX graph: :: - sage: import networkx # optional - networkx - sage: K = networkx.complete_bipartite_graph(12,7) # optional - networkx - sage: G = Graph(K) # optional - networkx - sage: G.degree() # optional - networkx + sage: import networkx # needs networkx + sage: K = networkx.complete_bipartite_graph(12,7) # needs networkx + sage: G = Graph(K) # needs networkx + sage: G.degree() # needs networkx [7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, 12] - graph6 or sparse6 format: @@ -125,7 +125,7 @@ sage: s = ':I`AKGsaOs`cI]Gb~' sage: G = Graph(s, sparse=True); G Looped multi-graph on 10 vertices - sage: G.plot().show() # or G.show() # optional - sage.plot + sage: G.plot().show() # or G.show() # needs sage.plot Note that the ``\`` character is an escape character in Python, and also a character used by graph6 strings: @@ -142,18 +142,18 @@ :: sage: G = Graph('Ihe\\n@GUA') - sage: G.plot().show() # or G.show() # optional - sage.plot + sage: G.plot().show() # or G.show() # needs sage.plot - adjacency matrix: In an adjacency matrix, each column and each row represent a vertex. If a 1 shows up in row `i`, column `j`, there is an edge `(i,j)`. :: - sage: M = Matrix([(0,1,0,0,1,1,0,0,0,0),(1,0,1,0,0,0,1,0,0,0), \ - (0,1,0,1,0,0,0,1,0,0), (0,0,1,0,1,0,0,0,1,0),(1,0,0,1,0,0,0,0,0,1), \ - (1,0,0,0,0,0,0,1,1,0), (0,1,0,0,0,0,0,0,1,1),(0,0,1,0,0,1,0,0,0,1), \ - (0,0,0,1,0,1,1,0,0,0), (0,0,0,0,1,0,1,1,0,0)]) - sage: M + sage: M = Matrix([(0,1,0,0,1,1,0,0,0,0), (1,0,1,0,0,0,1,0,0,0), # needs sage.modules + ....: (0,1,0,1,0,0,0,1,0,0), (0,0,1,0,1,0,0,0,1,0), + ....: (1,0,0,1,0,0,0,0,0,1), (1,0,0,0,0,0,0,1,1,0), (0,1,0,0,0,0,0,0,1,1), + ....: (0,0,1,0,0,1,0,0,0,1), (0,0,0,1,0,1,1,0,0,0), (0,0,0,0,1,0,1,1,0,0)]) + sage: M # needs sage.modules [0 1 0 0 1 1 0 0 0 0] [1 0 1 0 0 0 1 0 0 0] [0 1 0 1 0 0 0 1 0 0] @@ -164,16 +164,16 @@ [0 0 1 0 0 1 0 0 0 1] [0 0 0 1 0 1 1 0 0 0] [0 0 0 0 1 0 1 1 0 0] - sage: G = Graph(M); G + sage: G = Graph(M); G # needs sage.modules Graph on 10 vertices - sage: G.plot().show() # or G.show() # optional - sage.plot + sage: G.plot().show() # or G.show() # needs sage.modules sage.plot - incidence matrix: In an incidence matrix, each row represents a vertex and each column represents an edge. :: - sage: M = Matrix([(-1, 0, 0, 0, 1, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0), + sage: M = Matrix([(-1, 0, 0, 0, 1, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0), # needs sage.modules ....: ( 1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0), ....: ( 0, 1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0), ....: ( 0, 0, 1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0), @@ -183,7 +183,7 @@ ....: ( 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 0, 0, 1, 0, 0), ....: ( 0, 0, 0, 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 1, 0), ....: ( 0, 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 0, 0, 0, 1)]) - sage: M + sage: M # needs sage.modules [-1 0 0 0 1 0 0 0 0 0 -1 0 0 0 0] [ 1 -1 0 0 0 0 0 0 0 0 0 -1 0 0 0] [ 0 1 -1 0 0 0 0 0 0 0 0 0 -1 0 0] @@ -194,10 +194,10 @@ [ 0 0 0 0 0 1 -1 0 0 0 0 0 1 0 0] [ 0 0 0 0 0 0 0 0 1 -1 0 0 0 1 0] [ 0 0 0 0 0 0 1 -1 0 0 0 0 0 0 1] - sage: G = Graph(M); G + sage: G = Graph(M); G # needs sage.modules Graph on 10 vertices - sage: G.plot().show() # or G.show() # optional - sage.plot - sage: DiGraph(matrix(2,[0,0,-1,1]), format="incidence_matrix") + sage: G.plot().show() # or G.show() # needs sage.modules sage.plot + sage: DiGraph(matrix(2, [0,0,-1,1]), format="incidence_matrix") # needs sage.modules Traceback (most recent call last): ... ValueError: there must be two nonzero entries (-1 & 1) per column @@ -254,10 +254,10 @@ :: sage: G = graphs.PetersenGraph() - sage: G.plot().show() # or G.show() # optional - sage.plot + sage: G.plot().show() # or G.show() # needs sage.plot sage: G.degree_histogram() [0, 0, 0, 10] - sage: G.adjacency_matrix() + sage: G.adjacency_matrix() # needs sage.modules [0 1 0 0 1 1 0 0 0 0] [1 0 1 0 0 0 1 0 0 0] [0 1 0 1 0 0 0 1 0 0] @@ -272,7 +272,7 @@ :: sage: S = G.subgraph([0,1,2,3]) - sage: S.plot().show() # or S.show() # optional - sage.plot + sage: S.plot().show() # or S.show() # needs sage.plot sage: S.density() 1/2 @@ -280,7 +280,7 @@ sage: G = GraphQuery(display_cols=['graph6'], num_vertices=7, diameter=5) sage: L = G.get_graphs_list() - sage: graphs_list.show_graphs(L) # optional - sage.plot + sage: graphs_list.show_graphs(L) # needs sage.plot .. _Graph:labels: @@ -295,8 +295,8 @@ Note that vertex labels themselves cannot be mutable items:: - sage: M = Matrix( [[0,0],[0,0]] ) - sage: G = Graph({ 0 : { M : None } }) + sage: M = Matrix([[0,0], [0,0]]) # needs sage.modules + sage: G = Graph({ 0 : { M : None } }) # needs sage.modules Traceback (most recent call last): ... TypeError: mutable matrices are unhashable @@ -349,7 +349,7 @@ Show each graph as you iterate through the results:: - sage: for g in Q: # optional - sage.plot + sage: for g in Q: # needs sage.plot ....: show(g) Visualization @@ -359,11 +359,11 @@ view the graph in two dimensions via matplotlib with ``show()``. :: sage: G = graphs.RandomGNP(15,.3) - sage: G.show() # optional - sage.plot + sage: G.show() # needs sage.plot And you can view it in three dimensions via jmol with ``show3d()``. :: - sage: G.show3d() # optional - sage.plot + sage: G.show3d() # needs sage.plot Or it can be rendered with `\LaTeX`. This requires the right additions to a standard `\mbox{\rm\TeX}` installation. Then standard Sage commands, such as @@ -608,8 +608,8 @@ class Graph(GenericGraph): 'out' is the label for the edge on 2 and 5. Labels can be used as weights, if all the labels share some common parent.:: - sage: a, b, c, d, e, f = sorted(SymmetricGroup(3)) # optional - sage.groups - sage: Graph({b: {d: 'c', e: 'p'}, c: {d: 'p', e: 'c'}}) # optional - sage.groups + sage: a, b, c, d, e, f = sorted(SymmetricGroup(3)) # needs sage.groups + sage: Graph({b: {d: 'c', e: 'p'}, c: {d: 'p', e: 'c'}}) # needs sage.groups Graph on 4 vertices #. A dictionary of lists:: @@ -623,10 +623,10 @@ class Graph(GenericGraph): Construct the Paley graph over GF(13).:: - sage: g=Graph([GF(13), lambda i,j: i!=j and (i-j).is_square()]) - sage: g.vertices(sort=True) + sage: g = Graph([GF(13), lambda i,j: i!=j and (i-j).is_square()]) # needs sage.rings.finite_rings + sage: g.vertices(sort=True) # needs sage.rings.finite_rings [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] - sage: g.adjacency_matrix() + sage: g.adjacency_matrix() # needs sage.modules sage.rings.finite_rings [0 1 0 1 1 0 0 0 0 1 1 0 1] [1 0 1 0 1 1 0 0 0 0 1 1 0] [0 1 0 1 0 1 1 0 0 0 0 1 1] @@ -649,7 +649,7 @@ class Graph(GenericGraph): loops=False) sage: line_graph.vertices(sort=True) [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] - sage: line_graph.adjacency_matrix() + sage: line_graph.adjacency_matrix() # needs sage.modules [0 1 1 1 1 0] [1 0 1 1 0 1] [1 1 0 0 1 1] @@ -697,7 +697,7 @@ class Graph(GenericGraph): - an adjacency matrix:: - sage: M = graphs.PetersenGraph().am(); M + sage: M = graphs.PetersenGraph().am(); M # needs sage.modules [0 1 0 0 1 1 0 0 0 0] [1 0 1 0 0 0 1 0 0 0] [0 1 0 1 0 0 0 1 0 0] @@ -708,82 +708,84 @@ class Graph(GenericGraph): [0 0 1 0 0 1 0 0 0 1] [0 0 0 1 0 1 1 0 0 0] [0 0 0 0 1 0 1 1 0 0] - sage: Graph(M) + sage: Graph(M) # needs sage.modules Graph on 10 vertices :: - sage: Graph(matrix([[1,2],[2,4]]),loops=True,sparse=True) + sage: Graph(matrix([[1,2], [2,4]]), loops=True, sparse=True) # needs sage.modules Looped multi-graph on 2 vertices - sage: M = Matrix([[0,1,-1],[1,0,-1/2],[-1,-1/2,0]]); M + sage: M = Matrix([[0,1,-1], [1,0,-1/2], [-1,-1/2,0]]); M # needs sage.modules [ 0 1 -1] [ 1 0 -1/2] [ -1 -1/2 0] - sage: G = Graph(M,sparse=True); G + sage: G = Graph(M, sparse=True); G # needs sage.modules Graph on 3 vertices - sage: G.weighted() + sage: G.weighted() # needs sage.modules True - an incidence matrix:: - sage: M = Matrix(6, [-1,0,0,0,1, 1,-1,0,0,0, 0,1,-1,0,0, 0,0,1,-1,0, 0,0,0,1,-1, 0,0,0,0,0]); M + sage: M = Matrix(6, [-1,0,0,0,1, 1,-1,0,0,0, 0,1,-1,0,0, # needs sage.modules + ....: 0,0,1,-1,0, 0,0,0,1,-1, 0,0,0,0,0]); M [-1 0 0 0 1] [ 1 -1 0 0 0] [ 0 1 -1 0 0] [ 0 0 1 -1 0] [ 0 0 0 1 -1] [ 0 0 0 0 0] - sage: Graph(M) + sage: Graph(M) # needs sage.modules Graph on 6 vertices - sage: Graph(Matrix([[1],[1],[1]])) + sage: Graph(Matrix([[1],[1],[1]])) # needs sage.modules Traceback (most recent call last): ... - ValueError: there must be one or two nonzero entries per column in an incidence matrix, got entries [1, 1, 1] in column 0 - sage: Graph(Matrix([[1],[1],[0]])) + ValueError: there must be one or two nonzero entries per column + in an incidence matrix, got entries [1, 1, 1] in column 0 + sage: Graph(Matrix([[1],[1],[0]])) # needs sage.modules Graph on 3 vertices - sage: M = Matrix([[0,1,-1],[1,0,-1],[-1,-1,0]]); M + sage: M = Matrix([[0,1,-1], [1,0,-1], [-1,-1,0]]); M # needs sage.modules [ 0 1 -1] [ 1 0 -1] [-1 -1 0] - sage: Graph(M,sparse=True) + sage: Graph(M, sparse=True) # needs sage.modules Graph on 3 vertices - sage: M = Matrix([[0,1,1],[1,0,1],[-1,-1,0]]); M + sage: M = Matrix([[0,1,1], [1,0,1], [-1,-1,0]]); M # needs sage.modules [ 0 1 1] [ 1 0 1] [-1 -1 0] - sage: Graph(M) + sage: Graph(M) # needs sage.modules Traceback (most recent call last): ... ValueError: there must be one or two nonzero entries per column in an incidence matrix, got entries [1, 1] in column 2 Check that :trac:`9714` is fixed:: - sage: MA = Matrix([[1,2,0], [0,2,0], [0,0,1]]) - sage: GA = Graph(MA, format='adjacency_matrix') - sage: MI = GA.incidence_matrix(oriented=False) - sage: MI + sage: MA = Matrix([[1,2,0], [0,2,0], [0,0,1]]) # needs sage.modules + sage: GA = Graph(MA, format='adjacency_matrix') # needs sage.modules + sage: MI = GA.incidence_matrix(oriented=False); MI # needs sage.modules [2 1 1 0 0 0] [0 1 1 2 2 0] [0 0 0 0 0 2] - sage: Graph(MI).edges(sort=True, labels=None) + sage: Graph(MI).edges(sort=True, labels=None) # needs sage.modules [(0, 0), (0, 1), (0, 1), (1, 1), (1, 1), (2, 2)] - sage: M = Matrix([[1], [-1]]); M + sage: M = Matrix([[1], [-1]]); M # needs sage.modules [ 1] [-1] - sage: Graph(M).edges(sort=True) + sage: Graph(M).edges(sort=True) # needs sage.modules [(0, 1, None)] #. A Seidel adjacency matrix:: - sage: from sage.combinat.matrices.hadamard_matrix import \ - ....: regular_symmetric_hadamard_matrix_with_constant_diagonal as rshcd - sage: m=rshcd(16,1)- matrix.identity(16) - sage: Graph(m,format="seidel_adjacency_matrix").is_strongly_regular(parameters=True) + sage: from sage.combinat.matrices.hadamard_matrix import ( # needs sage.modules + ....: regular_symmetric_hadamard_matrix_with_constant_diagonal as rshcd) + sage: m = rshcd(16,1) - matrix.identity(16) # needs sage.modules + sage: Graph(m, # needs sage.modules + ....: format="seidel_adjacency_matrix").is_strongly_regular(parameters=True) (16, 6, 2, 2) #. List of edges, or labelled edges:: @@ -801,16 +803,16 @@ class Graph(GenericGraph): #. A NetworkX MultiGraph:: - sage: import networkx # optional - networkx - sage: g = networkx.MultiGraph({0:[1,2,3], 2:[4]}) # optional - networkx - sage: Graph(g) # optional - networkx + sage: import networkx # needs networkx + sage: g = networkx.MultiGraph({0:[1,2,3], 2:[4]}) # needs networkx + sage: Graph(g) # needs networkx Multi-graph on 5 vertices #. A NetworkX graph:: - sage: import networkx # optional - networkx - sage: g = networkx.Graph({0:[1,2,3], 2:[4]}) # optional - networkx - sage: DiGraph(g) # optional - networkx + sage: import networkx # needs networkx + sage: g = networkx.Graph({0:[1,2,3], 2:[4]}) # needs networkx + sage: DiGraph(g) # needs networkx Digraph on 5 vertices #. An igraph Graph (see also @@ -883,17 +885,17 @@ class Graph(GenericGraph): ... ValueError: An *undirected* igraph graph was expected. To build an directed graph, call the DiGraph constructor. - sage: m = matrix([[0, -1], [-1, 0]]) - sage: Graph(m, format="seidel_adjacency_matrix") + sage: m = matrix([[0, -1], [-1, 0]]) # needs sage.modules + sage: Graph(m, format="seidel_adjacency_matrix") # needs sage.modules Graph on 2 vertices - sage: m[0,1] = 1 - sage: Graph(m, format="seidel_adjacency_matrix") + sage: m[0,1] = 1 # needs sage.modules + sage: Graph(m, format="seidel_adjacency_matrix") # needs sage.modules Traceback (most recent call last): ... ValueError: the adjacency matrix of a Seidel graph must be symmetric - sage: m[0,1] = -1; m[1,1] = 1 - sage: Graph(m, format="seidel_adjacency_matrix") + sage: m[0,1] = -1; m[1,1] = 1 # needs sage.modules + sage: Graph(m, format="seidel_adjacency_matrix") # needs sage.modules Traceback (most recent call last): ... ValueError: the adjacency matrix of a Seidel graph must have 0s on the main diagonal @@ -907,7 +909,7 @@ class Graph(GenericGraph): Check that :trac:`27505` is fixed:: - sage: Graph(Graph().networkx_graph(), weighted=None, format='NX') + sage: Graph(Graph().networkx_graph(), weighted=None, format='NX') # needs networkx Graph on 0 vertices """ _directed = False @@ -923,12 +925,12 @@ def __init__(self, data=None, pos=None, loops=None, format=None, sage: G = Graph() sage: loads(dumps(G)) == G True - sage: a = matrix(2,2,[1,0,0,1]) - sage: Graph(a).adjacency_matrix() == a + sage: a = matrix(2,2,[1,0,0,1]) # needs sage.modules + sage: Graph(a).adjacency_matrix() == a # needs sage.modules True - sage: a = matrix(2,2,[2,0,0,1]) - sage: Graph(a,sparse=True).adjacency_matrix() == a + sage: a = matrix(2,2,[2,0,0,1]) # needs sage.modules + sage: Graph(a,sparse=True).adjacency_matrix() == a # needs sage.modules True The positions are copied when the graph is built from another graph :: @@ -973,7 +975,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, Verify that the int format works as expected (:trac:`12557`):: - sage: Graph(2).adjacency_matrix() + sage: Graph(2).adjacency_matrix() # needs sage.modules [0 0] [0 0] sage: Graph(3) == Graph(3,format='int') @@ -982,10 +984,10 @@ def __init__(self, data=None, pos=None, loops=None, format=None, Problem with weighted adjacency matrix (:trac:`13919`):: sage: B = {0:{1:2,2:5,3:4},1:{2:2,4:7},2:{3:1,4:4,5:3},3:{5:4},4:{5:1,6:5},5:{6:7}} - sage: grafo3 = Graph(B,weighted=True) - sage: matad = grafo3.weighted_adjacency_matrix() - sage: grafo4 = Graph(matad,format = "adjacency_matrix", weighted=True) - sage: grafo4.shortest_path(0,6,by_weight=True) + sage: grafo3 = Graph(B, weighted=True) + sage: matad = grafo3.weighted_adjacency_matrix() # needs sage.modules + sage: grafo4 = Graph(matad, format="adjacency_matrix", weighted=True) # needs sage.modules + sage: grafo4.shortest_path(0, 6, by_weight=True) # needs sage.modules [0, 1, 2, 5, 4, 6] Graphs returned when setting ``immutable=False`` are mutable:: @@ -1003,15 +1005,17 @@ def __init__(self, data=None, pos=None, loops=None, format=None, Check error messages for graphs built from incidence matrices (see :trac:`18440`):: - sage: Graph(matrix([[-1, 1, 0],[1, 0, 0]])) + sage: Graph(matrix([[-1, 1, 0],[1, 0, 0]])) # needs sage.modules Traceback (most recent call last): ... - ValueError: column 1 of the (oriented) incidence matrix contains only one nonzero value - sage: Graph(matrix([[1,1],[1,1],[1,0]])) + ValueError: column 1 of the (oriented) incidence matrix + contains only one nonzero value + sage: Graph(matrix([[1,1],[1,1],[1,0]])) # needs sage.modules Traceback (most recent call last): ... - ValueError: there must be one or two nonzero entries per column in an incidence matrix, got entries [1, 1, 1] in column 0 - sage: Graph(matrix([[3,1,1],[0,1,1]])) + ValueError: there must be one or two nonzero entries per column + in an incidence matrix, got entries [1, 1, 1] in column 0 + sage: Graph(matrix([[3,1,1],[0,1,1]])) # needs sage.modules Traceback (most recent call last): ... ValueError: each column of a non-oriented incidence matrix must sum to 2, but column 0 does not @@ -1695,7 +1699,7 @@ def is_cactus(self): Test a graph that is not outerplanar, see :trac:`24480`:: - sage: graphs.Balaban10Cage().is_cactus() + sage: graphs.Balaban10Cage().is_cactus() # needs networkx False """ self._scream_if_not_simple() @@ -1816,7 +1820,7 @@ def is_cograph(self): sage: graphs.HouseXGraph().is_cograph() True - sage: graphs.HouseGraph().is_cograph() + sage: graphs.HouseGraph().is_cograph() # needs sage.modules False .. TODO:: @@ -1827,9 +1831,9 @@ def is_cograph(self): TESTS:: - sage: [graphs.PathGraph(i).is_cograph() for i in range(6)] + sage: [graphs.PathGraph(i).is_cograph() for i in range(6)] # needs sage.modules [True, True, True, True, False, False] - sage: graphs.CycleGraph(5).is_cograph() # Self-complemented + sage: graphs.CycleGraph(5).is_cograph() # Self-complemented # needs sage.modules False """ # A cograph has no 4-vertex path as an induced subgraph. @@ -2136,7 +2140,7 @@ def is_overfull(self): sage: g = graphs.ClawGraph() sage: g Claw graph: Graph on 4 vertices - sage: edge_coloring(g, value_only=True) + sage: edge_coloring(g, value_only=True) # needs sage.numerical_mip 3 sage: g.is_overfull() False @@ -2191,7 +2195,7 @@ def is_overfull(self): sage: g.is_overfull() False sage: from sage.graphs.graph_coloring import edge_coloring - sage: max(g.degree()) + 1 == edge_coloring(g, value_only=True) + sage: max(g.degree()) + 1 == edge_coloring(g, value_only=True) # needs sage.numerical_mip True """ # # A possible optimized version. But the gain in speed is very little. @@ -2226,25 +2230,25 @@ def is_even_hole_free(self, certificate=False): Is the Petersen Graph even-hole-free :: sage: g = graphs.PetersenGraph() - sage: g.is_even_hole_free() + sage: g.is_even_hole_free() # needs sage.modules False As any chordal graph is hole-free, interval graphs behave the same way:: sage: g = graphs.RandomIntervalGraph(20) - sage: g.is_even_hole_free() + sage: g.is_even_hole_free() # needs sage.modules True It is clear, though, that a random Bipartite Graph which is not a forest has an even hole:: - sage: g = graphs.RandomBipartite(10, 10, .5) - sage: g.is_even_hole_free() and not g.is_forest() + sage: g = graphs.RandomBipartite(10, 10, .5) # needs numpy + sage: g.is_even_hole_free() and not g.is_forest() # needs numpy sage.modules False We can check the certificate returned is indeed an even cycle:: - sage: if not g.is_forest(): + sage: if not g.is_forest(): # needs numpy sage.modules ....: cycle = g.is_even_hole_free(certificate=True) ....: if cycle.order() % 2 == 1: ....: print("Error !") @@ -2259,17 +2263,18 @@ def is_even_hole_free(self, certificate=False): Bug reported in :trac:`9925`, and fixed by :trac:`9420`:: - sage: g = Graph(':SiBFGaCEF_@CE`DEGH`CEFGaCDGaCDEHaDEF`CEH`ABCDEF', loops=False, multiedges=False) - sage: g.is_even_hole_free() + sage: g = Graph(':SiBFGaCEF_@CE`DEGH`CEFGaCDGaCDEHaDEF`CEH`ABCDEF', + ....: loops=False, multiedges=False) + sage: g.is_even_hole_free() # needs sage.modules False - sage: g.is_even_hole_free(certificate=True) + sage: g.is_even_hole_free(certificate=True) # needs sage.modules Subgraph of (): Graph on 4 vertices Making sure there are no other counter-examples around :: sage: t = lambda x: (Graph(x).is_forest() or ....: isinstance(Graph(x).is_even_hole_free(certificate=True), Graph)) - sage: all( t(graphs.RandomBipartite(10, 10, .5)) for i in range(100) ) + sage: all(t(graphs.RandomBipartite(10, 10, .5)) for i in range(100)) # needs numpy sage.modules True """ girth = self.girth() @@ -2326,7 +2331,7 @@ def is_odd_hole_free(self, certificate=False): Is the Petersen Graph odd-hole-free :: sage: g = graphs.PetersenGraph() - sage: g.is_odd_hole_free() + sage: g.is_odd_hole_free() # needs sage.modules False Which was to be expected, as its girth is 5 :: @@ -2336,14 +2341,14 @@ def is_odd_hole_free(self, certificate=False): We can check the certificate returned is indeed a 5-cycle:: - sage: cycle = g.is_odd_hole_free(certificate=True) - sage: cycle.is_isomorphic(graphs.CycleGraph(5)) + sage: cycle = g.is_odd_hole_free(certificate=True) # needs sage.modules + sage: cycle.is_isomorphic(graphs.CycleGraph(5)) # needs sage.modules True As any chordal graph is hole-free, no interval graph has an odd hole:: sage: g = graphs.RandomIntervalGraph(20) - sage: g.is_odd_hole_free() + sage: g.is_odd_hole_free() # needs sage.modules True """ girth = self.odd_girth() @@ -2409,7 +2414,7 @@ def is_triangle_free(self, algorithm='dense_graph', certificate=False): or a complete Bipartite Graph:: sage: G = graphs.CompleteBipartiteGraph(5,6) - sage: G.is_triangle_free(algorithm='matrix') + sage: G.is_triangle_free(algorithm='matrix') # needs sage.modules True sage: G.is_triangle_free(algorithm='bitset') True @@ -2419,7 +2424,7 @@ def is_triangle_free(self, algorithm='dense_graph', certificate=False): a tripartite graph, though, contains many triangles:: sage: G = (3 * graphs.CompleteGraph(5)).complement() - sage: G.is_triangle_free(algorithm='matrix') + sage: G.is_triangle_free(algorithm='matrix') # needs sage.modules False sage: G.is_triangle_free(algorithm='bitset') False @@ -2542,8 +2547,11 @@ def is_split(self): graph if and only if does not contain the 4-cycle, 5-cycle or `2K_2` as an induced subgraph. Hence for the above graph we have:: - sage: forbidden_subgraphs = [graphs.CycleGraph(4), graphs.CycleGraph(5), 2 * graphs.CompleteGraph(2)] - sage: sum(g.subgraph_search_count(H,induced=True) for H in forbidden_subgraphs) + sage: forbidden_subgraphs = [graphs.CycleGraph(4), + ....: graphs.CycleGraph(5), + ....: 2 * graphs.CompleteGraph(2)] + sage: sum(g.subgraph_search_count(H, induced=True) # needs sage.modules + ....: for H in forbidden_subgraphs) 0 """ self._scream_if_not_simple() @@ -2593,45 +2601,45 @@ def is_perfect(self, certificate=False): A Bipartite Graph is always perfect :: - sage: g = graphs.RandomBipartite(8,4,.5) - sage: g.is_perfect() + sage: g = graphs.RandomBipartite(8,4,.5) # needs numpy + sage: g.is_perfect() # needs numpy sage.modules True So is the line graph of a bipartite graph:: - sage: g = graphs.RandomBipartite(4,3,0.7) - sage: g.line_graph().is_perfect() # long time + sage: g = graphs.RandomBipartite(4,3,0.7) # needs numpy + sage: g.line_graph().is_perfect() # long time # needs numpy sage.modules True As well as the Cartesian product of two complete graphs:: sage: g = graphs.CompleteGraph(3).cartesian_product(graphs.CompleteGraph(3)) - sage: g.is_perfect() + sage: g.is_perfect() # needs sage.modules True Interval Graphs, which are chordal graphs, too :: sage: g = graphs.RandomIntervalGraph(7) - sage: g.is_perfect() + sage: g.is_perfect() # needs sage.modules True The PetersenGraph, which is triangle-free and has chromatic number 3 is obviously not perfect:: sage: g = graphs.PetersenGraph() - sage: g.is_perfect() + sage: g.is_perfect() # needs sage.modules False We can obtain an induced 5-cycle as a certificate:: - sage: g.is_perfect(certificate=True) + sage: g.is_perfect(certificate=True) # needs sage.modules Subgraph of (Petersen graph): Graph on 5 vertices TESTS: Check that :trac:`13546` has been fixed:: - sage: Graph(':FgGE@I@GxGs', loops=False, multiedges=False).is_perfect() + sage: Graph(':FgGE@I@GxGs', loops=False, multiedges=False).is_perfect() # needs sage.modules False sage: g = Graph({0: [2, 3, 4, 5], ....: 1: [3, 4, 5, 6], @@ -2640,12 +2648,12 @@ def is_perfect(self, certificate=False): ....: 4: [0, 1, 2, 6], ....: 5: [0, 1, 2, 3], ....: 6: [1, 2, 3, 4]}) - sage: g.is_perfect() + sage: g.is_perfect() # needs sage.modules False TESTS:: - sage: Graph(':Ab').is_perfect() + sage: Graph(':Ab').is_perfect() # needs sage.modules Traceback (most recent call last): ... ValueError: This method is only defined for simple graphs, and yours is not one of them ! @@ -2654,7 +2662,7 @@ def is_perfect(self, certificate=False): sage: g.add_edge(0,0) sage: g.edges(sort=True) [(0, 0, None)] - sage: g.is_perfect() + sage: g.is_perfect() # needs sage.modules Traceback (most recent call last): ... ValueError: This method is only defined for simple graphs, and yours is not one of them ! @@ -2701,16 +2709,16 @@ def is_edge_transitive(self): EXAMPLES:: sage: P = graphs.PetersenGraph() - sage: P.is_edge_transitive() + sage: P.is_edge_transitive() # needs sage.libs.gap True sage: C = graphs.CubeGraph(3) - sage: C.is_edge_transitive() + sage: C.is_edge_transitive() # needs sage.libs.gap True - sage: G = graphs.GrayGraph() - sage: G.is_edge_transitive() + sage: G = graphs.GrayGraph() # needs networkx + sage: G.is_edge_transitive() # needs networkx sage.libs.gap True sage: P = graphs.PathGraph(4) - sage: P.is_edge_transitive() + sage: P.is_edge_transitive() # needs sage.libs.gap False """ from sage.libs.gap.libgap import libgap @@ -2747,10 +2755,10 @@ def is_arc_transitive(self): EXAMPLES:: sage: P = graphs.PetersenGraph() - sage: P.is_arc_transitive() + sage: P.is_arc_transitive() # needs sage.libs.gap True - sage: G = graphs.GrayGraph() - sage: G.is_arc_transitive() + sage: G = graphs.GrayGraph() # needs networkx + sage: G.is_arc_transitive() # needs networkx sage.libs.gap False """ from sage.libs.gap.libgap import libgap @@ -2784,13 +2792,13 @@ def is_half_transitive(self): The Petersen Graph is not half-transitive:: sage: P = graphs.PetersenGraph() - sage: P.is_half_transitive() + sage: P.is_half_transitive() # needs sage.libs.gap False The smallest half-transitive graph is the Holt Graph:: sage: H = graphs.HoltGraph() - sage: H.is_half_transitive() + sage: H.is_half_transitive() # needs sage.libs.gap True """ # A half-transitive graph always has only vertices of even degree @@ -2821,19 +2829,19 @@ def is_semi_symmetric(self): The Petersen graph is not semi-symmetric:: sage: P = graphs.PetersenGraph() - sage: P.is_semi_symmetric() + sage: P.is_semi_symmetric() # needs sage.libs.gap False The Gray graph is the smallest possible cubic semi-symmetric graph:: - sage: G = graphs.GrayGraph() - sage: G.is_semi_symmetric() + sage: G = graphs.GrayGraph() # needs networkx + sage: G.is_semi_symmetric() # needs networkx sage.libs.gap True Another well known semi-symmetric graph is the Ljubljana graph:: - sage: L = graphs.LjubljanaGraph() - sage: L.is_semi_symmetric() + sage: L = graphs.LjubljanaGraph() # needs networkx + sage: L.is_semi_symmetric() # needs networkx sage.libs.gap True """ # A semi-symmetric graph is always bipartite @@ -2955,8 +2963,8 @@ def degree_constrained_subgraph(self, bounds, solver=None, verbose=0, sage: g = graphs.CycleGraph(6) sage: bounds = lambda x: [1,1] - sage: m = g.degree_constrained_subgraph(bounds=bounds) - sage: m.size() + sage: m = g.degree_constrained_subgraph(bounds=bounds) # needs sage.numerical.mip + sage: m.size() # needs sage.numerical.mip 3 """ self._scream_if_not_simple() @@ -3161,8 +3169,8 @@ def minimum_outdegree_orientation(self, use_edge_labels=False, solver=None, verb optimal orientation is `\left\lceil \frac {nm} {n+m}\right\rceil`:: sage: g = graphs.CompleteBipartiteGraph(3,4) - sage: o = g.minimum_outdegree_orientation() - sage: max(o.out_degree()) == integer_ceil((4*3)/(3+4)) + sage: o = g.minimum_outdegree_orientation() # needs sage.numerical.mip + sage: max(o.out_degree()) == integer_ceil((4*3)/(3+4)) # needs sage.numerical.mip True """ self._scream_if_not_simple() @@ -3632,23 +3640,23 @@ def chromatic_index(self, solver=None, verbose=0, *, integrality_tolerance=1e-3) The path `P_n` with `n \geq 2` has chromatic index 2:: - sage: graphs.PathGraph(5).chromatic_index() + sage: graphs.PathGraph(5).chromatic_index() # needs sage.numerical.mip 2 The windmill graph with parameters `k,n` has chromatic index `(k-1)n`:: sage: k,n = 3,4 sage: G = graphs.WindmillGraph(k,n) - sage: G.chromatic_index() == (k-1)*n + sage: G.chromatic_index() == (k-1)*n # needs sage.numerical.mip True TESTS: Graphs without vertices or edges:: - sage: Graph().chromatic_index() + sage: Graph().chromatic_index() # needs sage.numerical.mip 0 - sage: Graph(2).chromatic_index() + sage: Graph(2).chromatic_index() # needs sage.numerical.mip 0 """ if not self.order() or not self.size(): @@ -3725,7 +3733,7 @@ def chromatic_number(self, algorithm="DLX", solver=None, verbose=0, A bipartite graph has (by definition) chromatic number 2:: - sage: graphs.RandomBipartite(50,50,0.7).chromatic_number() + sage: graphs.RandomBipartite(50,50,0.7).chromatic_number() # needs numpy 2 A complete multipartite graph with k parts has chromatic number `k`:: @@ -3855,14 +3863,13 @@ def coloring(self, algorithm="DLX", hex_colors=False, solver=None, verbose=0, True sage: are_equal_colorings(P, Q) True - sage: G.plot(partition=P) # optional - sage.plot + sage: G.plot(partition=P) # needs sage.plot Graphics object consisting of 16 graphics primitives - sage: G.coloring(hex_colors=True, algorithm="MILP") + sage: G.coloring(hex_colors=True, algorithm="MILP") # needs sage.plot {'#0000ff': [4], '#00ff00': [0, 6, 5], '#ff0000': [2, 1, 3]} - sage: H = G.coloring(hex_colors=True, algorithm="DLX") - sage: H + sage: H = G.coloring(hex_colors=True, algorithm="DLX"); H # needs sage.plot {'#0000ff': [4], '#00ff00': [1, 2, 3], '#ff0000': [0, 5, 6]} - sage: G.plot(vertex_colors=H) # optional - sage.plot + sage: G.plot(vertex_colors=H) # needs sage.plot Graphics object consisting of 16 graphics primitives .. PLOT:: @@ -3911,37 +3918,37 @@ def chromatic_symmetric_function(self, R=None): EXAMPLES:: - sage: s = SymmetricFunctions(ZZ).s() + sage: s = SymmetricFunctions(ZZ).s() # needs sage.combinat sage.modules sage: G = graphs.CycleGraph(5) - sage: XG = G.chromatic_symmetric_function(); XG + sage: XG = G.chromatic_symmetric_function(); XG # needs sage.combinat sage.modules p[1, 1, 1, 1, 1] - 5*p[2, 1, 1, 1] + 5*p[2, 2, 1] + 5*p[3, 1, 1] - 5*p[3, 2] - 5*p[4, 1] + 4*p[5] - sage: s(XG) + sage: s(XG) # needs sage.combinat sage.modules 30*s[1, 1, 1, 1, 1] + 10*s[2, 1, 1, 1] + 10*s[2, 2, 1] Not all graphs have a positive Schur expansion:: sage: G = graphs.ClawGraph() - sage: XG = G.chromatic_symmetric_function(); XG + sage: XG = G.chromatic_symmetric_function(); XG # needs sage.combinat sage.modules p[1, 1, 1, 1] - 3*p[2, 1, 1] + 3*p[3, 1] - p[4] - sage: s(XG) + sage: s(XG) # needs sage.combinat sage.modules 8*s[1, 1, 1, 1] + 5*s[2, 1, 1] - s[2, 2] + s[3, 1] We show that given a triangle `\{e_1, e_2, e_3\}`, we have `X_G = X_{G - e_1} + X_{G - e_2} - X_{G - e_1 - e_2}`:: sage: G = Graph([[1,2],[1,3],[2,3]]) - sage: XG = G.chromatic_symmetric_function() + sage: XG = G.chromatic_symmetric_function() # needs sage.combinat sage.modules sage: G1 = copy(G) sage: G1.delete_edge([1,2]) - sage: XG1 = G1.chromatic_symmetric_function() + sage: XG1 = G1.chromatic_symmetric_function() # needs sage.combinat sage.modules sage: G2 = copy(G) sage: G2.delete_edge([1,3]) - sage: XG2 = G2.chromatic_symmetric_function() + sage: XG2 = G2.chromatic_symmetric_function() # needs sage.combinat sage.modules sage: G3 = copy(G1) sage: G3.delete_edge([1,3]) - sage: XG3 = G3.chromatic_symmetric_function() - sage: XG == XG1 + XG2 - XG3 + sage: XG3 = G3.chromatic_symmetric_function() # needs sage.combinat sage.modules + sage: XG == XG1 + XG2 - XG3 # needs sage.combinat sage.modules True """ from sage.combinat.sf.sf import SymmetricFunctions @@ -3988,44 +3995,44 @@ def chromatic_quasisymmetric_function(self, t=None, R=None): EXAMPLES:: sage: G = Graph([[1,2,3], [[1,3], [2,3]]]) - sage: G.chromatic_quasisymmetric_function() + sage: G.chromatic_quasisymmetric_function() # needs sage.combinat sage.modules (2*t^2+2*t+2)*M[1, 1, 1] + M[1, 2] + t^2*M[2, 1] sage: G = graphs.PathGraph(4) - sage: XG = G.chromatic_quasisymmetric_function(); XG + sage: XG = G.chromatic_quasisymmetric_function(); XG # needs sage.combinat sage.modules (t^3+11*t^2+11*t+1)*M[1, 1, 1, 1] + (3*t^2+3*t)*M[1, 1, 2] + (3*t^2+3*t)*M[1, 2, 1] + (3*t^2+3*t)*M[2, 1, 1] + (t^2+t)*M[2, 2] - sage: XG.to_symmetric_function() + sage: XG.to_symmetric_function() # needs sage.combinat sage.modules (t^3+11*t^2+11*t+1)*m[1, 1, 1, 1] + (3*t^2+3*t)*m[2, 1, 1] + (t^2+t)*m[2, 2] sage: G = graphs.CompleteGraph(4) - sage: G.chromatic_quasisymmetric_function() + sage: G.chromatic_quasisymmetric_function() # needs sage.combinat sage.modules (t^6+3*t^5+5*t^4+6*t^3+5*t^2+3*t+1)*M[1, 1, 1, 1] Not all chromatic quasisymmetric functions are symmetric:: sage: G = Graph([[1,2], [1,5], [3,4], [3,5]]) - sage: G.chromatic_quasisymmetric_function().is_symmetric() + sage: G.chromatic_quasisymmetric_function().is_symmetric() # needs sage.combinat sage.modules False We check that at `t = 1`, we recover the usual chromatic symmetric function:: - sage: p = SymmetricFunctions(QQ).p() + sage: p = SymmetricFunctions(QQ).p() # needs sage.combinat sage.modules sage: G = graphs.CycleGraph(5) - sage: XG = G.chromatic_quasisymmetric_function(t=1); XG + sage: XG = G.chromatic_quasisymmetric_function(t=1); XG # needs sage.combinat sage.modules 120*M[1, 1, 1, 1, 1] + 30*M[1, 1, 1, 2] + 30*M[1, 1, 2, 1] + 30*M[1, 2, 1, 1] + 10*M[1, 2, 2] + 30*M[2, 1, 1, 1] + 10*M[2, 1, 2] + 10*M[2, 2, 1] - sage: p(XG.to_symmetric_function()) + sage: p(XG.to_symmetric_function()) # needs sage.combinat sage.modules p[1, 1, 1, 1, 1] - 5*p[2, 1, 1, 1] + 5*p[2, 2, 1] + 5*p[3, 1, 1] - 5*p[3, 2] - 5*p[4, 1] + 4*p[5] sage: G = graphs.ClawGraph() - sage: XG = G.chromatic_quasisymmetric_function(t=1); XG + sage: XG = G.chromatic_quasisymmetric_function(t=1); XG # needs sage.combinat sage.modules 24*M[1, 1, 1, 1] + 6*M[1, 1, 2] + 6*M[1, 2, 1] + M[1, 3] + 6*M[2, 1, 1] + M[3, 1] - sage: p(XG.to_symmetric_function()) + sage: p(XG.to_symmetric_function()) # needs sage.combinat sage.modules p[1, 1, 1, 1] - 3*p[2, 1, 1] + 3*p[3, 1] - p[4] """ from sage.combinat.ncsf_qsym.qsym import QuasiSymmetricFunctions @@ -4129,7 +4136,7 @@ def matching(self, value_only=False, algorithm="Edmonds", Maximum matching in a Pappus Graph:: sage: g = graphs.PappusGraph() - sage: g.matching(value_only=True) + sage: g.matching(value_only=True) # needs sage.networkx 9 Same test with the Linear Program formulation:: @@ -4149,7 +4156,7 @@ def matching(self, value_only=False, algorithm="Edmonds", and LP formulation:: sage: g = Graph([(0,1,0), (1,2,999), (2,3,-5)]) - sage: sorted(g.matching()) + sage: sorted(g.matching()) # needs sage.networkx [(0, 1, 0), (2, 3, -5)] sage: sorted(g.matching(algorithm="LP")) [(0, 1, 0), (2, 3, -5)] @@ -4158,7 +4165,7 @@ def matching(self, value_only=False, algorithm="Edmonds", LP formulation:: sage: g = Graph([(0,1,0), (1,2,999), (2,3,-5)]) - sage: g.matching(use_edge_labels=True) + sage: g.matching(use_edge_labels=True) # needs sage.networkx [(1, 2, 999)] sage: g.matching(algorithm="LP", use_edge_labels=True) [(1, 2, 999)] @@ -4168,10 +4175,10 @@ def matching(self, value_only=False, algorithm="Edmonds", sage: edge_list = [(0,0,5), (0,1,1), (0,2,2), (0,3,3), (1,2,6) ....: , (1,2,3), (1,3,3), (2,3,3)] sage: g = Graph(edge_list, loops=True, multiedges=True) - sage: m = g.matching(use_edge_labels=True) - sage: type(m) + sage: m = g.matching(use_edge_labels=True) # needs sage.networkx + sage: type(m) # needs sage.networkx - sage: sorted(m) + sage: sorted(m) # needs sage.networkx [(0, 3, 3), (1, 2, 6)] TESTS: @@ -4306,9 +4313,9 @@ def is_factor_critical(self, matching=None, algorithm='Edmonds', solver=None, ve Odd length cycles and odd cliques of order at least 3 are factor-critical graphs:: - sage: [graphs.CycleGraph(2*i + 1).is_factor_critical() for i in range(5)] + sage: [graphs.CycleGraph(2*i + 1).is_factor_critical() for i in range(5)] # needs networkx [True, True, True, True, True] - sage: [graphs.CompleteGraph(2*i + 1).is_factor_critical() for i in range(5)] + sage: [graphs.CompleteGraph(2*i + 1).is_factor_critical() for i in range(5)] # needs networkx [True, True, True, True, True] More generally, every Hamiltonian graph with an odd number of vertices @@ -4319,18 +4326,18 @@ def is_factor_critical(self, matching=None, algorithm='Edmonds', solver=None, ve sage: G.add_edge(14, 0) sage: G.is_hamiltonian() True - sage: G.is_factor_critical() + sage: G.is_factor_critical() # needs networkx True Friendship graphs are non-Hamiltonian factor-critical graphs:: - sage: [graphs.FriendshipGraph(i).is_factor_critical() for i in range(1, 5)] + sage: [graphs.FriendshipGraph(i).is_factor_critical() for i in range(1, 5)] # needs networkx [True, True, True, True] Bipartite graphs are not factor-critical:: - sage: G = graphs.RandomBipartite(randint(1, 10), randint(1, 10), .5) - sage: G.is_factor_critical() + sage: G = graphs.RandomBipartite(randint(1, 10), randint(1, 10), .5) # needs numpy + sage: G.is_factor_critical() # needs numpy False Graphs with even order are not factor critical:: @@ -4342,10 +4349,10 @@ def is_factor_critical(self, matching=None, algorithm='Edmonds', solver=None, ve One can specify a matching:: sage: F = graphs.FriendshipGraph(4) - sage: M = F.matching() - sage: F.is_factor_critical(matching=M) + sage: M = F.matching() # needs networkx + sage: F.is_factor_critical(matching=M) # needs networkx True - sage: F.is_factor_critical(matching=Graph(M)) + sage: F.is_factor_critical(matching=Graph(M)) # needs networkx True TESTS: @@ -4355,8 +4362,8 @@ def is_factor_critical(self, matching=None, algorithm='Edmonds', solver=None, ve sage: G = graphs.RandomGNP(15, .3) sage: while not G.is_biconnected(): ....: G = graphs.RandomGNP(15, .3) - sage: M = G.matching() - sage: G.is_factor_critical(matching=M[:-1]) + sage: M = G.matching() # needs networkx + sage: G.is_factor_critical(matching=M[:-1]) # needs networkx Traceback (most recent call last): ... ValueError: the input is not a near perfect matching of the graph @@ -4498,8 +4505,8 @@ def has_homomorphism_to(self, H, core=False, solver=None, verbose=0, with this method :: sage: g = graphs.CycleGraph(10) - sage: mapping = g.has_homomorphism_to(g, core = True) - sage: print("The size of the core is {}".format(len(set(mapping.values())))) + sage: mapping = g.has_homomorphism_to(g, core=True) # needs sage.numerical.mip + sage: print("The size of the core is {}".format(len(set(mapping.values())))) # needs sage.numerical.mip The size of the core is 2 OUTPUT: @@ -4513,18 +4520,18 @@ def has_homomorphism_to(self, H, core=False, solver=None, verbose=0, Is Petersen's graph 3-colorable:: sage: P = graphs.PetersenGraph() - sage: P.has_homomorphism_to(graphs.CompleteGraph(3)) is not False + sage: P.has_homomorphism_to(graphs.CompleteGraph(3)) is not False # needs sage.numerical.mip True An odd cycle admits a homomorphism to a smaller odd cycle, but not to an even cycle:: sage: g = graphs.CycleGraph(9) - sage: g.has_homomorphism_to(graphs.CycleGraph(5)) is not False + sage: g.has_homomorphism_to(graphs.CycleGraph(5)) is not False # needs sage.numerical.mip True - sage: g.has_homomorphism_to(graphs.CycleGraph(7)) is not False + sage: g.has_homomorphism_to(graphs.CycleGraph(7)) is not False # needs sage.numerical.mip True - sage: g.has_homomorphism_to(graphs.CycleGraph(4)) is not False + sage: g.has_homomorphism_to(graphs.CycleGraph(4)) is not False # needs sage.numerical.mip False """ self._scream_if_not_simple() @@ -4616,7 +4623,7 @@ def fractional_clique_number(self, solver='PPL', verbose=0, The fractional clique number of a `C_7` is `7/3`:: sage: g = graphs.CycleGraph(7) - sage: g.fractional_clique_number() + sage: g.fractional_clique_number() # needs sage.numerical.mip 7/3 """ return self.fractional_chromatic_number(solver=solver, verbose=verbose, @@ -4660,48 +4667,48 @@ def maximum_average_degree(self, value_only=True, solver=None, verbose=0): In any graph, the `Mad` is always larger than the average degree:: sage: g = graphs.RandomGNP(20,.3) - sage: mad_g = g.maximum_average_degree() - sage: g.average_degree() <= mad_g + sage: mad_g = g.maximum_average_degree() # needs sage.numerical.mip + sage: g.average_degree() <= mad_g # needs sage.numerical.mip True Unlike the average degree, the `Mad` of the disjoint union of two graphs is the maximum of the `Mad` of each graphs:: sage: h = graphs.RandomGNP(20,.3) - sage: mad_h = h.maximum_average_degree() - sage: (g+h).maximum_average_degree() == max(mad_g, mad_h) + sage: mad_h = h.maximum_average_degree() # needs sage.numerical.mip + sage: (g+h).maximum_average_degree() == max(mad_g, mad_h) # needs sage.numerical.mip True The subgraph of a regular graph realizing the maximum average degree is always the whole graph :: sage: g = graphs.CompleteGraph(5) - sage: mad_g = g.maximum_average_degree(value_only=False) - sage: g.is_isomorphic(mad_g) + sage: mad_g = g.maximum_average_degree(value_only=False) # needs sage.numerical.mip + sage: g.is_isomorphic(mad_g) # needs sage.numerical.mip True This also works for complete bipartite graphs :: sage: g = graphs.CompleteBipartiteGraph(3,4) - sage: mad_g = g.maximum_average_degree(value_only=False) - sage: g.is_isomorphic(mad_g) + sage: mad_g = g.maximum_average_degree(value_only=False) # needs sage.numerical.mip + sage: g.is_isomorphic(mad_g) # needs sage.numerical.mip True TESTS: Check corner cases:: - sage: Graph().maximum_average_degree(value_only=True) + sage: Graph().maximum_average_degree(value_only=True) # needs sage.numerical.mip 0 - sage: Graph().maximum_average_degree(value_only=False) + sage: Graph().maximum_average_degree(value_only=False) # needs sage.numerical.mip Graph on 0 vertices - sage: Graph(1).maximum_average_degree(value_only=True) + sage: Graph(1).maximum_average_degree(value_only=True) # needs sage.numerical.mip 0 - sage: Graph(1).maximum_average_degree(value_only=False) + sage: Graph(1).maximum_average_degree(value_only=False) # needs sage.numerical.mip Graph on 1 vertex - sage: Graph(2).maximum_average_degree(value_only=True) + sage: Graph(2).maximum_average_degree(value_only=True) # needs sage.numerical.mip 0 - sage: Graph(2).maximum_average_degree(value_only=False) + sage: Graph(2).maximum_average_degree(value_only=False) # needs sage.numerical.mip Graph on 1 vertex """ self._scream_if_not_simple() @@ -4794,7 +4801,7 @@ def independent_set_of_representatives(self, family, solver=None, verbose=0, sage: g = graphs.CompleteBipartiteGraph(3,3) sage: g.delete_edge(1,4) - sage: g.independent_set_of_representatives([[0,1,2],[3,4,5]]) + sage: g.independent_set_of_representatives([[0,1,2],[3,4,5]]) # needs sage.numerical.mip [1, 4] The Petersen Graph is 3-colorable, which can be expressed as an @@ -4806,12 +4813,12 @@ def independent_set_of_representatives(self, family, solver=None, verbose=0, sage: g = 3 * graphs.PetersenGraph() sage: n = g.order() / 3 sage: f = [[i, i + n, i + 2*n] for i in range(n)] - sage: isr = g.independent_set_of_representatives(f) - sage: c = [integer_floor(i / n) for i in isr] + sage: isr = g.independent_set_of_representatives(f) # needs sage.numerical.mip + sage: c = [integer_floor(i / n) for i in isr] # needs sage.numerical.mip sage: color_classes = [[], [], []] - sage: for v, i in enumerate(c): + sage: for v, i in enumerate(c): # needs sage.numerical.mip ....: color_classes[i].append(v) - sage: for classs in color_classes: + sage: for classs in color_classes: # needs sage.numerical.mip ....: g.subgraph(classs).size() == 0 True True @@ -4925,21 +4932,21 @@ def minor(self, H, solver=None, verbose=0, *, integrality_tolerance=1e-3): sage: g = graphs.GridGraph([4,4]) sage: h = graphs.CompleteGraph(4) - sage: L = g.minor(h) - sage: gg = g.subgraph(flatten(L.values(), max_level = 1)) - sage: _ = [gg.merge_vertices(l) for l in L.values() if len(l)>1] - sage: gg.is_isomorphic(h) + sage: L = g.minor(h) # needs sage.numerical.mip + sage: gg = g.subgraph(flatten(L.values(), max_level = 1)) # needs sage.numerical.mip + sage: _ = [gg.merge_vertices(l) for l in L.values() if len(l)>1] # needs sage.numerical.mip + sage: gg.is_isomorphic(h) # needs sage.numerical.mip True We can also try to prove this way that the Petersen graph is not planar, as it has a `K_5` minor:: sage: g = graphs.PetersenGraph() - sage: K5_minor = g.minor(graphs.CompleteGraph(5)) # long time + sage: K5_minor = g.minor(graphs.CompleteGraph(5)) # long time # needs sage.numerical.mip And even a `K_{3,3}` minor:: - sage: K33_minor = g.minor(graphs.CompleteBipartiteGraph(3,3)) # long time + sage: K33_minor = g.minor(graphs.CompleteBipartiteGraph(3,3)) # long time, needs sage.numerical.mip (It is much faster to use the linear-time test of planarity in this situation, though.) @@ -4951,7 +4958,7 @@ def minor(self, H, solver=None, verbose=0, *, integrality_tolerance=1e-3): sage: g = g.subgraph(edges = g.min_spanning_tree()) sage: g.is_tree() True - sage: L = g.minor(graphs.CompleteGraph(3)) + sage: L = g.minor(graphs.CompleteGraph(3)) # needs sage.numerical.mip Traceback (most recent call last): ... ValueError: This graph has no minor isomorphic to H ! @@ -5234,7 +5241,7 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None, [1, 1, 1] sage: G.eccentricity(algorithm = 'Floyd-Warshall-Cython') [1, 1, 1] - sage: G.eccentricity(by_weight = True, algorithm = 'Dijkstra_NetworkX') + sage: G.eccentricity(by_weight=True, algorithm='Dijkstra_NetworkX') # needs networkx [2, 1, 2] sage: G.eccentricity(by_weight = True, algorithm = 'Dijkstra_Boost') [2, 1, 2] @@ -5769,7 +5776,7 @@ def distance_graph(self, dist): sage: G = graphs.CompleteGraph(3) sage: H = G.cartesian_product(graphs.CompleteGraph(2)) sage: K = H.distance_graph(2) - sage: K.am() + sage: K.am() # needs sage.modules [0 0 0 1 0 1] [0 0 1 0 1 0] [0 1 0 0 0 1] @@ -5797,8 +5804,8 @@ def distance_graph(self, dist): that sum to the matrix of all ones:: sage: P = graphs.PathGraph(20) - sage: all_ones = sum([P.distance_graph(i).am() for i in range(20)]) - sage: all_ones == matrix(ZZ, 20, 20, [1]*400) + sage: all_ones = sum([P.distance_graph(i).am() for i in range(20)]) # needs sage.modules + sage: all_ones == matrix(ZZ, 20, 20, [1]*400) # needs sage.modules True Four-bit strings differing in one bit is the same as @@ -5825,7 +5832,7 @@ def distance_graph(self, dist): sage: G = graphs.CompleteGraph(3) sage: H = G.disjoint_union(graphs.CompleteGraph(2)) sage: L = H.distance_graph(Infinity) - sage: L.am() + sage: L.am() # needs sage.modules [0 0 0 1 1] [0 0 0 1 1] [0 0 0 1 1] @@ -5950,12 +5957,12 @@ def to_directed(self, data_structure=None, sparse=None): :trac:`22424`:: sage: G1 = graphs.RandomGNP(5,0.5) - sage: gp1 = G1.graphplot(save_pos=True) # optional - sage.plot + sage: gp1 = G1.graphplot(save_pos=True) # needs sage.plot sage: G2 = G1.to_directed() sage: G2.delete_vertex(0) sage: G2.add_vertex(5) - sage: gp2 = G2.graphplot() # optional - sage.plot - sage: gp1 = G1.graphplot() # optional - sage.plot + sage: gp2 = G2.graphplot() # needs sage.plot + sage: gp1 = G1.graphplot() # needs sage.plot Vertex labels will be retained (:trac:`14708`):: @@ -6114,14 +6121,14 @@ def seidel_adjacency_matrix(self, vertices=None, *, base_ring=None, **kwds): sage: G = graphs.CycleGraph(5) sage: G = G.disjoint_union(graphs.CompleteGraph(1)) - sage: G.seidel_adjacency_matrix().minpoly() + sage: G.seidel_adjacency_matrix().minpoly() # needs sage.libs.pari sage.modules x^2 - 5 Selecting the base ring:: - sage: G.seidel_adjacency_matrix()[0, 0].parent() + sage: G.seidel_adjacency_matrix()[0, 0].parent() # needs sage.modules Integer Ring - sage: G.seidel_adjacency_matrix(base_ring=RDF)[0, 0].parent() + sage: G.seidel_adjacency_matrix(base_ring=RDF)[0, 0].parent() # needs sage.modules Real Double Field """ set_immutable = kwds.pop('immutable', False) @@ -6161,7 +6168,7 @@ def seidel_switching(self, s, inplace=True): sage: G = graphs.CycleGraph(5) sage: G = G.disjoint_union(graphs.CompleteGraph(1)) sage: G.seidel_switching([(0,1),(1,0),(0,0)]) - sage: G.seidel_adjacency_matrix().minpoly() + sage: G.seidel_adjacency_matrix().minpoly() # needs sage.libs.pari sage.modules x^2 - 5 sage: G.is_connected() True @@ -6192,13 +6199,14 @@ def twograph(self): EXAMPLES:: - sage: p=graphs.PetersenGraph() - sage: p.twograph() + sage: p = graphs.PetersenGraph() + sage: p.twograph() # needs sage.modules Incidence structure with 10 points and 60 blocks sage: p=graphs.chang_graphs() sage: T8 = graphs.CompleteGraph(8).line_graph() - sage: C = T8.seidel_switching([(0,1,None),(2,3,None),(4,5,None),(6,7,None)],inplace=False) - sage: T8.twograph() == C.twograph() + sage: C = T8.seidel_switching([(0,1,None), (2,3,None), (4,5,None), (6,7,None)], + ....: inplace=False) + sage: T8.twograph() == C.twograph() # needs sage.modules True sage: T8.is_isomorphic(C) False @@ -6206,8 +6214,8 @@ def twograph(self): TESTS:: sage: from sage.combinat.designs.twographs import TwoGraph - sage: p=graphs.PetersenGraph().twograph() - sage: TwoGraph(p, check=True) + sage: p = graphs.PetersenGraph().twograph() # needs sage.modules + sage: TwoGraph(p, check=True) # needs sage.modules Incidence structure with 10 points and 60 blocks .. SEEALSO:: @@ -6341,19 +6349,19 @@ def topological_minor(self, H, vertices=False, paths=False, solver=None, verbose Petersen's graph has a topological `K_4`-minor:: sage: g = graphs.PetersenGraph() - sage: g.topological_minor(graphs.CompleteGraph(4)) + sage: g.topological_minor(graphs.CompleteGraph(4)) # needs sage.numerical.mip Subgraph of (Petersen graph): Graph on ... And a topological `K_{3,3}`-minor:: - sage: g.topological_minor(graphs.CompleteBipartiteGraph(3,3)) + sage: g.topological_minor(graphs.CompleteBipartiteGraph(3,3)) # needs sage.numerical.mip Subgraph of (Petersen graph): Graph on ... And of course, a tree has no topological `C_3`-minor:: sage: g = graphs.RandomGNP(15,.3) - sage: g = g.subgraph(edges = g.min_spanning_tree()) - sage: g.topological_minor(graphs.CycleGraph(3)) + sage: g = g.subgraph(edges=g.min_spanning_tree()) + sage: g.topological_minor(graphs.CycleGraph(3)) # needs sage.numerical.mip False """ self._scream_if_not_simple() @@ -6545,7 +6553,7 @@ def cliques_maximal(self, algorithm="native"): [2, 6], [2, 8], [3, 4], [3, 7], [3, 9], [4, 5], [4, 8], [5, 10], [5, 11], [6, 10], [6, 11], [7, 8], [7, 11], [8, 10], [9, 10], [9, 11]] sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2, 2]) # optional - sage.plot + sage: G.show(figsize=[2, 2]) # needs sage.plot sage: G.cliques_maximal() [[0, 1, 2], [0, 1, 3]] sage: C = graphs.PetersenGraph() @@ -6559,9 +6567,9 @@ def cliques_maximal(self, algorithm="native"): Comparing the two implementations:: sage: g = graphs.RandomGNP(20,.7) - sage: s1 = Set(map(Set, g.cliques_maximal(algorithm="NetworkX"))) + sage: s1 = Set(map(Set, g.cliques_maximal(algorithm="NetworkX"))) # needs networkx sage: s2 = Set(map(Set, g.cliques_maximal(algorithm="native"))) - sage: s1 == s2 + sage: s1 == s2 # needs networkx True """ if algorithm == "native": @@ -6720,7 +6728,7 @@ def clique_number(self, algorithm="Cliquer", cliques=None, solver=None, verbose= sage: C.clique_number() 4 sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2,2]) # optional - sage.plot + sage: G.show(figsize=[2,2]) # needs sage.plot sage: G.clique_number() 3 @@ -6744,9 +6752,9 @@ def clique_number(self, algorithm="Cliquer", cliques=None, solver=None, verbose= TESTS:: sage: g = graphs.PetersenGraph() - sage: g.clique_number(algorithm="MILP") + sage: g.clique_number(algorithm="MILP") # needs sage.numerical.mip 2 - sage: for i in range(10): # optional - mcqd + sage: for i in range(10): # optional - mcqd # needs sage.numerical.mip ....: g = graphs.RandomGNP(15,.5) ....: if g.clique_number() != g.clique_number(algorithm="mcqd"): ....: print("This is dead wrong !") @@ -6789,23 +6797,23 @@ def cliques_number_of(self, vertices=None, cliques=None): EXAMPLES:: sage: C = Graph('DJ{') - sage: C.cliques_number_of() + sage: C.cliques_number_of() # needs networkx {0: 1, 1: 1, 2: 1, 3: 1, 4: 2} sage: E = C.cliques_maximal() sage: E [[0, 4], [1, 2, 3, 4]] - sage: C.cliques_number_of(cliques=E) + sage: C.cliques_number_of(cliques=E) # needs networkx {0: 1, 1: 1, 2: 1, 3: 1, 4: 2} sage: F = graphs.Grid2dGraph(2,3) - sage: F.cliques_number_of() + sage: F.cliques_number_of() # needs networkx {(0, 0): 2, (0, 1): 3, (0, 2): 2, (1, 0): 2, (1, 1): 3, (1, 2): 2} - sage: F.cliques_number_of(vertices=[(0, 1), (1, 2)]) + sage: F.cliques_number_of(vertices=[(0, 1), (1, 2)]) # needs networkx {(0, 1): 3, (1, 2): 2} sage: F.cliques_number_of(vertices=(0, 1)) 3 sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2,2]) # optional - sage.plot - sage: G.cliques_number_of() + sage: G.show(figsize=[2,2]) # needs sage.plot + sage: G.cliques_number_of() # needs networkx {0: 2, 1: 2, 2: 1, 3: 1} """ if cliques is None: @@ -6840,14 +6848,14 @@ def cliques_get_max_clique_graph(self): EXAMPLES:: - sage: MCG = graphs.ChvatalGraph().cliques_get_max_clique_graph(); MCG + sage: MCG = graphs.ChvatalGraph().cliques_get_max_clique_graph(); MCG # needs networkx Graph on 24 vertices - sage: MCG.show(figsize=[2,2], vertex_size=20, vertex_labels=False) # optional - sage.plot + sage: MCG.show(figsize=[2,2], vertex_size=20, vertex_labels=False) # needs networkx sage.plot sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2,2]) # optional - sage.plot - sage: G.cliques_get_max_clique_graph() + sage: G.show(figsize=[2,2]) # needs sage.plot + sage: G.cliques_get_max_clique_graph() # needs networkx Graph on 2 vertices - sage: G.cliques_get_max_clique_graph().show(figsize=[2,2]) # optional - sage.plot + sage: G.cliques_get_max_clique_graph().show(figsize=[2,2]) # needs networkx sage.plot """ import networkx return Graph(networkx.make_max_clique_graph(self.networkx_graph(), create_using=networkx.MultiGraph()), @@ -6868,14 +6876,14 @@ def cliques_get_clique_bipartite(self, **kwds): EXAMPLES:: - sage: CBG = graphs.ChvatalGraph().cliques_get_clique_bipartite(); CBG + sage: CBG = graphs.ChvatalGraph().cliques_get_clique_bipartite(); CBG # needs networkx Bipartite graph on 36 vertices - sage: CBG.show(figsize=[2,2], vertex_size=20, vertex_labels=False) # optional - sage.plot + sage: CBG.show(figsize=[2,2], vertex_size=20, vertex_labels=False) # needs networkx sage.plot sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2,2]) # optional - sage.plot - sage: G.cliques_get_clique_bipartite() + sage: G.show(figsize=[2,2]) # needs sage.plot + sage: G.cliques_get_clique_bipartite() # needs networkx Bipartite graph on 6 vertices - sage: G.cliques_get_clique_bipartite().show(figsize=[2,2]) # optional - sage.plot + sage: G.cliques_get_clique_bipartite().show(figsize=[2,2]) # needs networkx sage.plot """ from .bipartite_graph import BipartiteGraph import networkx @@ -6958,7 +6966,7 @@ def independent_set(self, algorithm="Cliquer", value_only=False, reduction_rules As a linear program:: sage: C = graphs.PetersenGraph() - sage: len(C.independent_set(algorithm="MILP")) + sage: len(C.independent_set(algorithm="MILP")) # needs sage.numerical.mip 4 .. PLOT:: @@ -7057,9 +7065,9 @@ def vertex_cover(self, algorithm="Cliquer", value_only=False, The two algorithms should return the same result:: sage: g = graphs.RandomGNP(10, .5) - sage: vc1 = g.vertex_cover(algorithm="MILP") + sage: vc1 = g.vertex_cover(algorithm="MILP") # needs sage.numerical.mip sage: vc2 = g.vertex_cover(algorithm="Cliquer") - sage: len(vc1) == len(vc2) + sage: len(vc1) == len(vc2) # needs sage.numerical.mip True The cardinality of the vertex cover is unchanged when reduction rules @@ -7110,9 +7118,9 @@ def vertex_cover(self, algorithm="Cliquer", value_only=False, Issue :trac:`24287` is fixed:: sage: G = Graph([(0,1)]*5 + [(1,2)]*2, multiedges=True) - sage: G.vertex_cover(reduction_rules=True, algorithm='MILP') + sage: G.vertex_cover(reduction_rules=True, algorithm='MILP') # needs sage.numerical.mip [1] - sage: G.vertex_cover(reduction_rules=False) + sage: G.vertex_cover(reduction_rules=False) # needs sage.numerical.mip [1] Issue :trac:`25988` is fixed:: @@ -7466,20 +7474,20 @@ def cliques_vertex_clique_number(self, algorithm="cliquer", vertices=None, EXAMPLES:: sage: C = Graph('DJ{') - sage: C.cliques_vertex_clique_number() # optional - sage.plot + sage: C.cliques_vertex_clique_number() # needs sage.plot {0: 2, 1: 4, 2: 4, 3: 4, 4: 4} sage: E = C.cliques_maximal(); E [[0, 4], [1, 2, 3, 4]] - sage: C.cliques_vertex_clique_number(cliques=E, algorithm="networkx") # optional - sage.plot + sage: C.cliques_vertex_clique_number(cliques=E, algorithm="networkx") # needs networkx sage.plot {0: 2, 1: 4, 2: 4, 3: 4, 4: 4} sage: F = graphs.Grid2dGraph(2,3) - sage: F.cliques_vertex_clique_number(algorithm="networkx") # optional - sage.plot + sage: F.cliques_vertex_clique_number(algorithm="networkx") # needs networkx sage.plot {(0, 0): 2, (0, 1): 2, (0, 2): 2, (1, 0): 2, (1, 1): 2, (1, 2): 2} - sage: F.cliques_vertex_clique_number(vertices=[(0, 1), (1, 2)]) # optional - sage.plot + sage: F.cliques_vertex_clique_number(vertices=[(0, 1), (1, 2)]) # needs sage.plot {(0, 1): 2, (1, 2): 2} sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2,2]) # optional - sage.plot - sage: G.cliques_vertex_clique_number() # optional - sage.plot + sage: G.show(figsize=[2,2]) # needs sage.plot + sage: G.cliques_vertex_clique_number() # needs sage.plot {0: 3, 1: 3, 2: 3, 3: 3} """ if algorithm == "cliquer": @@ -7519,20 +7527,19 @@ def cliques_containing_vertex(self, vertices=None, cliques=None): EXAMPLES:: sage: C = Graph('DJ{') - sage: C.cliques_containing_vertex() + sage: C.cliques_containing_vertex() # needs networkx {0: [[0, 4]], 1: [[1, 2, 3, 4]], 2: [[1, 2, 3, 4]], 3: [[1, 2, 3, 4]], 4: [[0, 4], [1, 2, 3, 4]]} - sage: C.cliques_containing_vertex(4) + sage: C.cliques_containing_vertex(4) # needs networkx [[0, 4], [1, 2, 3, 4]] - sage: C.cliques_containing_vertex([0, 1]) + sage: C.cliques_containing_vertex([0, 1]) # needs networkx {0: [[0, 4]], 1: [[1, 2, 3, 4]]} - sage: E = C.cliques_maximal() - sage: E + sage: E = C.cliques_maximal(); E # needs networkx [[0, 4], [1, 2, 3, 4]] - sage: C.cliques_containing_vertex(cliques=E) + sage: C.cliques_containing_vertex(cliques=E) # needs networkx {0: [[0, 4]], 1: [[1, 2, 3, 4]], 2: [[1, 2, 3, 4]], @@ -7540,8 +7547,8 @@ def cliques_containing_vertex(self, vertices=None, cliques=None): 4: [[0, 4], [1, 2, 3, 4]]} sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) - sage: G.show(figsize=[2,2]) # optional - sage.plot - sage: G.cliques_containing_vertex() + sage: G.show(figsize=[2,2]) # needs sage.plot + sage: G.cliques_containing_vertex() # needs networkx {0: [[0, 1, 2], [0, 1, 3]], 1: [[0, 1, 2], [0, 1, 3]], 2: [[0, 1, 2]], @@ -7551,13 +7558,13 @@ def cliques_containing_vertex(self, vertices=None, cliques=None): number of cliques in which a vertex is involved equals its degree:: sage: F = graphs.Grid2dGraph(2,3) - sage: d = F.cliques_containing_vertex() - sage: all(F.degree(u) == len(cliques) for u,cliques in d.items()) + sage: d = F.cliques_containing_vertex() # needs networkx + sage: all(F.degree(u) == len(cliques) for u,cliques in d.items()) # needs networkx True - sage: d = F.cliques_containing_vertex(vertices=[(0, 1)]) - sage: list(d) + sage: d = F.cliques_containing_vertex(vertices=[(0, 1)]) # needs networkx + sage: list(d) # needs networkx [(0, 1)] - sage: sorted(sorted(x for x in L) for L in d[(0, 1)]) + sage: sorted(sorted(x for x in L) for L in d[(0, 1)]) # needs networkx [[(0, 0), (0, 1)], [(0, 1), (0, 2)], [(0, 1), (1, 1)]] """ if cliques is None: @@ -7717,19 +7724,20 @@ def cores(self, k=None, with_labels=False): sage: (graphs.FruchtGraph()).cores(with_labels=True) {0: 3, 1: 3, 2: 3, 3: 3, 4: 3, 5: 3, 6: 3, 7: 3, 8: 3, 9: 3, 10: 3, 11: 3} sage: set_random_seed(0) - sage: a = random_matrix(ZZ, 20, x=2, sparse=True, density=.1) + sage: a = random_matrix(ZZ, 20, x=2, sparse=True, density=.1) # needs sage.modules sage: b = Graph(20) - sage: b.add_edges(a.nonzero_positions(), loops=False) - sage: cores = b.cores(with_labels=True); cores - {0: 3, 1: 3, 2: 3, 3: 3, 4: 2, 5: 2, 6: 3, 7: 1, 8: 3, 9: 3, 10: 3, 11: 3, 12: 3, 13: 3, 14: 2, 15: 3, 16: 3, 17: 3, 18: 3, 19: 3} - sage: [v for v,c in cores.items() if c >= 2] # the vertices in the 2-core + sage: b.add_edges(a.nonzero_positions(), loops=False) # needs sage.modules + sage: cores = b.cores(with_labels=True); cores # needs sage.modules + {0: 3, 1: 3, 2: 3, 3: 3, 4: 2, 5: 2, 6: 3, 7: 1, 8: 3, 9: 3, 10: 3, + 11: 3, 12: 3, 13: 3, 14: 2, 15: 3, 16: 3, 17: 3, 18: 3, 19: 3} + sage: [v for v,c in cores.items() if c >= 2] # the vertices in the 2-core # needs sage.modules [0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] Checking the 2-core of a random lobster is indeed the empty set:: - sage: g = graphs.RandomLobster(20, .5, .5) - sage: ordering, core = g.cores(2) - sage: len(core) == 0 + sage: g = graphs.RandomLobster(20, .5, .5) # needs networkx + sage: ordering, core = g.cores(2) # needs networkx + sage: len(core) == 0 # needs networkx True Checking the cores of a bull graph:: @@ -8127,22 +8135,22 @@ def is_circumscribable(self, solver="ppl", verbose=0): EXAMPLES:: sage: C = graphs.CubeGraph(3) - sage: C.is_circumscribable() + sage: C.is_circumscribable() # needs sage.numerical.mip True sage: O = graphs.OctahedralGraph() - sage: O.is_circumscribable() + sage: O.is_circumscribable() # needs sage.numerical.mip True - sage: TT = polytopes.truncated_tetrahedron().graph() - sage: TT.is_circumscribable() + sage: TT = polytopes.truncated_tetrahedron().graph() # needs sage.geometry.polyhedron + sage: TT.is_circumscribable() # needs sage.geometry.polyhedron sage.numerical.mip False Stellating in a face of the octahedral graph is not circumscribable:: sage: f = set(flatten(choice(O.faces()))) sage: O.add_edges([[6, i] for i in f]) - sage: O.is_circumscribable() + sage: O.is_circumscribable() # needs sage.numerical.mip False .. SEEALSO:: @@ -8249,7 +8257,7 @@ def is_inscribable(self, solver="ppl", verbose=0): True sage: C = graphs.CubeGraph(3) - sage: C.is_inscribable() + sage: C.is_inscribable() # needs sage.numerical.mip True Cutting off a vertex from the cube yields an uninscribable graph:: @@ -8260,7 +8268,7 @@ def is_inscribable(self, solver="ppl", verbose=0): sage: C.add_edges(Combinations(triangle, 2)) sage: C.add_edges(zip(triangle, C.neighbors(v))) sage: C.delete_vertex(v) - sage: C.is_inscribable() + sage: C.is_inscribable() # needs sage.numerical.mip False Breaking a face of the cube yields an uninscribable graph:: @@ -8268,7 +8276,7 @@ def is_inscribable(self, solver="ppl", verbose=0): sage: C = graphs.CubeGraph(3) sage: face = choice(C.faces()) sage: C.add_edge([face[0][0], face[2][0]]) - sage: C.is_inscribable() + sage: C.is_inscribable() # needs sage.numerical.mip False @@ -8554,22 +8562,24 @@ def two_factor_petersen(self, solver=None, verbose=0, *, integrality_tolerance=1 edge-partitionned into `2`-regular graphs:: sage: g = graphs.CompleteGraph(7) - sage: classes = g.two_factor_petersen() - sage: for c in classes: + sage: classes = g.two_factor_petersen() # needs sage.numerical.mip + sage: for c in classes: # needs sage.numerical.mip ....: gg = Graph() ....: gg.add_edges(c) ....: print(max(gg.degree())<=2) True True True - sage: Set(set(classes[0]) | set(classes[1]) | set(classes[2])).cardinality() == g.size() + sage: Set(set(classes[0]) # needs sage.numerical.mip + ....: | set(classes[1]) + ....: | set(classes[2])).cardinality() == g.size() True :: sage: g = graphs.CirculantGraph(24, [7, 11]) - sage: cl = g.two_factor_petersen() - sage: g.plot(edge_colors={'black':cl[0], 'red':cl[1]}) # optional - sage.plot + sage: cl = g.two_factor_petersen() # needs sage.numerical.mip + sage: g.plot(edge_colors={'black':cl[0], 'red':cl[1]}) # needs sage.numerical.mip sage.plot Graphics object consisting of 73 graphics primitives """ @@ -8641,30 +8651,30 @@ def kirchhoff_symanzik_polynomial(self, name='t'): For the cycle of length 5:: sage: G = graphs.CycleGraph(5) - sage: G.kirchhoff_symanzik_polynomial() + sage: G.kirchhoff_symanzik_polynomial() # needs networkx sage.modules t0 + t1 + t2 + t3 + t4 One can use another letter for variables:: - sage: G.kirchhoff_symanzik_polynomial(name='u') + sage: G.kirchhoff_symanzik_polynomial(name='u') # needs networkx sage.modules u0 + u1 + u2 + u3 + u4 For the 'coffee bean' graph:: sage: G = Graph([(0,1,'a'),(0,1,'b'),(0,1,'c')], multiedges=True) - sage: G.kirchhoff_symanzik_polynomial() + sage: G.kirchhoff_symanzik_polynomial() # needs networkx sage.modules t0*t1 + t0*t2 + t1*t2 For the 'parachute' graph:: sage: G = Graph([(0,2,'a'),(0,2,'b'),(0,1,'c'),(1,2,'d')], multiedges=True) - sage: G.kirchhoff_symanzik_polynomial() + sage: G.kirchhoff_symanzik_polynomial() # needs networkx sage.modules t0*t1 + t0*t2 + t1*t2 + t1*t3 + t2*t3 For the complete graph with 4 vertices:: sage: G = graphs.CompleteGraph(4) - sage: G.kirchhoff_symanzik_polynomial() + sage: G.kirchhoff_symanzik_polynomial() # needs networkx sage.modules t0*t1*t3 + t0*t2*t3 + t1*t2*t3 + t0*t1*t4 + t0*t2*t4 + t1*t2*t4 + t1*t3*t4 + t2*t3*t4 + t0*t1*t5 + t0*t2*t5 + t1*t2*t5 + t0*t3*t5 + t2*t3*t5 + t0*t4*t5 + t1*t4*t5 + t3*t4*t5 @@ -8714,44 +8724,44 @@ def magnitude_function(self): EXAMPLES:: sage: g = Graph({1:[], 2:[]}) - sage: g.magnitude_function() + sage: g.magnitude_function() # needs sage.modules 2 sage: g = graphs.CycleGraph(4) - sage: g.magnitude_function() + sage: g.magnitude_function() # needs sage.modules 4/(q^2 + 2*q + 1) sage: g = graphs.CycleGraph(5) - sage: m = g.magnitude_function(); m + sage: m = g.magnitude_function(); m # needs sage.modules 5/(2*q^2 + 2*q + 1) One can expand the magnitude as a power series in `q` as follows:: sage: q = QQ[['q']].gen() - sage: m(q) + sage: m(q) # needs sage.modules 5 - 10*q + 10*q^2 - 20*q^4 + 40*q^5 - 40*q^6 + ... One can also use the substitution `q = exp(-t)` to obtain the magnitude function as a function of `t`:: sage: g = graphs.CycleGraph(6) - sage: m = g.magnitude_function() - sage: t = var('t') # optional - sage.symbolic - sage: m(exp(-t)) # optional - sage.symbolic + sage: m = g.magnitude_function() # needs sage.modules + sage: t = var('t') # needs sage.modules sage.symbolic + sage: m(exp(-t)) # needs sage.modules sage.symbolic 6/(2*e^(-t) + 2*e^(-2*t) + e^(-3*t) + 1) TESTS:: sage: g = Graph() - sage: g.magnitude_function() + sage: g.magnitude_function() # needs sage.modules 0 sage: g = Graph({1:[]}) - sage: g.magnitude_function() + sage: g.magnitude_function() # needs sage.modules 1 sage: g = graphs.PathGraph(4) - sage: g.magnitude_function() + sage: g.magnitude_function() # needs sage.modules (-2*q + 4)/(q + 1) REFERENCES: @@ -8805,20 +8815,20 @@ def ihara_zeta_function_inverse(self): EXAMPLES:: sage: G = graphs.CompleteGraph(4) - sage: factor(G.ihara_zeta_function_inverse()) + sage: factor(G.ihara_zeta_function_inverse()) # needs sage.libs.pari sage.modules (2*t - 1) * (t + 1)^2 * (t - 1)^3 * (2*t^2 + t + 1)^3 sage: G = graphs.CompleteGraph(5) - sage: factor(G.ihara_zeta_function_inverse()) + sage: factor(G.ihara_zeta_function_inverse()) # needs sage.libs.pari sage.modules (-1) * (3*t - 1) * (t + 1)^5 * (t - 1)^6 * (3*t^2 + t + 1)^4 sage: G = graphs.PetersenGraph() - sage: factor(G.ihara_zeta_function_inverse()) + sage: factor(G.ihara_zeta_function_inverse()) # needs sage.libs.pari sage.modules (-1) * (2*t - 1) * (t + 1)^5 * (t - 1)^6 * (2*t^2 + 2*t + 1)^4 * (2*t^2 - t + 1)^5 sage: G = graphs.RandomTree(10) - sage: G.ihara_zeta_function_inverse() + sage: G.ihara_zeta_function_inverse() # needs sage.libs.pari sage.modules 1 REFERENCES: @@ -9001,11 +9011,11 @@ def has_perfect_matching(self, algorithm="Edmonds", solver=None, verbose=0, EXAMPLES:: - sage: graphs.PetersenGraph().has_perfect_matching() + sage: graphs.PetersenGraph().has_perfect_matching() # needs networkx True - sage: graphs.WheelGraph(6).has_perfect_matching() + sage: graphs.WheelGraph(6).has_perfect_matching() # needs networkx True - sage: graphs.WheelGraph(5).has_perfect_matching() + sage: graphs.WheelGraph(5).has_perfect_matching() # needs networkx False sage: graphs.PetersenGraph().has_perfect_matching(algorithm="LP_matching") True @@ -9023,14 +9033,16 @@ def has_perfect_matching(self, algorithm="Edmonds", solver=None, verbose=0, TESTS:: sage: G = graphs.EmptyGraph() - sage: all(G.has_perfect_matching(algorithm=algo) for algo in ['Edmonds', 'LP_matching', 'LP']) + sage: all(G.has_perfect_matching(algorithm=algo) # needs networkx + ....: for algo in ['Edmonds', 'LP_matching', 'LP']) True Be careful with isolated vertices:: sage: G = graphs.PetersenGraph() sage: G.add_vertex(11) - sage: any(G.has_perfect_matching(algorithm=algo) for algo in ['Edmonds', 'LP_matching', 'LP']) + sage: any(G.has_perfect_matching(algorithm=algo) # needs networkx + ....: for algo in ['Edmonds', 'LP_matching', 'LP']) False """ if self.order() % 2: @@ -9089,30 +9101,30 @@ def effective_resistance(self, i, j, *, base_ring=None): Effective resistances in a straight linear 2-tree on 6 vertices :: sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)]) - sage: G.effective_resistance(0,1) + sage: G.effective_resistance(0,1) # needs sage.modules 34/55 - sage: G.effective_resistance(0,3) + sage: G.effective_resistance(0,3) # needs sage.modules 49/55 - sage: G.effective_resistance(1,4) + sage: G.effective_resistance(1,4) # needs sage.modules 9/11 - sage: G.effective_resistance(0,5) + sage: G.effective_resistance(0,5) # needs sage.modules 15/11 Effective resistances in a fan on 6 vertices :: sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)]) - sage: H.effective_resistance(1,5) + sage: H.effective_resistance(1,5) # needs sage.modules 6/5 - sage: H.effective_resistance(1,3) + sage: H.effective_resistance(1,3) # needs sage.modules 49/55 - sage: H.effective_resistance(1,1) + sage: H.effective_resistance(1,1) # needs sage.modules 0 Using a different base ring:: - sage: H.effective_resistance(1, 5, base_ring=RDF) # abs tol 1e-14 + sage: H.effective_resistance(1, 5, base_ring=RDF) # abs tol 1e-14 # needs sage.modules 1.2000000000000000 - sage: H.effective_resistance(1, 1, base_ring=RDF) + sage: H.effective_resistance(1, 1, base_ring=RDF) # needs sage.modules 0.0 .. SEEALSO:: @@ -9129,25 +9141,26 @@ def effective_resistance(self, i, j, *, base_ring=None): TESTS:: sage: G = graphs.CompleteGraph(4) - sage: all(G.effective_resistance(u, v) == 1/2 for u,v in G.edge_iterator(labels=False)) + sage: all(G.effective_resistance(u, v) == 1/2 # needs sage.modules + ....: for u,v in G.edge_iterator(labels=False)) True - sage: Graph(1).effective_resistance(0,0) + sage: Graph(1).effective_resistance(0,0) # needs sage.modules 0 sage: G = Graph([(0,1),(1,2)]) - sage: G.effective_resistance(0,2) + sage: G.effective_resistance(0,2) # needs sage.modules 2 sage: G = Graph([(0,1),(1,2),(2,0)]) - sage: G.effective_resistance(0,2) + sage: G.effective_resistance(0,2) # needs sage.modules 2/3 sage: G = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(1,2),(2,3),(3,4),(4,5),(5,1)]) - sage: r = G.effective_resistance(0,3) - sage: r == fibonacci(2*(5-3)+1)*fibonacci(2*3-1)/fibonacci(2*5) + sage: r = G.effective_resistance(0,3) # needs sage.modules + sage: r == fibonacci(2*(5-3)+1)*fibonacci(2*3-1)/fibonacci(2*5) # needs sage.modules True sage: G = graphs.PathGraph(4) sage: G.delete_edge(2,3) - sage: G.effective_resistance(0,2) + sage: G.effective_resistance(0,2) # needs sage.modules 2 - sage: G.effective_resistance(0,3) + sage: G.effective_resistance(0,3) # needs sage.modules +Infinity """ from sage.matrix.constructor import matrix @@ -9221,7 +9234,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, only non-adjacent vertex pairs :: sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)]) - sage: G.effective_resistance_matrix() + sage: G.effective_resistance_matrix() # needs sage.modules [ 0 0 0 49/55 59/55 15/11] [ 0 0 0 0 9/11 59/55] [ 0 0 0 0 0 49/55] @@ -9232,7 +9245,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, The same effective resistance matrix, this time including adjacent vertices :: - sage: G.effective_resistance_matrix(nonedgesonly=False) + sage: G.effective_resistance_matrix(nonedgesonly=False) # needs sage.modules [ 0 34/55 34/55 49/55 59/55 15/11] [34/55 0 26/55 31/55 9/11 59/55] [34/55 26/55 0 5/11 31/55 49/55] @@ -9244,7 +9257,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, vertices counting only non-adjacent vertex pairs :: sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)]) - sage: H.effective_resistance_matrix() + sage: H.effective_resistance_matrix() # needs sage.modules [ 0 0 0 0 0 0 0] [ 0 0 0 49/55 56/55 6/5 89/55] [ 0 0 0 0 4/5 56/55 81/55] @@ -9255,7 +9268,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, A different base ring:: - sage: H.effective_resistance_matrix(base_ring=RDF)[0, 0].parent() + sage: H.effective_resistance_matrix(base_ring=RDF)[0, 0].parent() # needs sage.modules Real Double Field .. SEEALSO:: @@ -9270,7 +9283,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, TESTS:: - sage: graphs.CompleteGraph(4).effective_resistance_matrix() + sage: graphs.CompleteGraph(4).effective_resistance_matrix() # needs sage.modules [0 0 0 0] [0 0 0 0] [0 0 0 0] @@ -9278,7 +9291,7 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, sage: G = Graph(multiedges=True, sparse=True) sage: G.add_edges([(0, 1)] * 3) - sage: G.effective_resistance_matrix() + sage: G.effective_resistance_matrix() # needs sage.modules Traceback (most recent call last): ... ValueError: This method is not known to work on graphs with @@ -9286,36 +9299,36 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, in the meantime if you want to use it please disallow multiedges using allow_multiple_edges(). - sage: graphs.CompleteGraph(4).effective_resistance_matrix(nonedgesonly=False) + sage: graphs.CompleteGraph(4).effective_resistance_matrix(nonedgesonly=False) # needs sage.modules [ 0 1/2 1/2 1/2] [1/2 0 1/2 1/2] [1/2 1/2 0 1/2] [1/2 1/2 1/2 0] - sage: Graph(1).effective_resistance_matrix() + sage: Graph(1).effective_resistance_matrix() # needs sage.modules [0] - sage: Graph().effective_resistance_matrix() + sage: Graph().effective_resistance_matrix() # needs sage.modules Traceback (most recent call last): ... ValueError: unable to compute effective resistance for an empty Graph object sage: G = Graph([(0,1),(1,2),(2,3),(3,0),(0,2)]) - sage: G.effective_resistance_matrix() + sage: G.effective_resistance_matrix() # needs sage.modules [0 0 0 0] [0 0 0 1] [0 0 0 0] [0 1 0 0] sage: G = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(1,2),(2,3),(3,4),(4,5),(5,1)]) - sage: r = G.effective_resistance_matrix(nonedgesonly=False)[0,3] - sage: r == fibonacci(2*(5-3)+1)*fibonacci(2*3-1)/fibonacci(2*5) + sage: r = G.effective_resistance_matrix(nonedgesonly=False)[0,3] # needs sage.modules + sage: r == fibonacci(2*(5-3)+1)*fibonacci(2*3-1)/fibonacci(2*5) # needs sage.libs.pari sage.modules True Ask for an immutable matrix:: sage: G = Graph([(0, 1)]) - sage: M = G.effective_resistance_matrix(immutable=False) - sage: M.is_immutable() + sage: M = G.effective_resistance_matrix(immutable=False) # needs sage.modules + sage: M.is_immutable() # needs sage.modules False - sage: M = G.effective_resistance_matrix(immutable=True) - sage: M.is_immutable() + sage: M = G.effective_resistance_matrix(immutable=True) # needs sage.modules + sage: M.is_immutable() # needs sage.modules True """ from sage.matrix.constructor import matrix @@ -9375,20 +9388,20 @@ def least_effective_resistance(self, nonedgesonly=True): straight linear 2-tree on 6 vertices:: sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)]) - sage: G.least_effective_resistance() + sage: G.least_effective_resistance() # needs sage.modules [(1, 4)] Pairs of (adjacent or non-adjacent) nodes with least effective resistance in a straight linear 2-tree on 6 vertices :: - sage: G.least_effective_resistance(nonedgesonly = False) + sage: G.least_effective_resistance(nonedgesonly=False) # needs sage.modules [(2, 3)] Pairs of non-adjacent nodes with least effective resistance in a fan on 6 vertices counting only non-adjacent vertex pairs :: sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)]) - sage: H.least_effective_resistance() + sage: H.least_effective_resistance() # needs sage.modules [(2, 4)] .. SEEALSO:: @@ -9405,14 +9418,14 @@ def least_effective_resistance(self, nonedgesonly=True): TESTS:: - sage: graphs.CompleteGraph(4).least_effective_resistance() + sage: graphs.CompleteGraph(4).least_effective_resistance() # needs sage.modules [] - sage: graphs.CompleteGraph(4).least_effective_resistance(nonedgesonly=False) + sage: graphs.CompleteGraph(4).least_effective_resistance(nonedgesonly=False) # needs sage.modules [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] - sage: Graph(1).least_effective_resistance() + sage: Graph(1).least_effective_resistance() # needs sage.modules [] sage: G = Graph([(0,1),(1,2),(2,3),(3,0),(0,2)]) - sage: G.least_effective_resistance() + sage: G.least_effective_resistance() # needs sage.modules [(1, 3)] """ n = self.order() @@ -9470,7 +9483,7 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, sage: G1 = Graph() sage: G1.add_edges([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)]) - sage: G1.common_neighbors_matrix(nonedgesonly = True) + sage: G1.common_neighbors_matrix(nonedgesonly=True) # needs sage.modules [0 0 0 2 1 0] [0 0 0 0 2 1] [0 0 0 0 0 2] @@ -9481,7 +9494,7 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, We now show the common neighbors matrix which includes adjacent vertices :: - sage: G1.common_neighbors_matrix(nonedgesonly = False) + sage: G1.common_neighbors_matrix(nonedgesonly=False) # needs sage.modules [0 1 1 2 1 0] [1 0 2 1 2 1] [1 2 0 2 1 2] @@ -9493,7 +9506,7 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, non-adjacent vertex pairs :: sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)]) - sage: H.common_neighbors_matrix() + sage: H.common_neighbors_matrix() # needs sage.modules [0 0 0 0 0 0 0] [0 0 0 2 1 1 1] [0 0 0 0 2 1 1] @@ -9504,7 +9517,7 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, A different base ring:: - sage: H.common_neighbors_matrix(base_ring=RDF) + sage: H.common_neighbors_matrix(base_ring=RDF) # needs sage.modules [0.0 0.0 0.0 0.0 0.0 0.0 0.0] [0.0 0.0 0.0 2.0 1.0 1.0 1.0] [0.0 0.0 0.0 0.0 2.0 1.0 1.0] @@ -9515,8 +9528,8 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, It is an error to input anything other than a simple graph:: - sage: G = Graph([(0,0)],loops=True) - sage: G.common_neighbors_matrix() + sage: G = Graph([(0,0)], loops=True) + sage: G.common_neighbors_matrix() # needs sage.modules Traceback (most recent call last): ... ValueError: This method is not known to work on graphs with loops. @@ -9532,15 +9545,15 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, TESTS:: sage: G = graphs.CompleteGraph(4) - sage: M = G.common_neighbors_matrix() - sage: M.is_zero() + sage: M = G.common_neighbors_matrix() # needs sage.modules + sage: M.is_zero() # needs sage.modules True - sage: Graph(1).common_neighbors_matrix() + sage: Graph(1).common_neighbors_matrix() # needs sage.modules [0] - sage: Graph().common_neighbors_matrix() + sage: Graph().common_neighbors_matrix() # needs sage.modules [] sage: G = Graph([(0,1),(1,2),(2,3),(3,0),(0,2)]) - sage: G.common_neighbors_matrix() + sage: G.common_neighbors_matrix() # needs sage.modules [0 0 0 0] [0 0 0 2] [0 0 0 0] @@ -9549,11 +9562,11 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, Asking for an immutable matrix:: sage: G = Graph([(0, 1)]) - sage: M = G.common_neighbors_matrix() - sage: M.is_immutable() + sage: M = G.common_neighbors_matrix() # needs sage.modules + sage: M.is_immutable() # needs sage.modules False - sage: M = G.common_neighbors_matrix(immutable=True) - sage: M.is_immutable() + sage: M = G.common_neighbors_matrix(immutable=True) # needs sage.modules + sage: M.is_immutable() # needs sage.modules True """ self._scream_if_not_simple() @@ -9593,19 +9606,19 @@ def most_common_neighbors(self, nonedgesonly=True): linear 2-tree :: sage: G1 = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)]) - sage: G1.most_common_neighbors() + sage: G1.most_common_neighbors() # needs sage.modules [(0, 3), (1, 4), (2, 5)] If we include non-adjacent pairs :: - sage: G1.most_common_neighbors(nonedgesonly = False) + sage: G1.most_common_neighbors(nonedgesonly=False) # needs sage.modules [(0, 3), (1, 2), (1, 4), (2, 3), (2, 5), (3, 4)] The common neighbors matrix for a fan on 6 vertices counting only non-adjacent vertex pairs :: sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)]) - sage: H.most_common_neighbors() + sage: H.most_common_neighbors() # needs sage.modules [(1, 3), (2, 4), (3, 5)] .. SEEALSO:: @@ -9616,22 +9629,22 @@ def most_common_neighbors(self, nonedgesonly=True): TESTS:: sage: G=graphs.CompleteGraph(4) - sage: G.most_common_neighbors() + sage: G.most_common_neighbors() # needs sage.modules [] - sage: G.most_common_neighbors(nonedgesonly=False) + sage: G.most_common_neighbors(nonedgesonly=False) # needs sage.modules [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] - sage: Graph(1).most_common_neighbors() + sage: Graph(1).most_common_neighbors() # needs sage.modules Traceback (most recent call last): ... ValueError: this method is defined for graphs with at least 2 vertices - sage: Graph().most_common_neighbors() + sage: Graph().most_common_neighbors() # needs sage.modules Traceback (most recent call last): ... ValueError: this method is defined for graphs with at least 2 vertices sage: G = Graph([(0,1),(1,2),(2,3),(3,0),(0,2)]) - sage: G.most_common_neighbors() + sage: G.most_common_neighbors() # needs sage.modules [(1, 3)] - sage: G.most_common_neighbors(nonedgesonly=False) + sage: G.most_common_neighbors(nonedgesonly=False) # needs sage.modules [(0, 2), (1, 3)] """ self._scream_if_not_simple() @@ -9682,18 +9695,18 @@ def arboricity(self, certificate=False): EXAMPLES:: sage: G = graphs.PetersenGraph() - sage: a,F = G.arboricity(True) - sage: a + sage: a, F = G.arboricity(True) # needs sage.modules + sage: a # needs sage.modules 2 - sage: all([f.is_forest() for f in F]) + sage: all([f.is_forest() for f in F]) # needs sage.modules True - sage: len(set.union(*[set(f.edges(sort=False)) for f in F])) == G.size() + sage: len(set.union(*[set(f.edges(sort=False)) for f in F])) == G.size() # needs sage.modules True TESTS:: sage: g = Graph() - sage: g.arboricity(True) + sage: g.arboricity(True) # needs sage.modules (0, []) """ from sage.matroids.constructor import Matroid diff --git a/src/sage/graphs/graph_coloring.pyx b/src/sage/graphs/graph_coloring.pyx index 60abd45d4d1..8360f71bfca 100644 --- a/src/sage/graphs/graph_coloring.pyx +++ b/src/sage/graphs/graph_coloring.pyx @@ -104,11 +104,12 @@ def format_coloring(data, value_only=False, hex_colors=False, vertex_color_dict= 3 sage: format_coloring(color_classes, value_only=False) {0: ['a', 'b'], 1: ['c'], 2: ['d']} - sage: format_coloring(color_classes, value_only=False, hex_colors=True) + sage: format_coloring(color_classes, value_only=False, hex_colors=True) # needs sage.plot {'#0000ff': ['d'], '#00ff00': ['c'], '#ff0000': ['a', 'b']} sage: format_coloring(color_classes, value_only=False, hex_colors=False, vertex_color_dict=True) {'a': 0, 'b': 0, 'c': 1, 'd': 2} - sage: format_coloring(color_classes, value_only=False, hex_colors=True, vertex_color_dict=True) + sage: format_coloring(color_classes, value_only=False, hex_colors=True, # needs sage.plot + ....: vertex_color_dict=True) {'a': '#ff0000', 'b': '#ff0000', 'c': '#00ff00', 'd': '#0000ff'} TESTS:: @@ -116,9 +117,10 @@ def format_coloring(data, value_only=False, hex_colors=False, vertex_color_dict= sage: from sage.graphs.graph_coloring import format_coloring sage: format_coloring([], value_only=True) [] - sage: format_coloring([], value_only=False, hex_colors=True) + sage: format_coloring([], value_only=False, hex_colors=True) # needs sage.plot {} - sage: format_coloring([], value_only=False, hex_colors=True, vertex_color_dict=True) + sage: format_coloring([], value_only=False, hex_colors=True, # needs sage.plot + ....: vertex_color_dict=True) {} sage: format_coloring([], value_only=False, hex_colors=False, vertex_color_dict=True) {} @@ -210,7 +212,7 @@ def all_graph_colorings(G, n, count_only=False, hex_colors=False, sage: from sage.graphs.graph_coloring import all_graph_colorings sage: G = Graph({0: [1, 2, 3], 1: [2]}) sage: n = 0 - sage: for C in all_graph_colorings(G, 3, hex_colors=True): + sage: for C in all_graph_colorings(G, 3, hex_colors=True): # needs sage.plot ....: parts = [C[k] for k in C] ....: for P in parts: ....: l = len(P) @@ -218,8 +220,8 @@ def all_graph_colorings(G, n, count_only=False, hex_colors=False, ....: for j in range(i + 1, l): ....: if G.has_edge(P[i], P[j]): ....: raise RuntimeError("Coloring Failed.") - ....: n+=1 - sage: print("G has %s 3-colorings." % n) + ....: n += 1 + sage: print("G has %s 3-colorings." % n) # needs sage.plot G has 12 3-colorings. TESTS:: @@ -237,11 +239,12 @@ def all_graph_colorings(G, n, count_only=False, hex_colors=False, ....: print(c) {0: 0, 2: 0, 1: 1} {1: 0, 0: 1, 2: 1} - sage: for c in all_graph_colorings(G, 2, hex_colors=True): + sage: for c in all_graph_colorings(G, 2, hex_colors=True): # needs sage.plot ....: print(sorted(c.items())) [('#00ffff', [1]), ('#ff0000', [0, 2])] [('#00ffff', [0, 2]), ('#ff0000', [1])] - sage: for c in all_graph_colorings(G, 2, hex_colors=True, vertex_color_dict=True): + sage: for c in all_graph_colorings(G, 2, hex_colors=True, # needs sage.plot + ....: vertex_color_dict=True): ....: print(c) {0: '#ff0000', 2: '#ff0000', 1: '#00ffff'} {1: '#ff0000', 0: '#00ffff', 2: '#00ffff'} @@ -513,7 +516,7 @@ def vertex_coloring(g, k=None, value_only=False, hex_colors=False, solver=None, sage: from sage.graphs.graph_coloring import vertex_coloring sage: g = graphs.PetersenGraph() - sage: vertex_coloring(g, value_only=True) + sage: vertex_coloring(g, value_only=True) # needs sage.numerical.mip 3 TESTS: @@ -532,7 +535,7 @@ def vertex_coloring(g, k=None, value_only=False, hex_colors=False, solver=None, :trac:`33559` is fixed:: sage: G = Graph('MgCgS?_O@IeTHKG??') - sage: len(G.coloring(algorithm='MILP')) + sage: len(G.coloring(algorithm='MILP')) # needs sage.numerical.mip 4 """ g._scream_if_not_simple(allow_multiple_edges=True) @@ -775,15 +778,15 @@ def fractional_chromatic_number(G, solver='PPL', verbose=0, The fractional chromatic number of a `C_5` is `5/2`:: sage: g = graphs.CycleGraph(5) - sage: g.fractional_chromatic_number() + sage: g.fractional_chromatic_number() # needs sage.numerical.mip 5/2 TESTS:: sage: G = graphs.RandomGNP(20, .2) - sage: a = G.fractional_chromatic_number(check_components=True) - sage: b = G.fractional_chromatic_number(check_components=False) - sage: a == b + sage: a = G.fractional_chromatic_number(check_components=True) # needs sage.numerical.mip + sage: b = G.fractional_chromatic_number(check_components=False) # needs sage.numerical.mip + sage: a == b # needs sage.numerical.mip True """ G._scream_if_not_simple() @@ -884,7 +887,7 @@ def fractional_chromatic_index(G, solver="PPL", verbose_constraints=False, verbo The fractional chromatic index of a `C_5` is `5/2`:: sage: g = graphs.CycleGraph(5) - sage: g.fractional_chromatic_index() + sage: g.fractional_chromatic_index() # needs sage.numerical.mip 5/2 TESTS: @@ -893,9 +896,9 @@ def fractional_chromatic_index(G, solver="PPL", verbose_constraints=False, verbo solvers:: sage: g = graphs.PetersenGraph() - sage: g.fractional_chromatic_index(solver='GLPK') # known bug (#23798) + sage: g.fractional_chromatic_index(solver='GLPK') # known bug # needs sage.numerical.mip 3.0 - sage: g.fractional_chromatic_index(solver='PPL') + sage: g.fractional_chromatic_index(solver='PPL') # needs sage.numerical.mip 3 """ G._scream_if_not_simple() @@ -1025,13 +1028,13 @@ def grundy_coloring(g, k, value_only=True, solver=None, verbose=0, sage: from sage.graphs.graph_coloring import grundy_coloring sage: g = graphs.PathGraph(4) - sage: grundy_coloring(g, 4) + sage: grundy_coloring(g, 4) # needs sage.numerical.mip 3 The Grundy number of the PetersenGraph is equal to 4:: sage: g = graphs.PetersenGraph() - sage: grundy_coloring(g, 5) + sage: grundy_coloring(g, 5) # needs sage.numerical.mip 4 It would have been sufficient to set the value of ``k`` to 4 in @@ -1179,13 +1182,13 @@ def b_coloring(g, k, value_only=True, solver=None, verbose=0, sage: from sage.graphs.graph_coloring import b_coloring sage: g = graphs.PathGraph(5) - sage: b_coloring(g, 5) + sage: b_coloring(g, 5) # needs sage.numerical.mip 3 The b-chromatic number of the Petersen Graph is equal to 3:: sage: g = graphs.PetersenGraph() - sage: b_coloring(g, 5) + sage: b_coloring(g, 5) # needs sage.numerical.mip 3 It would have been sufficient to set the value of ``k`` to 4 in this case, @@ -1380,32 +1383,33 @@ def edge_coloring(g, value_only=False, vizing=False, hex_colors=False, solver=No sage: from sage.graphs.graph_coloring import edge_coloring sage: g = graphs.PetersenGraph() - sage: edge_coloring(g, value_only=True, solver='GLPK') + sage: edge_coloring(g, value_only=True, solver='GLPK') # needs sage.numerical.mip 4 - sage: color_classes = edge_coloring(g, value_only=False, solver='GLPK') - sage: len(color_classes) + sage: color_classes = edge_coloring(g, value_only=False, solver='GLPK') # needs sage.numerical.mip + sage: len(color_classes) # needs sage.numerical.mip 4 - sage: len(set(frozenset(e) for C in color_classes for e in C)) == g.size() + sage: len(set(frozenset(e) for C in color_classes for e in C)) == g.size() # needs sage.numerical.mip True - sage: all(g.has_edge(e) for C in color_classes for e in C) + sage: all(g.has_edge(e) for C in color_classes for e in C) # needs sage.numerical.mip True - sage: all(len(Graph(C).matching()) == len(C) for C in color_classes) + sage: all(len(Graph(C).matching()) == len(C) for C in color_classes) # needs networkx sage.numerical.mip True - sage: color_classes = edge_coloring(g, value_only=False, hex_colors=True, solver='GLPK') - sage: sorted(color_classes.keys()) + sage: color_classes = edge_coloring(g, value_only=False, # needs sage.numerical.mip + ....: hex_colors=True, solver='GLPK') + sage: sorted(color_classes.keys()) # needs sage.numerical.mip ['#00ffff', '#7f00ff', '#7fff00', '#ff0000'] Complete graphs are colored using the linear-time round-robin coloring:: sage: from sage.graphs.graph_coloring import edge_coloring - sage: len(edge_coloring(graphs.CompleteGraph(20))) + sage: len(edge_coloring(graphs.CompleteGraph(20))) # needs sage.numerical.mip 19 The chromatic index of a non connected graph is the maximum over its connected components:: sage: g = graphs.CompleteGraph(4) + graphs.CompleteGraph(10) - sage: edge_coloring(g, value_only=True) + sage: edge_coloring(g, value_only=True) # needs sage.numerical.mip 9 TESTS: @@ -1413,11 +1417,11 @@ def edge_coloring(g, value_only=False, vizing=False, hex_colors=False, solver=No Graph without edge:: sage: g = Graph(2) - sage: edge_coloring(g) + sage: edge_coloring(g) # needs sage.numerical.mip [] - sage: edge_coloring(g, value_only=True) + sage: edge_coloring(g, value_only=True) # needs sage.numerical.mip 0 - sage: edge_coloring(g, hex_colors=True) + sage: edge_coloring(g, hex_colors=True) # needs sage.numerical.mip {} """ g._scream_if_not_simple() @@ -1564,7 +1568,7 @@ def _vizing_edge_coloring(g): True sage: all(g.has_edge(e) for C in color_classes for e in C) True - sage: all(len(Graph(C).matching()) == len(C) for C in color_classes) + sage: all(len(Graph(C).matching()) == len(C) for C in color_classes) # needs networkx True Coloring the edges of the Star Graph:: @@ -1832,22 +1836,23 @@ def linear_arboricity(g, plus_one=None, hex_colors=False, value_only=False, horizontal lines and the set of vertical lines are an admissible partition:: sage: from sage.graphs.graph_coloring import linear_arboricity - sage: g = graphs.Grid2dGraph(4, 4) - sage: g1,g2 = linear_arboricity(g) + sage: g = graphs.Grid2dGraph(4, 4) # needs sage.numerical.mip + sage: g1,g2 = linear_arboricity(g) # needs sage.numerical.mip Each graph is of course a forest:: - sage: g1.is_forest() and g2.is_forest() + sage: g1.is_forest() and g2.is_forest() # needs sage.numerical.mip True Of maximum degree 2:: - sage: max(g1.degree()) <= 2 and max(g2.degree()) <= 2 + sage: max(g1.degree()) <= 2 and max(g2.degree()) <= 2 # needs sage.numerical.mip True Which constitutes a partition of the whole edge set:: - sage: all((g1.has_edge(e) or g2.has_edge(e)) for e in g.edge_iterator(labels=None)) + sage: all((g1.has_edge(e) or g2.has_edge(e)) # needs sage.numerical.mip + ....: for e in g.edge_iterator(labels=None)) True TESTS: @@ -1855,15 +1860,15 @@ def linear_arboricity(g, plus_one=None, hex_colors=False, value_only=False, Asking for the value of the linear arboricity only (:trac:`24991`):: sage: from sage.graphs.graph_coloring import linear_arboricity - sage: sorted(linear_arboricity(G, value_only=True) for G in graphs(4)) + sage: sorted(linear_arboricity(G, value_only=True) for G in graphs(4)) # needs sage.numerical.mip [0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2] Test parameter ``hex_color`` (:trac:`26228`):: sage: from sage.graphs.graph_coloring import linear_arboricity sage: g = graphs.Grid2dGraph(4, 4) - sage: d = linear_arboricity(g, hex_colors=True) - sage: sorted(d) + sage: d = linear_arboricity(g, hex_colors=True) # needs sage.numerical.mip + sage: sorted(d) # needs sage.numerical.mip ['#00ffff', '#ff0000'] """ g._scream_if_not_simple() @@ -2036,21 +2041,22 @@ def acyclic_edge_coloring(g, hex_colors=False, value_only=False, k=0, sage: from sage.graphs.graph_coloring import acyclic_edge_coloring sage: g = graphs.CompleteGraph(8) - sage: colors = acyclic_edge_coloring(g) + sage: colors = acyclic_edge_coloring(g) # needs sage.numerical.mip Each color class is of course a matching :: - sage: all(max(gg.degree()) <= 1 for gg in colors) + sage: all(max(gg.degree()) <= 1 for gg in colors) # needs sage.numerical.mip True These matchings being a partition of the edge set:: - sage: all(any(gg.has_edge(e) for gg in colors) for e in g.edge_iterator(labels=False)) + sage: all(any(gg.has_edge(e) for gg in colors) # needs sage.numerical.mip + ....: for e in g.edge_iterator(labels=False)) True Besides, the union of any two of them is a forest :: - sage: all(g1.union(g2).is_forest() for g1 in colors for g2 in colors) + sage: all(g1.union(g2).is_forest() for g1 in colors for g2 in colors) # needs sage.numerical.mip True If one wants to acyclically color a cycle on `4` vertices, at least 3 colors @@ -2058,15 +2064,15 @@ def acyclic_edge_coloring(g, hex_colors=False, value_only=False, k=0, with only 2:: sage: g = graphs.CycleGraph(4) - sage: acyclic_edge_coloring(g, k=2) + sage: acyclic_edge_coloring(g, k=2) # needs sage.numerical.mip Traceback (most recent call last): ... ValueError: this graph cannot be colored with the given number of colors The optimal coloring give us `3` classes:: - sage: colors = acyclic_edge_coloring(g, k=None) - sage: len(colors) + sage: colors = acyclic_edge_coloring(g, k=None) # needs sage.numerical.mip + sage: len(colors) # needs sage.numerical.mip 3 TESTS: @@ -2074,32 +2080,32 @@ def acyclic_edge_coloring(g, hex_colors=False, value_only=False, k=0, Issue :trac:`24991` is fixed:: sage: from sage.graphs.graph_coloring import acyclic_edge_coloring - sage: sorted(acyclic_edge_coloring(G, value_only=True) for G in graphs(4)) + sage: sorted(acyclic_edge_coloring(G, value_only=True) for G in graphs(4)) # needs sage.numerical.mip [2, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5] Test parameter ``hex_color`` (:trac:`26228`):: sage: from sage.graphs.graph_coloring import acyclic_edge_coloring sage: g = graphs.CompleteGraph(4) - sage: d = acyclic_edge_coloring(g, hex_colors=True) - sage: sorted(d) + sage: d = acyclic_edge_coloring(g, hex_colors=True) # needs sage.numerical.mip + sage: sorted(d) # needs sage.numerical.mip ['#0066ff', '#00ff66', '#cbff00', '#cc00ff', '#ff0000'] The acyclic chromatic index of a graph without edge is 0 (:trac:`27079`):: sage: from sage.graphs.graph_coloring import acyclic_edge_coloring sage: g = Graph(3) - sage: acyclic_edge_coloring(g, k=None, value_only=True) + sage: acyclic_edge_coloring(g, k=None, value_only=True) # needs sage.numerical.mip 0 - sage: acyclic_edge_coloring(g, k=None, hex_colors=True) + sage: acyclic_edge_coloring(g, k=None, hex_colors=True) # needs sage.numerical.mip {} - sage: acyclic_edge_coloring(g, k=None, hex_colors=False) + sage: acyclic_edge_coloring(g, k=None, hex_colors=False) # needs sage.numerical.mip [] Empty graph (:trac:`27079`):: sage: from sage.graphs.graph_coloring import acyclic_edge_coloring - sage: acyclic_edge_coloring(Graph(), k=None, value_only=True) + sage: acyclic_edge_coloring(Graph(), k=None, value_only=True) # needs sage.numerical.mip 0 """ g._scream_if_not_simple(allow_multiple_edges=True) diff --git a/src/sage/graphs/graph_database.py b/src/sage/graphs/graph_database.py index 9274ca13452..b8e9226bc2c 100644 --- a/src/sage/graphs/graph_database.py +++ b/src/sage/graphs/graph_database.py @@ -120,7 +120,7 @@ def graph6_to_plot(graph6): EXAMPLES:: sage: from sage.graphs.graph_database import graph6_to_plot - sage: type(graph6_to_plot('D??')) # optional - sage.plot + sage: type(graph6_to_plot('D??')) # needs sage.plot """ g = Graph(str(graph6)) diff --git a/src/sage/graphs/graph_decompositions/bandwidth.pyx b/src/sage/graphs/graph_decompositions/bandwidth.pyx index d72c6e5ff80..bbd3916ac2b 100644 --- a/src/sage/graphs/graph_decompositions/bandwidth.pyx +++ b/src/sage/graphs/graph_decompositions/bandwidth.pyx @@ -160,7 +160,7 @@ def bandwidth(G, k=None): False sage: bandwidth(G) (5, [0, 4, 5, 8, 1, 9, 3, 7, 6, 2]) - sage: G.adjacency_matrix(vertices=[0, 4, 5, 8, 1, 9, 3, 7, 6, 2]) # optional - sage.modules + sage: G.adjacency_matrix(vertices=[0, 4, 5, 8, 1, 9, 3, 7, 6, 2]) # needs sage.modules [0 1 1 0 1 0 0 0 0 0] [1 0 0 0 0 1 1 0 0 0] [1 0 0 1 0 0 0 1 0 0] @@ -174,7 +174,7 @@ def bandwidth(G, k=None): sage: G = graphs.ChvatalGraph() sage: bandwidth(G) (6, [0, 5, 9, 4, 10, 1, 6, 11, 3, 8, 7, 2]) - sage: G.adjacency_matrix(vertices=[0, 5, 9, 4, 10, 1, 6, 11, 3, 8, 7, 2]) # optional - sage.modules + sage: G.adjacency_matrix(vertices=[0, 5, 9, 4, 10, 1, 6, 11, 3, 8, 7, 2]) # needs sage.modules [0 0 1 1 0 1 1 0 0 0 0 0] [0 0 0 1 1 1 0 1 0 0 0 0] [1 0 0 0 1 0 0 1 1 0 0 0] diff --git a/src/sage/graphs/graph_decompositions/cutwidth.pyx b/src/sage/graphs/graph_decompositions/cutwidth.pyx index 440d80ee2f6..208bd69dea4 100644 --- a/src/sage/graphs/graph_decompositions/cutwidth.pyx +++ b/src/sage/graphs/graph_decompositions/cutwidth.pyx @@ -372,7 +372,7 @@ def cutwidth(G, algorithm="exponential", cut_off=0, solver=None, verbose=False, sage: G = Graph([(0, 1)]) sage: cutwidth(G, algorithm="exponential") (1, [0, 1]) - sage: cutwidth(G, algorithm="MILP", solver='GLPK') + sage: cutwidth(G, algorithm="MILP", solver='GLPK') # needs sage.numerical.mip (1, [0, 1]) Cutwidth of a disconnected graph:: @@ -382,7 +382,7 @@ def cutwidth(G, algorithm="exponential", cut_off=0, solver=None, verbose=False, sage: G.add_edge(2, 3) sage: cutwidth(G, algorithm="exponential") (1, [2, 3, 0, 1, 4]) - sage: cutwidth(G, algorithm="MILP", solver='GLPK') + sage: cutwidth(G, algorithm="MILP", solver='GLPK') # needs sage.numerical.mip (1, [2, 3, 0, 1, 4]) """ from sage.graphs.graph import Graph @@ -643,9 +643,9 @@ def cutwidth_MILP(G, lower_bound=0, solver=None, verbose=0, sage: from sage.graphs.graph_decompositions import cutwidth sage: G = graphs.CycleGraph(5) - sage: cw, L = cutwidth.cutwidth_MILP(G); cw + sage: cw, L = cutwidth.cutwidth_MILP(G); cw # needs sage.numerical.mip 2 - sage: cw == cutwidth.width_of_cut_decomposition(G, L) + sage: cw == cutwidth.width_of_cut_decomposition(G, L) # needs sage.numerical.mip True sage: cwe, Le = cutwidth.cutwidth_dyn(G); cwe 2 @@ -654,18 +654,18 @@ def cutwidth_MILP(G, lower_bound=0, solver=None, verbose=0, sage: from sage.graphs.graph_decompositions import cutwidth sage: G = graphs.CompleteGraph(4) - sage: cw, L = cutwidth.cutwidth_MILP(G); cw + sage: cw, L = cutwidth.cutwidth_MILP(G); cw # needs sage.numerical.mip 4 - sage: cw == cutwidth.width_of_cut_decomposition(G, L) + sage: cw == cutwidth.width_of_cut_decomposition(G, L) # needs sage.numerical.mip True Cutwidth of a Path graph:: sage: from sage.graphs.graph_decompositions import cutwidth sage: G = graphs.PathGraph(3) - sage: cw, L = cutwidth.cutwidth_MILP(G); cw + sage: cw, L = cutwidth.cutwidth_MILP(G); cw # needs sage.numerical.mip 1 - sage: cw == cutwidth.width_of_cut_decomposition(G, L) + sage: cw == cutwidth.width_of_cut_decomposition(G, L) # needs sage.numerical.mip True TESTS: @@ -673,7 +673,7 @@ def cutwidth_MILP(G, lower_bound=0, solver=None, verbose=0, Comparison with exponential algorithm:: sage: from sage.graphs.graph_decompositions import cutwidth - sage: for i in range(2): # long time + sage: for i in range(2): # long time # needs sage.numerical.mip ....: G = graphs.RandomGNP(7, 0.3) ....: ve, le = cutwidth.cutwidth_dyn(G) ....: vm, lm = cutwidth.cutwidth_MILP(G, solver='GLPK') @@ -684,7 +684,7 @@ def cutwidth_MILP(G, lower_bound=0, solver=None, verbose=0, sage: from sage.graphs.graph_decompositions.cutwidth import cutwidth_MILP sage: G = graphs.CycleGraph(3) - sage: cutwidth_MILP(G, lower_bound=G.size()+1) + sage: cutwidth_MILP(G, lower_bound=G.size()+1) # needs sage.numerical.mip Traceback (most recent call last): ... MIPSolverException: ... diff --git a/src/sage/graphs/graph_decompositions/fast_digraph.pyx b/src/sage/graphs/graph_decompositions/fast_digraph.pyx index fd75e5e63c3..3d7c4b2fea7 100644 --- a/src/sage/graphs/graph_decompositions/fast_digraph.pyx +++ b/src/sage/graphs/graph_decompositions/fast_digraph.pyx @@ -41,7 +41,7 @@ cdef class FastDigraph: ....: 'cdef FastDigraph F = FastDigraph(G)', ....: 'cdef int i', ....: 'print([F.degree[i] for i in range(F.n)])'] - sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython + sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython [1, 2, 1] """ if D.order() > 8*sizeof(int): @@ -98,7 +98,7 @@ cdef class FastDigraph: ....: 'from sage.graphs.graph import Graph', ....: 'from sage.graphs.graph_decompositions.fast_digraph cimport FastDigraph', ....: 'FastDigraph(Graph([(0, 1), (1, 2)])).print_adjacency_matrix()'] - sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython + sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython 010 101 010 @@ -128,7 +128,7 @@ cdef inline int compute_out_neighborhood_cardinality(FastDigraph g, int S): ....: 'cdef FastDigraph F = FastDigraph(Graph([(0, 1), (1, 2)]))', ....: 'cdef int i', ....: 'print([compute_out_neighborhood_cardinality(F, 1<> 1) & 0x55555555) @@ -198,7 +198,7 @@ cdef inline int slow_popcount32(int i): ....: 'from sage.graphs.graph_decompositions.fast_digraph cimport slow_popcount32', ....: 'cdef int i', ....: 'print(all(popcount32(i) == slow_popcount32(i) for i in range(16)))'] - sage: cython(os.linesep.join(cython_code)) # optional - sage.misc.cython + sage: cython(os.linesep.join(cython_code)) # needs sage.misc.cython True """ # Slow popcount for 32bits integers diff --git a/src/sage/graphs/graph_decompositions/graph_products.pyx b/src/sage/graphs/graph_decompositions/graph_products.pyx index 7042eabbfaf..31f49206586 100644 --- a/src/sage/graphs/graph_decompositions/graph_products.pyx +++ b/src/sage/graphs/graph_decompositions/graph_products.pyx @@ -206,8 +206,8 @@ def is_cartesian_product(g, certificate=False, relabeling=False): Wagner's Graph (:trac:`13599`):: - sage: g = graphs.WagnerGraph() # optional - networkx - sage: g.is_cartesian_product() # optional - networkx + sage: g = graphs.WagnerGraph() # needs networkx + sage: g.is_cartesian_product() # needs networkx False Empty and one-element graph (:trac:`19546`):: diff --git a/src/sage/graphs/graph_decompositions/modular_decomposition.py b/src/sage/graphs/graph_decompositions/modular_decomposition.py index 230525e00e1..7a0c71c2fb1 100644 --- a/src/sage/graphs/graph_decompositions/modular_decomposition.py +++ b/src/sage/graphs/graph_decompositions/modular_decomposition.py @@ -610,7 +610,7 @@ def habib_maurer_algorithm(graph, g_classes=None): decompositions. :: sage: from sage.graphs.graph_decompositions.modular_decomposition import permute_decomposition - sage: permute_decomposition(2, habib_maurer_algorithm, 20, 0.5) # optional - sage.groups + sage: permute_decomposition(2, habib_maurer_algorithm, 20, 0.5) # needs sage.groups """ if graph.is_directed(): raise ValueError("Graph must be undirected") diff --git a/src/sage/graphs/graph_decompositions/tdlib.pyx b/src/sage/graphs/graph_decompositions/tdlib.pyx index 017b120abd3..a673b44d1ee 100644 --- a/src/sage/graphs/graph_decompositions/tdlib.pyx +++ b/src/sage/graphs/graph_decompositions/tdlib.pyx @@ -132,11 +132,12 @@ def treedecomposition_exact(G, lb=-1): TESTS:: - sage: import sage.graphs.graph_decompositions.tdlib as tdlib # optional - tdlib - sage: G = graphs.HouseGraph() # optional - tdlib - sage: T = tdlib.treedecomposition_exact(G) # optional - tdlib - sage: G = graphs.PetersenGraph() # optional - tdlib - sage: T = tdlib.treedecomposition_exact(G) # optional - tdlib + sage: # optional - tdlib + sage: import sage.graphs.graph_decompositions.tdlib as tdlib + sage: G = graphs.HouseGraph() + sage: T = tdlib.treedecomposition_exact(G) + sage: G = graphs.PetersenGraph() + sage: T = tdlib.treedecomposition_exact(G) """ cdef vector[unsigned int] V_G, E_G, E_T diff --git a/src/sage/graphs/graph_decompositions/vertex_separation.pyx b/src/sage/graphs/graph_decompositions/vertex_separation.pyx index bf6070e9c8f..c3e2948e9d6 100644 --- a/src/sage/graphs/graph_decompositions/vertex_separation.pyx +++ b/src/sage/graphs/graph_decompositions/vertex_separation.pyx @@ -665,7 +665,7 @@ def path_decomposition(G, algorithm="BAB", cut_off=None, upper_bound=None, verbo 2 sage: pw, L = path_decomposition(g, algorithm = "exponential"); pw 2 - sage: pw, L = path_decomposition(g, algorithm = "MILP"); pw + sage: pw, L = path_decomposition(g, algorithm="MILP"); pw # needs sage.numerical.mip 2 TESTS: @@ -766,19 +766,19 @@ def vertex_separation(G, algorithm="BAB", cut_off=None, upper_bound=None, verbos Comparison of methods:: sage: from sage.graphs.graph_decompositions.vertex_separation import vertex_separation - sage: G = digraphs.DeBruijn(2,3) # optional - sage.combinat - sage: vs,L = vertex_separation(G, algorithm="BAB"); vs # optional - sage.combinat + sage: G = digraphs.DeBruijn(2,3) # needs sage.combinat + sage: vs,L = vertex_separation(G, algorithm="BAB"); vs # needs sage.combinat 2 - sage: vs,L = vertex_separation(G, algorithm="exponential"); vs # optional - sage.combinat + sage: vs,L = vertex_separation(G, algorithm="exponential"); vs # needs sage.combinat 2 - sage: vs,L = vertex_separation(G, algorithm="MILP"); vs # optional - sage.combinat + sage: vs,L = vertex_separation(G, algorithm="MILP"); vs # needs sage.combinat sage.numerical.mip 2 sage: G = graphs.Grid2dGraph(3,3) sage: vs,L = vertex_separation(G, algorithm="BAB"); vs 3 sage: vs,L = vertex_separation(G, algorithm="exponential"); vs 3 - sage: vs,L = vertex_separation(G, algorithm="MILP"); vs + sage: vs,L = vertex_separation(G, algorithm="MILP"); vs # needs sage.numerical.mip 3 Digraphs with multiple strongly connected components:: @@ -805,7 +805,7 @@ def vertex_separation(G, algorithm="BAB", cut_off=None, upper_bound=None, verbos sage: from sage.graphs.graph_decompositions.vertex_separation import vertex_separation sage: G = graphs.PetersenGraph() - sage: vs, L = vertex_separation(G, algorithm="MILP", solver="SCIP"); vs # optional - pyscipopt + sage: vs, L = vertex_separation(G, algorithm="MILP", solver="SCIP"); vs # optional - pyscipopt, needs sage.numerical.mip 5 TESTS: @@ -954,8 +954,8 @@ def vertex_separation_exp(G, verbose=False): Graphs with non-integer vertices:: sage: from sage.graphs.graph_decompositions.vertex_separation import vertex_separation_exp - sage: D = digraphs.DeBruijn(2,3) # optional - sage.combinat - sage: vertex_separation_exp(D) # optional - sage.combinat + sage: D = digraphs.DeBruijn(2,3) # needs sage.combinat + sage: vertex_separation_exp(D) # needs sage.combinat (2, ['000', '001', '100', '010', '101', '011', '110', '111']) Given a too large graph:: @@ -1210,13 +1210,14 @@ def width_of_path_decomposition(G, L): Path decomposition of a BalancedTree:: + sage: # needs networkx sage: from sage.graphs.graph_decompositions import vertex_separation - sage: G = graphs.BalancedTree(3,2) # optional - networkx - sage: pw, L = vertex_separation.path_decomposition(G) # optional - networkx - sage: pw == vertex_separation.width_of_path_decomposition(G, L) # optional - networkx + sage: G = graphs.BalancedTree(3,2) + sage: pw, L = vertex_separation.path_decomposition(G) + sage: pw == vertex_separation.width_of_path_decomposition(G, L) True - sage: L.reverse() # optional - networkx - sage: pw == vertex_separation.width_of_path_decomposition(G, L) # optional - networkx + sage: L.reverse() + sage: pw == vertex_separation.width_of_path_decomposition(G, L) False Directed path decomposition of a circuit:: @@ -1305,9 +1306,9 @@ def _vertex_separation_MILP_formulation(G, integrality=False, solver=None): EXAMPLES:: sage: from sage.graphs.graph_decompositions.vertex_separation import _vertex_separation_MILP_formulation - sage: G = digraphs.DeBruijn(2,3) # optional - sage.combinat - sage: p, x, u, y, z = _vertex_separation_MILP_formulation(G) # optional - sage.combinat - sage: p # optional - sage.combinat + sage: G = digraphs.DeBruijn(2,3) # needs sage.combinat + sage: p, x, u, y, z = _vertex_separation_MILP_formulation(G) # needs sage.combinat sage.numerical.mip + sage: p # needs sage.combinat sage.numerical.mip Mixed Integer Program (minimization, 193 variables, 449 constraints) """ from sage.graphs.graph import Graph @@ -1419,20 +1420,21 @@ def vertex_separation_MILP(G, integrality=False, solver=None, verbose=0, Vertex separation of a De Bruijn digraph:: + sage: # needs sage.combinat sage: from sage.graphs.graph_decompositions import vertex_separation - sage: G = digraphs.DeBruijn(2,3) # optional - sage.combinat - sage: vs, L = vertex_separation.vertex_separation_MILP(G); vs # optional - sage.combinat + sage: G = digraphs.DeBruijn(2,3) + sage: vs, L = vertex_separation.vertex_separation_MILP(G); vs # needs sage.numerical.mip 2 - sage: vs == vertex_separation.width_of_path_decomposition(G, L) # optional - sage.combinat + sage: vs == vertex_separation.width_of_path_decomposition(G, L) # needs sage.numerical.mip True - sage: vse, Le = vertex_separation.vertex_separation(G); vse # optional - sage.combinat + sage: vse, Le = vertex_separation.vertex_separation(G); vse 2 The vertex separation of a circuit is 1:: sage: from sage.graphs.graph_decompositions import vertex_separation sage: G = digraphs.Circuit(6) - sage: vs, L = vertex_separation.vertex_separation_MILP(G); vs + sage: vs, L = vertex_separation.vertex_separation_MILP(G); vs # needs sage.numerical.mip 1 TESTS: @@ -1440,7 +1442,7 @@ def vertex_separation_MILP(G, integrality=False, solver=None, verbose=0, Comparison with exponential algorithm:: sage: from sage.graphs.graph_decompositions import vertex_separation - sage: for i in range(10): + sage: for i in range(10): # needs sage.numerical.mip ....: G = digraphs.RandomDirectedGNP(10, 0.2) ....: ve, le = vertex_separation.vertex_separation(G) ....: vm, lm = vertex_separation.vertex_separation_MILP(G) @@ -1450,7 +1452,7 @@ def vertex_separation_MILP(G, integrality=False, solver=None, verbose=0, Comparison with different values of the integrality parameter:: sage: from sage.graphs.graph_decompositions import vertex_separation - sage: for i in range(10): # long time (11s on sage.math, 2012) + sage: for i in range(10): # long time (11s on sage.math, 2012), needs sage.numerical.mip ....: G = digraphs.RandomDirectedGNP(10, 0.2) ....: va, la = vertex_separation.vertex_separation_MILP(G, integrality=False) ....: vb, lb = vertex_separation.vertex_separation_MILP(G, integrality=True) @@ -1460,7 +1462,7 @@ def vertex_separation_MILP(G, integrality=False, solver=None, verbose=0, Giving anything else than a Graph or a DiGraph:: sage: from sage.graphs.graph_decompositions import vertex_separation - sage: vertex_separation.vertex_separation_MILP([]) + sage: vertex_separation.vertex_separation_MILP([]) # needs sage.numerical.mip Traceback (most recent call last): ... ValueError: the first input parameter must be a Graph or a DiGraph diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index ba6992f5070..12e80870fc2 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -651,9 +651,9 @@ class GraphGenerators(): except for appropriately inheritable properties:: sage: property = lambda G: G.is_vertex_transitive() - sage: len(list(graphs(4, property))) + sage: len(list(graphs(4, property))) # needs sage.groups 1 - sage: sum(1 for g in graphs(4) if property(g)) + sage: sum(1 for g in graphs(4) if property(g)) # needs sage.groups 4 sage: property = lambda G: G.is_bipartite() @@ -1231,39 +1231,39 @@ def cospectral_graphs(self, vertices, matrix_function=lambda g: g.adjacency_matr EXAMPLES:: - sage: g=graphs.cospectral_graphs(5) - sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) + sage: g = graphs.cospectral_graphs(5) # needs sage.modules + sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) # needs sage.modules [['Dr?', 'Ds_']] - sage: g[0][1].am().charpoly()==g[0][1].am().charpoly() + sage: g[0][1].am().charpoly()==g[0][1].am().charpoly() # needs sage.modules True There are two sets of cospectral graphs on six vertices with no isolated vertices:: - sage: g=graphs.cospectral_graphs(6, graphs=lambda x: min(x.degree())>0) - sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) + sage: g = graphs.cospectral_graphs(6, graphs=lambda x: min(x.degree())>0) # needs sage.modules + sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) # needs sage.modules [['Ep__', 'Er?G'], ['ExGg', 'ExoG']] - sage: g[0][1].am().charpoly()==g[0][1].am().charpoly() + sage: g[0][1].am().charpoly()==g[0][1].am().charpoly() # needs sage.modules True - sage: g[1][1].am().charpoly()==g[1][1].am().charpoly() + sage: g[1][1].am().charpoly()==g[1][1].am().charpoly() # needs sage.modules True There is one pair of cospectral trees on eight vertices:: - sage: g=graphs.cospectral_graphs(6, graphs=graphs.trees(8)) - sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) + sage: g = graphs.cospectral_graphs(6, graphs=graphs.trees(8)) # needs sage.modules + sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) # needs sage.modules [['GiPC?C', 'GiQCC?']] - sage: g[0][1].am().charpoly()==g[0][1].am().charpoly() + sage: g[0][1].am().charpoly()==g[0][1].am().charpoly() # needs sage.modules True There are two sets of cospectral graphs (with respect to the Laplacian matrix) on six vertices:: - sage: g=graphs.cospectral_graphs(6, matrix_function=lambda g: g.laplacian_matrix()) - sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) + sage: g = graphs.cospectral_graphs(6, matrix_function=lambda g: g.laplacian_matrix()) # needs sage.modules + sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) # needs sage.modules [['Edq_', 'ErcG'], ['Exoo', 'EzcG']] - sage: g[0][1].laplacian_matrix().charpoly()==g[0][1].laplacian_matrix().charpoly() + sage: g[0][1].laplacian_matrix().charpoly()==g[0][1].laplacian_matrix().charpoly() # needs sage.modules True - sage: g[1][1].laplacian_matrix().charpoly()==g[1][1].laplacian_matrix().charpoly() + sage: g[1][1].laplacian_matrix().charpoly()==g[1][1].laplacian_matrix().charpoly() # needs sage.modules True To find cospectral graphs with respect to the normalized @@ -1278,10 +1278,12 @@ def cospectral_graphs(self, vertices, matrix_function=lambda g: g.adjacency_matr ....: for i in range(g.order()): ....: A.rescale_row(i, 1 / len(A.nonzero_positions_in_row(i))) ....: return A - sage: g = graphs.cospectral_graphs(5, matrix_function=DinverseA, graphs=lambda g: min(g.degree()) > 0) - sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) + sage: g = graphs.cospectral_graphs(5, matrix_function=DinverseA, # needs sage.modules + ....: graphs=lambda g: min(g.degree()) > 0) + sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) # needs sage.modules [['Dlg', 'Ds_']] - sage: g[0][1].laplacian_matrix(normalized=True).charpoly()==g[0][1].laplacian_matrix(normalized=True).charpoly() # optional - sage.symbolic + sage: (g[0][1].laplacian_matrix(normalized=True).charpoly() # needs sage.modules sage.symbolic + ....: == g[0][1].laplacian_matrix(normalized=True).charpoly()) True """ from sage.graphs.graph_generators import graphs as graph_gen diff --git a/src/sage/graphs/graph_generators_pyx.pyx b/src/sage/graphs/graph_generators_pyx.pyx index 716f4e5975a..060ea9275c6 100644 --- a/src/sage/graphs/graph_generators_pyx.pyx +++ b/src/sage/graphs/graph_generators_pyx.pyx @@ -55,8 +55,8 @@ def RandomGNP(n, p, bint directed=False, bint loops=False, seed=None): TESTS:: - sage: from numpy import mean # optional - numpy - sage: abs(mean([RandomGNP(200, .2).density() for i in range(30)]) - .2) < .001 # optional - numpy + sage: from numpy import mean # needs numpy + sage: abs(mean([RandomGNP(200, .2).density() for i in range(30)]) - .2) < .001 # needs numpy True sage: RandomGNP(150, .2, loops=True) Traceback (most recent call last): diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index 39b22a44b56..e46a2156809 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -185,9 +185,9 @@ def from_seidel_adjacency_matrix(G, M): sage: from sage.graphs.graph_input import from_seidel_adjacency_matrix sage: g = Graph() - sage: sam = graphs.PetersenGraph().seidel_adjacency_matrix() # optional - sage.modules - sage: from_seidel_adjacency_matrix(g, sam) # optional - sage.modules - sage: g.is_isomorphic(graphs.PetersenGraph()) # optional - sage.modules + sage: sam = graphs.PetersenGraph().seidel_adjacency_matrix() # needs sage.modules + sage: from_seidel_adjacency_matrix(g, sam) # needs sage.modules + sage: g.is_isomorphic(graphs.PetersenGraph()) # needs sage.modules True """ from sage.structure.element import is_Matrix @@ -236,8 +236,8 @@ def from_adjacency_matrix(G, M, loops=False, multiedges=False, weighted=False): sage: from sage.graphs.graph_input import from_adjacency_matrix sage: g = Graph() - sage: from_adjacency_matrix(g, graphs.PetersenGraph().adjacency_matrix()) # optional - sage.modules - sage: g.is_isomorphic(graphs.PetersenGraph()) # optional - sage.modules + sage: from_adjacency_matrix(g, graphs.PetersenGraph().adjacency_matrix()) # needs sage.modules + sage: g.is_isomorphic(graphs.PetersenGraph()) # needs sage.modules True """ from sage.structure.element import is_Matrix @@ -312,8 +312,8 @@ def from_incidence_matrix(G, M, loops=False, multiedges=False, weighted=False): sage: from sage.graphs.graph_input import from_incidence_matrix sage: g = Graph() - sage: from_incidence_matrix(g, graphs.PetersenGraph().incidence_matrix()) # optional - sage.modules - sage: g.is_isomorphic(graphs.PetersenGraph()) # optional - sage.modules + sage: from_incidence_matrix(g, graphs.PetersenGraph().incidence_matrix()) # needs sage.modules + sage: g.is_isomorphic(graphs.PetersenGraph()) # needs sage.modules True """ from sage.structure.element import is_Matrix @@ -378,37 +378,37 @@ def from_oriented_incidence_matrix(G, M, loops=False, multiedges=False, weighted sage: from sage.graphs.graph_input import from_oriented_incidence_matrix sage: g = DiGraph() - sage: im = digraphs.Circuit(10).incidence_matrix() # optional - sage.modules - sage: from_oriented_incidence_matrix(g, im) # optional - sage.modules - sage: g.is_isomorphic(digraphs.Circuit(10)) # optional - sage.modules + sage: im = digraphs.Circuit(10).incidence_matrix() # needs sage.modules + sage: from_oriented_incidence_matrix(g, im) # needs sage.modules + sage: g.is_isomorphic(digraphs.Circuit(10)) # needs sage.modules True TESTS: Fix bug reported in :trac:`22985`:: - sage: DiGraph(matrix ([[1,0,0,1],[0,0,1,1],[0,0,1,1]]).transpose()) # optional - sage.modules + sage: DiGraph(matrix ([[1,0,0,1],[0,0,1,1],[0,0,1,1]]).transpose()) # needs sage.modules Traceback (most recent call last): ... ValueError: each column represents an edge: -1 goes to 1 Handle incidence matrix containing a column with only zeros (:trac:`29275`):: - sage: m = Matrix([[0,1],[0,-1],[0,0]]); m # optional - sage.modules + sage: m = Matrix([[0,1],[0,-1],[0,0]]); m # needs sage.modules [ 0 1] [ 0 -1] [ 0 0] - sage: G = DiGraph(m, format='incidence_matrix') # optional - sage.modules - sage: list(G.edges(sort=True, labels=False)) # optional - sage.modules + sage: G = DiGraph(m, format='incidence_matrix') # needs sage.modules + sage: list(G.edges(sort=True, labels=False)) # needs sage.modules [(1, 0)] Handle incidence matrix [[1],[-1]] (:trac:`29275`):: - sage: m = Matrix([[1],[-1]]); m # optional - sage.modules + sage: m = Matrix([[1],[-1]]); m # needs sage.modules [ 1] [-1] - sage: G = DiGraph(m, format='incidence_matrix') # optional - sage.modules - sage: list(G.edges(sort=True, labels=False)) # optional - sage.modules + sage: G = DiGraph(m, format='incidence_matrix') # needs sage.modules + sage: list(G.edges(sort=True, labels=False)) # needs sage.modules [(1, 0)] """ from sage.structure.element import is_Matrix @@ -614,42 +614,42 @@ def from_networkx_graph(G, gnx, weighted=None, loops=None, multiedges=None, Feeding a :class:`Graph` with a NetworkX ``Graph``:: sage: from sage.graphs.graph_input import from_networkx_graph - sage: import networkx # optional - networkx + sage: import networkx # needs networkx sage: G = Graph() - sage: _ = gnx = networkx.Graph() # optional - networkx - sage: _ = gnx.add_edge(0, 1) # optional - networkx - sage: _ = gnx.add_edge(1, 2) # optional - networkx - sage: from_networkx_graph(G, gnx) # optional - networkx - sage: G.edges(sort=True, labels=False) # optional - networkx + sage: _ = gnx = networkx.Graph() # needs networkx + sage: _ = gnx.add_edge(0, 1) # needs networkx + sage: _ = gnx.add_edge(1, 2) # needs networkx + sage: from_networkx_graph(G, gnx) # needs networkx + sage: G.edges(sort=True, labels=False) # needs networkx [(0, 1), (1, 2)] Feeding a :class:`Graph` with a NetworkX ``MultiGraph``:: sage: G = Graph() - sage: gnx = networkx.MultiGraph() # optional - networkx - sage: _ = gnx.add_edge(0, 1) # optional - networkx - sage: _ = gnx.add_edge(0, 1) # optional - networkx - sage: from_networkx_graph(G, gnx) # optional - networkx - sage: G.edges(sort=True, labels=False) # optional - networkx + sage: gnx = networkx.MultiGraph() # needs networkx + sage: _ = gnx.add_edge(0, 1) # needs networkx + sage: _ = gnx.add_edge(0, 1) # needs networkx + sage: from_networkx_graph(G, gnx) # needs networkx + sage: G.edges(sort=True, labels=False) # needs networkx [(0, 1), (0, 1)] sage: G = Graph() - sage: from_networkx_graph(G, gnx, multiedges=False) # optional - networkx - sage: G.edges(sort=True, labels=False) # optional - networkx + sage: from_networkx_graph(G, gnx, multiedges=False) # needs networkx + sage: G.edges(sort=True, labels=False) # needs networkx [(0, 1)] When feeding a :class:`Graph` `G` with a NetworkX ``DiGraph`` `D`, `G` has one edge `(u, v)` whenever `D` has arc `(u, v)` or `(v, u)` or both:: sage: G = Graph() - sage: D = networkx.DiGraph() # optional - networkx - sage: _ = D.add_edge(0, 1) # optional - networkx - sage: from_networkx_graph(G, D) # optional - networkx - sage: G.edges(sort=True, labels=False) # optional - networkx + sage: D = networkx.DiGraph() # needs networkx + sage: _ = D.add_edge(0, 1) # needs networkx + sage: from_networkx_graph(G, D) # needs networkx + sage: G.edges(sort=True, labels=False) # needs networkx [(0, 1)] sage: G = Graph() - sage: _ = D.add_edge(1, 0) # optional - networkx - sage: from_networkx_graph(G, D) # optional - networkx - sage: G.edges(sort=True, labels=False) # optional - networkx + sage: _ = D.add_edge(1, 0) # needs networkx + sage: from_networkx_graph(G, D) # needs networkx + sage: G.edges(sort=True, labels=False) # needs networkx [(0, 1)] When feeding a :class:`Graph` `G` with a NetworkX ``MultiDiGraph`` `D`, the @@ -657,50 +657,50 @@ def from_networkx_graph(G, gnx, weighted=None, loops=None, multiedges=None, of arcs `(u, v)` and the number of arcs `(v, u)` in D`:: sage: G = Graph() - sage: D = networkx.MultiDiGraph() # optional - networkx - sage: _ = D.add_edge(0, 1) # optional - networkx - sage: _ = D.add_edge(1, 0) # optional - networkx - sage: _ = D.add_edge(1, 0) # optional - networkx - sage: D.edges() # optional - networkx + sage: D = networkx.MultiDiGraph() # needs networkx + sage: _ = D.add_edge(0, 1) # needs networkx + sage: _ = D.add_edge(1, 0) # needs networkx + sage: _ = D.add_edge(1, 0) # needs networkx + sage: D.edges() # needs networkx OutMultiEdgeDataView([(0, 1), (1, 0), (1, 0)]) - sage: from_networkx_graph(G, D) # optional - networkx - sage: G.edges(sort=True, labels=False) # optional - networkx + sage: from_networkx_graph(G, D) # needs networkx + sage: G.edges(sort=True, labels=False) # needs networkx [(0, 1), (0, 1)] Feeding a :class:`DiGraph` with a NetworkX ``DiGraph``:: sage: from sage.graphs.graph_input import from_networkx_graph - sage: import networkx # optional - networkx + sage: import networkx # needs networkx sage: G = DiGraph() - sage: _ = gnx = networkx.DiGraph() # optional - networkx - sage: _ = gnx.add_edge(0, 1) # optional - networkx - sage: _ = gnx.add_edge(1, 2) # optional - networkx - sage: from_networkx_graph(G, gnx) # optional - networkx - sage: G.edges(sort=True, labels=False) # optional - networkx + sage: _ = gnx = networkx.DiGraph() # needs networkx + sage: _ = gnx.add_edge(0, 1) # needs networkx + sage: _ = gnx.add_edge(1, 2) # needs networkx + sage: from_networkx_graph(G, gnx) # needs networkx + sage: G.edges(sort=True, labels=False) # needs networkx [(0, 1), (1, 2)] Feeding a :class:`DiGraph` with a NetworkX ``MultiDiGraph``:: sage: G = DiGraph() - sage: gnx = networkx.MultiDiGraph() # optional - networkx - sage: _ = gnx.add_edge(0, 1) # optional - networkx - sage: _ = gnx.add_edge(0, 1) # optional - networkx - sage: from_networkx_graph(G, gnx) # optional - networkx - sage: G.edges(sort=True, labels=False) # optional - networkx + sage: gnx = networkx.MultiDiGraph() # needs networkx + sage: _ = gnx.add_edge(0, 1) # needs networkx + sage: _ = gnx.add_edge(0, 1) # needs networkx + sage: from_networkx_graph(G, gnx) # needs networkx + sage: G.edges(sort=True, labels=False) # needs networkx [(0, 1), (0, 1)] sage: G = DiGraph() - sage: from_networkx_graph(G, gnx, multiedges=False) # optional - networkx - sage: G.edges(sort=True, labels=False) # optional - networkx + sage: from_networkx_graph(G, gnx, multiedges=False) # needs networkx + sage: G.edges(sort=True, labels=False) # needs networkx [(0, 1)] When feeding a :class:`DiGraph` `G` with a NetworkX ``Graph`` `H`, `G` has both arcs `(u, v)` and `(v, u)` if `G` has edge `(u, v)`:: sage: G = DiGraph() - sage: H = networkx.Graph() # optional - networkx - sage: _ = H.add_edge(0, 1) # optional - networkx - sage: from_networkx_graph(G, H) # optional - networkx - sage: G.edges(labels=False, sort=True) # optional - networkx + sage: H = networkx.Graph() # needs networkx + sage: _ = H.add_edge(0, 1) # needs networkx + sage: from_networkx_graph(G, H) # needs networkx + sage: G.edges(labels=False, sort=True) # needs networkx [(0, 1), (1, 0)] When feeding a :class:`DiGraph` `G` with a NetworkX ``MultiGraph`` `H`, `G` @@ -708,18 +708,18 @@ def from_networkx_graph(G, gnx, weighted=None, loops=None, multiedges=None, unless parameter ``multiedges`` is set to ``False``:: sage: G = DiGraph() - sage: H = networkx.MultiGraph() # optional - networkx - sage: _ = H.add_edge(0, 1) # optional - networkx - sage: _ = H.add_edge(0, 1) # optional - networkx - sage: _ = H.add_edge(0, 1) # optional - networkx - sage: H.edges() # optional - networkx + sage: H = networkx.MultiGraph() # needs networkx + sage: _ = H.add_edge(0, 1) # needs networkx + sage: _ = H.add_edge(0, 1) # needs networkx + sage: _ = H.add_edge(0, 1) # needs networkx + sage: H.edges() # needs networkx MultiEdgeDataView([(0, 1), (0, 1), (0, 1)]) - sage: from_networkx_graph(G, H) # optional - networkx - sage: G.edges(labels=False, sort=True) # optional - networkx + sage: from_networkx_graph(G, H) # needs networkx + sage: G.edges(labels=False, sort=True) # needs networkx [(0, 1), (0, 1), (0, 1), (1, 0), (1, 0), (1, 0)] sage: G = DiGraph() - sage: from_networkx_graph(G, H, multiedges=False) # optional - networkx - sage: G.edges(labels=False, sort=True) # optional - networkx + sage: from_networkx_graph(G, H, multiedges=False) # needs networkx + sage: G.edges(labels=False, sort=True) # needs networkx [(0, 1), (1, 0)] TESTS: @@ -736,7 +736,7 @@ def from_networkx_graph(G, gnx, weighted=None, loops=None, multiedges=None, ``DiGraph`` or ``MultiDiGraph``:: sage: from sage.graphs.graph_input import from_networkx_graph - sage: from_networkx_graph(Graph(), "bar") # optional - networkx + sage: from_networkx_graph(Graph(), "bar") # needs networkx Traceback (most recent call last): ... ValueError: the second parameter must be a NetworkX (Multi)(Di)Graph diff --git a/src/sage/graphs/graph_latex.py b/src/sage/graphs/graph_latex.py index 7666151fb50..7988f6e3518 100644 --- a/src/sage/graphs/graph_latex.py +++ b/src/sage/graphs/graph_latex.py @@ -265,14 +265,14 @@ package. So it is worth viewing this in the notebook to see the effects of various defaults and choices.:: - sage: var('x y u w') # optional - sage.symbolic + sage: var('x y u w') # needs sage.symbolic (x, y, u, w) sage: G = Graph(loops=True) - sage: for i in range(5): # optional - sage.symbolic + sage: for i in range(5): # needs sage.symbolic ....: for j in range(i+1, 5): ....: G.add_edge((i, j), label=(x^i*y^j).expand()) - sage: G.add_edge((0,0), label=sin(u)) # optional - sage.symbolic - sage: G.add_edge((4,4), label=w^5) # optional - sage.symbolic + sage: G.add_edge((0,0), label=sin(u)) # needs sage.symbolic + sage: G.add_edge((4,4), label=w^5) # needs sage.symbolic sage: G.set_pos(G.layout_circular()) sage: G.set_latex_options( ....: units='in', @@ -307,7 +307,7 @@ ....: ) sage: from sage.graphs.graph_latex import check_tkz_graph sage: check_tkz_graph() # random - depends on TeX installation - sage: print(latex(G)) # optional - sage.symbolic + sage: print(latex(G)) # needs sage.symbolic \begin{tikzpicture} \definecolor{cv0}{rgb}{0.8,0.8,0.8} \definecolor{cfv0}{rgb}{0.0,0.0,1.0} diff --git a/src/sage/graphs/graph_list.py b/src/sage/graphs/graph_list.py index 4a43987a79b..6994a821948 100644 --- a/src/sage/graphs/graph_list.py +++ b/src/sage/graphs/graph_list.py @@ -258,17 +258,17 @@ def to_graphics_array(graph_list, **kwds): sage: glist = [] sage: for i in range(999): ....: glist.append(graphs.RandomGNP(6, .45)) - sage: garray = graphs_list.to_graphics_array(glist) # optional - sage.plot - sage: garray.nrows(), garray.ncols() # optional - sage.plot + sage: garray = graphs_list.to_graphics_array(glist) # needs sage.plot + sage: garray.nrows(), garray.ncols() # needs sage.plot (250, 4) See the .plot() or .show() documentation for an individual graph for options, all of which are available from :func:`to_graphics_array`:: sage: glist = [] - sage: for _ in range(10): # optional - networkx + sage: for _ in range(10): # needs networkx ....: glist.append(graphs.RandomLobster(41, .3, .4)) - sage: graphs_list.to_graphics_array(glist, layout='spring', vertex_size=20) # optional - networkx sage.plot + sage: graphs_list.to_graphics_array(glist, layout='spring', vertex_size=20) # needs networkx sage.plot Graphics Array of size 3 x 4 """ from sage.graphs import graph @@ -342,7 +342,7 @@ def show_graphs(graph_list, **kwds): Show the graphs in a graphics array:: - sage: graphs_list.show_graphs(glist) # optional - sage.plot + sage: graphs_list.show_graphs(glist) # needs sage.plot Example where more than one graphics array is used:: @@ -350,15 +350,15 @@ def show_graphs(graph_list, **kwds): sage: g = gq.get_graphs_list() sage: len(g) 34 - sage: graphs_list.show_graphs(g) # optional - sage.plot + sage: graphs_list.show_graphs(g) # needs sage.plot See the .plot() or .show() documentation for an individual graph for options, all of which are available from :func:`to_graphics_array`:: sage: glist = [] - sage: for _ in range(10): + sage: for _ in range(10): # needs networkx ....: glist.append(graphs.RandomLobster(41, .3, .4)) - sage: graphs_list.show_graphs(glist, layout='spring', vertex_size=20) # optional - sage.plot + sage: graphs_list.show_graphs(glist, layout='spring', vertex_size=20) # needs sage.plot """ graph_list = list(graph_list) for i in range(len(graph_list) // 20 + 1): diff --git a/src/sage/graphs/graph_plot_js.py b/src/sage/graphs/graph_plot_js.py index ad846d7a474..a29e7293df8 100644 --- a/src/sage/graphs/graph_plot_js.py +++ b/src/sage/graphs/graph_plot_js.py @@ -174,14 +174,15 @@ def gen_html_code(G, sage: graphs.DodecahedralGraph().show(method="js") # optional -- internet sage.plot - sage: g = digraphs.DeBruijn(2, 2) # optional - sage.combinat - sage: g.allow_multiple_edges(True) # optional - sage.combinat - sage: g.add_edge("10", "10", "a") # optional - sage.combinat - sage: g.add_edge("10", "10", "b") # optional - sage.combinat - sage: g.add_edge("10", "10", "c") # optional - sage.combinat - sage: g.add_edge("10", "10", "d") # optional - sage.combinat - sage: g.add_edge("01", "11", "1") # optional - sage.combinat - sage: g.show(method="js", vertex_labels=True,edge_labels=True, # optional - sage.combinat sage.plot + sage: # needs sage.combinat + sage: g = digraphs.DeBruijn(2, 2) + sage: g.allow_multiple_edges(True) + sage: g.add_edge("10", "10", "a") + sage: g.add_edge("10", "10", "b") + sage: g.add_edge("10", "10", "c") + sage: g.add_edge("10", "10", "d") + sage: g.add_edge("01", "11", "1") + sage: g.show(method="js", vertex_labels=True, edge_labels=True, ....: link_distance=200, gravity=.05, charge=-500, ....: edge_partition=[[("11", "12", "2"), ("21", "21", "a")]], ....: edge_thickness=4) diff --git a/src/sage/graphs/hypergraph_generators.py b/src/sage/graphs/hypergraph_generators.py index c3e42da9565..3d6a7d28cd6 100644 --- a/src/sage/graphs/hypergraph_generators.py +++ b/src/sage/graphs/hypergraph_generators.py @@ -217,7 +217,7 @@ def CompleteUniform(self, n, k): sage: h = hypergraphs.CompleteUniform(5, 2); h Incidence structure with 5 points and 10 blocks - sage: len(h.packing()) + sage: len(h.packing()) # needs sage.numerical.mip 2 """ from sage.combinat.designs.incidence_structures import IncidenceStructure @@ -306,34 +306,35 @@ def BinomialRandomUniform(self, n, k, p): EXAMPLES:: - sage: hypergraphs.BinomialRandomUniform(50, 3, 1).num_blocks() # optional - numpy + sage: hypergraphs.BinomialRandomUniform(50, 3, 1).num_blocks() # needs numpy 19600 - sage: hypergraphs.BinomialRandomUniform(50, 3, 0).num_blocks() # optional - numpy + sage: hypergraphs.BinomialRandomUniform(50, 3, 0).num_blocks() # needs numpy 0 TESTS:: - sage: hypergraphs.BinomialRandomUniform(50, 3, -0.1) # optional - numpy + sage: # needs numpy + sage: hypergraphs.BinomialRandomUniform(50, 3, -0.1) Traceback (most recent call last): ... ValueError: edge probability should be in [0,1] - sage: hypergraphs.BinomialRandomUniform(50, 3, 1.1) # optional - numpy + sage: hypergraphs.BinomialRandomUniform(50, 3, 1.1) Traceback (most recent call last): ... ValueError: edge probability should be in [0,1] - sage: hypergraphs.BinomialRandomUniform(-50, 3, 0.17) # optional - numpy + sage: hypergraphs.BinomialRandomUniform(-50, 3, 0.17) Traceback (most recent call last): ... ValueError: number of vertices should be non-negative - sage: hypergraphs.BinomialRandomUniform(50.9, 3, 0.17) # optional - numpy + sage: hypergraphs.BinomialRandomUniform(50.9, 3, 0.17) Traceback (most recent call last): ... ValueError: number of vertices should be an integer - sage: hypergraphs.BinomialRandomUniform(50, -3, 0.17) # optional - numpy + sage: hypergraphs.BinomialRandomUniform(50, -3, 0.17) Traceback (most recent call last): ... ValueError: the uniformity should be non-negative - sage: hypergraphs.BinomialRandomUniform(50, I, 0.17) # optional - numpy + sage: hypergraphs.BinomialRandomUniform(50, I, 0.17) Traceback (most recent call last): ... ValueError: the uniformity should be an integer diff --git a/src/sage/graphs/independent_sets.pyx b/src/sage/graphs/independent_sets.pyx index d894f1706ed..23c8677b34a 100644 --- a/src/sage/graphs/independent_sets.pyx +++ b/src/sage/graphs/independent_sets.pyx @@ -162,7 +162,7 @@ cdef class IndependentSets: ....: IS2.extend(map(Set, list(G.subgraph_search_iterator(Graph(n), induced=True, return_graphs=False)))) ....: if len(IS) != len(set(IS2)): ....: raise ValueError("something goes wrong") - sage: for i in range(5): + sage: for i in range(5): # needs sage.modules ....: check_with_subgraph_search(graphs.RandomGNP(11, .3)) Empty graph:: diff --git a/src/sage/graphs/isoperimetric_inequalities.pyx b/src/sage/graphs/isoperimetric_inequalities.pyx index b6dfa40d06d..1d01e311c1c 100644 --- a/src/sage/graphs/isoperimetric_inequalities.pyx +++ b/src/sage/graphs/isoperimetric_inequalities.pyx @@ -209,8 +209,8 @@ def edge_isoperimetric_number(g): In general, for `d`-regular graphs the edge-isoperimetric number is `d` times larger than the Cheeger constant of the graph:: - sage: g = graphs.RandomRegular(3, 10) # optional - networkx - sage: g.edge_isoperimetric_number() == g.cheeger_constant() * 3 # optional - networkx + sage: g = graphs.RandomRegular(3, 10) # needs networkx + sage: g.edge_isoperimetric_number() == g.cheeger_constant() * 3 # needs networkx True And the edge-isoperimetric constant of a disconnected graph is `0`:: diff --git a/src/sage/graphs/line_graph.pyx b/src/sage/graphs/line_graph.pyx index 656c9c08909..a30055e891c 100644 --- a/src/sage/graphs/line_graph.pyx +++ b/src/sage/graphs/line_graph.pyx @@ -176,8 +176,8 @@ def is_line_graph(g, certificate=False): This is indeed the subgraph returned:: - sage: C = graphs.PetersenGraph().is_line_graph(certificate=True)[1] # optional - sage.modules - sage: C.is_isomorphic(graphs.ClawGraph()) # optional - sage.modules + sage: C = graphs.PetersenGraph().is_line_graph(certificate=True)[1] # needs sage.modules + sage: C.is_isomorphic(graphs.ClawGraph()) # needs sage.modules True The house graph is a line graph:: @@ -188,11 +188,12 @@ def is_line_graph(g, certificate=False): But what is the graph whose line graph is the house ?:: - sage: is_line, R, isom = g.is_line_graph(certificate=True) # optional - sage.modules - sage: R.sparse6_string() # optional - sage.modules + sage: # needs sage.modules + sage: is_line, R, isom = g.is_line_graph(certificate=True) + sage: R.sparse6_string() ':DaHI~' - sage: R.show() # optional - sage.modules sage.plot - sage: isom # optional - sage.modules + sage: R.show() # needs sage.plot + sage: isom {0: (0, 1), 1: (0, 2), 2: (1, 3), 3: (2, 3), 4: (3, 4)} TESTS: @@ -201,8 +202,8 @@ def is_line_graph(g, certificate=False): sage: g = 2 * graphs.CycleGraph(3) sage: gl = g.line_graph().relabel(inplace=False) - sage: new_g = gl.is_line_graph(certificate=True)[1] # optional - sage.modules - sage: g.line_graph().is_isomorphic(gl) # optional - sage.modules + sage: new_g = gl.is_line_graph(certificate=True)[1] # needs sage.modules + sage: g.line_graph().is_isomorphic(gl) # needs sage.modules True Verify that :trac:`29740` is fixed:: @@ -314,7 +315,7 @@ def line_graph(g, labels=True): (1, 2, None), (1, 3, None), (2, 3, None)] - sage: h.am() # optional - sage.modules + sage: h.am() # needs sage.modules [0 1 1 1 1 0] [1 0 1 1 0 1] [1 1 0 0 1 1] @@ -324,7 +325,7 @@ def line_graph(g, labels=True): sage: h2 = g.line_graph(labels=False) sage: h2.vertices(sort=True) [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] - sage: h2.am() == h.am() + sage: h2.am() == h.am() # needs sage.modules True sage: g = DiGraph([[1..4], lambda i,j: i < j]) sage: h = g.line_graph() diff --git a/src/sage/graphs/matchpoly.pyx b/src/sage/graphs/matchpoly.pyx index 7845b225f9c..e98cc8d6b63 100644 --- a/src/sage/graphs/matchpoly.pyx +++ b/src/sage/graphs/matchpoly.pyx @@ -328,9 +328,9 @@ def complete_poly(n): Checking the numerical results up to 20:: - sage: from sage.functions.orthogonal_polys import hermite # optional - sage.symbolic - sage: p = lambda n: 2^(-n/2)*hermite(n, x/sqrt(2)) # optional - sage.symbolic - sage: all(p(i) == complete_poly(i) for i in range(2, 20)) # optional - sage.symbolic + sage: from sage.functions.orthogonal_polys import hermite # needs sage.symbolic + sage: p = lambda n: 2^(-n/2)*hermite(n, x/sqrt(2)) # needs sage.symbolic + sage: all(p(i) == complete_poly(i) for i in range(2, 20)) # needs sage.symbolic True """ # global complete_matching_polys # if we do eventually make it a C array... diff --git a/src/sage/graphs/partial_cube.py b/src/sage/graphs/partial_cube.py index 0ec81f6b200..70456e548c9 100644 --- a/src/sage/graphs/partial_cube.py +++ b/src/sage/graphs/partial_cube.py @@ -110,8 +110,8 @@ def breadth_first_level_search(G, start): EXAMPLES:: - sage: H = digraphs.DeBruijn(3,2) # optional - sage.combinat - sage: list(sage.graphs.partial_cube.breadth_first_level_search(H, '00')) # optional - sage.combinat + sage: H = digraphs.DeBruijn(3,2) # needs sage.combinat + sage: list(sage.graphs.partial_cube.breadth_first_level_search(H, '00')) # needs sage.combinat [{'00': {'01', '02'}}, {'01': {'10', '11', '12'}, '02': {'20', '21', '22'}}, {'10': set(), @@ -162,9 +162,9 @@ def depth_first_traversal(G, start): EXAMPLES:: - sage: H = digraphs.DeBruijn(3,2) # optional - sage.combinat - sage: t = list(sage.graphs.partial_cube.depth_first_traversal(H, '00')) # optional - sage.combinat - sage: len(t) # optional - sage.combinat + sage: H = digraphs.DeBruijn(3,2) # needs sage.combinat + sage: t = list(sage.graphs.partial_cube.depth_first_traversal(H, '00')) # needs sage.combinat + sage: len(t) # needs sage.combinat 16 """ neighbors = G.neighbor_out_iterator diff --git a/src/sage/graphs/path_enumeration.pyx b/src/sage/graphs/path_enumeration.pyx index 032ebd95ec2..50836ffdcb9 100644 --- a/src/sage/graphs/path_enumeration.pyx +++ b/src/sage/graphs/path_enumeration.pyx @@ -432,20 +432,20 @@ def shortest_simple_paths(self, source, target, weight_function=None, [1, 2, 3, 4, 5], [1, 6, 9, 3, 4, 5], [1, 6, 9, 11, 10, 5]] - sage: G = digraphs.DeBruijn(2, 3) - sage: for u,v in G.edges(sort=True, labels=False): + sage: G = digraphs.DeBruijn(2, 3) # needs sage.combinat + sage: for u,v in G.edges(sort=True, labels=False): # needs sage.combinat ....: G.set_edge_label(u, v, 1) - sage: G.allow_multiple_edges(True) - sage: for u,v in G.edges(sort=True, labels=False): + sage: G.allow_multiple_edges(True) # needs sage.combinat + sage: for u,v in G.edges(sort=True, labels=False): # needs sage.combinat ....: G.add_edge(u, v, 2) - sage: list(G.shortest_simple_paths('000', '111')) + sage: list(G.shortest_simple_paths('000', '111')) # needs sage.combinat [['000', '001', '011', '111'], ['000', '001', '010', '101', '011', '111']] - sage: list(G.shortest_simple_paths('000', '111', by_weight=True)) + sage: list(G.shortest_simple_paths('000', '111', by_weight=True)) # needs sage.combinat [['000', '001', '011', '111'], ['000', '001', '010', '101', '011', '111']] - sage: list(G.shortest_simple_paths('000', '111', by_weight=True, report_weight=True)) + sage: list(G.shortest_simple_paths('000', '111', by_weight=True, report_weight=True)) # needs sage.combinat [(3, ['000', '001', '011', '111']), (5, ['000', '001', '010', '101', '011', '111'])] - sage: list(G.shortest_simple_paths('000', '111', by_weight=True, report_weight=True, report_edges=True, labels=True)) + sage: list(G.shortest_simple_paths('000', '111', by_weight=True, report_weight=True, report_edges=True, labels=True)) # needs sage.combinat [(3, [('000', '001', 1), ('001', '011', 1), ('011', '111', 1)]), (5, [('000', '001', 1), @@ -470,12 +470,12 @@ def shortest_simple_paths(self, source, target, weight_function=None, Check for consistency of results of Yen's and Feng's:: - sage: G = digraphs.DeBruijn(2, 4) + sage: G = digraphs.DeBruijn(2, 4) # needs sage.combinat sage: s = set() - sage: for p in G.shortest_simple_paths('0000', '1111', by_weight=False, algorithm='Yen'): + sage: for p in G.shortest_simple_paths('0000', '1111', by_weight=False, algorithm='Yen'): # needs sage.combinat ....: s.add(tuple(p)) sage: k = set() - sage: for p in G.shortest_simple_paths('0000', '1111', by_weight=False, algorithm='Feng'): + sage: for p in G.shortest_simple_paths('0000', '1111', by_weight=False, algorithm='Feng'): # needs sage.combinat ....: k.add(tuple(p)) sage: k == s True diff --git a/src/sage/graphs/planarity.pyx b/src/sage/graphs/planarity.pyx index 839039a2bde..ff501043ea5 100644 --- a/src/sage/graphs/planarity.pyx +++ b/src/sage/graphs/planarity.pyx @@ -72,17 +72,18 @@ def is_planar(g, kuratowski=False, set_pos=False, set_embedding=False, circular= vertices. In fact, to try to track down a segfault, we do it twice. :: - sage: import networkx.generators.atlas # long time # optional - networkx - sage: atlas_graphs = [Graph(i) for i in networkx.generators.atlas.graph_atlas_g()] # long time # optional - networkx - sage: a = [i for i in [1..1252] if atlas_graphs[i].is_planar()] # long time # optional - networkx - sage: b = [i for i in [1..1252] if atlas_graphs[i].is_planar()] # long time # optional - networkx - sage: a == b # long time # optional - networkx + sage: # long time, needs networkx + sage: import networkx.generators.atlas + sage: atlas_graphs = [Graph(i) for i in networkx.generators.atlas.graph_atlas_g()] + sage: a = [i for i in [1..1252] if atlas_graphs[i].is_planar()] + sage: b = [i for i in [1..1252] if atlas_graphs[i].is_planar()] + sage: a == b True There were some problems with ``set_pos`` stability in the past, so let's check if this runs without exception:: - sage: for i, g in enumerate(atlas_graphs): # long time # optional - networkx + sage: for i, g in enumerate(atlas_graphs): # long time # needs networkx ....: if (not g.is_connected() or i == 0): ....: continue ....: _ = g.is_planar(set_embedding=True, set_pos=True) diff --git a/src/sage/graphs/schnyder.py b/src/sage/graphs/schnyder.py index 5427a93691e..40f6d923656 100644 --- a/src/sage/graphs/schnyder.py +++ b/src/sage/graphs/schnyder.py @@ -743,7 +743,7 @@ def minimal_schnyder_wood(graph, root_edge=None, minimal=True, check=True): sage: newg = minimal_schnyder_wood(g) sage: newg.edges(sort=True) [(0, -3, 'red'), (0, -2, 'blue'), (0, -1, 'green')] - sage: newg.plot(color_by_label={'red':'red','blue':'blue', # optional - sage.plot + sage: newg.plot(color_by_label={'red':'red','blue':'blue', # needs sage.plot ....: 'green':'green',None:'black'}) Graphics object consisting of 8 graphics primitives diff --git a/src/sage/graphs/spanning_tree.pyx b/src/sage/graphs/spanning_tree.pyx index 08f441d90a8..11fd83c0759 100644 --- a/src/sage/graphs/spanning_tree.pyx +++ b/src/sage/graphs/spanning_tree.pyx @@ -196,6 +196,7 @@ def kruskal(G, by_weight=True, weight_function=None, check_weight=False, check=F The input graph must be connected. :: + sage: # long time sage: def my_disconnected_graph(n, ntries, directed=False, multiedges=False, loops=False): ....: G = Graph() ....: k = randint(2, n) @@ -216,14 +217,14 @@ def kruskal(G, by_weight=True, weight_function=None, check_weight=False, check=F ....: v = randint(0, k-1) ....: G.delete_edge(u, v) ....: return G - sage: G = my_disconnected_graph(100, 50, directed=False, multiedges=False, loops=False) # long time - sage: kruskal(G, check=True) # long time + sage: G = my_disconnected_graph(100, 50, directed=False, multiedges=False, loops=False) + sage: kruskal(G, check=True) [] - sage: G = my_disconnected_graph(100, 50, directed=False, multiedges=True, loops=False) # long time - sage: kruskal(G, check=True) # long time + sage: G = my_disconnected_graph(100, 50, directed=False, multiedges=True, loops=False) + sage: kruskal(G, check=True) [] - sage: G = my_disconnected_graph(100, 50, directed=False, multiedges=True, loops=True) # long time - sage: kruskal(G, check=True) # long time + sage: G = my_disconnected_graph(100, 50, directed=False, multiedges=True, loops=True) + sage: kruskal(G, check=True) [] If the input graph is a tree, then return its edges:: @@ -568,12 +569,13 @@ def filter_kruskal_iterator(G, threshold=10000, by_weight=True, weight_function= The weights of the spanning trees returned by :func:`kruskal_iterator` and :func:`filter_kruskal_iterator` are the same:: + sage: # needs networkx sage: from sage.graphs.spanning_tree import kruskal_iterator - sage: G = graphs.RandomBarabasiAlbert(50, 2) # optional - networkx - sage: for u, v in G.edge_iterator(labels=False): # optional - networkx + sage: G = graphs.RandomBarabasiAlbert(50, 2) + sage: for u, v in G.edge_iterator(labels=False): ....: G.set_edge_label(u, v, randint(1, 10)) - sage: G.weighted(True) # optional - networkx - sage: sum(e[2] for e in kruskal_iterator(G)) == sum(e[2] # optional - networkx + sage: G.weighted(True) + sage: sum(e[2] for e in kruskal_iterator(G)) == sum(e[2] ....: for e in filter_kruskal_iterator(G, threshold=20)) True @@ -976,7 +978,7 @@ def random_spanning_tree(G, output_as_graph=False, by_weight=False, weight_funct sage: pos = G.get_pos() sage: T = G.random_spanning_tree(True) sage: T.set_pos(pos) - sage: T.show(vertex_labels=False) # optional - sage.plot + sage: T.show(vertex_labels=False) # needs sage.plot We can also use edge weights to change the probability of returning a spanning tree:: @@ -1000,11 +1002,12 @@ def random_spanning_tree(G, output_as_graph=False, by_weight=False, weight_funct Check that the spanning tree returned when using weights is a tree:: - sage: G = graphs.RandomBarabasiAlbert(50, 2) # optional - networkx - sage: for u, v in G.edge_iterator(labels=False): # optional - networkx + sage: # needs networkx + sage: G = graphs.RandomBarabasiAlbert(50, 2) + sage: for u, v in G.edge_iterator(labels=False): ....: G.set_edge_label(u, v, randint(1, 10)) - sage: T = G.random_spanning_tree(by_weight=True, output_as_graph=True) # optional - networkx - sage: T.is_tree() # optional - networkx + sage: T = G.random_spanning_tree(by_weight=True, output_as_graph=True) + sage: T.is_tree() True TESTS:: @@ -1088,12 +1091,12 @@ def spanning_trees(g, labels=False): sage: G = Graph([(1,2),(1,2),(1,3),(1,3),(2,3),(1,4)], multiedges=True) sage: len(list(G.spanning_trees())) 8 - sage: G.spanning_trees_count() # optional - sage.modules + sage: G.spanning_trees_count() # needs sage.modules 8 sage: G = Graph([(1,2),(2,3),(3,1),(3,4),(4,5),(4,5),(4,6)], multiedges=True) sage: len(list(G.spanning_trees())) 6 - sage: G.spanning_trees_count() # optional - sage.modules + sage: G.spanning_trees_count() # needs sage.modules 6 .. SEEALSO:: diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 3d48b45e58d..1c9e8699905 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -70,9 +70,9 @@ def is_paley(int v, int k, int l, int mu): sage: from sage.graphs.strongly_regular_db import is_paley sage: t = is_paley(13,6,2,3); t (..., 13) - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.rings.finite_rings Paley graph with parameter 13: Graph on 13 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (13, 6, 2, 3) sage: t = is_paley(5,5,5,5); t """ @@ -110,18 +110,18 @@ def is_mathon_PC_srg(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_mathon_PC_srg - sage: t = is_mathon_PC_srg(45,22,10,11); t + sage: t = is_mathon_PC_srg(45,22,10,11); t # needs sage.libs.pari (..., 1) - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.libs.pari Mathon's PC SRG on 45 vertices: Graph on 45 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari (45, 22, 10, 11) TESTS:: - sage: t = is_mathon_PC_srg(5,5,5,5); t - sage: mu = 1895 # t=5 case -- the construction cannot work - sage: t = is_mathon_PC_srg(4*mu+1,2*mu,mu-1,mu); t + sage: t = is_mathon_PC_srg(5,5,5,5); t # needs sage.libs.pari + sage: mu = 1895 # t=5 case -- the construction cannot work # needs sage.libs.pari + sage: t = is_mathon_PC_srg(4*mu+1,2*mu,mu-1,mu); t # needs sage.libs.pari """ cdef int t if (v % 4 == 1 and @@ -162,6 +162,7 @@ def is_muzychuk_S6(int v, int k, int l, int mu): EXAMPLES:: + sage: # needs sage.libs.pari sage: from sage.graphs.strongly_regular_db import is_muzychuk_S6 sage: t = is_muzychuk_S6(378, 116, 34, 36) sage: G = t[0](*t[1:]); G @@ -211,6 +212,7 @@ def is_orthogonal_array_block_graph(int v, int k, int l, int mu): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: from sage.graphs.strongly_regular_db import is_orthogonal_array_block_graph sage: t = is_orthogonal_array_block_graph(64, 35, 18, 20); t (..., 5, 8) @@ -218,20 +220,20 @@ def is_orthogonal_array_block_graph(int v, int k, int l, int mu): OA(5,8): Graph on 64 vertices sage: g.is_strongly_regular(parameters=True) (64, 35, 18, 20) - sage: t=is_orthogonal_array_block_graph(225,98,43,42); t + sage: t = is_orthogonal_array_block_graph(225,98,43,42); t (..., 4) sage: g = t[0](*t[1:]); g Pasechnik Graph_4: Graph on 225 vertices sage: g.is_strongly_regular(parameters=True) (225, 98, 43, 42) - sage: t=is_orthogonal_array_block_graph(225,112,55,56); t + sage: t = is_orthogonal_array_block_graph(225,112,55,56); t (..., 4) sage: g = t[0](*t[1:]); g skewhad^2_4: Graph on 225 vertices sage: g.is_strongly_regular(parameters=True) (225, 112, 55, 56) - sage: t = is_orthogonal_array_block_graph(5,5,5,5); t + sage: t = is_orthogonal_array_block_graph(5,5,5,5); t # needs sage.combinat sage.modules """ # notations from # https://www.win.tue.nl/~aeb/graphs/OA.html @@ -356,11 +358,11 @@ def is_affine_polar(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_affine_polar - sage: t = is_affine_polar(81,32,13,12); t + sage: t = is_affine_polar(81,32,13,12); t # needs sage.rings.finite_rings (..., 4, 3) - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.rings.finite_rings Affine Polar Graph VO^+(4,3): Graph on 81 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (81, 32, 13, 12) sage: t = is_affine_polar(5,5,5,5); t @@ -413,12 +415,12 @@ def is_orthogonal_polar(int v, int k, int l, int mu): sage: from sage.graphs.strongly_regular_db import is_orthogonal_polar sage: t = is_orthogonal_polar(85, 20, 3, 5); t (, 5, 4, '') - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.rings.finite_rings Orthogonal Polar Graph O(5, 4): Graph on 85 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (85, 20, 3, 5) - sage: t = is_orthogonal_polar(5,5,5,5); t + sage: t = is_orthogonal_polar(5,5,5,5); t # needs sage.rings.finite_rings TESTS: @@ -428,7 +430,7 @@ def is_orthogonal_polar(int v, int k, int l, int mu): (, 5, 4, '') sage: is_orthogonal_polar(119,54,21,27) (, 8, 2, '-') - sage: is_orthogonal_polar(130,48,20,16) + sage: is_orthogonal_polar(130,48,20,16) # needs sage.rings.finite_rings (, 6, 3, '+') """ @@ -487,25 +489,26 @@ def is_goethals_seidel(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_goethals_seidel - sage: t = is_goethals_seidel(28, 15, 6, 10); t + sage: t = is_goethals_seidel(28, 15, 6, 10); t # needs sage.combinat sage.modules [, 3, 3] - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.combinat sage.modules Graph on 28 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.combinat sage.modules (28, 15, 6, 10) - sage: t = is_goethals_seidel(256, 135, 70, 72); t + sage: t = is_goethals_seidel(256, 135, 70, 72); t # needs sage.combinat sage.modules [, 2, 15] - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.combinat sage.modules Graph on 256 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.combinat sage.modules (256, 135, 70, 72) - sage: t = is_goethals_seidel(5,5,5,5); t + sage: t = is_goethals_seidel(5,5,5,5); t # needs sage.combinat sage.modules TESTS:: - sage: for p in [(16, 9, 4, 6), (28, 15, 6, 10), (64, 35, 18, 20), (120, 63, 30, 36), + sage: for p in [(16, 9, 4, 6), (28, 15, 6, 10), # needs sage.combinat sage.modules + ....: (64, 35, 18, 20), (120, 63, 30, 36), ....: (144, 77, 40, 42), (256, 135, 70, 72), (400, 209, 108, 110), ....: (496, 255, 126, 136), (540, 275, 130, 150), (576, 299, 154, 156), ....: (780, 399, 198, 210), (784, 405, 208, 210), (976, 495, 238, 264)]: @@ -567,26 +570,27 @@ def is_NOodd(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_NOodd - sage: t = is_NOodd(120, 51, 18, 24); t + sage: t = is_NOodd(120, 51, 18, 24); t # needs sage.libs.pari (, 5, 4, '-') - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.libs.pari NO^-(5, 4): Graph on 120 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari (120, 51, 18, 24) TESTS: All of ``NO^+(2m+1,q)`` and ``NO^-(2m+1,q)`` appear:: + sage: # needs sage.libs.pari sage: t = is_NOodd(120, 51, 18, 24); t (, 5, 4, '-') sage: t = is_NOodd(136, 75, 42, 40); t (, 5, 4, '+') - sage: t=is_NOodd(378, 260, 178, 180); t + sage: t = is_NOodd(378, 260, 178, 180); t (, 7, 3, '+') - sage: t=is_NOodd(45, 32, 22, 24); t + sage: t = is_NOodd(45, 32, 22, 24); t (, 5, 3, '+') - sage: t=is_NOodd(351, 224, 142, 144); t + sage: t = is_NOodd(351, 224, 142, 144); t (, 7, 3, '-') sage: t = is_NOodd(325, 144, 68, 60); t (, 5, 5, '+') @@ -637,22 +641,22 @@ def is_NOperp_F5(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_NOperp_F5 - sage: t = is_NOperp_F5(10, 3, 0, 1); t + sage: t = is_NOperp_F5(10, 3, 0, 1); t # needs sage.libs.pari (, 3, 5, '-', 1) - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.libs.pari NO^-,perp(3, 5): Graph on 10 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari (10, 3, 0, 1) TESTS: All of ``NO^+,perp(2m+1,5)`` and ``NO^-,perp(2m+1,5)`` appear:: - sage: t = is_NOperp_F5(325, 60, 15, 10); t + sage: t = is_NOperp_F5(325, 60, 15, 10); t # needs sage.libs.pari (, 5, 5, '+', 1) - sage: t = is_NOperp_F5(300, 65, 10, 15); t + sage: t = is_NOperp_F5(300, 65, 10, 15); t # needs sage.libs.pari (, 5, 5, '-', 1) - sage: t = is_NOperp_F5(5,5,5,5); t + sage: t = is_NOperp_F5(5,5,5,5); t # needs sage.libs.pari """ cdef int n r, s = eigenvalues(v, k, l, mu) # 2*e*5**(n-1), -e*5**(n-1); note exceptional case n=1 @@ -692,22 +696,22 @@ def is_NO_F2(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_NO_F2 - sage: t = is_NO_F2(10, 3, 0, 1); t + sage: t = is_NO_F2(10, 3, 0, 1); t # needs sage.libs.pari (, 4, 2, '-') - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.libs.pari NO^-(4, 2): Graph on 10 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari (10, 3, 0, 1) TESTS: All of ``NO^+(2m,2)`` and ``NO^-(2m,2)`` appear:: - sage: t = is_NO_F2(36, 15, 6, 6); t + sage: t = is_NO_F2(36, 15, 6, 6); t # needs sage.libs.pari (, 6, 2, '-') - sage: t = is_NO_F2(28, 15, 6, 10); t + sage: t = is_NO_F2(28, 15, 6, 10); t # needs sage.libs.pari (, 6, 2, '+') - sage: t = is_NO_F2(5,5,5,5); t + sage: t = is_NO_F2(5,5,5,5); t # needs sage.libs.pari """ cdef int n, e, p p, n = is_prime_power(k+1, get_data=True) # k+1==2**(2*n-2) @@ -743,22 +747,22 @@ def is_NO_F3(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_NO_F3 - sage: t = is_NO_F3(15, 6, 1, 3); t + sage: t = is_NO_F3(15, 6, 1, 3); t # needs sage.libs.pari (, 4, 3, '-') - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.libs.pari NO^-(4, 3): Graph on 15 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari (15, 6, 1, 3) TESTS: All of ``NO^+(2m,3)`` and ``NO^-(2m,3)`` appear:: - sage: t = is_NO_F3(126, 45, 12, 18); t + sage: t = is_NO_F3(126, 45, 12, 18); t # needs sage.libs.pari (, 6, 3, '-') - sage: t = is_NO_F3(117, 36, 15, 9); t + sage: t = is_NO_F3(117, 36, 15, 9); t # needs sage.libs.pari (, 6, 3, '+') - sage: t = is_NO_F3(5,5,5,5); t + sage: t = is_NO_F3(5,5,5,5); t # needs sage.libs.pari """ cdef int n, e, p r, s = eigenvalues(v, k, l, mu) # e*3**(n-1), -e*3**(n-2) @@ -799,15 +803,16 @@ def is_NU(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_NU - sage: t = is_NU(40, 27, 18, 18); t + sage: t = is_NU(40, 27, 18, 18); t # needs sage.libs.pari (, 4, 2) - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.libs.pari NU(4, 2): Graph on 40 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari (40, 27, 18, 18) TESTS:: + sage: # needs sage.libs.pari sage: t = is_NU(176, 135, 102, 108); t (, 5, 2) sage: t = is_NU(540, 224, 88, 96); t @@ -866,16 +871,16 @@ def is_haemers(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_haemers - sage: t = is_haemers(96, 19, 2, 4); t + sage: t = is_haemers(96, 19, 2, 4); t # needs sage.libs.pari (, 4) - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.libs.pari Haemers(4): Graph on 96 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari (96, 19, 2, 4) TESTS:: - sage: t = is_haemers(5,5,5,5); t + sage: t = is_haemers(5,5,5,5); t # needs sage.libs.pari """ cdef int q, n, p p, n = is_prime_power(mu, get_data=True) @@ -908,20 +913,20 @@ def is_cossidente_penttila(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_cossidente_penttila - sage: t = is_cossidente_penttila(378, 52, 1, 8); t + sage: t = is_cossidente_penttila(378, 52, 1, 8); t # needs sage.libs.pari (, 5) - sage: g = t[0](*t[1:]); g # optional - gap_packages + sage: g = t[0](*t[1:]); g # optional - gap_packages # needs sage.libs.pari CossidentePenttila(5): Graph on 378 vertices - sage: g.is_strongly_regular(parameters=True) # optional - gap_packages + sage: g.is_strongly_regular(parameters=True) # optional - gap_packages, needs sage.libs.pari (378, 52, 1, 8) TESTS:: - sage: t = is_cossidente_penttila(56,10,0,2); t + sage: t = is_cossidente_penttila(56,10,0,2); t # needs sage.libs.pari (, 3) - sage: t = is_cossidente_penttila(1376,150,2,18); t + sage: t = is_cossidente_penttila(1376,150,2,18); t # needs sage.libs.pari (, 7) - sage: t = is_cossidente_penttila(5,5,5,5); t + sage: t = is_cossidente_penttila(5,5,5,5); t # needs sage.libs.pari """ cdef int q, n, p q = 2*l + 3 @@ -1008,12 +1013,13 @@ def is_polhill(int v, int k, int l, int mu): EXAMPLES:: + sage: # needs sage.rings.finite_rings sage: from sage.graphs.strongly_regular_db import is_polhill sage: t = is_polhill(1024, 231, 38, 56); t [. at ...>] - sage: g = t[0](*t[1:]); g # not tested (too long) + sage: g = t[0](*t[1:]); g # not tested (too long) Graph on 1024 vertices - sage: g.is_strongly_regular(parameters=True) # not tested (too long) + sage: g.is_strongly_regular(parameters=True) # not tested (too long) (1024, 231, 38, 56) sage: t = is_polhill(1024, 264, 56, 72); t [. at ...>] @@ -1156,11 +1162,11 @@ def is_RSHCD(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_RSHCD - sage: t = is_RSHCD(64,27,10,12); t + sage: t = is_RSHCD(64,27,10,12); t # needs sage.combinat sage.modules [, 64, 27, 10, 12] - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.combinat sage.modules Graph on 64 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.combinat sage.modules (64, 27, 10, 12) """ if SRG_from_RSHCD(v, k, l, mu, existence=True) is True: @@ -1191,26 +1197,27 @@ def SRG_from_RSHCD(v, k, l, mu, existence=False, check=True): some graphs :: sage: from sage.graphs.strongly_regular_db import SRG_from_RSHCD - sage: SRG_from_RSHCD(784, 0, 14, 38, existence=True) + sage: SRG_from_RSHCD(784, 0, 14, 38, existence=True) # needs sage.combinat sage.modules False - sage: SRG_from_RSHCD(784, 377, 180, 182, existence=True) + sage: SRG_from_RSHCD(784, 377, 180, 182, existence=True) # needs sage.combinat sage.modules True - sage: SRG_from_RSHCD(144, 65, 28, 30) + sage: SRG_from_RSHCD(144, 65, 28, 30) # needs sage.combinat sage.modules Graph on 144 vertices an example with vertex-transitive automorphism group, found during the implementation of the case `v=324` :: - sage: G=SRG_from_RSHCD(324,152,70,72) # long time - sage: a=G.automorphism_group() # long time - sage: a.order() # long time + sage: # long time, needs sage.combinat sage.modules + sage: G = SRG_from_RSHCD(324,152,70,72) + sage: a = G.automorphism_group() + sage: a.order() 2592 - sage: len(a.orbits()) # long time + sage: len(a.orbits()) 1 TESTS:: - sage: SRG_from_RSHCD(784, 0, 14, 38) + sage: SRG_from_RSHCD(784, 0, 14, 38) # needs sage.combinat sage.modules Traceback (most recent call last): ... ValueError: I do not know how to build a (784, 0, 14, 38)-SRG from a RSHCD @@ -1267,19 +1274,20 @@ def is_unitary_polar(int v, int k, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_unitary_polar - sage: t = is_unitary_polar(45, 12, 3, 3); t + sage: t = is_unitary_polar(45, 12, 3, 3); t # needs sage.libs.pari (, 4, 2) - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.libs.pari Unitary Polar Graph U(4, 2); GQ(4, 2): Graph on 45 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.pari (45, 12, 3, 3) - sage: t = is_unitary_polar(5,5,5,5); t + sage: t = is_unitary_polar(5,5,5,5); t # needs sage.libs.pari TESTS: All the ``U(n,q)`` appear:: + sage: # needs sage.libs.pari sage: t = is_unitary_polar(45, 12, 3, 3); t (, 4, 2) sage: t = is_unitary_polar(165, 36, 3, 9); t @@ -1342,6 +1350,7 @@ def is_unitary_dual_polar(int v, int k, int l, int mu): EXAMPLES:: + sage: # needs sage.libs.pari sage: from sage.graphs.strongly_regular_db import is_unitary_dual_polar sage: t = is_unitary_dual_polar(297, 40, 7, 5); t (, 5, 2) @@ -1353,7 +1362,7 @@ def is_unitary_dual_polar(int v, int k, int l, int mu): TESTS:: - sage: is_unitary_dual_polar(6832, 270, 26, 10) + sage: is_unitary_dual_polar(6832, 270, 26, 10) # needs sage.libs.pari (, 5, 3) """ r, s = eigenvalues(v, k, l, mu) @@ -1392,6 +1401,7 @@ def is_GQqmqp(int v, int k, int l, int mu): EXAMPLES:: + sage: # needs sage.libs.pari sage: from sage.graphs.strongly_regular_db import is_GQqmqp sage: t = is_GQqmqp(27,10,1,5); t (, 3, False) @@ -1418,19 +1428,19 @@ def is_GQqmqp(int v, int k, int l, int mu): TESTS:: - sage: (S,T)=(127,129) - sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t + sage: (S,T) = (127,129) + sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t # needs sage.libs.pari (, 128, False) - sage: (S,T)=(129,127) - sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t + sage: (S,T) = (129,127) + sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t # needs sage.libs.pari (, 128, True) - sage: (S,T)=(124,126) - sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t + sage: (S,T) = (124,126) + sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t # needs sage.libs.pari (, 125, False) - sage: (S,T)=(126,124) - sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t + sage: (S,T) = (126,124) + sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t # needs sage.libs.pari (, 125, True) - sage: t = is_GQqmqp(5,5,5,5); t + sage: t = is_GQqmqp(5,5,5,5); t # needs sage.libs.pari """ # do we have GQ(s,t)? we must have mu=t+1, s=l+1, # v=(s+1)(st+1), k=s(t+1) @@ -1484,17 +1494,17 @@ def is_twograph_descendant_of_srg(int v, int k0, int l, int mu): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import is_twograph_descendant_of_srg - sage: t = is_twograph_descendant_of_srg(27, 10, 1, 5); t + sage: t = is_twograph_descendant_of_srg(27, 10, 1, 5); t # needs sage.rings.finite_rings (.la at... - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # needs sage.rings.finite_rings descendant of complement(Johnson graph with parameters 8,2) at {0, 1}: Graph on 27 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (27, 10, 1, 5) sage: t = is_twograph_descendant_of_srg(5,5,5,5); t TESTS:: - sage: graphs.strongly_regular_graph(279, 150, 85, 75, existence=True) + sage: graphs.strongly_regular_graph(279, 150, 85, 75, existence=True) # needs sage.combinat True sage: graphs.strongly_regular_graph(279, 150, 85, 75).is_strongly_regular(parameters=True) # optional - gap_packages internet (279, 150, 85, 75) @@ -1545,6 +1555,7 @@ def is_taylor_twograph_srg(int v, int k, int l, int mu): EXAMPLES:: + sage: # needs sage.libs.pari sage: from sage.graphs.strongly_regular_db import is_taylor_twograph_srg sage: t = is_taylor_twograph_srg(28, 15, 6, 10); t (, 3) @@ -1556,7 +1567,7 @@ def is_taylor_twograph_srg(int v, int k, int l, int mu): TESTS:: - sage: is_taylor_twograph_srg(730, 369, 168, 205) + sage: is_taylor_twograph_srg(730, 369, 168, 205) # needs sage.libs.pari (, 9) """ @@ -1595,13 +1606,13 @@ def is_switch_skewhad(int v, int k, int l, int mu): EXAMPLES:: - sage: graphs.strongly_regular_graph(226, 105, 48, 49) + sage: graphs.strongly_regular_graph(226, 105, 48, 49) # needs sage.combinat sage.modules switch skewhad^2+*_4: Graph on 226 vertices TESTS:: sage: from sage.graphs.strongly_regular_db import is_switch_skewhad - sage: t = is_switch_skewhad(5,5,5,5); t + sage: t = is_switch_skewhad(5,5,5,5); t # needs sage.combinat sage.modules """ from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix @@ -1642,22 +1653,22 @@ def is_switch_OA_srg(int v, int k, int l, int mu): EXAMPLES:: - sage: graphs.strongly_regular_graph(170, 78, 35, 36) # indirect doctest + sage: graphs.strongly_regular_graph(170, 78, 35, 36) # indirect doctest # needs sage.combinat sage.modules Graph on 170 vertices TESTS:: sage: from sage.graphs.strongly_regular_db import is_switch_OA_srg sage: t = is_switch_OA_srg(5,5,5,5); t - sage: t = is_switch_OA_srg(170, 78, 35, 36) - sage: t[0](*t[1:]).is_strongly_regular(parameters=True) + sage: t = is_switch_OA_srg(170, 78, 35, 36) # needs sage.schemes + sage: t[0](*t[1:]).is_strongly_regular(parameters=True) # needs sage.schemes (170, 78, 35, 36) - sage: t = is_switch_OA_srg(290, 136, 63, 64) - sage: t[0](*t[1:]).is_strongly_regular(parameters=True) + sage: t = is_switch_OA_srg(290, 136, 63, 64) # needs sage.schemes + sage: t[0](*t[1:]).is_strongly_regular(parameters=True) # needs sage.schemes (290, 136, 63, 64) - sage: is_switch_OA_srg(626, 300, 143, 144) + sage: is_switch_OA_srg(626, 300, 143, 144) # needs sage.schemes (.switch_OA_srg at ..., 12, 25) - sage: is_switch_OA_srg(842, 406, 195, 196) + sage: is_switch_OA_srg(842, 406, 195, 196) # needs sage.schemes (.switch_OA_srg at ..., 14, 29) """ cdef int n_2_p_1 = v @@ -1700,15 +1711,15 @@ def is_nowhere0_twoweight(int v, int k, int l, int mu): EXAMPLES:: - sage: graphs.strongly_regular_graph(196, 60, 14, 20) + sage: graphs.strongly_regular_graph(196, 60, 14, 20) # needs sage.combinat sage.modules Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices TESTS:: sage: from sage.graphs.strongly_regular_db import is_nowhere0_twoweight - sage: t = is_nowhere0_twoweight(1800, 728, 268, 312); t + sage: t = is_nowhere0_twoweight(1800, 728, 268, 312); t # needs sage.libs.pari (, 16) - sage: t = is_nowhere0_twoweight(5,5,5,5); t + sage: t = is_nowhere0_twoweight(5,5,5,5); t # needs sage.libs.pari """ from sage.graphs.generators.classical_geometries import Nowhere0WordsTwoWeightCodeGraph @@ -1787,22 +1798,22 @@ def eigenmatrix(int v, int k, int l, int mu): Petersen's graph's C-algebra does not have a dual coming from an s.r.g.:: sage: from sage.graphs.strongly_regular_db import eigenmatrix - sage: P=eigenmatrix(10,3,0,1); P + sage: P = eigenmatrix(10,3,0,1); P # needs sage.modules [ 1 3 6] [ 1 1 -2] [ 1 -2 1] - sage: 10*P^-1 + sage: 10*P^-1 # needs sage.modules [ 1 5 4] [ 1 5/3 -8/3] [ 1 -5/3 2/3] The line graph of `K_{3,3}` is self-dual:: - sage: P=eigenmatrix(9,4,1,2); P + sage: P = eigenmatrix(9,4,1,2); P # needs sage.modules [ 1 4 4] [ 1 1 -2] [ 1 -2 1] - sage: 9*P^-1 + sage: 9*P^-1 # needs sage.modules [ 1 4 4] [ 1 1 -2] [ 1 -2 1] @@ -1810,11 +1821,12 @@ def eigenmatrix(int v, int k, int l, int mu): A strongly regular graph with a non-isomorphic dual coming from another strongly regular graph:: - sage: graphs.strongly_regular_graph(243,220,199,200, existence=True) + sage: # needs sage.modules + sage: graphs.strongly_regular_graph(243,220,199,200, existence=True) # needs sage.combinat True - sage: graphs.strongly_regular_graph(243,110,37,60, existence=True) + sage: graphs.strongly_regular_graph(243,110,37,60, existence=True) # needs sage.combinat True - sage: P=eigenmatrix(243,220,199,200); P + sage: P = eigenmatrix(243,220,199,200); P [ 1 220 22] [ 1 4 -5] [ 1 -5 4] @@ -1882,7 +1894,7 @@ def _H_3_cayley_graph(L): TESTS:: sage: from sage.graphs.strongly_regular_db import _H_3_cayley_graph - sage: _H_3_cayley_graph(["100","110","130","140","200","230","240","300"]) + sage: _H_3_cayley_graph(["100","110","130","140","200","230","240","300"]) # needs sage.groups Graph on 100 vertices """ from sage.groups.free_group import FreeGroup @@ -1955,9 +1967,9 @@ def SRG_105_32_4_12(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_105_32_4_12 - sage: G = SRG_105_32_4_12(); G + sage: G = SRG_105_32_4_12(); G # needs sage.rings.finite_rings Aut L(3,4) on flags: Graph on 105 vertices - sage: G.is_strongly_regular(parameters=True) + sage: G.is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (105, 32, 4, 12) """ from sage.combinat.designs.block_design import ProjectiveGeometryDesign @@ -2009,8 +2021,8 @@ def SRG_144_39_6_12(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_144_39_6_12 - sage: G = SRG_144_39_6_12() - sage: G.is_strongly_regular(parameters=True) + sage: G = SRG_144_39_6_12() # needs sage.libs.gap + sage: G.is_strongly_regular(parameters=True) # needs sage.libs.gap (144, 39, 6, 12) """ from sage.libs.gap.libgap import libgap @@ -2107,8 +2119,8 @@ def SRG_210_99_48_45(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_210_99_48_45 - sage: g=SRG_210_99_48_45() - sage: g.is_strongly_regular(parameters=True) + sage: g = SRG_210_99_48_45() # needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # needs sage.libs.gap (210, 99, 48, 45) """ from sage.libs.gap.libgap import libgap @@ -2154,8 +2166,8 @@ def SRG_243_110_37_60(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_243_110_37_60 - sage: G = SRG_243_110_37_60() - sage: G.is_strongly_regular(parameters=True) + sage: G = SRG_243_110_37_60() # needs sage.modules sage.rings.finite_rings + sage: G.is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings (243, 110, 37, 60) """ from sage.coding.golay_code import GolayCode @@ -2365,13 +2377,13 @@ def strongly_regular_from_two_weight_code(L): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import strongly_regular_from_two_weight_code - sage: x=("100022021001111", - ....: "010011211122000", - ....: "001021112100011", - ....: "000110120222220") - sage: M = Matrix(GF(3),[list(l) for l in x]) - sage: G = strongly_regular_from_two_weight_code(LinearCode(M)) - sage: G.is_strongly_regular(parameters=True) + sage: x = ("100022021001111", + ....: "010011211122000", + ....: "001021112100011", + ....: "000110120222220") + sage: M = Matrix(GF(3),[list(l) for l in x]) # needs sage.modules sage.rings.finite_rings + sage: G = strongly_regular_from_two_weight_code(LinearCode(M)) # needs sage.modules sage.rings.finite_rings + sage: G.is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings (81, 50, 31, 30) """ from sage.structure.element import is_Matrix @@ -2472,10 +2484,10 @@ def strongly_regular_from_two_intersection_set(M): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import strongly_regular_from_two_intersection_set - sage: S = Matrix([(0,0,1),(0,1,0)] + [(1,x^2,x) for x in GF(4,'b')]) - sage: g = strongly_regular_from_two_intersection_set(S); g + sage: S = Matrix([(0,0,1),(0,1,0)] + [(1,x^2,x) for x in GF(4,'b')]) # needs sage.modules sage.rings.finite_rings + sage: g = strongly_regular_from_two_intersection_set(S); g # needs sage.modules sage.rings.finite_rings two-intersection set in PG(3,4): Graph on 64 vertices - sage: g.is_strongly_regular(parameters=True) + sage: g.is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings (64, 18, 2, 6) """ from itertools import product @@ -2662,8 +2674,8 @@ def SRG_1288_792_476_504(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_1288_792_476_504 - sage: G = SRG_1288_792_476_504() # long time - sage: G.is_strongly_regular(parameters=True) # long time + sage: G = SRG_1288_792_476_504() # long time # needs sage.rings.finite_rings + sage: G.is_strongly_regular(parameters=True) # long time # needs sage.rings.finite_rings (1288, 792, 476, 504) """ from sage.coding.golay_code import GolayCode @@ -2691,7 +2703,7 @@ cdef bint seems_feasible(int v, int k, int l, int mu): :trac:`32306` is fixed:: sage: from sage.graphs.strongly_regular_db import strongly_regular_graph - sage: strongly_regular_graph(16384, 8256, 4160, 4160, existence=True) + sage: strongly_regular_graph(16384, 8256, 4160, 4160, existence=True) # needs sage.combinat sage.modules True """ cdef uint_fast32_t tmp[2] @@ -2821,9 +2833,9 @@ def strongly_regular_graph(int v, int k, int l, int mu=-1, bint existence=False, An set of parameters proved in a paper to be infeasible:: - sage: graphs.strongly_regular_graph(324,57,0,12,existence=True) + sage: graphs.strongly_regular_graph(324,57,0,12,existence=True) # needs sage.combinat sage.modules False - sage: graphs.strongly_regular_graph(324,57,0,12) + sage: graphs.strongly_regular_graph(324,57,0,12) # needs sage.combinat sage.modules Traceback (most recent call last): ... EmptySetError: Andries Brouwer's database reports that no (324, 57, 0, @@ -2832,9 +2844,9 @@ def strongly_regular_graph(int v, int k, int l, int mu=-1, bint existence=False, A set of parameters unknown to be realizable in Andries Brouwer's database:: - sage: graphs.strongly_regular_graph(324,95,22,30,existence=True) + sage: graphs.strongly_regular_graph(324,95,22,30,existence=True) # needs sage.combinat Unknown - sage: graphs.strongly_regular_graph(324,95,22,30) + sage: graphs.strongly_regular_graph(324,95,22,30) # needs sage.combinat Traceback (most recent call last): ... RuntimeError: Andries Brouwer's database reports that no @@ -2843,9 +2855,9 @@ def strongly_regular_graph(int v, int k, int l, int mu=-1, bint existence=False, A large unknown set of parameters (not in Andries Brouwer's database):: - sage: graphs.strongly_regular_graph(1394,175,0,25,existence=True) + sage: graphs.strongly_regular_graph(1394,175,0,25,existence=True) # needs sage.combinat Unknown - sage: graphs.strongly_regular_graph(1394,175,0,25) + sage: graphs.strongly_regular_graph(1394,175,0,25) # needs sage.combinat Traceback (most recent call last): ... RuntimeError: Sage cannot figure out if a (1394, 175, 0, 25)-strongly @@ -2860,11 +2872,11 @@ def strongly_regular_graph(int v, int k, int l, int mu=-1, bint existence=False, Check that :trac:`26513` is fixed:: - sage: graphs.strongly_regular_graph(539, 288, 162, 144) + sage: graphs.strongly_regular_graph(539, 288, 162, 144) # needs sage.combinat descendant of (540, 264, 138, 120)-strongly regular graph at ... 539 vertices - sage: graphs.strongly_regular_graph(539, 250, 105, 125) + sage: graphs.strongly_regular_graph(539, 250, 105, 125) # needs sage.combinat descendant of (540, 275, 130, 150)-strongly regular graph at ... 539 vertices - sage: graphs.strongly_regular_graph(209, 100, 45, 50) + sage: graphs.strongly_regular_graph(209, 100, 45, 50) # needs sage.libs.pari descendant of complement(merging of S_7 on Circulant(6,[1,4])s) at ... 209 vertices @@ -2930,11 +2942,11 @@ def strongly_regular_graph_lazy(int v, int k, int l, int mu=-1, bint existence=F (3, 4)) sage: g(p) complement(Multipartite Graph with set sizes [4, 4, 4]): Graph on 12 vertices - sage: g=strongly_regular_graph_lazy(539,250,105); g + sage: g = strongly_regular_graph_lazy(539,250,105); g # needs sage.combinat sage.modules (.la at...>, 5, 11) - sage: g[0](*g[1:]) + sage: g[0](*g[1:]) # needs sage.combinat sage.modules descendant of (540, 275, 130, 150)-strongly regular graph at 0: Graph on 539 vertices """ load_brouwer_database() @@ -3065,14 +3077,16 @@ def apparently_feasible_parameters(int n): (16, 9, 4, 6), (16, 10, 6, 6), (17, 8, 3, 4)} - sage: all(graphs.strongly_regular_graph(*x,existence=True) is True for x in small_feasible) + sage: all(graphs.strongly_regular_graph(*x,existence=True) is True # needs sage.libs.pari + ....: for x in small_feasible) True But that becomes wrong for `v<60` (because of the non-existence of a `(49,16,3,6)`-strongly regular graph):: sage: small_feasible = apparently_feasible_parameters(60) - sage: all(graphs.strongly_regular_graph(*x,existence=True) is True for x in small_feasible) + sage: all(graphs.strongly_regular_graph(*x,existence=True) is True # needs sage.libs.pari + ....: for x in small_feasible) False """ cdef int v, k, l, mu @@ -3100,28 +3114,28 @@ def _build_small_srg_database(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import _build_small_srg_database - sage: _build_small_srg_database() + sage: _build_small_srg_database() # needs sage.modules sage.rings.finite_rings TESTS: Make sure that all two-weight codes yield the strongly regular graphs we expect:: - sage: graphs.strongly_regular_graph(81, 50, 31, 30) + sage: graphs.strongly_regular_graph(81, 50, 31, 30) # needs sage.libs.pari complement(two-intersection set in PG(4,3)): Graph on 81 vertices - sage: graphs.strongly_regular_graph(243, 220, 199, 200) # long time + sage: graphs.strongly_regular_graph(243, 220, 199, 200) # long time, needs sage.rings.finite_rings two-weight code: [55, 5] linear code over GF(3): Graph on 243 vertices - sage: graphs.strongly_regular_graph(256, 153, 92, 90) + sage: graphs.strongly_regular_graph(256, 153, 92, 90) # needs sage.combinat complement(two-intersection set in PG(4,4)): Graph on 256 vertices - sage: graphs.strongly_regular_graph(256, 170, 114, 110) + sage: graphs.strongly_regular_graph(256, 170, 114, 110) # needs sage.combinat complement(two-intersection set in PG(8,2)): Graph on 256 vertices - sage: graphs.strongly_regular_graph(256, 187, 138, 132) + sage: graphs.strongly_regular_graph(256, 187, 138, 132) # needs sage.combinat complement(two-intersection set in PG(8,2)): Graph on 256 vertices - sage: graphs.strongly_regular_graph(512, 73, 12, 10) # not tested (too long) + sage: graphs.strongly_regular_graph(512, 73, 12, 10) # not tested (too long), needs sage.rings.finite_rings two-weight code: [219, 9] linear code over GF(2): Graph on 512 vertices sage: graphs.strongly_regular_graph(512, 219, 106, 84) # long time two-intersection set in PG(9,2): Graph on 512 vertices - sage: graphs.strongly_regular_graph(512, 315, 202, 180) # not tested (too long) + sage: graphs.strongly_regular_graph(512, 315, 202, 180) # not tested (too long), needs sage.rings.finite_rings two-weight code: [70, 9] linear code over GF(2): Graph on 512 vertices sage: graphs.strongly_regular_graph(625, 364, 213, 210) # long time complement(two-intersection set in PG(4,5)): Graph on 625 vertices diff --git a/src/sage/graphs/traversals.pyx b/src/sage/graphs/traversals.pyx index a565d46fdcb..6180cb8db08 100644 --- a/src/sage/graphs/traversals.pyx +++ b/src/sage/graphs/traversals.pyx @@ -338,16 +338,17 @@ def lex_BFS(G, reverse=False, tree=False, initial_vertex=None, algorithm="fast") Different orderings for different traversals:: - sage: G = digraphs.DeBruijn(2,3) # optional - sage.combinat - sage: G.lex_BFS(initial_vertex='000', algorithm="fast") # optional - sage.combinat + sage: # needs sage.combinat + sage: G = digraphs.DeBruijn(2,3) + sage: G.lex_BFS(initial_vertex='000', algorithm="fast") ['000', '001', '100', '010', '011', '110', '101', '111'] - sage: G.lex_BFS(initial_vertex='000', algorithm="slow") # optional - sage.combinat + sage: G.lex_BFS(initial_vertex='000', algorithm="slow") ['000', '001', '100', '010', '011', '110', '101', '111'] - sage: G.lex_DFS(initial_vertex='000') # optional - sage.combinat + sage: G.lex_DFS(initial_vertex='000') ['000', '001', '100', '010', '101', '110', '011', '111'] - sage: G.lex_UP(initial_vertex='000') # optional - sage.combinat + sage: G.lex_UP(initial_vertex='000') ['000', '001', '010', '101', '110', '111', '011', '100'] - sage: G.lex_DOWN(initial_vertex='000') # optional - sage.combinat + sage: G.lex_DOWN(initial_vertex='000') ['000', '001', '100', '011', '010', '110', '111', '101'] TESTS: @@ -541,14 +542,15 @@ def lex_UP(G, reverse=False, tree=False, initial_vertex=None): Different orderings for different traversals:: - sage: G = digraphs.DeBruijn(2,3) # optional - sage.combinat - sage: G.lex_BFS(initial_vertex='000') # optional - sage.combinat + sage: # needs sage.combinat + sage: G = digraphs.DeBruijn(2,3) + sage: G.lex_BFS(initial_vertex='000') ['000', '001', '100', '010', '011', '110', '101', '111'] - sage: G.lex_DFS(initial_vertex='000') # optional - sage.combinat + sage: G.lex_DFS(initial_vertex='000') ['000', '001', '100', '010', '101', '110', '011', '111'] - sage: G.lex_UP(initial_vertex='000') # optional - sage.combinat + sage: G.lex_UP(initial_vertex='000') ['000', '001', '010', '101', '110', '111', '011', '100'] - sage: G.lex_DOWN(initial_vertex='000') # optional - sage.combinat + sage: G.lex_DOWN(initial_vertex='000') ['000', '001', '100', '011', '010', '110', '111', '101'] TESTS: @@ -714,14 +716,15 @@ def lex_DFS(G, reverse=False, tree=False, initial_vertex=None): Different orderings for different traversals:: - sage: G = digraphs.DeBruijn(2,3) # optional - sage.combinat - sage: G.lex_BFS(initial_vertex='000') # optional - sage.combinat + sage: # needs sage.combinat + sage: G = digraphs.DeBruijn(2,3) + sage: G.lex_BFS(initial_vertex='000') ['000', '001', '100', '010', '011', '110', '101', '111'] - sage: G.lex_DFS(initial_vertex='000') # optional - sage.combinat + sage: G.lex_DFS(initial_vertex='000') ['000', '001', '100', '010', '101', '110', '011', '111'] - sage: G.lex_UP(initial_vertex='000') # optional - sage.combinat + sage: G.lex_UP(initial_vertex='000') ['000', '001', '010', '101', '110', '111', '011', '100'] - sage: G.lex_DOWN(initial_vertex='000') # optional - sage.combinat + sage: G.lex_DOWN(initial_vertex='000') ['000', '001', '100', '011', '010', '110', '111', '101'] TESTS: @@ -889,14 +892,15 @@ def lex_DOWN(G, reverse=False, tree=False, initial_vertex=None): Different orderings for different traversals:: - sage: G = digraphs.DeBruijn(2,3) # optional - sage.combinat - sage: G.lex_BFS(initial_vertex='000') # optional - sage.combinat + sage: # needs sage.combinat + sage: G = digraphs.DeBruijn(2,3) + sage: G.lex_BFS(initial_vertex='000') ['000', '001', '100', '010', '011', '110', '101', '111'] - sage: G.lex_DFS(initial_vertex='000') # optional - sage.combinat + sage: G.lex_DFS(initial_vertex='000') ['000', '001', '100', '010', '101', '110', '011', '111'] - sage: G.lex_UP(initial_vertex='000') # optional - sage.combinat + sage: G.lex_UP(initial_vertex='000') ['000', '001', '010', '101', '110', '111', '011', '100'] - sage: G.lex_DOWN(initial_vertex='000') # optional - sage.combinat + sage: G.lex_DOWN(initial_vertex='000') ['000', '001', '100', '011', '010', '110', '111', '101'] TESTS: diff --git a/src/sage/graphs/tutte_polynomial.py b/src/sage/graphs/tutte_polynomial.py index 6794c960805..5a7b048ddfe 100644 --- a/src/sage/graphs/tutte_polynomial.py +++ b/src/sage/graphs/tutte_polynomial.py @@ -532,7 +532,7 @@ def tutte_polynomial(G, edge_selector=None, cache=None): The Tutte polynomial of any tree of order `n` is `x^{n-1}`:: - sage: all(T.tutte_polynomial() == x**9 for T in graphs.trees(10)) # optional - sage.symbolic + sage: all(T.tutte_polynomial() == x**9 for T in graphs.trees(10)) # needs sage.symbolic True The Tutte polynomial of the Petersen graph is:: @@ -550,7 +550,7 @@ def tutte_polynomial(G, edge_selector=None, cache=None): sage: G = graphs.RandomGNP(10,0.6) sage: while not G.is_connected(): ....: G = graphs.RandomGNP(10,0.6) - sage: G.tutte_polynomial()(1,1) == G.spanning_trees_count() + sage: G.tutte_polynomial()(1,1) == G.spanning_trees_count() # needs sage.modules True Given that `T(x,y)` is the Tutte polynomial of a graph `G` with @@ -560,7 +560,7 @@ def tutte_polynomial(G, edge_selector=None, cache=None): sage: G = graphs.OctahedralGraph() sage: T = G.tutte_polynomial() sage: R = PolynomialRing(ZZ, 'x') - sage: R((-1)^5*x*T(1-x,0)).factor() # optional - sage.symbolic + sage: R((-1)^5*x*T(1-x,0)).factor() # needs sage.symbolic (x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32) sage: G.chromatic_polynomial().factor() (x - 2) * (x - 1) * x * (x^3 - 9*x^2 + 29*x - 32) diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index c49511207e5..958de960d86 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -175,11 +175,11 @@ cdef class EdgesView: With a directed graph:: - sage: G = digraphs.DeBruijn(2, 2) # optional - sage.combinat - sage: E = EdgesView(G, labels=False, sort=True); E # optional - sage.combinat + sage: G = digraphs.DeBruijn(2, 2) # needs sage.combinat + sage: E = EdgesView(G, labels=False, sort=True); E # needs sage.combinat [('00', '00'), ('00', '01'), ('01', '10'), ('01', '11'), ('10', '00'), ('10', '01'), ('11', '10'), ('11', '11')] - sage: E = EdgesView(G, labels=False, sort=True, key=lambda e:(e[1], e[0])); E # optional - sage.combinat + sage: E = EdgesView(G, labels=False, sort=True, key=lambda e:(e[1], e[0])); E # needs sage.combinat [('00', '00'), ('10', '00'), ('00', '01'), ('10', '01'), ('01', '10'), ('11', '10'), ('01', '11'), ('11', '11')] From bc9bb1befa259c500a9fa9eb4bdfad8127586455 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 2 Aug 2023 16:19:53 -0700 Subject: [PATCH 76/87] src/sage/graphs/graph.py: Use more block # needs --- src/sage/graphs/graph.py | 249 +++++++++++++++++++++------------------ 1 file changed, 137 insertions(+), 112 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index c6a32319305..0f207ffb1ee 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -112,10 +112,11 @@ :: - sage: import networkx # needs networkx - sage: K = networkx.complete_bipartite_graph(12,7) # needs networkx - sage: G = Graph(K) # needs networkx - sage: G.degree() # needs networkx + sage: # needs networkx + sage: import networkx + sage: K = networkx.complete_bipartite_graph(12,7) + sage: G = Graph(K) + sage: G.degree() [7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, 12] - graph6 or sparse6 format: @@ -149,11 +150,12 @@ :: - sage: M = Matrix([(0,1,0,0,1,1,0,0,0,0), (1,0,1,0,0,0,1,0,0,0), # needs sage.modules + sage: # needs sage.modules + sage: M = Matrix([(0,1,0,0,1,1,0,0,0,0), (1,0,1,0,0,0,1,0,0,0), ....: (0,1,0,1,0,0,0,1,0,0), (0,0,1,0,1,0,0,0,1,0), ....: (1,0,0,1,0,0,0,0,0,1), (1,0,0,0,0,0,0,1,1,0), (0,1,0,0,0,0,0,0,1,1), ....: (0,0,1,0,0,1,0,0,0,1), (0,0,0,1,0,1,1,0,0,0), (0,0,0,0,1,0,1,1,0,0)]) - sage: M # needs sage.modules + sage: M [0 1 0 0 1 1 0 0 0 0] [1 0 1 0 0 0 1 0 0 0] [0 1 0 1 0 0 0 1 0 0] @@ -164,16 +166,17 @@ [0 0 1 0 0 1 0 0 0 1] [0 0 0 1 0 1 1 0 0 0] [0 0 0 0 1 0 1 1 0 0] - sage: G = Graph(M); G # needs sage.modules + sage: G = Graph(M); G Graph on 10 vertices - sage: G.plot().show() # or G.show() # needs sage.modules sage.plot + sage: G.plot().show() # or G.show() # needs sage.plot - incidence matrix: In an incidence matrix, each row represents a vertex and each column represents an edge. :: - sage: M = Matrix([(-1, 0, 0, 0, 1, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0), # needs sage.modules + sage: # needs sage.modules + sage: M = Matrix([(-1, 0, 0, 0, 1, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0), ....: ( 1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0), ....: ( 0, 1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0), ....: ( 0, 0, 1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0), @@ -183,7 +186,7 @@ ....: ( 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 0, 0, 1, 0, 0), ....: ( 0, 0, 0, 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 1, 0), ....: ( 0, 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 0, 0, 0, 1)]) - sage: M # needs sage.modules + sage: M [-1 0 0 0 1 0 0 0 0 0 -1 0 0 0 0] [ 1 -1 0 0 0 0 0 0 0 0 0 -1 0 0 0] [ 0 1 -1 0 0 0 0 0 0 0 0 0 -1 0 0] @@ -194,10 +197,10 @@ [ 0 0 0 0 0 1 -1 0 0 0 0 0 1 0 0] [ 0 0 0 0 0 0 0 0 1 -1 0 0 0 1 0] [ 0 0 0 0 0 0 1 -1 0 0 0 0 0 0 1] - sage: G = Graph(M); G # needs sage.modules + sage: G = Graph(M); G Graph on 10 vertices - sage: G.plot().show() # or G.show() # needs sage.modules sage.plot - sage: DiGraph(matrix(2, [0,0,-1,1]), format="incidence_matrix") # needs sage.modules + sage: G.plot().show() # or G.show() # needs sage.plot + sage: DiGraph(matrix(2, [0,0,-1,1]), format="incidence_matrix") Traceback (most recent call last): ... ValueError: there must be two nonzero entries (-1 & 1) per column @@ -764,13 +767,14 @@ class Graph(GenericGraph): Check that :trac:`9714` is fixed:: - sage: MA = Matrix([[1,2,0], [0,2,0], [0,0,1]]) # needs sage.modules - sage: GA = Graph(MA, format='adjacency_matrix') # needs sage.modules - sage: MI = GA.incidence_matrix(oriented=False); MI # needs sage.modules + sage: # needs sage.modules + sage: MA = Matrix([[1,2,0], [0,2,0], [0,0,1]]) + sage: GA = Graph(MA, format='adjacency_matrix') + sage: MI = GA.incidence_matrix(oriented=False); MI [2 1 1 0 0 0] [0 1 1 2 2 0] [0 0 0 0 0 2] - sage: Graph(MI).edges(sort=True, labels=None) # needs sage.modules + sage: Graph(MI).edges(sort=True, labels=None) [(0, 0), (0, 1), (0, 1), (1, 1), (1, 1), (2, 2)] sage: M = Matrix([[1], [-1]]); M # needs sage.modules @@ -826,11 +830,12 @@ class Graph(GenericGraph): If ``vertex_labels`` is ``True``, the names of the vertices are given by the vertex attribute ``'name'``, if available:: - sage: g = igraph.Graph([(0,1),(0,2)], vertex_attrs={'name':['a','b','c']}) # optional - python_igraph - sage: Graph(g).vertices(sort=True) # optional - python_igraph + sage: # optional - python_igraph + sage: g = igraph.Graph([(0,1),(0,2)], vertex_attrs={'name':['a','b','c']}) + sage: Graph(g).vertices(sort=True) ['a', 'b', 'c'] - sage: g = igraph.Graph([(0,1),(0,2)], vertex_attrs={'label':['a','b','c']}) # optional - python_igraph - sage: Graph(g).vertices(sort=True) # optional - python_igraph + sage: g = igraph.Graph([(0,1),(0,2)], vertex_attrs={'label':['a','b','c']}) + sage: Graph(g).vertices(sort=True) [0, 1, 2] If the igraph Graph has edge attributes, they are used as edge labels:: @@ -885,11 +890,12 @@ class Graph(GenericGraph): ... ValueError: An *undirected* igraph graph was expected. To build an directed graph, call the DiGraph constructor. - sage: m = matrix([[0, -1], [-1, 0]]) # needs sage.modules - sage: Graph(m, format="seidel_adjacency_matrix") # needs sage.modules + sage: # needs sage.modules + sage: m = matrix([[0, -1], [-1, 0]]) + sage: Graph(m, format="seidel_adjacency_matrix") Graph on 2 vertices - sage: m[0,1] = 1 # needs sage.modules - sage: Graph(m, format="seidel_adjacency_matrix") # needs sage.modules + sage: m[0,1] = 1 + sage: Graph(m, format="seidel_adjacency_matrix") Traceback (most recent call last): ... ValueError: the adjacency matrix of a Seidel graph must be symmetric @@ -3937,18 +3943,19 @@ def chromatic_symmetric_function(self, R=None): We show that given a triangle `\{e_1, e_2, e_3\}`, we have `X_G = X_{G - e_1} + X_{G - e_2} - X_{G - e_1 - e_2}`:: + sage: # needs sage.combinat sage.modules sage: G = Graph([[1,2],[1,3],[2,3]]) - sage: XG = G.chromatic_symmetric_function() # needs sage.combinat sage.modules + sage: XG = G.chromatic_symmetric_function() sage: G1 = copy(G) sage: G1.delete_edge([1,2]) - sage: XG1 = G1.chromatic_symmetric_function() # needs sage.combinat sage.modules + sage: XG1 = G1.chromatic_symmetric_function() sage: G2 = copy(G) sage: G2.delete_edge([1,3]) - sage: XG2 = G2.chromatic_symmetric_function() # needs sage.combinat sage.modules + sage: XG2 = G2.chromatic_symmetric_function() sage: G3 = copy(G1) sage: G3.delete_edge([1,3]) - sage: XG3 = G3.chromatic_symmetric_function() # needs sage.combinat sage.modules - sage: XG == XG1 + XG2 - XG3 # needs sage.combinat sage.modules + sage: XG3 = G3.chromatic_symmetric_function() + sage: XG == XG1 + XG2 - XG3 True """ from sage.combinat.sf.sf import SymmetricFunctions @@ -3994,19 +4001,20 @@ def chromatic_quasisymmetric_function(self, t=None, R=None): EXAMPLES:: + sage: # needs sage.combinat sage.modules sage: G = Graph([[1,2,3], [[1,3], [2,3]]]) - sage: G.chromatic_quasisymmetric_function() # needs sage.combinat sage.modules + sage: G.chromatic_quasisymmetric_function() (2*t^2+2*t+2)*M[1, 1, 1] + M[1, 2] + t^2*M[2, 1] sage: G = graphs.PathGraph(4) - sage: XG = G.chromatic_quasisymmetric_function(); XG # needs sage.combinat sage.modules + sage: XG = G.chromatic_quasisymmetric_function(); XG (t^3+11*t^2+11*t+1)*M[1, 1, 1, 1] + (3*t^2+3*t)*M[1, 1, 2] + (3*t^2+3*t)*M[1, 2, 1] + (3*t^2+3*t)*M[2, 1, 1] + (t^2+t)*M[2, 2] - sage: XG.to_symmetric_function() # needs sage.combinat sage.modules + sage: XG.to_symmetric_function() (t^3+11*t^2+11*t+1)*m[1, 1, 1, 1] + (3*t^2+3*t)*m[2, 1, 1] + (t^2+t)*m[2, 2] sage: G = graphs.CompleteGraph(4) - sage: G.chromatic_quasisymmetric_function() # needs sage.combinat sage.modules + sage: G.chromatic_quasisymmetric_function() (t^6+3*t^5+5*t^4+6*t^3+5*t^2+3*t+1)*M[1, 1, 1, 1] Not all chromatic quasisymmetric functions are symmetric:: @@ -4698,17 +4706,18 @@ def maximum_average_degree(self, value_only=True, solver=None, verbose=0): Check corner cases:: - sage: Graph().maximum_average_degree(value_only=True) # needs sage.numerical.mip + sage: # needs sage.numerical.mip + sage: Graph().maximum_average_degree(value_only=True) 0 - sage: Graph().maximum_average_degree(value_only=False) # needs sage.numerical.mip + sage: Graph().maximum_average_degree(value_only=False) Graph on 0 vertices - sage: Graph(1).maximum_average_degree(value_only=True) # needs sage.numerical.mip + sage: Graph(1).maximum_average_degree(value_only=True) 0 - sage: Graph(1).maximum_average_degree(value_only=False) # needs sage.numerical.mip + sage: Graph(1).maximum_average_degree(value_only=False) Graph on 1 vertex - sage: Graph(2).maximum_average_degree(value_only=True) # needs sage.numerical.mip + sage: Graph(2).maximum_average_degree(value_only=True) 0 - sage: Graph(2).maximum_average_degree(value_only=False) # needs sage.numerical.mip + sage: Graph(2).maximum_average_degree(value_only=False) Graph on 1 vertex """ self._scream_if_not_simple() @@ -4810,15 +4819,16 @@ def independent_set_of_representatives(self, family, solver=None, verbose=0, partition of the set of vertices the family defined by the three copies of each vertex. The ISR of such a family defines a 3-coloring:: + sage: # needs sage.numerical.mip sage: g = 3 * graphs.PetersenGraph() sage: n = g.order() / 3 sage: f = [[i, i + n, i + 2*n] for i in range(n)] - sage: isr = g.independent_set_of_representatives(f) # needs sage.numerical.mip - sage: c = [integer_floor(i / n) for i in isr] # needs sage.numerical.mip + sage: isr = g.independent_set_of_representatives(f) + sage: c = [integer_floor(i / n) for i in isr] sage: color_classes = [[], [], []] - sage: for v, i in enumerate(c): # needs sage.numerical.mip + sage: for v, i in enumerate(c): ....: color_classes[i].append(v) - sage: for classs in color_classes: # needs sage.numerical.mip + sage: for classs in color_classes: ....: g.subgraph(classs).size() == 0 True True @@ -4930,12 +4940,13 @@ def minor(self, H, solver=None, verbose=0, *, integrality_tolerance=1e-3): Trying to find a minor isomorphic to `K_4` in the `4\times 4` grid:: + sage: # needs sage.numerical.mip sage: g = graphs.GridGraph([4,4]) sage: h = graphs.CompleteGraph(4) - sage: L = g.minor(h) # needs sage.numerical.mip - sage: gg = g.subgraph(flatten(L.values(), max_level = 1)) # needs sage.numerical.mip - sage: _ = [gg.merge_vertices(l) for l in L.values() if len(l)>1] # needs sage.numerical.mip - sage: gg.is_isomorphic(h) # needs sage.numerical.mip + sage: L = g.minor(h) + sage: gg = g.subgraph(flatten(L.values(), max_level = 1)) + sage: _ = [gg.merge_vertices(l) for l in L.values() if len(l)>1] + sage: gg.is_isomorphic(h) True We can also try to prove this way that the Petersen graph is not planar, @@ -5819,11 +5830,12 @@ def distance_graph(self, dist): The graph of eight-bit strings, adjacent if different in an odd number of bits:: - sage: G = graphs.CubeGraph(8) # long time - sage: H = G.distance_graph([1,3,5,7]) # long time - sage: degrees = [0]*sum([binomial(8,j) for j in [1,3,5,7]]) # long time - sage: degrees.append(2^8) # long time - sage: degrees == H.degree_histogram() # long time + sage: # long time + sage: G = graphs.CubeGraph(8) + sage: H = G.distance_graph([1,3,5,7]) + sage: degrees = [0]*sum([binomial(8,j) for j in [1,3,5,7]]) + sage: degrees.append(2^8) + sage: degrees == H.degree_histogram() True An example of using ``Infinity`` as the distance in a graph that is not @@ -7526,20 +7538,21 @@ def cliques_containing_vertex(self, vertices=None, cliques=None): EXAMPLES:: + sage: # needs networkx sage: C = Graph('DJ{') - sage: C.cliques_containing_vertex() # needs networkx + sage: C.cliques_containing_vertex() {0: [[0, 4]], 1: [[1, 2, 3, 4]], 2: [[1, 2, 3, 4]], 3: [[1, 2, 3, 4]], 4: [[0, 4], [1, 2, 3, 4]]} - sage: C.cliques_containing_vertex(4) # needs networkx + sage: C.cliques_containing_vertex(4) [[0, 4], [1, 2, 3, 4]] - sage: C.cliques_containing_vertex([0, 1]) # needs networkx + sage: C.cliques_containing_vertex([0, 1]) {0: [[0, 4]], 1: [[1, 2, 3, 4]]} - sage: E = C.cliques_maximal(); E # needs networkx + sage: E = C.cliques_maximal(); E [[0, 4], [1, 2, 3, 4]] - sage: C.cliques_containing_vertex(cliques=E) # needs networkx + sage: C.cliques_containing_vertex(cliques=E) {0: [[0, 4]], 1: [[1, 2, 3, 4]], 2: [[1, 2, 3, 4]], @@ -7557,14 +7570,15 @@ def cliques_containing_vertex(self, vertices=None, cliques=None): Since each clique of a 2 dimensional grid corresponds to an edge, the number of cliques in which a vertex is involved equals its degree:: + sage: # needs networkx sage: F = graphs.Grid2dGraph(2,3) - sage: d = F.cliques_containing_vertex() # needs networkx - sage: all(F.degree(u) == len(cliques) for u,cliques in d.items()) # needs networkx + sage: d = F.cliques_containing_vertex() + sage: all(F.degree(u) == len(cliques) for u,cliques in d.items()) True - sage: d = F.cliques_containing_vertex(vertices=[(0, 1)]) # needs networkx - sage: list(d) # needs networkx + sage: d = F.cliques_containing_vertex(vertices=[(0, 1)]) + sage: list(d) [(0, 1)] - sage: sorted(sorted(x for x in L) for L in d[(0, 1)]) # needs networkx + sage: sorted(sorted(x for x in L) for L in d[(0, 1)]) [[(0, 0), (0, 1)], [(0, 1), (0, 2)], [(0, 1), (1, 1)]] """ if cliques is None: @@ -7723,14 +7737,16 @@ def cores(self, k=None, with_labels=False): [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] sage: (graphs.FruchtGraph()).cores(with_labels=True) {0: 3, 1: 3, 2: 3, 3: 3, 4: 3, 5: 3, 6: 3, 7: 3, 8: 3, 9: 3, 10: 3, 11: 3} + + sage: # needs sage.modules sage: set_random_seed(0) - sage: a = random_matrix(ZZ, 20, x=2, sparse=True, density=.1) # needs sage.modules + sage: a = random_matrix(ZZ, 20, x=2, sparse=True, density=.1) sage: b = Graph(20) - sage: b.add_edges(a.nonzero_positions(), loops=False) # needs sage.modules - sage: cores = b.cores(with_labels=True); cores # needs sage.modules + sage: b.add_edges(a.nonzero_positions(), loops=False) + sage: cores = b.cores(with_labels=True); cores {0: 3, 1: 3, 2: 3, 3: 3, 4: 2, 5: 2, 6: 3, 7: 1, 8: 3, 9: 3, 10: 3, 11: 3, 12: 3, 13: 3, 14: 2, 15: 3, 16: 3, 17: 3, 18: 3, 19: 3} - sage: [v for v,c in cores.items() if c >= 2] # the vertices in the 2-core # needs sage.modules + sage: [v for v,c in cores.items() if c >= 2] # the vertices in the 2-core [0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] Checking the 2-core of a random lobster is indeed the empty set:: @@ -9100,24 +9116,26 @@ def effective_resistance(self, i, j, *, base_ring=None): Effective resistances in a straight linear 2-tree on 6 vertices :: + sage: # needs sage.modules sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)]) - sage: G.effective_resistance(0,1) # needs sage.modules + sage: G.effective_resistance(0,1) 34/55 - sage: G.effective_resistance(0,3) # needs sage.modules + sage: G.effective_resistance(0,3) 49/55 - sage: G.effective_resistance(1,4) # needs sage.modules + sage: G.effective_resistance(1,4) 9/11 - sage: G.effective_resistance(0,5) # needs sage.modules + sage: G.effective_resistance(0,5) 15/11 Effective resistances in a fan on 6 vertices :: + sage: # needs sage.modules sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)]) - sage: H.effective_resistance(1,5) # needs sage.modules + sage: H.effective_resistance(1,5) 6/5 - sage: H.effective_resistance(1,3) # needs sage.modules + sage: H.effective_resistance(1,3) 49/55 - sage: H.effective_resistance(1,1) # needs sage.modules + sage: H.effective_resistance(1,1) 0 Using a different base ring:: @@ -9140,27 +9158,28 @@ def effective_resistance(self, i, j, *, base_ring=None): TESTS:: + sage: # needs sage.modules sage: G = graphs.CompleteGraph(4) - sage: all(G.effective_resistance(u, v) == 1/2 # needs sage.modules + sage: all(G.effective_resistance(u, v) == 1/2 ....: for u,v in G.edge_iterator(labels=False)) True - sage: Graph(1).effective_resistance(0,0) # needs sage.modules + sage: Graph(1).effective_resistance(0,0) 0 sage: G = Graph([(0,1),(1,2)]) - sage: G.effective_resistance(0,2) # needs sage.modules + sage: G.effective_resistance(0,2) 2 sage: G = Graph([(0,1),(1,2),(2,0)]) - sage: G.effective_resistance(0,2) # needs sage.modules + sage: G.effective_resistance(0,2) 2/3 sage: G = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(1,2),(2,3),(3,4),(4,5),(5,1)]) - sage: r = G.effective_resistance(0,3) # needs sage.modules - sage: r == fibonacci(2*(5-3)+1)*fibonacci(2*3-1)/fibonacci(2*5) # needs sage.modules + sage: r = G.effective_resistance(0,3) + sage: r == fibonacci(2*(5-3)+1)*fibonacci(2*3-1)/fibonacci(2*5) True sage: G = graphs.PathGraph(4) sage: G.delete_edge(2,3) - sage: G.effective_resistance(0,2) # needs sage.modules + sage: G.effective_resistance(0,2) 2 - sage: G.effective_resistance(0,3) # needs sage.modules + sage: G.effective_resistance(0,3) +Infinity """ from sage.matrix.constructor import matrix @@ -9299,36 +9318,38 @@ def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, in the meantime if you want to use it please disallow multiedges using allow_multiple_edges(). - sage: graphs.CompleteGraph(4).effective_resistance_matrix(nonedgesonly=False) # needs sage.modules + sage: # needs sage.modules + sage: graphs.CompleteGraph(4).effective_resistance_matrix(nonedgesonly=False) [ 0 1/2 1/2 1/2] [1/2 0 1/2 1/2] [1/2 1/2 0 1/2] [1/2 1/2 1/2 0] - sage: Graph(1).effective_resistance_matrix() # needs sage.modules + sage: Graph(1).effective_resistance_matrix() [0] - sage: Graph().effective_resistance_matrix() # needs sage.modules + sage: Graph().effective_resistance_matrix() Traceback (most recent call last): ... ValueError: unable to compute effective resistance for an empty Graph object sage: G = Graph([(0,1),(1,2),(2,3),(3,0),(0,2)]) - sage: G.effective_resistance_matrix() # needs sage.modules + sage: G.effective_resistance_matrix() [0 0 0 0] [0 0 0 1] [0 0 0 0] [0 1 0 0] sage: G = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(1,2),(2,3),(3,4),(4,5),(5,1)]) - sage: r = G.effective_resistance_matrix(nonedgesonly=False)[0,3] # needs sage.modules - sage: r == fibonacci(2*(5-3)+1)*fibonacci(2*3-1)/fibonacci(2*5) # needs sage.libs.pari sage.modules + sage: r = G.effective_resistance_matrix(nonedgesonly=False)[0,3] + sage: r == fibonacci(2*(5-3)+1)*fibonacci(2*3-1)/fibonacci(2*5) # needs sage.libs.pari True Ask for an immutable matrix:: + sage: # needs sage.modules sage: G = Graph([(0, 1)]) - sage: M = G.effective_resistance_matrix(immutable=False) # needs sage.modules - sage: M.is_immutable() # needs sage.modules + sage: M = G.effective_resistance_matrix(immutable=False) + sage: M.is_immutable() False - sage: M = G.effective_resistance_matrix(immutable=True) # needs sage.modules - sage: M.is_immutable() # needs sage.modules + sage: M = G.effective_resistance_matrix(immutable=True) + sage: M.is_immutable() True """ from sage.matrix.constructor import matrix @@ -9418,14 +9439,15 @@ def least_effective_resistance(self, nonedgesonly=True): TESTS:: - sage: graphs.CompleteGraph(4).least_effective_resistance() # needs sage.modules + sage: # needs sage.modules + sage: graphs.CompleteGraph(4).least_effective_resistance() [] - sage: graphs.CompleteGraph(4).least_effective_resistance(nonedgesonly=False) # needs sage.modules + sage: graphs.CompleteGraph(4).least_effective_resistance(nonedgesonly=False) [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] - sage: Graph(1).least_effective_resistance() # needs sage.modules + sage: Graph(1).least_effective_resistance() [] sage: G = Graph([(0,1),(1,2),(2,3),(3,0),(0,2)]) - sage: G.least_effective_resistance() # needs sage.modules + sage: G.least_effective_resistance() [(1, 3)] """ n = self.order() @@ -9544,16 +9566,17 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, TESTS:: + sage: # needs sage.modules sage: G = graphs.CompleteGraph(4) - sage: M = G.common_neighbors_matrix() # needs sage.modules - sage: M.is_zero() # needs sage.modules + sage: M = G.common_neighbors_matrix() + sage: M.is_zero() True - sage: Graph(1).common_neighbors_matrix() # needs sage.modules + sage: Graph(1).common_neighbors_matrix() [0] - sage: Graph().common_neighbors_matrix() # needs sage.modules + sage: Graph().common_neighbors_matrix() [] sage: G = Graph([(0,1),(1,2),(2,3),(3,0),(0,2)]) - sage: G.common_neighbors_matrix() # needs sage.modules + sage: G.common_neighbors_matrix() [0 0 0 0] [0 0 0 2] [0 0 0 0] @@ -9561,12 +9584,13 @@ def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, Asking for an immutable matrix:: + sage: # needs sage.modules sage: G = Graph([(0, 1)]) - sage: M = G.common_neighbors_matrix() # needs sage.modules - sage: M.is_immutable() # needs sage.modules + sage: M = G.common_neighbors_matrix() + sage: M.is_immutable() False - sage: M = G.common_neighbors_matrix(immutable=True) # needs sage.modules - sage: M.is_immutable() # needs sage.modules + sage: M = G.common_neighbors_matrix(immutable=True) + sage: M.is_immutable() True """ self._scream_if_not_simple() @@ -9628,23 +9652,24 @@ def most_common_neighbors(self, nonedgesonly=True): TESTS:: - sage: G=graphs.CompleteGraph(4) - sage: G.most_common_neighbors() # needs sage.modules + sage: # needs sage.modules + sage: G = graphs.CompleteGraph(4) + sage: G.most_common_neighbors() [] - sage: G.most_common_neighbors(nonedgesonly=False) # needs sage.modules + sage: G.most_common_neighbors(nonedgesonly=False) [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] - sage: Graph(1).most_common_neighbors() # needs sage.modules + sage: Graph(1).most_common_neighbors() Traceback (most recent call last): ... ValueError: this method is defined for graphs with at least 2 vertices - sage: Graph().most_common_neighbors() # needs sage.modules + sage: Graph().most_common_neighbors() Traceback (most recent call last): ... ValueError: this method is defined for graphs with at least 2 vertices sage: G = Graph([(0,1),(1,2),(2,3),(3,0),(0,2)]) - sage: G.most_common_neighbors() # needs sage.modules + sage: G.most_common_neighbors() [(1, 3)] - sage: G.most_common_neighbors(nonedgesonly=False) # needs sage.modules + sage: G.most_common_neighbors(nonedgesonly=False) [(0, 2), (1, 3)] """ self._scream_if_not_simple() From d7b2cb24fac46d8475656bd52d978bc68d4568b2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 2 Aug 2023 16:40:01 -0700 Subject: [PATCH 77/87] sage.graphs: Use more block # needs --- src/sage/graphs/base/c_graph.pyx | 11 +-- src/sage/graphs/bipartite_graph.py | 126 +++++++++++++++------------- src/sage/graphs/centrality.pyx | 26 +++--- src/sage/graphs/domination.py | 70 ++++++++-------- src/sage/graphs/generators/basic.py | 113 ++++++++++++++----------- 5 files changed, 187 insertions(+), 159 deletions(-) diff --git a/src/sage/graphs/base/c_graph.pyx b/src/sage/graphs/base/c_graph.pyx index 0f5c09aa12f..79e62e13a33 100644 --- a/src/sage/graphs/base/c_graph.pyx +++ b/src/sage/graphs/base/c_graph.pyx @@ -1576,12 +1576,13 @@ cdef class CGraphBackend(GenericGraphBackend): We check that the bug described in :trac:`8406` is gone:: + sage: # needs sage.rings.finite_rings sage: G = Graph() - sage: R. = GF(3**3) # needs sage.rings.finite_rings - sage: S. = R[] # needs sage.rings.finite_rings - sage: G.add_vertex(a**2) # needs sage.rings.finite_rings - sage: G.add_vertex(x) # needs sage.rings.finite_rings - sage: G.vertices(sort=True) # needs sage.rings.finite_rings + sage: R. = GF(3**3) + sage: S. = R[] + sage: G.add_vertex(a**2) + sage: G.add_vertex(x) + sage: G.vertices(sort=True) [a^2, x] And that the bug described in :trac:`9610` is gone:: diff --git a/src/sage/graphs/bipartite_graph.py b/src/sage/graphs/bipartite_graph.py index 0aaae8e1551..b2c9fdbf3db 100644 --- a/src/sage/graphs/bipartite_graph.py +++ b/src/sage/graphs/bipartite_graph.py @@ -198,16 +198,17 @@ class BipartiteGraph(Graph): #. From a reduced adjacency matrix:: - sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), # needs sage.modules + sage: # needs sage.modules + sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), ....: (0,1,0,1,0,1,0), (1,1,0,1,0,0,1)]) - sage: M # needs sage.modules + sage: M [1 1 1 0 0 0 0] [1 0 0 1 1 0 0] [0 1 0 1 0 1 0] [1 1 0 1 0 0 1] - sage: H = BipartiteGraph(M); H # needs sage.modules + sage: H = BipartiteGraph(M); H Bipartite graph on 11 vertices - sage: H.edges(sort=True) # needs sage.modules + sage: H.edges(sort=True) [(0, 7, None), (0, 8, None), (0, 10, None), @@ -244,13 +245,14 @@ class BipartiteGraph(Graph): :: - sage: F. = GF(4) # needs sage.modules sage.rings.finite_rings - sage: MS = MatrixSpace(F, 2, 3) # needs sage.modules sage.rings.finite_rings - sage: M = MS.matrix([[0, 1, a + 1], [a, 1, 1]]) # needs sage.modules sage.rings.finite_rings - sage: B = BipartiteGraph(M, weighted=True, sparse=True) # needs sage.modules sage.rings.finite_rings - sage: B.edges(sort=True) # needs sage.modules sage.rings.finite_rings + sage: # needs sage.modules sage.rings.finite_rings + sage: F. = GF(4) + sage: MS = MatrixSpace(F, 2, 3) + sage: M = MS.matrix([[0, 1, a + 1], [a, 1, 1]]) + sage: B = BipartiteGraph(M, weighted=True, sparse=True) + sage: B.edges(sort=True) [(0, 4, a), (1, 3, 1), (1, 4, 1), (2, 3, a + 1), (2, 4, 1)] - sage: B.weighted() # needs sage.modules sage.rings.finite_rings + sage: B.weighted() True #. From an alist file:: @@ -311,10 +313,11 @@ class BipartiteGraph(Graph): #. From a NetworkX bipartite graph:: - sage: import networkx # needs networkx - sage: G = graphs.OctahedralGraph() # needs networkx - sage: N = networkx.make_clique_bipartite(G.networkx_graph()) # needs networkx - sage: B = BipartiteGraph(N) # needs networkx + sage: # needs networkx + sage: import networkx + sage: G = graphs.OctahedralGraph() + sage: N = networkx.make_clique_bipartite(G.networkx_graph()) + sage: B = BipartiteGraph(N) TESTS: @@ -328,15 +331,16 @@ class BipartiteGraph(Graph): Ensure that we can construct a ``BipartiteGraph`` with isolated vertices via the reduced adjacency matrix (:trac:`10356`):: - sage: a = BipartiteGraph(matrix(2, 2, [1, 0, 1, 0])) # needs sage.modules - sage: a # needs sage.modules + sage: # needs sage.modules + sage: a = BipartiteGraph(matrix(2, 2, [1, 0, 1, 0])) + sage: a Bipartite graph on 4 vertices - sage: a.vertices(sort=True) # needs sage.modules + sage: a.vertices(sort=True) [0, 1, 2, 3] - sage: g = BipartiteGraph(matrix(4, 4, [1] * 4 + [0] * 12)) # needs sage.modules - sage: g.vertices(sort=True) # needs sage.modules + sage: g = BipartiteGraph(matrix(4, 4, [1] * 4 + [0] * 12)) + sage: g.vertices(sort=True) [0, 1, 2, 3, 4, 5, 6, 7] - sage: sorted(g.left.union(g.right)) # needs sage.modules + sage: sorted(g.left.union(g.right)) [0, 1, 2, 3, 4, 5, 6, 7] Make sure that loops are not allowed (:trac:`23275`):: @@ -1806,19 +1810,20 @@ def save_afile(self, fname): EXAMPLES:: - sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), # needs sage.modules + sage: # needs sage.modules + sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), ....: (0,1,0,1,0,1,0), (1,1,0,1,0,0,1)]) - sage: M # needs sage.modules + sage: M [1 1 1 0 0 0 0] [1 0 0 1 1 0 0] [0 1 0 1 0 1 0] [1 1 0 1 0 0 1] - sage: b = BipartiteGraph(M) # needs sage.modules - sage: import tempfile # needs sage.modules - sage: with tempfile.NamedTemporaryFile() as f: # needs sage.modules + sage: b = BipartiteGraph(M) + sage: import tempfile + sage: with tempfile.NamedTemporaryFile() as f: ....: b.save_afile(f.name) ....: b2 = BipartiteGraph(f.name) - sage: b.is_isomorphic(b2) # needs sage.modules + sage: b.is_isomorphic(b2) True TESTS:: @@ -1923,54 +1928,57 @@ def reduced_adjacency_matrix(self, sparse=True, *, base_ring=None, **kwds): Bipartite graphs that are not weighted will return a matrix over ZZ, unless a base ring is specified:: - sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), # needs sage.modules + sage: # needs sage.modules + sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), ....: (0,1,0,1,0,1,0), (1,1,0,1,0,0,1)]) - sage: B = BipartiteGraph(M) # needs sage.modules - sage: N = B.reduced_adjacency_matrix(); N # needs sage.modules + sage: B = BipartiteGraph(M) + sage: N = B.reduced_adjacency_matrix(); N [1 1 1 0 0 0 0] [1 0 0 1 1 0 0] [0 1 0 1 0 1 0] [1 1 0 1 0 0 1] - sage: N == M # needs sage.modules + sage: N == M True - sage: N[0,0].parent() # needs sage.modules + sage: N[0,0].parent() Integer Ring - sage: N2 = B.reduced_adjacency_matrix(base_ring=RDF); N2 # needs sage.modules + sage: N2 = B.reduced_adjacency_matrix(base_ring=RDF); N2 [1.0 1.0 1.0 0.0 0.0 0.0 0.0] [1.0 0.0 0.0 1.0 1.0 0.0 0.0] [0.0 1.0 0.0 1.0 0.0 1.0 0.0] [1.0 1.0 0.0 1.0 0.0 0.0 1.0] - sage: N2[0, 0].parent() # needs sage.modules + sage: N2[0, 0].parent() Real Double Field Multi-edge graphs also return a matrix over ZZ, unless a base ring is specified:: - sage: M = Matrix([(1,1,2,0,0), (0,2,1,1,1), (0,1,2,1,1)]) # needs sage.modules - sage: B = BipartiteGraph(M, multiedges=True, sparse=True) # needs sage.modules - sage: N = B.reduced_adjacency_matrix() # needs sage.modules - sage: N == M # needs sage.modules + sage: # needs sage.modules + sage: M = Matrix([(1,1,2,0,0), (0,2,1,1,1), (0,1,2,1,1)]) + sage: B = BipartiteGraph(M, multiedges=True, sparse=True) + sage: N = B.reduced_adjacency_matrix() + sage: N == M True - sage: N[0,0].parent() # needs sage.modules + sage: N[0,0].parent() Integer Ring - sage: N2 = B.reduced_adjacency_matrix(base_ring=RDF) # needs sage.modules - sage: N2[0, 0].parent() # needs sage.modules + sage: N2 = B.reduced_adjacency_matrix(base_ring=RDF) + sage: N2[0, 0].parent() Real Double Field Weighted graphs will return a matrix over the ring given by their (first) weights, unless a base ring is specified:: - sage: F. = GF(4) # needs sage.modules sage.rings.finite_rings - sage: MS = MatrixSpace(F, 2, 3) # needs sage.modules sage.rings.finite_rings - sage: M = MS.matrix([[0, 1, a+1], [a, 1, 1]]) # needs sage.modules sage.rings.finite_rings - sage: B = BipartiteGraph(M, weighted=True, sparse=True) # needs sage.modules sage.rings.finite_rings - sage: N = B.reduced_adjacency_matrix(sparse=False) # needs sage.modules sage.rings.finite_rings - sage: N == M # needs sage.modules sage.rings.finite_rings + sage: # needs sage.modules sage.rings.finite_rings + sage: F. = GF(4) + sage: MS = MatrixSpace(F, 2, 3) + sage: M = MS.matrix([[0, 1, a+1], [a, 1, 1]]) + sage: B = BipartiteGraph(M, weighted=True, sparse=True) + sage: N = B.reduced_adjacency_matrix(sparse=False) + sage: N == M True - sage: N[0,0].parent() # needs sage.modules sage.rings.finite_rings + sage: N[0,0].parent() Finite Field in a of size 2^2 - sage: N2 = B.reduced_adjacency_matrix(base_ring=F) # needs sage.modules sage.rings.finite_rings - sage: N2[0, 0].parent() # needs sage.modules sage.rings.finite_rings + sage: N2 = B.reduced_adjacency_matrix(base_ring=F) + sage: N2[0, 0].parent() Finite Field in a of size 2^2 TESTS:: @@ -1989,11 +1997,12 @@ def reduced_adjacency_matrix(self, sparse=True, *, base_ring=None, **kwds): An error is raised if the specified base ring is not compatible with the type of the weights of the bipartite graph:: - sage: F. = GF(4) # needs sage.modules sage.rings.finite_rings - sage: MS = MatrixSpace(F, 2, 3) # needs sage.modules sage.rings.finite_rings - sage: M = MS.matrix([[0, 1, a+1], [a, 1, 1]]) # needs sage.modules sage.rings.finite_rings - sage: B = BipartiteGraph(M, weighted=True, sparse=True) # needs sage.modules sage.rings.finite_rings - sage: B.reduced_adjacency_matrix(base_ring=RDF) # needs sage.modules sage.rings.finite_rings + sage: # needs sage.modules sage.rings.finite_rings + sage: F. = GF(4) + sage: MS = MatrixSpace(F, 2, 3) + sage: M = MS.matrix([[0, 1, a+1], [a, 1, 1]]) + sage: B = BipartiteGraph(M, weighted=True, sparse=True) + sage: B.reduced_adjacency_matrix(base_ring=RDF) Traceback (most recent call last): ... TypeError: float() argument must be a string or a ...number, not 'sage.rings.finite_rings.element_givaro.FiniteField_givaroElement' @@ -2295,10 +2304,11 @@ def vertex_cover(self, algorithm="Konig", value_only=False, The two algorithms should return the same result:: - sage: g = BipartiteGraph(graphs.RandomBipartite(10, 10, .5)) # needs numpy - sage: vc1 = g.vertex_cover(algorithm="Konig") # needs numpy - sage: vc2 = g.vertex_cover(algorithm="Cliquer") # needs numpy - sage: len(vc1) == len(vc2) # needs numpy + sage: # needs numpy + sage: g = BipartiteGraph(graphs.RandomBipartite(10, 10, .5)) + sage: vc1 = g.vertex_cover(algorithm="Konig") + sage: vc2 = g.vertex_cover(algorithm="Cliquer") + sage: len(vc1) == len(vc2) True TESTS: diff --git a/src/sage/graphs/centrality.pyx b/src/sage/graphs/centrality.pyx index fa659c13d94..0f6e83565ee 100755 --- a/src/sage/graphs/centrality.pyx +++ b/src/sage/graphs/centrality.pyx @@ -638,34 +638,36 @@ def centrality_closeness_top_k(G, int k=1, int verbose=0): The result is correct:: + sage: # needs networkx sage: from sage.graphs.centrality import centrality_closeness_top_k sage: import random sage: n = 20 sage: m = random.randint(1, n * (n - 1) / 2) sage: k = random.randint(1, n) - sage: g = graphs.RandomGNM(n, m) # needs networkx - sage: topk = centrality_closeness_top_k(g, k) # needs networkx - sage: centr = g.centrality_closeness(algorithm='BFS') # needs networkx - sage: sorted_centr = sorted(centr.values(), reverse=True) # needs networkx - sage: len(topk) == min(k, len(sorted_centr)) # needs networkx + sage: g = graphs.RandomGNM(n, m) + sage: topk = centrality_closeness_top_k(g, k) + sage: centr = g.centrality_closeness(algorithm='BFS') + sage: sorted_centr = sorted(centr.values(), reverse=True) + sage: len(topk) == min(k, len(sorted_centr)) True - sage: all(abs(topk[i][0] - sorted_centr[i]) < 1e-12 for i in range(len(topk))) # needs networkx + sage: all(abs(topk[i][0] - sorted_centr[i]) < 1e-12 for i in range(len(topk))) True Directed case:: + sage: # needs networkx sage: from sage.graphs.centrality import centrality_closeness_top_k sage: import random sage: n = 20 sage: m = random.randint(1, n * (n - 1)) sage: k = random.randint(1, n) - sage: g = digraphs.RandomDirectedGNM(n, m) # needs networkx - sage: topk = centrality_closeness_top_k(g, k) # needs networkx - sage: centr = g.centrality_closeness(algorithm='BFS') # needs networkx - sage: sorted_centr = sorted(centr.values(), reverse=True) # needs networkx - sage: len(topk) == min(k, len(sorted_centr)) # needs networkx + sage: g = digraphs.RandomDirectedGNM(n, m) + sage: topk = centrality_closeness_top_k(g, k) + sage: centr = g.centrality_closeness(algorithm='BFS') + sage: sorted_centr = sorted(centr.values(), reverse=True) + sage: len(topk) == min(k, len(sorted_centr)) True - sage: all(abs(topk[i][0] - sorted_centr[i]) < 1e-12 for i in range(len(topk))) # needs networkx + sage: all(abs(topk[i][0] - sorted_centr[i]) < 1e-12 for i in range(len(topk))) True """ cdef list res diff --git a/src/sage/graphs/domination.py b/src/sage/graphs/domination.py index a92c814c7fa..00cc3ed5900 100644 --- a/src/sage/graphs/domination.py +++ b/src/sage/graphs/domination.py @@ -312,28 +312,30 @@ def dominating_sets(g, k=1, independent=False, total=False, Independent distance-`k` dominating sets of a Path graph:: + sage: # needs sage.numerical.mip sage: G = graphs.PathGraph(6) - sage: sorted(G.dominating_sets(k=1, independent=True)) # needs sage.numerical.mip + sage: sorted(G.dominating_sets(k=1, independent=True)) [[1, 4]] - sage: sorted(G.dominating_sets(k=2, independent=True)) # needs sage.numerical.mip + sage: sorted(G.dominating_sets(k=2, independent=True)) [[0, 3], [0, 4], [0, 5], [1, 3], [1, 4], [1, 5], [2, 4], [2, 5]] - sage: sorted(G.dominating_sets(k=3, independent=True)) # needs sage.numerical.mip + sage: sorted(G.dominating_sets(k=3, independent=True)) [[2], [3]] The dominating set is calculated for both the directed and undirected graphs (modification introduced in :trac:`17905`):: + sage: # needs sage.numerical.mip sage: g = digraphs.Path(3) - sage: g.dominating_set(value_only=True) # needs sage.numerical.mip + sage: g.dominating_set(value_only=True) 2 - sage: list(g.dominating_sets()) # needs sage.numerical.mip + sage: list(g.dominating_sets()) [[0, 1], [0, 2]] - sage: list(g.dominating_sets(k=2)) # needs sage.numerical.mip + sage: list(g.dominating_sets(k=2)) [[0]] sage: g = graphs.PathGraph(3) - sage: g.dominating_set(value_only=True) # needs sage.numerical.mip + sage: g.dominating_set(value_only=True) 1 - sage: next(g.dominating_sets()) # needs sage.numerical.mip + sage: next(g.dominating_sets()) [1] TESTS:: @@ -780,32 +782,32 @@ def minimal_dominating_sets(G, to_dominate=None, work_on_copy=False, k=1): sage: ll = list(graphs.PetersenGraph().minimal_dominating_sets()) sage: pp = [{0, 2, 6}, - ....: {0, 9, 3}, - ....: {0, 8, 7}, - ....: {1, 3, 7}, - ....: {1, 4, 5}, - ....: {8, 1, 9}, - ....: {8, 2, 4}, - ....: {9, 2, 5}, - ....: {3, 5, 6}, - ....: {4, 6, 7}, - ....: {0, 8, 2, 9}, - ....: {0, 3, 6, 7}, - ....: {1, 3, 5, 9}, - ....: {8, 1, 4, 7}, - ....: {2, 4, 5, 6}, - ....: {0, 1, 2, 3, 4}, - ....: {0, 1, 2, 5, 7}, - ....: {0, 1, 4, 6, 9}, - ....: {0, 1, 5, 6, 8}, - ....: {0, 8, 3, 4, 5}, - ....: {0, 9, 4, 5, 7}, - ....: {8, 1, 2, 3, 6}, - ....: {1, 2, 9, 6, 7}, - ....: {9, 2, 3, 4, 7}, - ....: {8, 2, 3, 5, 7}, - ....: {8, 9, 3, 4, 6}, - ....: {8, 9, 5, 6, 7}] + ....: {0, 9, 3}, + ....: {0, 8, 7}, + ....: {1, 3, 7}, + ....: {1, 4, 5}, + ....: {8, 1, 9}, + ....: {8, 2, 4}, + ....: {9, 2, 5}, + ....: {3, 5, 6}, + ....: {4, 6, 7}, + ....: {0, 8, 2, 9}, + ....: {0, 3, 6, 7}, + ....: {1, 3, 5, 9}, + ....: {8, 1, 4, 7}, + ....: {2, 4, 5, 6}, + ....: {0, 1, 2, 3, 4}, + ....: {0, 1, 2, 5, 7}, + ....: {0, 1, 4, 6, 9}, + ....: {0, 1, 5, 6, 8}, + ....: {0, 8, 3, 4, 5}, + ....: {0, 9, 4, 5, 7}, + ....: {8, 1, 2, 3, 6}, + ....: {1, 2, 9, 6, 7}, + ....: {9, 2, 3, 4, 7}, + ....: {8, 2, 3, 5, 7}, + ....: {8, 9, 3, 4, 6}, + ....: {8, 9, 5, 6, 7}] sage: len(ll) == len(pp) and all(x in pp for x in ll) and all(x in ll for x in pp) True diff --git a/src/sage/graphs/generators/basic.py b/src/sage/graphs/generators/basic.py index 89555fec008..314d66aef43 100644 --- a/src/sage/graphs/generators/basic.py +++ b/src/sage/graphs/generators/basic.py @@ -248,7 +248,7 @@ def CycleGraph(n): Compare plotting using the predefined layout and networkx:: - sage: # needs networkx + sage: # needs networkx sage.plot sage: import networkx sage: n = networkx.cycle_graph(23) sage: spring23 = Graph(n) @@ -259,34 +259,36 @@ def CycleGraph(n): We next view many cycle graphs as a Sage graphics array. First we use the ``CycleGraph`` constructor, which fills in the position dictionary:: + sage: # needs networkx sage.plot sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.CycleGraph(i+3) ....: g.append(k) - sage: for i in range(3): # needs sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # needs sage.plot - sage: G.show() # long time # needs sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time Compare to plotting with the spring-layout algorithm:: + sage: # needs networkx sage.plot sage: g = [] sage: j = [] - sage: for i in range(9): # needs networkx + sage: for i in range(9): ....: spr = networkx.cycle_graph(i+3) ....: k = Graph(spr) ....: g.append(k) - sage: for i in range(3): # needs networkx sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # needs networkx sage.plot - sage: G.show() # long time # needs networkx sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time TESTS: @@ -335,42 +337,45 @@ def CompleteGraph(n): We view many Complete graphs with a Sage Graphics Array, first with this constructor (i.e., the position dictionary filled):: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.CompleteGraph(i+3) ....: g.append(k) - sage: for i in range(3): # needs sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # needs sage.plot - sage: G.show() # long time # needs sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time We compare to plotting with the spring-layout algorithm:: - sage: import networkx # needs networkx + sage: # needs networkx sage.plot + sage: import networkx sage: g = [] sage: j = [] - sage: for i in range(9): # needs networkx + sage: for i in range(9): ....: spr = networkx.complete_graph(i+3) ....: k = Graph(spr) ....: g.append(k) - sage: for i in range(3): # needs networkx sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # needs networkx sage.plot - sage: G.show() # long time # needs networkx sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time Compare the constructors (results will vary):: - sage: import networkx # needs networkx - sage: t = cputime() # needs networkx - sage: n = networkx.complete_graph(389); spring389 = Graph(n) # needs networkx - sage: cputime(t) # random # needs networkx + sage: # needs networkx + sage: import networkx + sage: t = cputime() + sage: n = networkx.complete_graph(389); spring389 = Graph(n) + sage: cputime(t) # random 0.59203700000000126 sage: t = cputime() sage: posdict389 = graphs.CompleteGraph(389) @@ -379,11 +384,12 @@ def CompleteGraph(n): We compare plotting:: - sage: import networkx # needs networkx - sage: n = networkx.complete_graph(23) # needs networkx - sage: spring23 = Graph(n) # needs networkx + sage: # needs networkx + sage: import networkx + sage: n = networkx.complete_graph(23) + sage: spring23 = Graph(n) sage: posdict23 = graphs.CompleteGraph(23) - sage: spring23.show() # long time # needs networkx sage.plot + sage: spring23.show() # long time # needs sage.plot sage: posdict23.show() # long time # needs sage.plot """ G = Graph(n, name="Complete graph") @@ -404,16 +410,17 @@ def CorrelationGraph(seqs, alpha, include_anticorrelation): EXAMPLES: + sage: # needs numpy sage: from sage.graphs.generators.basic import CorrelationGraph sage: data = [[1,2,3], [4,5,6], [7,8,9999]] - sage: CG1 = CorrelationGraph(data, 0.9, False) # needs numpy - sage: CG2 = CorrelationGraph(data, 0.9, True) # needs numpy - sage: CG3 = CorrelationGraph(data, 0.1, True) # needs numpy - sage: CG1.edges(sort=False) # needs numpy + sage: CG1 = CorrelationGraph(data, 0.9, False) + sage: CG2 = CorrelationGraph(data, 0.9, True) + sage: CG3 = CorrelationGraph(data, 0.1, True) + sage: CG1.edges(sort=False) [(0, 0, None), (0, 1, None), (1, 1, None), (2, 2, None)] - sage: CG2.edges(sort=False) # needs numpy + sage: CG2.edges(sort=False) [(0, 0, None), (0, 1, None), (1, 1, None), (2, 2, None)] - sage: CG3.edges(sort=False) # needs numpy + sage: CG3.edges(sort=False) [(0, 0, None), (0, 1, None), (0, 2, None), (1, 1, None), (1, 2, None), (2, 2, None)] """ @@ -478,9 +485,10 @@ def CompleteBipartiteGraph(p, q, set_position=True): Two ways of constructing the complete bipartite graph, using different layout algorithms:: - sage: import networkx # needs networkx - sage: n = networkx.complete_bipartite_graph(389, 157) # long time # needs networkx - sage: spring_big = Graph(n) # long time # needs networkx + sage: # needs networkx + sage: import networkx + sage: n = networkx.complete_bipartite_graph(389, 157) # long time + sage: spring_big = Graph(n) # long time sage: posdict_big = graphs.CompleteBipartiteGraph(389, 157) # long time Compare the plotting:: @@ -512,19 +520,20 @@ def CompleteBipartiteGraph(p, q, set_position=True): We compare to plotting with the spring-layout algorithm:: + sage: # needs networkx sage.plot sage: g = [] sage: j = [] - sage: for i in range(9): # needs networkx + sage: for i in range(9): ....: spr = networkx.complete_bipartite_graph(i+1,4) ....: k = Graph(spr) ....: g.append(k) - sage: for i in range(3): # needs networkx sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # needs networkx sage.plot - sage: G.show() # long time # needs networkx sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time :trac:`12155`:: @@ -1111,18 +1120,19 @@ def LadderGraph(n): Create several ladder graphs in a Sage graphics array:: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.LadderGraph(i+2) ....: g.append(k) - sage: for i in range(3): # needs sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # needs sage.plot - sage: G.show() # long time # needs sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time """ pos_dict = {} for i in range(n): @@ -1268,10 +1278,11 @@ def StarGraph(n): Compare the plots:: - sage: n = networkx.star_graph(23) # needs networkx - sage: spring23 = Graph(n) # needs networkx + sage: # needs networkx sage.plot + sage: n = networkx.star_graph(23) + sage: spring23 = Graph(n) sage: posdict23 = graphs.StarGraph(23) - sage: spring23.show() # long time # needs networkx + sage: spring23.show() # long time sage: posdict23.show() # long time View many star graphs as a Sage Graphics Array @@ -1280,36 +1291,38 @@ def StarGraph(n): :: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.StarGraph(i+3) ....: g.append(k) - sage: for i in range(3): # needs sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # needs sage.plot - sage: G.show() # long time # needs sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time Compared to plotting with the spring-layout algorithm :: + sage: # needs networkx sage.plot sage: g = [] sage: j = [] - sage: for i in range(9): # needs networkx + sage: for i in range(9): ....: spr = networkx.star_graph(i+3) ....: k = Graph(spr) ....: g.append(k) - sage: for i in range(3): # needs networkx sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # needs networkx sage.plot - sage: G.show() # long time # needs networkx sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time """ G = Graph({0: list(range(1, n + 1))}, name="Star graph", format="dict_of_lists") G.set_pos({0: (0, 0)}) From db061a95a817934ad2e4336754e8748ed50788c1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 2 Aug 2023 17:22:15 -0700 Subject: [PATCH 78/87] sage.graphs: Use even more block # needs --- src/sage/graphs/generators/random.py | 50 ++-- src/sage/graphs/generators/smallgraphs.py | 18 +- src/sage/graphs/generic_graph.py | 268 ++++++++++-------- src/sage/graphs/graph.py | 22 +- src/sage/graphs/graph_coloring.pyx | 61 ++-- .../vertex_separation.pyx | 11 +- src/sage/graphs/graph_generators.py | 67 +++-- src/sage/graphs/graph_input.py | 114 ++++---- src/sage/graphs/graph_latex.py | 81 +++--- src/sage/graphs/graph_plot_js.py | 10 +- src/sage/graphs/path_enumeration.pyx | 27 +- src/sage/graphs/strongly_regular_db.pyx | 11 +- 12 files changed, 394 insertions(+), 346 deletions(-) diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index 22459ca6930..5dab4071f49 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -162,18 +162,19 @@ def RandomBarabasiAlbert(n, m, seed=None): We view many random graphs using a graphics array:: + sage: # needs networkx sage.plot sage: g = [] sage: j = [] - sage: for i in range(1,10): # needs networkx + sage: for i in range(1,10): ....: k = graphs.RandomBarabasiAlbert(i+3, 3) ....: g.append(k) - sage: for i in range(3): # needs networkx sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # needs networkx sage.plot - sage: G.show() # long time # needs networkx sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time When `m = 1`, the generated graph is a tree:: @@ -690,18 +691,19 @@ def RandomGNM(n, m, dense=False, seed=None): We view many random graphs using a graphics array:: + sage: # needs networkx sage.plot sage: g = [] sage: j = [] - sage: for i in range(9): # needs networkx + sage: for i in range(9): ....: k = graphs.RandomGNM(i+3, i^2-i) ....: g.append(k) - sage: for i in range(3): # needs networkx sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # needs networkx sage.plot - sage: G.show() # long time # needs networkx sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time """ if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) @@ -1446,7 +1448,7 @@ def RandomTreePowerlaw(n, gamma=3, tries=1000, seed=None): :: sage: G = graphs.RandomTreePowerlaw(15, 2) # needs networkx - sage: if G: # random output # long time # needs networkx sage.plot + sage: if G: # random output # long time, needs networkx sage.plot ....: G.show() """ if seed is None: @@ -1486,7 +1488,7 @@ def RandomRegular(d, n, seed=None): :: sage: G = graphs.RandomRegular(3, 20) # needs networkx - sage: if G: # random output # long time # needs networkx sage.plot + sage: if G: # random output # long time, needs networkx sage.plot ....: G.show() REFERENCES: @@ -2101,17 +2103,18 @@ def RandomBicubicPlanar(n, seed=None): EXAMPLES:: + sage: # needs sage.combinat sage: n = randint(200, 300) - sage: G = graphs.RandomBicubicPlanar(n) # needs sage.combinat - sage: G.order() == 2*n # needs sage.combinat + sage: G = graphs.RandomBicubicPlanar(n) + sage: G.order() == 2*n True - sage: G.size() == 3*n # needs sage.combinat + sage: G.size() == 3*n True - sage: G.is_bipartite() and G.is_planar() and G.is_regular(3) # needs sage.combinat + sage: G.is_bipartite() and G.is_planar() and G.is_regular(3) True - sage: dic = {'red': [v for v in G.vertices(sort=False) if v[0] == 'n'], # needs sage.combinat + sage: dic = {'red': [v for v in G.vertices(sort=False) if v[0] == 'n'], ....: 'blue': [v for v in G.vertices(sort=False) if v[0] != 'n']} - sage: G.plot(vertex_labels=False, vertex_size=20, vertex_colors=dic) # needs sage.combinat sage.plot + sage: G.plot(vertex_labels=False, vertex_size=20, vertex_colors=dic) # needs sage.plot Graphics object consisting of ... graphics primitives .. PLOT:: @@ -2213,17 +2216,18 @@ def RandomUnitDiskGraph(n, radius=.1, side=1, seed=None): When using twice the same seed, the vertices get the same positions:: + sage: # needs scipy sage: from sage.misc.randstate import current_randstate sage: seed = current_randstate().seed() - sage: G = graphs.RandomUnitDiskGraph(20, radius=.5, side=1, seed=seed) # needs scipy - sage: H = graphs.RandomUnitDiskGraph(20, radius=.2, side=1, seed=seed) # needs scipy - sage: H.is_subgraph(G, induced=False) # needs scipy + sage: G = graphs.RandomUnitDiskGraph(20, radius=.5, side=1, seed=seed) + sage: H = graphs.RandomUnitDiskGraph(20, radius=.2, side=1, seed=seed) + sage: H.is_subgraph(G, induced=False) True - sage: H.size() <= G.size() # needs scipy + sage: H.size() <= G.size() True - sage: Gpos = G.get_pos() # needs scipy - sage: Hpos = H.get_pos() # needs scipy - sage: all(Gpos[u] == Hpos[u] for u in G) # needs scipy + sage: Gpos = G.get_pos() + sage: Hpos = H.get_pos() + sage: all(Gpos[u] == Hpos[u] for u in G) True When the radius is more than `\sqrt{2 \text{side}}`, the graph is a clique:: diff --git a/src/sage/graphs/generators/smallgraphs.py b/src/sage/graphs/generators/smallgraphs.py index e879b708aaf..ccc4610bb8c 100644 --- a/src/sage/graphs/generators/smallgraphs.py +++ b/src/sage/graphs/generators/smallgraphs.py @@ -2108,7 +2108,7 @@ def HortonGraph(): 96 sage: g.chromatic_number() 2 - sage: g.is_hamiltonian() # not tested # needs sage.numerical.mip + sage: g.is_hamiltonian() # not tested (veeeery long) # needs sage.numerical.mip False """ g = Graph(name="Horton Graph") @@ -4540,11 +4540,7 @@ def TutteGraph(): 4 sage: g.automorphism_group().cardinality() # needs sage.groups 3 -<<<<<<< HEAD - sage: g.is_hamiltonian() -======= sage: g.is_hamiltonian() # needs sage.numerical.mip ->>>>>>> 85d4a8d443 (./sage -fixdoctests --probe all --distribution 'sagemath-graphs[modules]' src/sage/graphs/generators/smallgraphs.py; ./sage -fixdoctests src/sage/graphs/generators/smallgraphs.py) False """ g = Graph(name="Tutte Graph") @@ -4723,11 +4719,7 @@ def _EllipticLinesProjectivePlaneScheme(k): TESTS:: sage: from sage.graphs.generators.smallgraphs import _EllipticLinesProjectivePlaneScheme -<<<<<<< HEAD - sage: _EllipticLinesProjectivePlaneScheme(2) -======= sage: _EllipticLinesProjectivePlaneScheme(2) # needs sage.libs.gap ->>>>>>> 85d4a8d443 (./sage -fixdoctests --probe all --distribution 'sagemath-graphs[modules]' src/sage/graphs/generators/smallgraphs.py; ./sage -fixdoctests src/sage/graphs/generators/smallgraphs.py) [ [1 0 0 0 0 0] [0 1 1 1 1 0] [0 0 0 0 0 1] [0 1 0 0 0 0] [1 0 1 1 0 1] [0 0 0 0 1 0] @@ -5042,20 +5034,12 @@ def IoninKharaghani765Graph(): EXAMPLES:: -<<<<<<< HEAD - sage: g = graphs.IoninKharaghani765Graph(); g -======= sage: g = graphs.IoninKharaghani765Graph(); g # needs sage.modules sage.rings.finite_rings ->>>>>>> 85d4a8d443 (./sage -fixdoctests --probe all --distribution 'sagemath-graphs[modules]' src/sage/graphs/generators/smallgraphs.py; ./sage -fixdoctests src/sage/graphs/generators/smallgraphs.py) Ionin-Kharaghani: Graph on 765 vertices TESTS:: -<<<<<<< HEAD - sage: graphs.strongly_regular_graph(765, 192, 48, 48) -======= sage: graphs.strongly_regular_graph(765, 192, 48, 48) # needs sage.modules sage.rings.finite_rings ->>>>>>> 85d4a8d443 (./sage -fixdoctests --probe all --distribution 'sagemath-graphs[modules]' src/sage/graphs/generators/smallgraphs.py; ./sage -fixdoctests src/sage/graphs/generators/smallgraphs.py) Ionin-Kharaghani: Graph on 765 vertices .. TODO:: diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 64cdd8dffcb..afae6f5de21 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -6872,43 +6872,46 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None ... EmptySetError: this graph does not contain the required number of trees/arborescences - By Edmond's theorem, a graph which is `k`-connected always has `k` + By Edmonds' theorem, a graph which is `k`-connected always has `k` edge-disjoint arborescences, regardless of the root we pick:: + sage: # needs sage.numerical.mip sage: g = digraphs.RandomDirectedGNP(11, .3) # reduced from 30 to 11, cf. #32169 sage: k = Integer(g.edge_connectivity()) - sage: while not k: # needs sage.numerical.mip + sage: while not k: ....: g = digraphs.RandomDirectedGNP(11, .3) ....: k = Integer(g.edge_connectivity()) - sage: arborescences = g.edge_disjoint_spanning_trees(k) # long time (up to 15s on sage.math, 2011), needs sage.numerical.mip - sage: all(a.is_directed_acyclic() for a in arborescences) # long time, needs sage.numerical.mip + sage: arborescences = g.edge_disjoint_spanning_trees(k) # long time (up to 15s on sage.math, 2011) + sage: all(a.is_directed_acyclic() for a in arborescences) # long time True - sage: all(a.is_connected() for a in arborescences) # long time # needs sage.numerical.mip + sage: all(a.is_connected() for a in arborescences) # long time True In the undirected case, we can only ensure half of it:: + sage: # needs sage.numerical.mip sage: g = graphs.RandomGNP(14, .3) # reduced from 30 to 14, see #32169 - sage: while not g.is_biconnected(): # needs sage.numerical.mip + sage: while not g.is_biconnected(): ....: g = graphs.RandomGNP(14, .3) - sage: k = Integer(g.edge_connectivity()) // 2 # needs sage.numerical.mip - sage: trees = g.edge_disjoint_spanning_trees(k) # needs sage.numerical.mip - sage: all(t.is_tree() for t in trees) # needs sage.numerical.mip + sage: k = Integer(g.edge_connectivity()) // 2 + sage: trees = g.edge_disjoint_spanning_trees(k) + sage: all(t.is_tree() for t in trees) True Check the validity of the algorithms for undirected graphs:: + sage: # needs sage.numerical.mip sage: g = graphs.RandomGNP(12, .7) sage: k = Integer(g.edge_connectivity()) // 2 - sage: trees = g.edge_disjoint_spanning_trees(k, algorithm="MILP") # needs sage.numerical.mip - sage: all(t.is_tree() for t in trees) # needs sage.numerical.mip + sage: trees = g.edge_disjoint_spanning_trees(k, algorithm="MILP") + sage: all(t.is_tree() for t in trees) True - sage: all(g.order() == t.size() + 1 for t in trees) # needs sage.numerical.mip + sage: all(g.order() == t.size() + 1 for t in trees) True - sage: trees = g.edge_disjoint_spanning_trees(k, algorithm="Roskind-Tarjan") # needs sage.numerical.mip - sage: all(t.is_tree() for t in trees) # needs sage.numerical.mip + sage: trees = g.edge_disjoint_spanning_trees(k, algorithm="Roskind-Tarjan") + sage: all(t.is_tree() for t in trees) True - sage: all(g.order() == t.size() + 1 for t in trees) # needs sage.numerical.mip + sage: all(g.order() == t.size() + 1 for t in trees) True Example of :trac:`32169`:: @@ -7634,12 +7637,13 @@ def max_cut(self, value_only=True, use_edge_labels=False, vertices=False, Quite obviously, the max cut of a bipartite graph is the number of edges, and the two sets of vertices are the two sides:: + sage: # needs sage.numerical.mip sage: g = graphs.CompleteBipartiteGraph(5,6) - sage: [ value, edges, [ setA, setB ]] = g.max_cut(vertices=True) # needs sage.numerical.mip - sage: value == 5*6 # needs sage.numerical.mip + sage: [ value, edges, [ setA, setB ]] = g.max_cut(vertices=True) + sage: value == 5*6 True - sage: bsetA, bsetB = map(list, g.bipartite_sets()) # needs sage.numerical.mip - sage: ((bsetA == setA and bsetB == setB) # needs sage.numerical.mip + sage: bsetA, bsetB = map(list, g.bipartite_sets()) + sage: ((bsetA == setA and bsetB == setB) ....: or (bsetA == setB and bsetB == setA)) True @@ -7882,15 +7886,16 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", Trivial graphs:: + sage: # needs sage.numerical.mip sage: G = Graph() sage: G.add_vertex(0) - sage: G.longest_path() # needs sage.numerical.mip + sage: G.longest_path() Graph on 0 vertices - sage: G.longest_path(use_edge_labels=True) # needs sage.numerical.mip + sage: G.longest_path(use_edge_labels=True) [0, Graph on 0 vertices] - sage: graphs.CompleteGraph(1).longest_path() # needs sage.numerical.mip + sage: graphs.CompleteGraph(1).longest_path() Graph on 0 vertices - sage: graphs.CompleteGraph(1).longest_path(use_edge_labels=True) # needs sage.numerical.mip + sage: graphs.CompleteGraph(1).longest_path(use_edge_labels=True) [0, Graph on 0 vertices] Random test for digraphs:: @@ -8192,16 +8197,17 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, starting from vertex `(0, 0)` and ending at vertex `(2, 2)`, but no Hamiltonian path starting from `(0, 0)` and ending at `(0, 1)`:: + sage: # needs sage.numerical.mip sage: g = graphs.Grid2dGraph(3, 3) - sage: g.hamiltonian_path() # needs sage.numerical.mip + sage: g.hamiltonian_path() Hamiltonian path from 2D Grid Graph for [3, 3]: Graph on 9 vertices - sage: g.hamiltonian_path(s=(0, 0), t=(2, 2)) # needs sage.numerical.mip + sage: g.hamiltonian_path(s=(0, 0), t=(2, 2)) Hamiltonian path from 2D Grid Graph for [3, 3]: Graph on 9 vertices - sage: g.hamiltonian_path(s=(0, 0), t=(2, 2), use_edge_labels=True) # needs sage.numerical.mip + sage: g.hamiltonian_path(s=(0, 0), t=(2, 2), use_edge_labels=True) (8, Hamiltonian path from 2D Grid Graph for [3, 3]: Graph on 9 vertices) - sage: g.hamiltonian_path(s=(0, 0), t=(0, 1)) is None # needs sage.numerical.mip + sage: g.hamiltonian_path(s=(0, 0), t=(0, 1)) is None True - sage: g.hamiltonian_path(s=(0, 0), t=(0, 1), use_edge_labels=True) # needs sage.numerical.mip + sage: g.hamiltonian_path(s=(0, 0), t=(0, 1), use_edge_labels=True) (0, None) TESTS: @@ -8505,14 +8511,15 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, Search for a minimum and a maximum weight Hamiltonian cycle:: + sage: # needs sage.numerical.mip sage: G = Graph([(0, 1, 1), (0, 2, 2), (0, 3, 1), (1, 2, 1), (1, 3, 2), (2, 3, 1)]) - sage: tsp = G.traveling_salesman_problem(use_edge_labels=True, # needs sage.numerical.mip + sage: tsp = G.traveling_salesman_problem(use_edge_labels=True, ....: maximize=False) - sage: print(sum(tsp.edge_labels())) # needs sage.numerical.mip + sage: print(sum(tsp.edge_labels())) 4 - sage: tsp = G.traveling_salesman_problem(use_edge_labels=True, # needs sage.numerical.mip + sage: tsp = G.traveling_salesman_problem(use_edge_labels=True, ....: maximize=True) - sage: print(sum(tsp.edge_labels())) # needs sage.numerical.mip + sage: print(sum(tsp.edge_labels())) 6 TESTS: @@ -8554,47 +8561,49 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, Simple tests for multiple edges and loops:: + sage: # needs sage.numerical.mip sage: G = DiGraph(multiedges=True, loops=True) - sage: G.is_hamiltonian() # needs sage.numerical.mip + sage: G.is_hamiltonian() False sage: G.add_vertex(0) - sage: G.is_hamiltonian() # needs sage.numerical.mip + sage: G.is_hamiltonian() False sage: G.add_edge(0, 0, 1) sage: G.add_edge(0, 0, 2) - sage: tsp = G.traveling_salesman_problem(use_edge_labels=True) # needs sage.numerical.mip + sage: tsp = G.traveling_salesman_problem(use_edge_labels=True) Traceback (most recent call last): ... EmptySetError: the given graph is not Hamiltonian sage: G.add_vertex(1) - sage: G.is_hamiltonian() # needs sage.numerical.mip + sage: G.is_hamiltonian() False sage: G.add_edge(0, 1, 2) sage: G.add_edge(0, 1, 3) sage: G.add_edge(1, 1, 1) sage: G.add_edge(1, 0, 2) - sage: G.is_hamiltonian() # needs sage.numerical.mip + sage: G.is_hamiltonian() True - sage: tsp = G.traveling_salesman_problem(use_edge_labels=True) # needs sage.numerical.mip - sage: sum(tsp.edge_labels()) # needs sage.numerical.mip + sage: tsp = G.traveling_salesman_problem(use_edge_labels=True) + sage: sum(tsp.edge_labels()) 4 Graphs on 2 vertices:: - sage: Graph([(0, 1), (0, 1)], multiedges=True).is_hamiltonian() # needs sage.numerical.mip + sage: # needs sage.numerical.mip + sage: Graph([(0, 1), (0, 1)], multiedges=True).is_hamiltonian() True - sage: DiGraph([(0, 1), (0, 1)], multiedges=True).is_hamiltonian() # needs sage.numerical.mip + sage: DiGraph([(0, 1), (0, 1)], multiedges=True).is_hamiltonian() False - sage: DiGraph([(0, 1), (1, 0)], multiedges=True).is_hamiltonian() # needs sage.numerical.mip + sage: DiGraph([(0, 1), (1, 0)], multiedges=True).is_hamiltonian() True sage: G = digraphs.Complete(2, loops=True) - sage: G.is_hamiltonian() # needs sage.numerical.mip + sage: G.is_hamiltonian() True sage: G.remove_loops() - sage: G.is_hamiltonian() # needs sage.numerical.mip + sage: G.is_hamiltonian() True sage: G.allow_loops(False) - sage: G.is_hamiltonian() # needs sage.numerical.mip + sage: G.is_hamiltonian() True Check that weight 0 edges are handled correctly (see :trac:`16214`):: @@ -9100,12 +9109,13 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, The necessary example:: + sage: # needs sage.numerical.mip sage: g = graphs.PetersenGraph() - sage: fvs = g.feedback_vertex_set() # needs sage.numerical.mip - sage: len(fvs) # needs sage.numerical.mip + sage: fvs = g.feedback_vertex_set() + sage: len(fvs) 3 - sage: g.delete_vertices(fvs) # needs sage.numerical.mip - sage: g.is_forest() # needs sage.numerical.mip + sage: g.delete_vertices(fvs) + sage: g.is_forest() True In a digraph built from a graph, any edge is replaced by arcs going in @@ -9114,15 +9124,16 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, of its neighbors removed: a feedback vertex set is in this situation a vertex cover:: + sage: # needs sage.numerical.mip sage: cycle = graphs.CycleGraph(5) sage: dcycle = DiGraph(cycle) - sage: cycle.vertex_cover(value_only=True) # needs sage.numerical.mip + sage: cycle.vertex_cover(value_only=True) 3 - sage: feedback = dcycle.feedback_vertex_set() # needs sage.numerical.mip - sage: len(feedback) # needs sage.numerical.mip + sage: feedback = dcycle.feedback_vertex_set() + sage: len(feedback) 3 - sage: u,v = next(cycle.edge_iterator(labels=None)) # needs sage.numerical.mip - sage: u in feedback or v in feedback # needs sage.numerical.mip + sage: u,v = next(cycle.edge_iterator(labels=None)) + sage: u in feedback or v in feedback True For a circuit, the minimum feedback arc set is clearly `1`:: @@ -9662,17 +9673,18 @@ def nowhere_zero_flow(self, k=None, solver=None, verbose=0, *, integrality_toler Loops and multiple edges:: + sage: # needs sage.numerical.mip sage: g = Graph([(0, 0), (0, 0)], loops=True, multiedges=True) - sage: g.nowhere_zero_flow().edges(sort=True) # needs sage.numerical.mip + sage: g.nowhere_zero_flow().edges(sort=True) [(0, 0, 1), (0, 0, 1)] sage: g = Graph([(0, 0), (0, 1), (0, 1)], loops=True, multiedges=True) - sage: g.nowhere_zero_flow(k=2).edges(sort=True) # needs sage.numerical.mip + sage: g.nowhere_zero_flow(k=2).edges(sort=True) [(0, 0, 1), (0, 1, 1), (1, 0, 1)] sage: g = DiGraph([(0, 0), (0, 0)], loops=True, multiedges=True) - sage: g.nowhere_zero_flow().edges(sort=True) # needs sage.numerical.mip + sage: g.nowhere_zero_flow().edges(sort=True) [(0, 0, 1), (0, 0, 1)] sage: g = DiGraph([(0, 0), (0, 1), (0, 1)], loops=True, multiedges=True) - sage: g.nowhere_zero_flow(k=2).edges(sort=True) # needs sage.numerical.mip + sage: g.nowhere_zero_flow(k=2).edges(sort=True) [(0, 0, 1), (0, 1, -1), (0, 1, 1)] Multiple connected components:: @@ -11401,13 +11413,14 @@ def vertices(self, sort=None, key=None, degree=None, vertex_property=None): are first-class objects in Python, we can specify precisely the function from the Sage library that we wish to use as the key:: + sage: # needs sage.libs.flint sage: t = polygen(QQ, 't') sage: K = Graph({5*t: [t^2], t^2: [t^2+2], t^2+2: [4*t^2-6], 4*t^2-6: [5*t]}) - sage: from sage.rings.polynomial.polynomial_rational_flint import Polynomial_rational_flint # needs sage.libs.flint - sage: dsc = Polynomial_rational_flint.discriminant # needs sage.libs.flint - sage: verts = K.vertices(sort=True, key=dsc); verts # needs sage.libs.flint + sage: from sage.rings.polynomial.polynomial_rational_flint import Polynomial_rational_flint + sage: dsc = Polynomial_rational_flint.discriminant + sage: verts = K.vertices(sort=True, key=dsc); verts [t^2 + 2, t^2, 5*t, 4*t^2 - 6] - sage: [x.discriminant() for x in verts] # needs sage.libs.flint + sage: [x.discriminant() for x in verts] [-8, 0, 1, 96] TESTS: @@ -16192,21 +16205,22 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, The result does not depend on the algorithm:: + sage: # needs networkx sage: import random sage: import itertools sage: n = random.randint(2,20) sage: m = random.randint(0, n*(n-1)/2) - sage: g = graphs.RandomGNM(n,m) # needs networkx - sage: c1 = g.centrality_closeness(algorithm='BFS') # needs networkx - sage: c2 = g.centrality_closeness(algorithm='NetworkX') # needs networkx - sage: c3 = g.centrality_closeness(algorithm='Dijkstra_Boost') # needs networkx - sage: c4 = g.centrality_closeness(algorithm='Floyd-Warshall-Cython') # needs networkx - sage: c5 = g.centrality_closeness(algorithm='Floyd-Warshall-Python') # needs networkx - sage: c6 = g.centrality_closeness(algorithm='Johnson_Boost') # needs networkx - sage: len(c1)==len(c2)==len(c3)==len(c4)==len(c5)==len(c6) # needs networkx + sage: g = graphs.RandomGNM(n,m) + sage: c1 = g.centrality_closeness(algorithm='BFS') + sage: c2 = g.centrality_closeness(algorithm='NetworkX') + sage: c3 = g.centrality_closeness(algorithm='Dijkstra_Boost') + sage: c4 = g.centrality_closeness(algorithm='Floyd-Warshall-Cython') + sage: c5 = g.centrality_closeness(algorithm='Floyd-Warshall-Python') + sage: c6 = g.centrality_closeness(algorithm='Johnson_Boost') + sage: len(c1)==len(c2)==len(c3)==len(c4)==len(c5)==len(c6) True - sage: c = [c1,c2,c3,c4,c5,c6] # needs networkx - sage: all( sum(abs(ci[v] - cj[v]) for v in g if g.degree(v)) < 1e-12 # needs networkx + sage: c = [c1,c2,c3,c4,c5,c6] + sage: all( sum(abs(ci[v] - cj[v]) for v in g if g.degree(v)) < 1e-12 ....: for ci, cj in itertools.combinations(c, 2) ) True @@ -16232,21 +16246,22 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, Weighted graphs:: + sage: # needs networkx sage: import random sage: import itertools sage: n = random.randint(2,20) sage: m = random.randint(0, n*(n-1)/2) - sage: g = graphs.RandomGNM(n,m) # needs networkx - sage: for v,w in g.edges(sort=True, labels=False): # needs networkx + sage: g = graphs.RandomGNM(n,m) + sage: for v,w in g.edges(sort=True, labels=False): ....: g.set_edge_label(v,w,float(random.uniform(1,100))) - sage: c1 = g.centrality_closeness(by_weight=True, algorithm='NetworkX') # needs networkx - sage: c2 = g.centrality_closeness(by_weight=True, algorithm='Dijkstra_Boost') # needs networkx - sage: c3 = g.centrality_closeness(by_weight=True, algorithm='Floyd-Warshall-Python') # needs networkx - sage: c4 = g.centrality_closeness(by_weight=True, algorithm='Johnson_Boost') # needs networkx - sage: len(c1)==len(c2)==len(c3)==len(c4) # needs networkx - True - sage: c = [c1,c2,c3,c4] # needs networkx - sage: all( sum(abs(ci[v] - cj[v]) for v in g if g.degree(v)) < 1e-12 # needs networkx + sage: c1 = g.centrality_closeness(by_weight=True, algorithm='NetworkX') + sage: c2 = g.centrality_closeness(by_weight=True, algorithm='Dijkstra_Boost') + sage: c3 = g.centrality_closeness(by_weight=True, algorithm='Floyd-Warshall-Python') + sage: c4 = g.centrality_closeness(by_weight=True, algorithm='Johnson_Boost') + sage: len(c1)==len(c2)==len(c3)==len(c4) + True + sage: c = [c1,c2,c3,c4] + sage: all( sum(abs(ci[v] - cj[v]) for v in g if g.degree(v)) < 1e-12 ....: for ci, cj in itertools.combinations(c, 2) ) True @@ -20255,16 +20270,17 @@ def layout_graphviz(self, dim=2, prog='dot', **options): By default, an acyclic layout is computed using ``graphviz``'s ``dot`` layout program. One may specify an alternative layout program:: - sage: g.plot(layout="graphviz", prog="dot") # optional - dot2tex graphviz + sage: # optional - dot2tex graphviz + sage: g.plot(layout="graphviz", prog="dot") Graphics object consisting of 29 graphics primitives - sage: g.plot(layout="graphviz", prog="neato") # optional - dot2tex graphviz + sage: g.plot(layout="graphviz", prog="neato") Graphics object consisting of 29 graphics primitives - sage: g.plot(layout="graphviz", prog="twopi") # optional - dot2tex graphviz + sage: g.plot(layout="graphviz", prog="twopi") Graphics object consisting of 29 graphics primitives - sage: g.plot(layout="graphviz", prog="fdp") # optional - dot2tex graphviz + sage: g.plot(layout="graphviz", prog="fdp") Graphics object consisting of 29 graphics primitives sage: g = graphs.BalancedTree(5,2) # needs networkx - sage: g.plot(layout="graphviz", prog="circo") # optional - dot2tex graphviz, needs networkx + sage: g.plot(layout="graphviz", prog="circo") # needs networkx Graphics object consisting of 62 graphics primitives .. TODO:: @@ -20289,14 +20305,14 @@ def layout_graphviz(self, dim=2, prog='dot', **options): Make sure that :trac:`12364` is fixed:: - sage: # needs sage.combinat + sage: # needs sage.combinat sage.modules sage: m = WordMorphism('a->abb,b->ba') sage: w = m.fixed_point('a') - sage: prefix = Word(list(w[:100])) # needs sage.modules - sage: pals = prefix.palindromes() # needs sage.modules - sage: poset = Poset((pals, lambda x,y: x.is_factor(y))) # needs sage.modules - sage: H = poset.hasse_diagram() # needs sage.modules - sage: d = H.layout_graphviz() # optional - dot2tex graphviz # needs sage.modules + sage: prefix = Word(list(w[:100])) + sage: pals = prefix.palindromes() + sage: poset = Poset((pals, lambda x,y: x.is_factor(y))) + sage: H = poset.hasse_diagram() + sage: d = H.layout_graphviz() # optional - dot2tex graphviz """ assert_have_dot2tex() assert dim == 2, "3D graphviz layout not implemented" @@ -22115,11 +22131,12 @@ def spectrum(self, laplacian=False): test both the Laplacian construction and the computation of eigenvalues. :: + sage: # needs sage.modules sage.rings.number_field sage: H = graphs.HoffmanSingletonGraph() - sage: evals = H.spectrum() # needs sage.modules sage.rings.number_field - sage: lap = [7 - x for x in evals] # needs sage.modules sage.rings.number_field - sage: lap.sort(reverse=True) # needs sage.modules sage.rings.number_field - sage: lap == H.spectrum(laplacian=True) # needs sage.modules sage.rings.number_field + sage: evals = H.spectrum() + sage: lap = [7 - x for x in evals] + sage: lap.sort(reverse=True) + sage: lap == H.spectrum(laplacian=True) True """ # Ideally the spectrum should return something like a Factorization object @@ -22976,6 +22993,7 @@ def automorphism_group(self, partition=None, verbosity=0, Graphs:: + sage: # needs sage.groups sage: graphs_query = GraphQuery(display_cols=['graph6'],num_vertices=4) sage: L = graphs_query.get_graphs_list() sage: graphs_list.show_graphs(L) # needs sage.plot @@ -22994,7 +23012,7 @@ def automorphism_group(self, partition=None, verbosity=0, (4, ((2,3), (0,1))) (24, ((2,3), (1,2), (0,1))) sage: C = graphs.CubeGraph(4) - sage: G = C.automorphism_group() # needs sage.groups + sage: G = C.automorphism_group() sage: M = G.character_table() # random order of rows, thus abs() below sage: QQ(M.determinant()).abs() 712483534798848 @@ -23003,8 +23021,9 @@ def automorphism_group(self, partition=None, verbosity=0, :: + sage: # needs sage.groups sage: D = graphs.DodecahedralGraph() - sage: G = D.automorphism_group() # needs sage.groups + sage: G = D.automorphism_group() sage: A5 = AlternatingGroup(5) sage: Z2 = CyclicPermutationGroup(2) sage: H = A5.direct_product(Z2)[0] #see documentation for direct_product to explain the [0] @@ -23045,15 +23064,16 @@ def automorphism_group(self, partition=None, verbosity=0, sage: G.automorphism_group(edge_labels=True) # needs sage.groups Permutation Group with generators [(0,1)] + sage: # needs sage.groups sage: foo = Graph(sparse=True) sage: bar = Graph(sparse=True) sage: foo.add_edges([(0,1,1),(1,2,2), (2,3,3)]) sage: bar.add_edges([(0,1,1),(1,2,2), (2,3,3)]) - sage: foo.automorphism_group(edge_labels=True) # needs sage.groups + sage: foo.automorphism_group(edge_labels=True) Permutation Group with generators [()] - sage: foo.automorphism_group() # needs sage.groups + sage: foo.automorphism_group() Permutation Group with generators [(0,3)(1,2)] - sage: bar.automorphism_group(edge_labels=True) # needs sage.groups + sage: bar.automorphism_group(edge_labels=True) Permutation Group with generators [()] You can also ask for just the order of the group:: @@ -23066,16 +23086,17 @@ def automorphism_group(self, partition=None, verbosity=0, :: + sage: # needs sage.groups sage: G = graphs.PetersenGraph() - sage: G.automorphism_group(return_group=False, orbits=True, algorithm='sage') # needs sage.groups + sage: G.automorphism_group(return_group=False, orbits=True, algorithm='sage') [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]] - sage: orb = G.automorphism_group(partition=[[0],list(range(1,10))], # needs sage.groups + sage: orb = G.automorphism_group(partition=[[0],list(range(1,10))], ....: return_group=False, orbits=True, algorithm='sage') - sage: sorted([sorted(o) for o in orb], key=len) # needs sage.groups + sage: sorted([sorted(o) for o in orb], key=len) [[0], [1, 4, 5], [2, 3, 6, 7, 8, 9]] sage: C = graphs.CubeGraph(3) - sage: orb = C.automorphism_group(orbits=True, return_group=False, algorithm='sage') # needs sage.groups - sage: [sorted(o) for o in orb] # needs sage.groups + sage: orb = C.automorphism_group(orbits=True, return_group=False, algorithm='sage') + sage: [sorted(o) for o in orb] [['000', '001', '010', '011', '100', '101', '110', '111']] One can also use the faster algorithm for computing the automorphism @@ -23101,17 +23122,18 @@ def automorphism_group(self, partition=None, verbosity=0, Labeled automorphism group:: - sage: d = digraphs.DeBruijn(3,2) # needs sage.combinat - sage: A = d.automorphism_group(algorithm='sage') # needs sage.combinat + sage: # needs sage.combinat sage.groups + sage: d = digraphs.DeBruijn(3,2) + sage: A = d.automorphism_group(algorithm='sage') sage: A_target = PermutationGroup(["('02','10','21')('00','11','22')('01','12','20')", ....: "('02','01')('10','20')('21','12')('22','11')"]) - sage: A.is_isomorphic(A_target) # needs sage.combinat + sage: A.is_isomorphic(A_target) True - sage: d.allow_multiple_edges(True) # needs sage.combinat - sage: d.add_edge(('00', '00', '0')) # needs sage.combinat - sage: A = d.automorphism_group(algorithm='sage') # needs sage.combinat + sage: d.allow_multiple_edges(True) + sage: d.add_edge(('00', '00', '0')) + sage: A = d.automorphism_group(algorithm='sage') sage: A_target = PermutationGroup(["('01','02')('10','20')('11','22')('12','21')"]) - sage: A.is_isomorphic(A_target) # needs sage.combinat + sage: A.is_isomorphic(A_target) True The labeling is correct:: @@ -23142,19 +23164,21 @@ def automorphism_group(self, partition=None, verbosity=0, We check that the representations of the groups returned with ``'sage'`` and ``'bliss'`` are the same (:trac:`27571`):: - sage: G = graphs.PaleyGraph(9) # needs sage.libs.pari - sage: a1 = G.automorphism_group(algorithm='sage') # needs sage.groups + sage: # needs sage.groups sage.libs.pari + sage: G = graphs.PaleyGraph(9) + sage: a1 = G.automorphism_group(algorithm='sage') sage: V = sorted(G, reverse=True) - sage: a2 = G.automorphism_group(algorithm='sage', partition=[V]) # needs sage.groups - sage: a1.is_isomorphic(a2) # needs sage.groups + sage: a2 = G.automorphism_group(algorithm='sage', partition=[V]) + sage: a1.is_isomorphic(a2) True - sage: str(a1) == str(a2) # needs sage.groups + sage: str(a1) == str(a2) False sage: b1 = G.automorphism_group(algorithm='bliss') # optional - bliss - sage: str(a1) == str(b1) # optional - bliss # needs sage.groups + sage: str(a1) == str(b1) # optional - bliss True - sage: b2 = G.automorphism_group(algorithm='bliss', partition=[V]) # optional - bliss - sage: str(a2) == str(b2) # optional - bliss # needs sage.groups + sage: b2 = G.automorphism_group(algorithm='bliss', # optional - bliss + ....: partition=[V]) + sage: str(a2) == str(b2) # optional - bliss True """ from sage.features.bliss import Bliss diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 0f207ffb1ee..30a63bff8a7 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -3869,13 +3869,15 @@ def coloring(self, algorithm="DLX", hex_colors=False, solver=None, verbose=0, True sage: are_equal_colorings(P, Q) True - sage: G.plot(partition=P) # needs sage.plot + + sage: # needs sage.plot + sage: G.plot(partition=P) Graphics object consisting of 16 graphics primitives - sage: G.coloring(hex_colors=True, algorithm="MILP") # needs sage.plot + sage: G.coloring(hex_colors=True, algorithm="MILP") {'#0000ff': [4], '#00ff00': [0, 6, 5], '#ff0000': [2, 1, 3]} - sage: H = G.coloring(hex_colors=True, algorithm="DLX"); H # needs sage.plot + sage: H = G.coloring(hex_colors=True, algorithm="DLX"); H {'#0000ff': [4], '#00ff00': [1, 2, 3], '#ff0000': [0, 5, 6]} - sage: G.plot(vertex_colors=H) # needs sage.plot + sage: G.plot(vertex_colors=H) Graphics object consisting of 16 graphics primitives .. PLOT:: @@ -7486,20 +7488,22 @@ def cliques_vertex_clique_number(self, algorithm="cliquer", vertices=None, EXAMPLES:: sage: C = Graph('DJ{') - sage: C.cliques_vertex_clique_number() # needs sage.plot + sage: C.cliques_vertex_clique_number() {0: 2, 1: 4, 2: 4, 3: 4, 4: 4} sage: E = C.cliques_maximal(); E [[0, 4], [1, 2, 3, 4]] - sage: C.cliques_vertex_clique_number(cliques=E, algorithm="networkx") # needs networkx sage.plot + sage: C.cliques_vertex_clique_number(cliques=E, algorithm="networkx") # needs networkx {0: 2, 1: 4, 2: 4, 3: 4, 4: 4} + sage: F = graphs.Grid2dGraph(2,3) - sage: F.cliques_vertex_clique_number(algorithm="networkx") # needs networkx sage.plot + sage: F.cliques_vertex_clique_number(algorithm="networkx") # needs networkx {(0, 0): 2, (0, 1): 2, (0, 2): 2, (1, 0): 2, (1, 1): 2, (1, 2): 2} - sage: F.cliques_vertex_clique_number(vertices=[(0, 1), (1, 2)]) # needs sage.plot + sage: F.cliques_vertex_clique_number(vertices=[(0, 1), (1, 2)]) {(0, 1): 2, (1, 2): 2} + sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) sage: G.show(figsize=[2,2]) # needs sage.plot - sage: G.cliques_vertex_clique_number() # needs sage.plot + sage: G.cliques_vertex_clique_number() {0: 3, 1: 3, 2: 3, 3: 3} """ if algorithm == "cliquer": diff --git a/src/sage/graphs/graph_coloring.pyx b/src/sage/graphs/graph_coloring.pyx index 8360f71bfca..f11bc3c4a05 100644 --- a/src/sage/graphs/graph_coloring.pyx +++ b/src/sage/graphs/graph_coloring.pyx @@ -1381,48 +1381,49 @@ def edge_coloring(g, value_only=False, vizing=False, hex_colors=False, solver=No The Petersen graph has chromatic index 4:: - sage: from sage.graphs.graph_coloring import edge_coloring - sage: g = graphs.PetersenGraph() - sage: edge_coloring(g, value_only=True, solver='GLPK') # needs sage.numerical.mip - 4 - sage: color_classes = edge_coloring(g, value_only=False, solver='GLPK') # needs sage.numerical.mip - sage: len(color_classes) # needs sage.numerical.mip - 4 - sage: len(set(frozenset(e) for C in color_classes for e in C)) == g.size() # needs sage.numerical.mip - True - sage: all(g.has_edge(e) for C in color_classes for e in C) # needs sage.numerical.mip - True - sage: all(len(Graph(C).matching()) == len(C) for C in color_classes) # needs networkx sage.numerical.mip - True - sage: color_classes = edge_coloring(g, value_only=False, # needs sage.numerical.mip - ....: hex_colors=True, solver='GLPK') - sage: sorted(color_classes.keys()) # needs sage.numerical.mip - ['#00ffff', '#7f00ff', '#7fff00', '#ff0000'] + sage: # needs sage.numerical.mip + sage: from sage.graphs.graph_coloring import edge_coloring + sage: g = graphs.PetersenGraph() + sage: edge_coloring(g, value_only=True, solver='GLPK') + 4 + sage: color_classes = edge_coloring(g, value_only=False, solver='GLPK') + sage: len(color_classes) + 4 + sage: len(set(frozenset(e) for C in color_classes for e in C)) == g.size() + True + sage: all(g.has_edge(e) for C in color_classes for e in C) + True + sage: all(len(Graph(C).matching()) == len(C) for C in color_classes) # needs networkx + True + sage: color_classes = edge_coloring(g, value_only=False, + ....: hex_colors=True, solver='GLPK') + sage: sorted(color_classes.keys()) + ['#00ffff', '#7f00ff', '#7fff00', '#ff0000'] Complete graphs are colored using the linear-time round-robin coloring:: - sage: from sage.graphs.graph_coloring import edge_coloring - sage: len(edge_coloring(graphs.CompleteGraph(20))) # needs sage.numerical.mip - 19 + sage: from sage.graphs.graph_coloring import edge_coloring + sage: len(edge_coloring(graphs.CompleteGraph(20))) # needs sage.numerical.mip + 19 The chromatic index of a non connected graph is the maximum over its connected components:: - sage: g = graphs.CompleteGraph(4) + graphs.CompleteGraph(10) - sage: edge_coloring(g, value_only=True) # needs sage.numerical.mip - 9 + sage: g = graphs.CompleteGraph(4) + graphs.CompleteGraph(10) + sage: edge_coloring(g, value_only=True) # needs sage.numerical.mip + 9 TESTS: Graph without edge:: - sage: g = Graph(2) - sage: edge_coloring(g) # needs sage.numerical.mip - [] - sage: edge_coloring(g, value_only=True) # needs sage.numerical.mip - 0 - sage: edge_coloring(g, hex_colors=True) # needs sage.numerical.mip - {} + sage: g = Graph(2) + sage: edge_coloring(g) # needs sage.numerical.mip + [] + sage: edge_coloring(g, value_only=True) # needs sage.numerical.mip + 0 + sage: edge_coloring(g, hex_colors=True) # needs sage.numerical.mip + {} """ g._scream_if_not_simple() diff --git a/src/sage/graphs/graph_decompositions/vertex_separation.pyx b/src/sage/graphs/graph_decompositions/vertex_separation.pyx index c3e2948e9d6..19a1e07ba2e 100644 --- a/src/sage/graphs/graph_decompositions/vertex_separation.pyx +++ b/src/sage/graphs/graph_decompositions/vertex_separation.pyx @@ -766,13 +766,16 @@ def vertex_separation(G, algorithm="BAB", cut_off=None, upper_bound=None, verbos Comparison of methods:: sage: from sage.graphs.graph_decompositions.vertex_separation import vertex_separation - sage: G = digraphs.DeBruijn(2,3) # needs sage.combinat - sage: vs,L = vertex_separation(G, algorithm="BAB"); vs # needs sage.combinat + + sage: # needs sage.combinat + sage: G = digraphs.DeBruijn(2,3) + sage: vs,L = vertex_separation(G, algorithm="BAB"); vs 2 - sage: vs,L = vertex_separation(G, algorithm="exponential"); vs # needs sage.combinat + sage: vs,L = vertex_separation(G, algorithm="exponential"); vs 2 - sage: vs,L = vertex_separation(G, algorithm="MILP"); vs # needs sage.combinat sage.numerical.mip + sage: vs,L = vertex_separation(G, algorithm="MILP"); vs # needs sage.numerical.mip 2 + sage: G = graphs.Grid2dGraph(3,3) sage: vs,L = vertex_separation(G, algorithm="BAB"); vs 3 diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index 12e80870fc2..f1d53f31e95 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -1239,12 +1239,13 @@ def cospectral_graphs(self, vertices, matrix_function=lambda g: g.adjacency_matr There are two sets of cospectral graphs on six vertices with no isolated vertices:: - sage: g = graphs.cospectral_graphs(6, graphs=lambda x: min(x.degree())>0) # needs sage.modules - sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) # needs sage.modules + sage: # needs sage.modules + sage: g = graphs.cospectral_graphs(6, graphs=lambda x: min(x.degree())>0) + sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) [['Ep__', 'Er?G'], ['ExGg', 'ExoG']] - sage: g[0][1].am().charpoly()==g[0][1].am().charpoly() # needs sage.modules + sage: g[0][1].am().charpoly()==g[0][1].am().charpoly() True - sage: g[1][1].am().charpoly()==g[1][1].am().charpoly() # needs sage.modules + sage: g[1][1].am().charpoly()==g[1][1].am().charpoly() True There is one pair of cospectral trees on eight vertices:: @@ -1258,12 +1259,13 @@ def cospectral_graphs(self, vertices, matrix_function=lambda g: g.adjacency_matr There are two sets of cospectral graphs (with respect to the Laplacian matrix) on six vertices:: - sage: g = graphs.cospectral_graphs(6, matrix_function=lambda g: g.laplacian_matrix()) # needs sage.modules - sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) # needs sage.modules + sage: # needs sage.modules + sage: g = graphs.cospectral_graphs(6, matrix_function=lambda g: g.laplacian_matrix()) + sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) [['Edq_', 'ErcG'], ['Exoo', 'EzcG']] - sage: g[0][1].laplacian_matrix().charpoly()==g[0][1].laplacian_matrix().charpoly() # needs sage.modules + sage: g[0][1].laplacian_matrix().charpoly()==g[0][1].laplacian_matrix().charpoly() True - sage: g[1][1].laplacian_matrix().charpoly()==g[1][1].laplacian_matrix().charpoly() # needs sage.modules + sage: g[1][1].laplacian_matrix().charpoly()==g[1][1].laplacian_matrix().charpoly() True To find cospectral graphs with respect to the normalized @@ -1463,11 +1465,12 @@ def fullerenes(self, order, ipr=False): The unique fullerene graph on 20 vertices is isomorphic to the dodecahedron graph. :: - sage: gen = graphs.fullerenes(20) # optional buckygen - sage: g = next(gen) # optional buckygen - sage: g.is_isomorphic(graphs.DodecahedralGraph()) # optional buckygen + sage: # optional - buckygen + sage: gen = graphs.fullerenes(20) + sage: g = next(gen) + sage: g.is_isomorphic(graphs.DodecahedralGraph()) True - sage: g.get_embedding() # optional buckygen + sage: g.get_embedding() {1: [2, 3, 4], 2: [1, 5, 6], 3: [1, 7, 8], @@ -1488,7 +1491,7 @@ def fullerenes(self, order, ipr=False): 18: [12, 20, 13], 19: [14, 20, 15], 20: [17, 19, 18]} - sage: g.plot3d(layout='spring') # optional buckygen + sage: g.plot3d(layout='spring') Graphics3d Object """ # number of vertices should be positive @@ -1741,12 +1744,13 @@ def plantri_gen(self, options=""): (usually inside a loop). Or it can be used to create an entire list all at once if there is sufficient memory to contain it:: - sage: gen = graphs.plantri_gen("6") # optional plantri - sage: next(gen) # optional plantri + sage: # optional - plantri + sage: gen = graphs.plantri_gen("6") + sage: next(gen) Graph on 6 vertices - sage: next(gen) # optional plantri + sage: next(gen) Graph on 6 vertices - sage: next(gen) # optional plantri + sage: next(gen) Traceback (most recent call last): ... StopIteration @@ -1915,13 +1919,14 @@ def planar_graphs(self, order, minimum_degree=None, Specifying lower and upper bounds on the number of edges:: - sage: len(list(graphs.planar_graphs(4))) # optional plantri + sage: # optional - plantri + sage: len(list(graphs.planar_graphs(4))) 6 - sage: len(list(graphs.planar_graphs(4, minimum_edges=4))) # optional plantri + sage: len(list(graphs.planar_graphs(4, minimum_edges=4))) 4 - sage: len(list(graphs.planar_graphs(4, maximum_edges=4))) # optional plantri + sage: len(list(graphs.planar_graphs(4, maximum_edges=4))) 4 - sage: len(list(graphs.planar_graphs(4, minimum_edges=4, maximum_edges=4))) # optional plantri + sage: len(list(graphs.planar_graphs(4, minimum_edges=4, maximum_edges=4))) 2 Specifying the maximum size of a face:: @@ -1936,11 +1941,12 @@ def planar_graphs(self, order, minimum_degree=None, The number of edges in a planar graph is equal to the number of edges in its dual:: - sage: planar = list(graphs.planar_graphs(5,dual=True)) # optional -- plantri - sage: dual_planar = list(graphs.planar_graphs(5,dual=False)) # optional -- plantri - sage: planar_sizes = [g.size() for g in planar] # optional -- plantri - sage: dual_planar_sizes = [g.size() for g in dual_planar] # optional -- plantri - sage: planar_sizes == dual_planar_sizes # optional -- plantri + sage: # optional - plantri + sage: planar = list(graphs.planar_graphs(5,dual=True)) + sage: dual_planar = list(graphs.planar_graphs(5,dual=False)) + sage: planar_sizes = [g.size() for g in planar] + sage: dual_planar_sizes = [g.size() for g in dual_planar] + sage: planar_sizes == dual_planar_sizes True """ if order < 0: @@ -2262,11 +2268,12 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None The cube is the only 3-connected planar quadrangulation on 8 vertices:: - sage: gen = graphs.quadrangulations(8, minimum_connectivity=3) # optional plantri - sage: g = next(gen) # optional plantri - sage: g.is_isomorphic(graphs.CubeGraph(3)) # optional plantri + sage: # optional - plantri + sage: gen = graphs.quadrangulations(8, minimum_connectivity=3) + sage: g = next(gen) + sage: g.is_isomorphic(graphs.CubeGraph(3)) True - sage: next(gen) # optional plantri + sage: next(gen) Traceback (most recent call last): ... StopIteration diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index e46a2156809..193afc9c4eb 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -613,113 +613,121 @@ def from_networkx_graph(G, gnx, weighted=None, loops=None, multiedges=None, Feeding a :class:`Graph` with a NetworkX ``Graph``:: + sage: # needs networkx sage: from sage.graphs.graph_input import from_networkx_graph - sage: import networkx # needs networkx + sage: import networkx sage: G = Graph() - sage: _ = gnx = networkx.Graph() # needs networkx - sage: _ = gnx.add_edge(0, 1) # needs networkx - sage: _ = gnx.add_edge(1, 2) # needs networkx - sage: from_networkx_graph(G, gnx) # needs networkx - sage: G.edges(sort=True, labels=False) # needs networkx + sage: _ = gnx = networkx.Graph() + sage: _ = gnx.add_edge(0, 1) + sage: _ = gnx.add_edge(1, 2) + sage: from_networkx_graph(G, gnx) + sage: G.edges(sort=True, labels=False) [(0, 1), (1, 2)] Feeding a :class:`Graph` with a NetworkX ``MultiGraph``:: + sage: # needs networkx sage: G = Graph() - sage: gnx = networkx.MultiGraph() # needs networkx - sage: _ = gnx.add_edge(0, 1) # needs networkx - sage: _ = gnx.add_edge(0, 1) # needs networkx - sage: from_networkx_graph(G, gnx) # needs networkx - sage: G.edges(sort=True, labels=False) # needs networkx + sage: gnx = networkx.MultiGraph() + sage: _ = gnx.add_edge(0, 1) + sage: _ = gnx.add_edge(0, 1) + sage: from_networkx_graph(G, gnx) + sage: G.edges(sort=True, labels=False) [(0, 1), (0, 1)] sage: G = Graph() - sage: from_networkx_graph(G, gnx, multiedges=False) # needs networkx - sage: G.edges(sort=True, labels=False) # needs networkx + sage: from_networkx_graph(G, gnx, multiedges=False) + sage: G.edges(sort=True, labels=False) [(0, 1)] When feeding a :class:`Graph` `G` with a NetworkX ``DiGraph`` `D`, `G` has one edge `(u, v)` whenever `D` has arc `(u, v)` or `(v, u)` or both:: + sage: # needs networkx sage: G = Graph() - sage: D = networkx.DiGraph() # needs networkx - sage: _ = D.add_edge(0, 1) # needs networkx - sage: from_networkx_graph(G, D) # needs networkx - sage: G.edges(sort=True, labels=False) # needs networkx + sage: D = networkx.DiGraph() + sage: _ = D.add_edge(0, 1) + sage: from_networkx_graph(G, D) + sage: G.edges(sort=True, labels=False) [(0, 1)] sage: G = Graph() - sage: _ = D.add_edge(1, 0) # needs networkx - sage: from_networkx_graph(G, D) # needs networkx - sage: G.edges(sort=True, labels=False) # needs networkx + sage: _ = D.add_edge(1, 0) + sage: from_networkx_graph(G, D) + sage: G.edges(sort=True, labels=False) [(0, 1)] When feeding a :class:`Graph` `G` with a NetworkX ``MultiDiGraph`` `D`, the number of edges between `u` and `v` in `G` is the maximum between the number of arcs `(u, v)` and the number of arcs `(v, u)` in D`:: + sage: # needs networkx sage: G = Graph() - sage: D = networkx.MultiDiGraph() # needs networkx - sage: _ = D.add_edge(0, 1) # needs networkx - sage: _ = D.add_edge(1, 0) # needs networkx - sage: _ = D.add_edge(1, 0) # needs networkx - sage: D.edges() # needs networkx + sage: D = networkx.MultiDiGraph() + sage: _ = D.add_edge(0, 1) + sage: _ = D.add_edge(1, 0) + sage: _ = D.add_edge(1, 0) + sage: D.edges() OutMultiEdgeDataView([(0, 1), (1, 0), (1, 0)]) - sage: from_networkx_graph(G, D) # needs networkx - sage: G.edges(sort=True, labels=False) # needs networkx + sage: from_networkx_graph(G, D) + sage: G.edges(sort=True, labels=False) [(0, 1), (0, 1)] Feeding a :class:`DiGraph` with a NetworkX ``DiGraph``:: + sage: # needs networkx sage: from sage.graphs.graph_input import from_networkx_graph - sage: import networkx # needs networkx + sage: import networkx sage: G = DiGraph() - sage: _ = gnx = networkx.DiGraph() # needs networkx - sage: _ = gnx.add_edge(0, 1) # needs networkx - sage: _ = gnx.add_edge(1, 2) # needs networkx - sage: from_networkx_graph(G, gnx) # needs networkx - sage: G.edges(sort=True, labels=False) # needs networkx + sage: _ = gnx = networkx.DiGraph() + sage: _ = gnx.add_edge(0, 1) + sage: _ = gnx.add_edge(1, 2) + sage: from_networkx_graph(G, gnx) + sage: G.edges(sort=True, labels=False) [(0, 1), (1, 2)] Feeding a :class:`DiGraph` with a NetworkX ``MultiDiGraph``:: + sage: # needs networkx sage: G = DiGraph() - sage: gnx = networkx.MultiDiGraph() # needs networkx - sage: _ = gnx.add_edge(0, 1) # needs networkx - sage: _ = gnx.add_edge(0, 1) # needs networkx - sage: from_networkx_graph(G, gnx) # needs networkx - sage: G.edges(sort=True, labels=False) # needs networkx + sage: gnx = networkx.MultiDiGraph() + sage: _ = gnx.add_edge(0, 1) + sage: _ = gnx.add_edge(0, 1) + sage: from_networkx_graph(G, gnx) + sage: G.edges(sort=True, labels=False) [(0, 1), (0, 1)] sage: G = DiGraph() - sage: from_networkx_graph(G, gnx, multiedges=False) # needs networkx - sage: G.edges(sort=True, labels=False) # needs networkx + sage: from_networkx_graph(G, gnx, multiedges=False) + sage: G.edges(sort=True, labels=False) [(0, 1)] When feeding a :class:`DiGraph` `G` with a NetworkX ``Graph`` `H`, `G` has both arcs `(u, v)` and `(v, u)` if `G` has edge `(u, v)`:: + sage: # needs networkx sage: G = DiGraph() - sage: H = networkx.Graph() # needs networkx - sage: _ = H.add_edge(0, 1) # needs networkx - sage: from_networkx_graph(G, H) # needs networkx - sage: G.edges(labels=False, sort=True) # needs networkx + sage: H = networkx.Graph() + sage: _ = H.add_edge(0, 1) + sage: from_networkx_graph(G, H) + sage: G.edges(labels=False, sort=True) [(0, 1), (1, 0)] When feeding a :class:`DiGraph` `G` with a NetworkX ``MultiGraph`` `H`, `G` has `k` arcs `(u, v)` and `k` arcs `(v, u)` if `H` has `k` edges `(u, v)`, unless parameter ``multiedges`` is set to ``False``:: + sage: # needs networkx sage: G = DiGraph() - sage: H = networkx.MultiGraph() # needs networkx - sage: _ = H.add_edge(0, 1) # needs networkx - sage: _ = H.add_edge(0, 1) # needs networkx - sage: _ = H.add_edge(0, 1) # needs networkx - sage: H.edges() # needs networkx + sage: H = networkx.MultiGraph() + sage: _ = H.add_edge(0, 1) + sage: _ = H.add_edge(0, 1) + sage: _ = H.add_edge(0, 1) + sage: H.edges() MultiEdgeDataView([(0, 1), (0, 1), (0, 1)]) - sage: from_networkx_graph(G, H) # needs networkx - sage: G.edges(labels=False, sort=True) # needs networkx + sage: from_networkx_graph(G, H) + sage: G.edges(labels=False, sort=True) [(0, 1), (0, 1), (0, 1), (1, 0), (1, 0), (1, 0)] sage: G = DiGraph() - sage: from_networkx_graph(G, H, multiedges=False) # needs networkx - sage: G.edges(labels=False, sort=True) # needs networkx + sage: from_networkx_graph(G, H, multiedges=False) + sage: G.edges(labels=False, sort=True) [(0, 1), (1, 0)] TESTS: diff --git a/src/sage/graphs/graph_latex.py b/src/sage/graphs/graph_latex.py index 7988f6e3518..e495ca160a4 100644 --- a/src/sage/graphs/graph_latex.py +++ b/src/sage/graphs/graph_latex.py @@ -84,12 +84,12 @@ sage: H = graphs.HeawoodGraph() sage: H.set_latex_options( - ....: graphic_size=(5,5), - ....: vertex_size=0.2, - ....: edge_thickness=0.04, - ....: edge_color='green', - ....: vertex_color='green', - ....: vertex_label_color='red' + ....: graphic_size=(5,5), + ....: vertex_size=0.2, + ....: edge_thickness=0.04, + ....: edge_color='green', + ....: vertex_color='green', + ....: vertex_label_color='red' ....: ) At this point, ``view(H)`` should call ``pdflatex`` to process the string @@ -265,49 +265,50 @@ package. So it is worth viewing this in the notebook to see the effects of various defaults and choices.:: - sage: var('x y u w') # needs sage.symbolic + sage: # needs sage.symbolic + sage: var('x y u w') (x, y, u, w) sage: G = Graph(loops=True) - sage: for i in range(5): # needs sage.symbolic + sage: for i in range(5): ....: for j in range(i+1, 5): ....: G.add_edge((i, j), label=(x^i*y^j).expand()) - sage: G.add_edge((0,0), label=sin(u)) # needs sage.symbolic - sage: G.add_edge((4,4), label=w^5) # needs sage.symbolic + sage: G.add_edge((0,0), label=sin(u)) + sage: G.add_edge((4,4), label=w^5) sage: G.set_pos(G.layout_circular()) sage: G.set_latex_options( - ....: units='in', - ....: graphic_size=(8,8), - ....: margins=(1,2,2,1), - ....: scale=0.5, - ....: vertex_color='0.8', - ....: vertex_colors={1:'aqua', 3:'y', 4:'#0000FF'}, - ....: vertex_fill_color='blue', - ....: vertex_fill_colors={1:'green', 3:'b', 4:'#FF00FF'}, - ....: vertex_label_color='brown', - ....: vertex_label_colors={0:'g',1:'purple',2:'#007F00'}, - ....: vertex_shape='diamond', - ....: vertex_shapes={1:'rectangle', 2:'sphere', 3:'sphere', 4:'circle'}, - ....: vertex_size=0.3, - ....: vertex_sizes={0:1.0, 2:0.3, 4:1.0}, - ....: vertex_label_placements = {2:(0.6, 180), 4:(0,45)}, - ....: edge_color='purple', - ....: edge_colors={(0,2):'g',(3,4):'red'}, - ....: edge_fills=True, - ....: edge_fill_color='green', - ....: edge_label_colors={(2,3):'y',(0,4):'blue'}, - ....: edge_thickness=0.05, - ....: edge_thicknesses={(3,4):0.2, (0,4):0.02}, - ....: edge_labels=True, - ....: edge_label_sloped=True, - ....: edge_label_slopes={(0,3):False, (2,4):False}, - ....: edge_label_placement=0.50, - ....: edge_label_placements={(0,4):'above', (2,3):'left', (0,0):'above', (4,4):'below'}, - ....: loop_placement=(2.0, 'NO'), - ....: loop_placements={4:(8.0, 'EA')} + ....: units='in', + ....: graphic_size=(8,8), + ....: margins=(1,2,2,1), + ....: scale=0.5, + ....: vertex_color='0.8', + ....: vertex_colors={1:'aqua', 3:'y', 4:'#0000FF'}, + ....: vertex_fill_color='blue', + ....: vertex_fill_colors={1:'green', 3:'b', 4:'#FF00FF'}, + ....: vertex_label_color='brown', + ....: vertex_label_colors={0:'g',1:'purple',2:'#007F00'}, + ....: vertex_shape='diamond', + ....: vertex_shapes={1:'rectangle', 2:'sphere', 3:'sphere', 4:'circle'}, + ....: vertex_size=0.3, + ....: vertex_sizes={0:1.0, 2:0.3, 4:1.0}, + ....: vertex_label_placements = {2:(0.6, 180), 4:(0,45)}, + ....: edge_color='purple', + ....: edge_colors={(0,2):'g',(3,4):'red'}, + ....: edge_fills=True, + ....: edge_fill_color='green', + ....: edge_label_colors={(2,3):'y',(0,4):'blue'}, + ....: edge_thickness=0.05, + ....: edge_thicknesses={(3,4):0.2, (0,4):0.02}, + ....: edge_labels=True, + ....: edge_label_sloped=True, + ....: edge_label_slopes={(0,3):False, (2,4):False}, + ....: edge_label_placement=0.50, + ....: edge_label_placements={(0,4):'above', (2,3):'left', (0,0):'above', (4,4):'below'}, + ....: loop_placement=(2.0, 'NO'), + ....: loop_placements={4:(8.0, 'EA')} ....: ) sage: from sage.graphs.graph_latex import check_tkz_graph sage: check_tkz_graph() # random - depends on TeX installation - sage: print(latex(G)) # needs sage.symbolic + sage: print(latex(G)) \begin{tikzpicture} \definecolor{cv0}{rgb}{0.8,0.8,0.8} \definecolor{cfv0}{rgb}{0.0,0.0,1.0} diff --git a/src/sage/graphs/graph_plot_js.py b/src/sage/graphs/graph_plot_js.py index a29e7293df8..3bcabb58152 100644 --- a/src/sage/graphs/graph_plot_js.py +++ b/src/sage/graphs/graph_plot_js.py @@ -164,15 +164,15 @@ def gen_html_code(G, EXAMPLES:: - sage: graphs.RandomTree(50).show(method="js") # optional -- internet sage.plot + sage: graphs.RandomTree(50).show(method="js") # optional - internet, needs sage.plot sage: g = graphs.PetersenGraph() - sage: g.show(method="js", vertex_partition=g.coloring()) # optional -- internet sage.plot + sage: g.show(method="js", vertex_partition=g.coloring()) # optional - internet, needs sage.plot - sage: graphs.DodecahedralGraph().show(method="js", # optional -- internet sage.plot + sage: graphs.DodecahedralGraph().show(method="js", # optional - internet, needs sage.plot ....: force_spring_layout=True) - sage: graphs.DodecahedralGraph().show(method="js") # optional -- internet sage.plot + sage: graphs.DodecahedralGraph().show(method="js") # optional - internet, needs sage.plot sage: # needs sage.combinat sage: g = digraphs.DeBruijn(2, 2) @@ -182,7 +182,7 @@ def gen_html_code(G, sage: g.add_edge("10", "10", "c") sage: g.add_edge("10", "10", "d") sage: g.add_edge("01", "11", "1") - sage: g.show(method="js", vertex_labels=True, edge_labels=True, + sage: g.show(method="js", vertex_labels=True, edge_labels=True, # optional - internet, needs sage.plot ....: link_distance=200, gravity=.05, charge=-500, ....: edge_partition=[[("11", "12", "2"), ("21", "21", "a")]], ....: edge_thickness=4) diff --git a/src/sage/graphs/path_enumeration.pyx b/src/sage/graphs/path_enumeration.pyx index 50836ffdcb9..5709d2b87c4 100644 --- a/src/sage/graphs/path_enumeration.pyx +++ b/src/sage/graphs/path_enumeration.pyx @@ -346,41 +346,49 @@ def shortest_simple_paths(self, source, target, weight_function=None, EXAMPLES:: - sage: g = DiGraph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20), (3, 5, 10), (4, 5, 30)]) + sage: g = DiGraph([(1, 2, 20), (1, 3, 10), (1, 4, 30), + ....: (2, 5, 20), (3, 5, 10), (4, 5, 30)]) sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm="Yen")) [[1, 3, 5], [1, 2, 5], [1, 4, 5]] sage: list(g.shortest_simple_paths(1, 5, algorithm="Yen")) [[1, 2, 5], [1, 3, 5], [1, 4, 5]] sage: list(g.shortest_simple_paths(1, 1)) [[1]] - sage: list(g.shortest_simple_paths(1, 5, by_weight=True, report_edges=True, report_weight=True, labels=True)) + sage: list(g.shortest_simple_paths(1, 5, by_weight=True, + ....: report_edges=True, report_weight=True, labels=True)) [(20, [(1, 3, 10), (3, 5, 10)]), (40, [(1, 2, 20), (2, 5, 20)]), (60, [(1, 4, 30), (4, 5, 30)])] - sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm="Feng", report_edges=True, report_weight=True)) + sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm="Feng", + ....: report_edges=True, report_weight=True)) [(20, [(1, 3), (3, 5)]), (40, [(1, 2), (2, 5)]), (60, [(1, 4), (4, 5)])] sage: list(g.shortest_simple_paths(1, 5, report_edges=True, report_weight=True)) [(2, [(1, 4), (4, 5)]), (2, [(1, 3), (3, 5)]), (2, [(1, 2), (2, 5)])] sage: list(g.shortest_simple_paths(1, 5, by_weight=True, report_edges=True)) [[(1, 3), (3, 5)], [(1, 2), (2, 5)], [(1, 4), (4, 5)]] - sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm="Feng", report_edges=True, labels=True)) + sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm="Feng", + ....: report_edges=True, labels=True)) [[(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)], [(1, 4, 30), (4, 5, 30)]] - sage: g = Graph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20), (3, 5, 10), (4, 5, 30), (1, 6, 100), (5, 6, 5)]) + sage: g = Graph([(1, 2, 20), (1, 3, 10), (1, 4, 30), (2, 5, 20), + ....: (3, 5, 10), (4, 5, 30), (1, 6, 100), (5, 6, 5)]) sage: list(g.shortest_simple_paths(1, 6, by_weight = True)) [[1, 3, 5, 6], [1, 2, 5, 6], [1, 4, 5, 6], [1, 6]] sage: list(g.shortest_simple_paths(1, 6, algorithm="Yen")) [[1, 6], [1, 2, 5, 6], [1, 3, 5, 6], [1, 4, 5, 6]] - sage: list(g.shortest_simple_paths(1, 6, report_edges=True, report_weight=True, labels=True)) + sage: list(g.shortest_simple_paths(1, 6, + ....: report_edges=True, report_weight=True, labels=True)) [(1, [(1, 6, 100)]), (3, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]), (3, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]), (3, [(1, 4, 30), (4, 5, 30), (5, 6, 5)])] - sage: list(g.shortest_simple_paths(1, 6, report_edges=True, report_weight=True, labels=True, by_weight=True)) + sage: list(g.shortest_simple_paths(1, 6, by_weight=True, + ....: report_edges=True, report_weight=True, labels=True)) [(25, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]), (45, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]), (65, [(1, 4, 30), (4, 5, 30), (5, 6, 5)]), (100, [(1, 6, 100)])] - sage: list(g.shortest_simple_paths(1, 6, report_edges=True, labels=True, by_weight=True)) + sage: list(g.shortest_simple_paths(1, 6, by_weight=True, + ....: report_edges=True, labels=True)) [[(1, 3, 10), (3, 5, 10), (5, 6, 5)], [(1, 2, 20), (2, 5, 20), (5, 6, 5)], [(1, 4, 30), (4, 5, 30), (5, 6, 5)], @@ -432,6 +440,8 @@ def shortest_simple_paths(self, source, target, weight_function=None, [1, 2, 3, 4, 5], [1, 6, 9, 3, 4, 5], [1, 6, 9, 11, 10, 5]] + + sage: # needs sage.combinat sage: G = digraphs.DeBruijn(2, 3) # needs sage.combinat sage: for u,v in G.edges(sort=True, labels=False): # needs sage.combinat ....: G.set_edge_label(u, v, 1) @@ -470,6 +480,7 @@ def shortest_simple_paths(self, source, target, weight_function=None, Check for consistency of results of Yen's and Feng's:: + sage: # needs sage.combinat sage: G = digraphs.DeBruijn(2, 4) # needs sage.combinat sage: s = set() sage: for p in G.shortest_simple_paths('0000', '1111', by_weight=False, algorithm='Yen'): # needs sage.combinat diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 1c9e8699905..338d469e383 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -1428,19 +1428,20 @@ def is_GQqmqp(int v, int k, int l, int mu): TESTS:: + sage: # needs sage.libs.pari sage: (S,T) = (127,129) - sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t # needs sage.libs.pari + sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t (, 128, False) sage: (S,T) = (129,127) - sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t # needs sage.libs.pari + sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t (, 128, True) sage: (S,T) = (124,126) - sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t # needs sage.libs.pari + sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t (, 125, False) sage: (S,T) = (126,124) - sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t # needs sage.libs.pari + sage: t = is_GQqmqp((S+1)*(S*T+1), S*(T+1), S-1, T+1); t (, 125, True) - sage: t = is_GQqmqp(5,5,5,5); t # needs sage.libs.pari + sage: t = is_GQqmqp(5,5,5,5); t """ # do we have GQ(s,t)? we must have mu=t+1, s=l+1, # v=(s+1)(st+1), k=s(t+1) From abdcae83dd7aef72ba6f71ecfe82e3db05801b71 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 2 Aug 2023 17:54:16 -0700 Subject: [PATCH 79/87] sage.graphs: Use yet more block # needs --- .../graphs/generators/classical_geometries.py | 47 ++-- .../graphs/generators/distance_regular.pyx | 74 ++++--- src/sage/graphs/generators/families.py | 200 ++++++++++-------- src/sage/graphs/generators/intersection.py | 13 +- src/sage/graphs/generators/platonic_solids.py | 47 ++-- src/sage/graphs/generic_graph.py | 15 +- src/sage/graphs/path_enumeration.pyx | 22 +- 7 files changed, 224 insertions(+), 194 deletions(-) diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index 48481b3b240..ab928c67713 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -67,14 +67,8 @@ def SymplecticPolarGraph(d, q, algorithm=None): (40, 12, 2, 4) sage: O.is_isomorphic(G) False - sage: O.is_isomorphic(G) # optional - GOT (with --distribution 'sagemath-graphs[modules]') - Traceback (most recent call last): - ... - File "", line 1, in - O.is_isomorphic(G) - AttributeError: 'function' object has no attribute 'is_isomorphic' - sage: S = graphs.SymplecticPolarGraph(6,4,algorithm="gap") # not tested (long time), needs sage.libs.gap - sage: S.is_strongly_regular(parameters=True) # not tested (long time) # needs sage.libs.gap + sage: S = graphs.SymplecticPolarGraph(6, 4, algorithm="gap") # not tested (long time) + sage: S.is_strongly_regular(parameters=True) # not tested (long time) (1365, 340, 83, 85) TESTS:: @@ -273,7 +267,7 @@ def _orthogonal_polar_graph(m, q, sign="+", point_type=[0]): `NO^{-,\perp}(5,5)`:: sage: g = _orthogonal_polar_graph(5,5,point_type=[2,3]) # long time, needs sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # long time # needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) # long time, needs sage.libs.gap (300, 65, 10, 15) `NO^{+,\perp}(5,5)`:: @@ -487,19 +481,22 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): NO^-,perp(3, 5): Graph on 10 vertices sage: g.is_strongly_regular(parameters=True) (10, 3, 0, 1) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'+') # long time, needs sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # long time # needs sage.libs.gap + + sage: # long time, needs sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'+') + sage: g.is_strongly_regular(parameters=True) (117, 36, 15, 9) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'-'); g # long time + sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,3,'-'); g NO^-(6, 3): Graph on 126 vertices - sage: g.is_strongly_regular(parameters=True) # long time # needs sage.libs.gap + sage: g.is_strongly_regular(parameters=True) (126, 45, 12, 18) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'-') # long time, needs sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # long time # needs sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'-') + sage: g.is_strongly_regular(parameters=True) (300, 104, 28, 40) - sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'+') # long time, needs sage.libs.gap - sage: g.is_strongly_regular(parameters=True) # long time # needs sage.libs.gap + sage: g = graphs.NonisotropicOrthogonalPolarGraph(5,5,'+') + sage: g.is_strongly_regular(parameters=True) (325, 144, 68, 60) + sage: g = graphs.NonisotropicOrthogonalPolarGraph(6,4,'+') Traceback (most recent call last): ... @@ -871,11 +868,11 @@ def TaylorTwographDescendantSRG(q, clique_partition=False): sage: g.is_strongly_regular(parameters=True) (27, 10, 1, 5) sage: from sage.combinat.designs.twographs import taylor_twograph - sage: T = taylor_twograph(3) # long time # needs sage.rings.finite_rings - sage: g.is_isomorphic(T.descendant(T.ground_set()[1])) # long time # needs sage.rings.finite_rings + sage: T = taylor_twograph(3) # long time + sage: g.is_isomorphic(T.descendant(T.ground_set()[1])) # long time True - sage: g = graphs.TaylorTwographDescendantSRG(5) # not tested (long time) - sage: g.is_strongly_regular(parameters=True) # not tested (long time) + sage: g = graphs.TaylorTwographDescendantSRG(5) # not tested (long time) + sage: g.is_strongly_regular(parameters=True) # not tested (long time) (125, 52, 15, 26) TESTS:: @@ -1198,7 +1195,7 @@ def HaemersGraph(q, hyperoval=None, hyperoval_matching=None, field=None, check_h ... RuntimeError: incorrect hyperoval - sage: g = graphs.HaemersGraph(8); g # not tested (long time) # needs sage.rings.finite_rings + sage: g = graphs.HaemersGraph(8); g # not tested (long time) # needs sage.rings.finite_rings Haemers(8): Graph on 640 vertices sage: g.is_strongly_regular(parameters=True) # not tested (long time) # needs sage.rings.finite_rings (640, 71, 6, 8) @@ -1498,9 +1495,9 @@ def OrthogonalDualPolarGraph(e, d, q): sage: G.is_distance_regular(True) ([7, 6, 4, None], [None, 1, 3, 7]) sage: G = graphs.OrthogonalDualPolarGraph(0,3,3) # long time - sage: G.is_distance_regular(True) # long time + sage: G.is_distance_regular(True) # long time ([39, 36, 27, None], [None, 1, 4, 13]) - sage: G.order() # long time + sage: G.order() # long time 1120 REFERENCES: @@ -1514,7 +1511,7 @@ def OrthogonalDualPolarGraph(e, d, q): sage: G.is_distance_regular(True) ([14, 12, 8, None], [None, 1, 3, 7]) sage: G = graphs.OrthogonalDualPolarGraph(-1,3,2) # long time - sage: G.is_distance_regular(True) # long time + sage: G.is_distance_regular(True) # long time ([28, 24, 16, None], [None, 1, 3, 7]) sage: G = graphs.OrthogonalDualPolarGraph(1,3,4) sage: G.is_distance_regular(True) diff --git a/src/sage/graphs/generators/distance_regular.pyx b/src/sage/graphs/generators/distance_regular.pyx index edcb9ad4cfa..15bd3594185 100644 --- a/src/sage/graphs/generators/distance_regular.pyx +++ b/src/sage/graphs/generators/distance_regular.pyx @@ -1418,15 +1418,16 @@ def GeneralisedOctagonGraph(const int s, const int t): EXAMPLES:: - sage: G = graphs.GeneralisedOctagonGraph(1, 4) # needs sage.libs.gap - sage: G.is_distance_regular(True) # needs sage.libs.gap - ([5, 4, 4, 4, None], [None, 1, 1, 1, 5]) - sage: G = graphs.GeneralisedOctagonGraph(2, 4) # optional - gap_packages internet - sage: G.is_distance_regular(True) # optional - gap_packages internet - ([10, 8, 8, 8, None], [None, 1, 1, 1, 5]) - sage: G = graphs.GeneralisedOctagonGraph(5, 1) # needs sage.libs.gap - sage: G.is_distance_regular(True) # needs sage.libs.gap - ([10, 5, 5, 5, None], [None, 1, 1, 1, 2]) + sage: # needs sage.libs.gap + sage: G = graphs.GeneralisedOctagonGraph(1, 4) + sage: G.is_distance_regular(True) + ([5, 4, 4, 4, None], [None, 1, 1, 1, 5]) + sage: G = graphs.GeneralisedOctagonGraph(2, 4) # optional - gap_packages internet + sage: G.is_distance_regular(True) # optional - gap_packages internet + ([10, 8, 8, 8, None], [None, 1, 1, 1, 5]) + sage: G = graphs.GeneralisedOctagonGraph(5, 1) + sage: G.is_distance_regular(True) + ([10, 5, 5, 5, None], [None, 1, 1, 1, 2]) .. NOTE:: @@ -1528,13 +1529,14 @@ def GeneralisedHexagonGraph(const int s, const int t): EXAMPLES:: + sage: # needs sage.libs.gap sage: G = graphs.GeneralisedHexagonGraph(5, 5) # optional - gap_packages internet sage: G.is_distance_regular(True) # optional - gap_packages internet ([30, 25, 25, None], [None, 1, 1, 6]) - sage: G = graphs.GeneralisedHexagonGraph(7, 1) # needs sage.libs.gap - sage: G.is_distance_regular(True) # needs sage.libs.gap + sage: G = graphs.GeneralisedHexagonGraph(7, 1) + sage: G.is_distance_regular(True) ([14, 7, 7, None], [None, 1, 1, 2]) - sage: graphs.GeneralisedHexagonGraph(1, 1) # needs sage.libs.gap + sage: graphs.GeneralisedHexagonGraph(1, 1) Cycle graph: Graph on 6 vertices .. NOTE:: @@ -1752,16 +1754,17 @@ def _line_graph_generalised_polygon(H): EXAMPLES:: - sage: from sage.graphs.generators.distance_regular import \ - ....: _line_graph_generalised_polygon - sage: G = graphs.GeneralisedHexagonGraph(1, 8) # needs sage.libs.gap - sage: H = _line_graph_generalised_polygon(G) # needs sage.libs.gap - sage: H.is_distance_regular(True) # needs sage.libs.gap - ([16, 8, 8, None], [None, 1, 1, 2]) - sage: G = graphs.GeneralisedHexagonGraph(3, 3) # optional - gap_packages internet - sage: H = _line_graph_generalised_polygon(G) # optional - gap_packages internet - sage: G.is_isomorphic(H) # optional - gap_packages internet - True + sage: # needs sage.libs.gap + sage: from sage.graphs.generators.distance_regular import \ + ....: _line_graph_generalised_polygon + sage: G = graphs.GeneralisedHexagonGraph(1, 8) + sage: H = _line_graph_generalised_polygon(G) + sage: H.is_distance_regular(True) + ([16, 8, 8, None], [None, 1, 1, 2]) + sage: G = graphs.GeneralisedHexagonGraph(3, 3) # optional - gap_packages internet + sage: H = _line_graph_generalised_polygon(G) # optional - gap_packages internet + sage: G.is_isomorphic(H) # optional - gap_packages internet + True REFERENCES: @@ -2416,19 +2419,20 @@ def is_near_polygon(array): TESTS:: + sage: # needs sage.combinat sage.libs.pari sage: from sage.graphs.generators.distance_regular import ( ....: is_near_polygon, near_polygon_graph) - sage: is_near_polygon([7, 6, 6, 4, 4, 1, 1, 3, 3, 7]) # needs sage.combinat sage.libs.pari + sage: is_near_polygon([7, 6, 6, 4, 4, 1, 1, 3, 3, 7]) (4, (2, 2)) sage: near_polygon_graph(4, (2, 2)) Double Grassmann graph (5, 2, 2): Graph on 310 vertices - sage: near_polygon_graph(*is_near_polygon([3, 2, 2, 1, 1, 3])) # needs sage.combinat sage.rings.finite_rings + sage: near_polygon_graph(*is_near_polygon([3, 2, 2, 1, 1, 3])) # needs sage.rings.finite_rings Generalised hexagon of order (1, 2): Graph on 14 vertices - sage: is_near_polygon([16, 12, 8, 4, 1, 2, 3, 4]) # needs sage.combinat sage.libs.pari + sage: is_near_polygon([16, 12, 8, 4, 1, 2, 3, 4]) (6, (4, 5)) - sage: is_near_polygon([]) # needs sage.combinat sage.libs.pari + sage: is_near_polygon([]) False - sage: is_near_polygon([25, 16, 9, 4, 1, 1, 4, 9, 16, 25]) # JohnsonGraph # needs sage.combinat sage.libs.pari + sage: is_near_polygon([25, 16, 9, 4, 1, 1, 4, 9, 16, 25]) # JohnsonGraph False """ from sage.arith.misc import is_prime_power @@ -2719,21 +2723,23 @@ def distance_regular_graph(list arr, existence=False, check=True): TESTS:: sage: graphs.distance_regular_graph([3, 2, 2, 1, 1, 1, 1, 2, 2, 3], # needs sage.combinat - ....: existence=True) + ....: existence=True) True sage: graphs.distance_regular_graph([3, 2, 2, 1, 2, 1, 1, 2, 2, 3], - ....: existence=True) + ....: existence=True) False sage: graphs.distance_regular_graph([18, 16, 16, 1, 1, 9]) # optional - internet gap_packages Generalised hexagon of order (2, 8): Graph on 819 vertices - sage: graphs.distance_regular_graph([14, 12, 10, 8, 6, 4, 2, # needs sage.combinat - ....: 1, 2, 3, 4, 5, 6, 7]) + + sage: # needs sage.combinat + sage: graphs.distance_regular_graph([14, 12, 10, 8, 6, 4, 2, + ....: 1, 2, 3, 4, 5, 6, 7]) Hamming Graph with parameters 7,3: Graph on 2187 vertices - sage: graphs.distance_regular_graph([66, 45, 28, 1, 6, 30]) # needs sage.combinat + sage: graphs.distance_regular_graph([66, 45, 28, 1, 6, 30]) Graph on 1024 vertices - sage: graphs.distance_regular_graph([6,5,5,5,1,1,1,6]) # needs sage.combinat + sage: graphs.distance_regular_graph([6,5,5,5,1,1,1,6]) Generalised octagon of order (1, 5): Graph on 312 vertices - sage: graphs.distance_regular_graph([64, 60, 1, 1, 15, 64], check=True) # needs sage.combinat + sage: graphs.distance_regular_graph([64, 60, 1, 1, 15, 64], check=True) Graph on 325 vertices """ from sage.misc.unknown import Unknown diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index dba8ec3d5c9..3ef2c3a5556 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -544,16 +544,17 @@ def BalancedTree(r, h): A tree is bipartite. If its vertex set is finite, then it is planar. :: + sage: # needs networkx sage: r = randint(2, 5); h = randint(1, 7) - sage: T = graphs.BalancedTree(r, h) # needs networkx - sage: T.is_bipartite() # needs networkx + sage: T = graphs.BalancedTree(r, h) + sage: T.is_bipartite() True - sage: T.is_planar() # needs networkx + sage: T.is_planar() True - sage: v = (r^(h + 1) - 1) / (r - 1) # needs networkx - sage: T.order() == v # needs networkx + sage: v = (r^(h + 1) - 1) / (r - 1) + sage: T.order() == v True - sage: T.size() == v - 1 # needs networkx + sage: T.size() == v - 1 True TESTS: @@ -627,11 +628,13 @@ def BarbellGraph(n1, n2): True sage: K_n1 = graphs.CompleteGraph(n1) sage: P_n2 = graphs.PathGraph(n2) - sage: s_K = g.subgraph_search(K_n1, induced=True) # needs sage.modules - sage: s_P = g.subgraph_search(P_n2, induced=True) # needs sage.modules - sage: K_n1.is_isomorphic(s_K) # needs sage.modules + + sage: # needs sage.modules + sage: s_K = g.subgraph_search(K_n1, induced=True) + sage: s_P = g.subgraph_search(P_n2, induced=True) + sage: K_n1.is_isomorphic(s_K) True - sage: P_n2.is_isomorphic(s_P) # needs sage.modules + sage: P_n2.is_isomorphic(s_P) True TESTS:: @@ -1076,51 +1079,54 @@ def CirculantGraph(n, adjacency): EXAMPLES: Compare plotting using the predefined layout and networkx:: - sage: import networkx # needs networkx - sage: n = networkx.cycle_graph(23) # needs networkx - sage: spring23 = Graph(n) # needs networkx + sage: # needs networkx + sage: import networkx + sage: n = networkx.cycle_graph(23) + sage: spring23 = Graph(n) sage: posdict23 = graphs.CirculantGraph(23,2) - sage: spring23.show() # long time # needs networkx + sage: spring23.show() # long time sage: posdict23.show() # long time We next view many cycle graphs as a Sage graphics array. First we use the ``CirculantGraph`` constructor, which fills in the position dictionary:: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.CirculantGraph(i+4, i+1) ....: g.append(k) - sage: for i in range(3): # needs sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # needs sage.plot - sage: G.show() # long time # needs sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time Compare to plotting with the spring-layout algorithm:: + sage: # needs networkx sage.plot sage: g = [] sage: j = [] - sage: for i in range(9): # needs networkx + sage: for i in range(9): ....: spr = networkx.cycle_graph(i+3) ....: k = Graph(spr) ....: g.append(k) - sage: for i in range(3): # needs networkx sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # needs networkx sage.plot - sage: G.show() # long time # needs networkx sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time Passing a 1 into adjacency should give the cycle. :: - sage: graphs.CirculantGraph(6,1)==graphs.CycleGraph(6) + sage: graphs.CirculantGraph(6,1) == graphs.CycleGraph(6) True sage: graphs.CirculantGraph(7,[1,3]).edges(sort=True, labels=false) [(0, 1), @@ -1187,20 +1193,21 @@ def CubeGraph(n, embedding=1): Plot several `n`-cubes in a Sage Graphics Array:: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(6): ....: k = graphs.CubeGraph(i+1) ....: g.append(k) ... - sage: for i in range(2): # needs sage.plot + sage: for i in range(2): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) ... - sage: G = graphics_array(j) # needs sage.plot - sage: G.show(figsize=[6,4]) # long time # needs sage.plot + sage: G = graphics_array(j) + sage: G.show(figsize=[6,4]) # long time Use the plot options to display larger `n`-cubes:: @@ -1438,17 +1445,18 @@ def FriendshipGraph(n): The first few friendship graphs. :: + sage: # needs sage.plot sage: A = []; B = [] sage: for i in range(9): ....: g = graphs.FriendshipGraph(i + 1) ....: A.append(g) - sage: for i in range(3): # needs sage.plot + sage: for i in range(3): ....: n = [] ....: for j in range(3): ....: n.append(A[3*i + j].plot(vertex_size=20, vertex_labels=False)) ....: B.append(n) - sage: G = graphics_array(B) # needs sage.plot - sage: G.show() # long time # needs sage.plot + sage: G = graphics_array(B) + sage: G.show() # long time For `n = 1`, the friendship graph `F_1` is isomorphic to the cycle graph `C_3`, whose visual representation is a triangle. :: @@ -2225,13 +2233,14 @@ def LCFGraph(n, shift_list, repeats): The largest cubic nonplanar graph of diameter three:: - sage: G = graphs.LCFGraph(20, [-10,-7,-5,4,7,-10,-7,-4,5,7, # needs networkx + sage: # needs networkx + sage: G = graphs.LCFGraph(20, [-10,-7,-5,4,7,-10,-7,-4,5,7, ....: -10,-7,6,-5,7,-10,-7,5,-6,7], 1) - sage: G.degree() # needs networkx + sage: G.degree() [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] - sage: G.diameter() # needs networkx + sage: G.diameter() 3 - sage: G.show() # long time # needs networkx sage.plot + sage: G.show() # long time # needs sage.plot PLOTTING: LCF Graphs are plotted as an n-cycle with edges in the middle, as described above. @@ -2630,14 +2639,15 @@ def SquaredSkewHadamardMatrixGraph(n): EXAMPLES:: - sage: G = graphs.SquaredSkewHadamardMatrixGraph(4) # needs sage.modules - sage: G.is_strongly_regular(parameters=True) # needs sage.modules + sage: # needs sage.modules + sage: G = graphs.SquaredSkewHadamardMatrixGraph(4) + sage: G.is_strongly_regular(parameters=True) (225, 112, 55, 56) - sage: G = graphs.SquaredSkewHadamardMatrixGraph(5) # needs sage.modules - sage: G.is_strongly_regular(parameters=True) # long time # needs sage.modules + sage: G = graphs.SquaredSkewHadamardMatrixGraph(5) + sage: G.is_strongly_regular(parameters=True) # long time (361, 180, 89, 90) - sage: G = graphs.SquaredSkewHadamardMatrixGraph(9) # needs sage.modules - sage: G.is_strongly_regular(parameters=True) # not tested # needs sage.modules + sage: G = graphs.SquaredSkewHadamardMatrixGraph(9) + sage: G.is_strongly_regular(parameters=True) # not tested (1225, 612, 305, 306) TESTS:: @@ -3187,13 +3197,14 @@ def SierpinskiGasketGraph(n): EXAMPLES:: - sage: s4 = graphs.SierpinskiGasketGraph(4); s4 # needs sage.modules + sage: # needs sage.modules + sage: s4 = graphs.SierpinskiGasketGraph(4); s4 Graph on 42 vertices - sage: s4.size() # needs sage.modules + sage: s4.size() 81 - sage: s4.degree_histogram() # needs sage.modules + sage: s4.degree_histogram() [0, 0, 3, 0, 39] - sage: s4.is_hamiltonian() # needs sage.modules + sage: s4.is_hamiltonian() True REFERENCES: @@ -3284,20 +3295,21 @@ def GeneralizedSierpinskiGraph(G, k, stretch=None): The generalized Sierpinski graph of dimension `k` of any graph `G` with `n` vertices and `m` edges has `n^k` vertices and `m\sum_{i=0}^{k-1}n^i` edges:: + sage: # needs sage.modules sage: n = randint(2, 6) sage: k = randint(1, 5) sage: G = graphs.RandomGNP(n, .5) sage: m = G.size() - sage: S = graphs.GeneralizedSierpinskiGraph(G, k) # needs sage.modules - sage: S.order() == n**k # needs sage.modules + sage: S = graphs.GeneralizedSierpinskiGraph(G, k) + sage: S.order() == n**k True - sage: S.size() == m*sum([n**i for i in range(k)]) # needs sage.modules + sage: S.size() == m*sum([n**i for i in range(k)]) True sage: G = graphs.CompleteGraph(n) - sage: S = graphs.GeneralizedSierpinskiGraph(G, k) # needs sage.modules - sage: S.order() == n**k # needs sage.modules + sage: S = graphs.GeneralizedSierpinskiGraph(G, k) + sage: S.order() == n**k True - sage: S.size() == (n*(n - 1)/2)*sum([n**i for i in range(k)]) # needs sage.modules + sage: S.size() == (n*(n - 1)/2)*sum([n**i for i in range(k)]) True The positions of the vertices of the output graph are determined from the @@ -3322,18 +3334,19 @@ def GeneralizedSierpinskiGraph(G, k, stretch=None): TESTS:: - sage: graphs.GeneralizedSierpinskiGraph(Graph(), 3) # needs sage.modules + sage: # needs sage.modules + sage: graphs.GeneralizedSierpinskiGraph(Graph(), 3) Generalized Sierpinski Graph of Graph on 0 vertices of dimension 3: Graph on 0 vertices - sage: graphs.GeneralizedSierpinskiGraph(Graph(1), 3).vertices(sort=False) # needs sage.modules + sage: graphs.GeneralizedSierpinskiGraph(Graph(1), 3).vertices(sort=False) [(0, 0, 0)] - sage: G = graphs.GeneralizedSierpinskiGraph(Graph(2), 3) # needs sage.modules - sage: G.order(), G.size() # needs sage.modules + sage: G = graphs.GeneralizedSierpinskiGraph(Graph(2), 3) + sage: G.order(), G.size() (8, 0) - sage: graphs.GeneralizedSierpinskiGraph("foo", 1) # needs sage.modules + sage: graphs.GeneralizedSierpinskiGraph("foo", 1) Traceback (most recent call last): ... ValueError: parameter G must be a Graph - sage: graphs.GeneralizedSierpinskiGraph(Graph(), 0) # needs sage.modules + sage: graphs.GeneralizedSierpinskiGraph(Graph(), 0) Traceback (most recent call last): ... ValueError: parameter k must be >= 1 @@ -3401,46 +3414,49 @@ def WheelGraph(n): We view many wheel graphs with a Sage Graphics Array, first with this constructor (i.e., the position dictionary filled):: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.WheelGraph(i+3) ....: g.append(k) ... - sage: for i in range(3): # needs sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) ... - sage: G = graphics_array(j) # needs sage.plot - sage: G.show() # long time # needs sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time Next, using the spring-layout algorithm:: - sage: import networkx # needs networkx + sage: # needs networkx sage.plot + sage: import networkx sage: g = [] sage: j = [] - sage: for i in range(9): # needs networkx + sage: for i in range(9): ....: spr = networkx.wheel_graph(i+3) ....: k = Graph(spr) ....: g.append(k) ... - sage: for i in range(3): # needs networkx sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) ... - sage: G = graphics_array(j) # needs networkx sage.plot - sage: G.show() # long time # needs networkx sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time Compare the plotting:: - sage: n = networkx.wheel_graph(23) # needs networkx - sage: spring23 = Graph(n) # needs networkx + sage: # needs networkx sage.plot + sage: n = networkx.wheel_graph(23) + sage: spring23 = Graph(n) sage: posdict23 = graphs.WheelGraph(23) - sage: spring23.show() # long time # needs networkx + sage: spring23.show() # long time sage: posdict23.show() # long time """ from sage.graphs.generators.basic import CycleGraph @@ -3744,10 +3760,11 @@ def RingedTree(k, vertex_labels=True): EXAMPLES:: - sage: G = graphs.RingedTree(5) # needs networkx - sage: P = G.plot(vertex_labels=False, vertex_size=10) # needs networkx sage.plot - sage: P.show() # long time # needs networkx sage.plot - sage: G.vertices(sort=True) # needs networkx + sage: # needs networkx + sage: G = graphs.RingedTree(5) + sage: P = G.plot(vertex_labels=False, vertex_size=10) # needs sage.plot + sage: P.show() # long time # needs sage.plot + sage: G.vertices(sort=True) ['', '0', '00', '000', '0000', '0001', '001', '0010', '0011', '01', '010', '0100', '0101', '011', '0110', '0111', '1', '10', '100', '1000', '1001', '101', '1010', '1011', '11', '110', '1100', '1101', @@ -3900,15 +3917,16 @@ def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None): Supplying ``G`` and ``L`` (constructed from the automorphism group of ``G``). :: - sage: G = graphs.PaleyGraph(9) # needs sage.rings.finite_rings - sage: a = G.automorphism_group(partition=[sorted(G)]) # needs sage.groups sage.rings.finite_rings - sage: it = (x for x in a.normal_subgroups() if x.order() == 9) # needs sage.groups sage.rings.finite_rings - sage: subg = next(iter(it)) # needs sage.groups sage.rings.finite_rings - sage: r = [matrix(libgap.PermutationMat(libgap(z), 9).sage()) # needs sage.groups sage.libs.gap sage.rings.finite_rings + sage: # needs sage.groups sage.libs.gap sage.rings.finite_rings + sage: G = graphs.PaleyGraph(9) + sage: a = G.automorphism_group(partition=[sorted(G)]) + sage: it = (x for x in a.normal_subgroups() if x.order() == 9) + sage: subg = next(iter(it)) + sage: r = [matrix(libgap.PermutationMat(libgap(z), 9).sage()) ....: for z in subg] - sage: ff = list(map(lambda y: (y[0]-1,y[1]-1), # needs sage.groups sage.libs.gap sage.rings.finite_rings + sage: ff = list(map(lambda y: (y[0]-1,y[1]-1), ....: Permutation(map(lambda x: 1+r.index(x^-1), r)).cycle_tuples()[1:])) - sage: L = sum(i*(r[a]-r[b]) for i,(a,b) in zip(range(1,len(ff)+1), ff)); L # needs sage.groups sage.libs.gap sage.rings.finite_rings + sage: L = sum(i*(r[a]-r[b]) for i,(a,b) in zip(range(1,len(ff)+1), ff)); L [ 0 1 -1 -3 -2 -4 3 4 2] [-1 0 1 -4 -3 -2 2 3 4] [ 1 -1 0 -2 -4 -3 4 2 3] @@ -3919,16 +3937,17 @@ def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None): [-4 -3 -2 2 3 4 -1 0 1] [-2 -4 -3 4 2 3 1 -1 0] - sage: G.relabel(range(9)) # needs sage.rings.finite_rings - sage: G3x3 = graphs.MathonPseudocyclicStronglyRegularGraph(2, G=G, L=L) # needs sage.modules sage.rings.finite_rings - sage: G3x3.is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings + sage: # needs sage.modules sage.rings.finite_rings + sage: G.relabel(range(9)) + sage: G3x3 = graphs.MathonPseudocyclicStronglyRegularGraph(2, G=G, L=L) # needs sage.groups sage.libs.gap + sage: G3x3.is_strongly_regular(parameters=True) (441, 220, 109, 110) - sage: G3x3.automorphism_group(algorithm="bliss").order() # optional - bliss, needs sage.modules sage.rings.finite_rings + sage: G3x3.automorphism_group(algorithm="bliss").order() # optional - bliss 27 - sage: G9 = graphs.MathonPseudocyclicStronglyRegularGraph(2) # needs sage.modules sage.rings.finite_rings - sage: G9.is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings + sage: G9 = graphs.MathonPseudocyclicStronglyRegularGraph(2) + sage: G9.is_strongly_regular(parameters=True) (441, 220, 109, 110) - sage: G9.automorphism_group(algorithm="bliss").order() # optional - bliss, needs sage.modules sage.rings.finite_rings + sage: G9.automorphism_group(algorithm="bliss").order() # optional - bliss 9 TESTS:: @@ -4137,27 +4156,28 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False): TESTS:: - sage: graphs.MuzychukS6Graph(2,2,Phi='random',Sigma='random').is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings + sage: # needs sage.modules + sage: graphs.MuzychukS6Graph(2,2,Phi='random',Sigma='random').is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (16, 5, 0, 2) - sage: graphs.MuzychukS6Graph(3,3,Phi='random',Sigma='random').is_strongly_regular(parameters=True) # needs sage.modules sage.rings.finite_rings + sage: graphs.MuzychukS6Graph(3,3,Phi='random',Sigma='random').is_strongly_regular(parameters=True) # needs sage.rings.finite_rings (378, 116, 34, 36) - sage: graphs.MuzychukS6Graph(3,2) # needs sage.modules + sage: graphs.MuzychukS6Graph(3,2) Traceback (most recent call last): ... AssertionError: n must be even or d must be odd - sage: graphs.MuzychukS6Graph(6,2) # needs sage.modules + sage: graphs.MuzychukS6Graph(6,2) Traceback (most recent call last): ... AssertionError: n must be a prime power - sage: graphs.MuzychukS6Graph(3,1) # needs sage.modules + sage: graphs.MuzychukS6Graph(3,1) Traceback (most recent call last): ... AssertionError: d must be at least 2 - sage: graphs.MuzychukS6Graph(3,3,Phi=42) # needs sage.modules sage.rings.finite_rings + sage: graphs.MuzychukS6Graph(3,3,Phi=42) # needs sage.rings.finite_rings Traceback (most recent call last): ... AssertionError: Phi must be a dictionary or 'random' or 'fixed' - sage: graphs.MuzychukS6Graph(3,3,Sigma=42) # needs sage.modules sage.rings.finite_rings + sage: graphs.MuzychukS6Graph(3,3,Sigma=42) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: Sigma must be 'random' or 'fixed' diff --git a/src/sage/graphs/generators/intersection.py b/src/sage/graphs/generators/intersection.py index 06368795029..0de3715e0e1 100644 --- a/src/sage/graphs/generators/intersection.py +++ b/src/sage/graphs/generators/intersection.py @@ -429,14 +429,15 @@ def OrthogonalArrayBlockGraph(k, n, OA=None): Two graphs built from different orthogonal arrays are also different:: + sage: # needs sage.modules sage: k = 4; n = 10 - sage: OAa = designs.orthogonal_arrays.build(k,n) # needs sage.modules - sage: OAb = [[(x+1)%n for x in R] for R in OAa] # needs sage.modules - sage: set(map(tuple,OAa)) == set(map(tuple,OAb)) # needs sage.modules + sage: OAa = designs.orthogonal_arrays.build(k,n) + sage: OAb = [[(x+1)%n for x in R] for R in OAa] + sage: set(map(tuple,OAa)) == set(map(tuple,OAb)) False - sage: Ga = graphs.OrthogonalArrayBlockGraph(k, n, OAa) # needs sage.modules - sage: Gb = graphs.OrthogonalArrayBlockGraph(k, n, OAb) # needs sage.modules - sage: Ga == Gb # needs sage.modules + sage: Ga = graphs.OrthogonalArrayBlockGraph(k, n, OAa) + sage: Gb = graphs.OrthogonalArrayBlockGraph(k, n, OAb) + sage: Ga == Gb False As ``OAb`` was obtained from ``OAa`` by a relabelling the two graphs are diff --git a/src/sage/graphs/generators/platonic_solids.py b/src/sage/graphs/generators/platonic_solids.py index b0f97da83fa..38e070a054a 100644 --- a/src/sage/graphs/generators/platonic_solids.py +++ b/src/sage/graphs/generators/platonic_solids.py @@ -39,7 +39,7 @@ def TetrahedralGraph(): Construct and show a Tetrahedral graph:: sage: g = graphs.TetrahedralGraph() - sage: g.show() # long time + sage: g.show() # long time # needs sage.plot The following example requires networkx:: @@ -48,19 +48,20 @@ def TetrahedralGraph(): Compare this Tetrahedral, Wheel(4), Complete(4), and the Tetrahedral plotted with the spring-layout algorithm below in a Sage graphics array:: + sage: # needs networkx sage.plot sage: tetra_pos = graphs.TetrahedralGraph() - sage: tetra_spring = Graph(NX.tetrahedral_graph()) # needs networkx + sage: tetra_spring = Graph(NX.tetrahedral_graph()) sage: wheel = graphs.WheelGraph(4) sage: complete = graphs.CompleteGraph(4) - sage: g = [tetra_pos, tetra_spring, wheel, complete] # needs networkx + sage: g = [tetra_pos, tetra_spring, wheel, complete] sage: j = [] - sage: for i in range(2): # needs networkx sage.plot + sage: for i in range(2): ....: n = [] ....: for m in range(2): ....: n.append(g[i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # needs networkx sage.plot - sage: G.show() # long time # needs networkx sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time """ edges = [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] pos = {0: (0, 0), @@ -88,23 +89,24 @@ def HexahedralGraph(): Construct and show a Hexahedral graph:: sage: g = graphs.HexahedralGraph() - sage: g.show() # long time + sage: g.show() # long time # needs sage.plot Create several hexahedral graphs in a Sage graphics array. They will be drawn differently due to the use of the spring-layout algorithm:: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.HexahedralGraph() ....: g.append(k) - sage: for i in range(3): # needs sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # needs sage.plot - sage: G.show() # long time # needs sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time """ adj = {0: [1, 3, 4], 1: [2, 5], 2: [3, 6], 3: [7], 4: [5, 7], 5: [6], 6: [7]} pos = { @@ -145,18 +147,19 @@ def OctahedralGraph(): Create several octahedral graphs in a Sage graphics array They will be drawn differently due to the use of the spring-layout algorithm:: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.OctahedralGraph() ....: g.append(k) - sage: for i in range(3): # needs sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # needs sage.plot - sage: G.show() # long time # needs sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time """ adj = {0: [1, 2, 3, 4], 1: [2, 3, 5], 2: [4, 5], 3: [4, 5], 4: [5]} G = Graph(adj, format='dict_of_lists', name="Octahedron") @@ -184,23 +187,24 @@ def IcosahedralGraph(): Construct and show an Octahedral graph:: sage: g = graphs.IcosahedralGraph() - sage: g.show() # long time + sage: g.show() # long time # needs sage.plot Create several icosahedral graphs in a Sage graphics array. They will be drawn differently due to the use of the spring-layout algorithm:: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.IcosahedralGraph() ....: g.append(k) - sage: for i in range(3): # needs sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # needs sage.plot - sage: G.show() # long time # needs sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time """ adj = {0: [1, 5, 7, 8, 11], 1: [2, 5, 6, 8], 2: [3, 6, 8, 9], 3: [4, 6, 9, 10], 4: [5, 6, 10, 11], 5: [6, 11], @@ -228,23 +232,24 @@ def DodecahedralGraph(): Construct and show a Dodecahedral graph:: sage: g = graphs.DodecahedralGraph() - sage: g.show() # long time + sage: g.show() # long time # needs sage.plot Create several dodecahedral graphs in a Sage graphics array They will be drawn differently due to the use of the spring-layout algorithm:: + sage: # needs sage.plot sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.DodecahedralGraph() ....: g.append(k) - sage: for i in range(3): # needs sage.plot + sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) - sage: G = graphics_array(j) # needs sage.plot - sage: G.show() # long time # needs sage.plot + sage: G = graphics_array(j) + sage: G.show() # long time """ adj = {0: [1, 10, 19], 1: [2, 8], 2: [3, 6], 3: [4, 19], 4: [5, 17], 5: [6, 15], 6: [7], 7: [8, 14], 8: [9], 9: [10, 13], 10: [11], diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index afae6f5de21..0c2dc0a79df 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -16400,8 +16400,8 @@ def triangles_count(self, algorithm=None): The 2-dimensional DeBruijn graph of 2 symbols has 2 directed `C_3`:: - sage: G = digraphs.DeBruijn(2,2) # needs sage.combinat - sage: G.triangles_count() # needs sage.combinat + sage: G = digraphs.DeBruijn(2,2) # needs sage.combinat + sage: G.triangles_count() # needs sage.combinat 2 The directed `n`-cycle is trivially triangle free for `n > 3`:: @@ -20779,15 +20779,16 @@ def plot(self, **options): :: - sage: from sage.plot.colors import rainbow # needs sage.plot + sage: # needs sage.plot + sage: from sage.plot.colors import rainbow sage: C = graphs.CubeGraph(5) - sage: R = rainbow(5) # needs sage.plot - sage: edge_colors = {R[i]: [] for i in range(5)} # needs sage.plot - sage: for u, v, l in C.edges(sort=False): # needs sage.plot + sage: R = rainbow(5) + sage: edge_colors = {R[i]: [] for i in range(5)} + sage: for u, v, l in C.edges(sort=False): ....: for i in range(5): ....: if u[i] != v[i]: ....: edge_colors[R[i]].append((u, v, l)) - sage: C.plot(vertex_labels=False, vertex_size=0, # needs sage.plot + sage: C.plot(vertex_labels=False, vertex_size=0, ....: edge_colors=edge_colors).show() :: diff --git a/src/sage/graphs/path_enumeration.pyx b/src/sage/graphs/path_enumeration.pyx index 5709d2b87c4..0e5304bcae4 100644 --- a/src/sage/graphs/path_enumeration.pyx +++ b/src/sage/graphs/path_enumeration.pyx @@ -442,20 +442,20 @@ def shortest_simple_paths(self, source, target, weight_function=None, [1, 6, 9, 11, 10, 5]] sage: # needs sage.combinat - sage: G = digraphs.DeBruijn(2, 3) # needs sage.combinat - sage: for u,v in G.edges(sort=True, labels=False): # needs sage.combinat + sage: G = digraphs.DeBruijn(2, 3) + sage: for u,v in G.edges(sort=True, labels=False): ....: G.set_edge_label(u, v, 1) - sage: G.allow_multiple_edges(True) # needs sage.combinat - sage: for u,v in G.edges(sort=True, labels=False): # needs sage.combinat + sage: G.allow_multiple_edges(True) + sage: for u,v in G.edges(sort=True, labels=False): ....: G.add_edge(u, v, 2) - sage: list(G.shortest_simple_paths('000', '111')) # needs sage.combinat + sage: list(G.shortest_simple_paths('000', '111')) [['000', '001', '011', '111'], ['000', '001', '010', '101', '011', '111']] - sage: list(G.shortest_simple_paths('000', '111', by_weight=True)) # needs sage.combinat + sage: list(G.shortest_simple_paths('000', '111', by_weight=True)) [['000', '001', '011', '111'], ['000', '001', '010', '101', '011', '111']] - sage: list(G.shortest_simple_paths('000', '111', by_weight=True, report_weight=True)) # needs sage.combinat + sage: list(G.shortest_simple_paths('000', '111', by_weight=True, report_weight=True)) [(3, ['000', '001', '011', '111']), (5, ['000', '001', '010', '101', '011', '111'])] - sage: list(G.shortest_simple_paths('000', '111', by_weight=True, report_weight=True, report_edges=True, labels=True)) # needs sage.combinat + sage: list(G.shortest_simple_paths('000', '111', by_weight=True, report_weight=True, report_edges=True, labels=True)) [(3, [('000', '001', 1), ('001', '011', 1), ('011', '111', 1)]), (5, [('000', '001', 1), @@ -481,12 +481,12 @@ def shortest_simple_paths(self, source, target, weight_function=None, Check for consistency of results of Yen's and Feng's:: sage: # needs sage.combinat - sage: G = digraphs.DeBruijn(2, 4) # needs sage.combinat + sage: G = digraphs.DeBruijn(2, 4) sage: s = set() - sage: for p in G.shortest_simple_paths('0000', '1111', by_weight=False, algorithm='Yen'): # needs sage.combinat + sage: for p in G.shortest_simple_paths('0000', '1111', by_weight=False, algorithm='Yen'): ....: s.add(tuple(p)) sage: k = set() - sage: for p in G.shortest_simple_paths('0000', '1111', by_weight=False, algorithm='Feng'): # needs sage.combinat + sage: for p in G.shortest_simple_paths('0000', '1111', by_weight=False, algorithm='Feng'): ....: k.add(tuple(p)) sage: k == s True From fe792827001e37b8d43e952bdbdd8ca6da334c8f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 2 Aug 2023 19:52:49 -0700 Subject: [PATCH 80/87] sage -fixdoctests: Fix handling of 2 file arguments --- src/bin/sage-fixdoctests | 46 +++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/src/bin/sage-fixdoctests b/src/bin/sage-fixdoctests index 3a0b904b8b3..1b99e0e38ea 100755 --- a/src/bin/sage-fixdoctests +++ b/src/bin/sage-fixdoctests @@ -314,9 +314,9 @@ def process_block(block, src_in_lines, file_optional_tags): def output_filename(filename): if len(args.filename) == 2 and not args.overwrite and not args.no_overwrite: if args.filename[0] == filename: - print("sage-fixdoctests: When passing two filenames, the second one is taken as an output filename; " - "this is deprecated. To pass two input filenames, use the option --overwrite.") return args.filename[1] + else: + return None return filename + ".fixed" if args.no_overwrite: return filename + ".fixed" @@ -340,7 +340,14 @@ else: print(f'Doctester exited with error status {status}') sys.exit(status) # Run the doctester, putting the output of the test into sage's temporary directory - input_args = " ".join(shlex.quote(f) for f in args.filename) + if len(args.filename) == 2 and not args.overwrite and not args.no_overwrite: + print("sage-fixdoctests: When passing two filenames, the second one is taken as an output filename; " + "this is deprecated. To pass two input filenames, use the option --overwrite.") + + input_filenames = [args.filename[0]] + else: + input_filenames = args.filename + input_args = " ".join(shlex.quote(f) for f in input_filenames) cmdline = f'{shlex.quote(executable)} -t -p {environment_args}{long_args}{probe_args}{lib_args}{input_args}' print(f'Running "{cmdline}"') os.system(f'{cmdline} > {shlex.quote(doc_file)}') @@ -364,7 +371,7 @@ def block_filename(block): def expanded_filename_args(): DD = DocTestDefaults(optional='all') - DC = DocTestController(DD, args.filename) + DC = DocTestController(DD, input_filenames) DC.add_files() DC.expand_files_into_sources() for source in DC.sources: @@ -418,22 +425,23 @@ def process_grouped_blocks(grouped_iterator): persistent_optional_tags = {} if src_in_lines != shallow_copy_of_src_in_lines: - output = output_filename(input) - with open(output, 'w') as test_output: - for line in src_in_lines: - if line is None: - continue - test_output.write(line) - test_output.write('\n') - - # Show summary of changes - if input != output: - print("The fixed doctests have been saved as '{0}'.".format(output)) + if (output := output_filename(input)) is None: + print(f"Not saving modifications made in '{input}'") else: - relative = os.path.relpath(output, SAGE_ROOT) - print(f"The input file '{output}' has been overwritten.") - if not relative.startswith('..'): - subprocess.call(['git', '--no-pager', 'diff', relative], cwd=SAGE_ROOT) + with open(output, 'w') as test_output: + for line in src_in_lines: + if line is None: + continue + test_output.write(line) + test_output.write('\n') + # Show summary of changes + if input != output : + print("The fixed doctests have been saved as '{0}'.".format(output)) + else: + relative = os.path.relpath(output, SAGE_ROOT) + print(f"The input file '{output}' has been overwritten.") + if not relative.startswith('..'): + subprocess.call(['git', '--no-pager', 'diff', relative], cwd=SAGE_ROOT) else: print(f"No fixes made in '{input}'") From 2dccf184dd769b9dfc7cb0afe76082381122f87b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 2 Aug 2023 22:51:42 -0700 Subject: [PATCH 81/87] sage -fixdoctests: Suppress 'too few successful tests' message --- src/bin/sage-fixdoctests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/sage-fixdoctests b/src/bin/sage-fixdoctests index 1b99e0e38ea..50387881ad3 100755 --- a/src/bin/sage-fixdoctests +++ b/src/bin/sage-fixdoctests @@ -370,7 +370,7 @@ def block_filename(block): return m.group(1) def expanded_filename_args(): - DD = DocTestDefaults(optional='all') + DD = DocTestDefaults(optional='all', warn_long=10000) DC = DocTestController(DD, input_filenames) DC.add_files() DC.expand_files_into_sources() From a8d6ef0720223ae7e3ce81590581db1bb2b3d586 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 3 Aug 2023 16:57:07 -0700 Subject: [PATCH 82/87] pkgs/sagemath-standard/MANIFEST.in: Exclude all__*.py files belonging to distributions related to optional packages --- src/MANIFEST.in | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/MANIFEST.in b/src/MANIFEST.in index 0f6e2a37890..02e05c34512 100644 --- a/src/MANIFEST.in +++ b/src/MANIFEST.in @@ -47,6 +47,14 @@ include sage/geometry/triangulation/functions.cc # Exclude extension modules shipped by optional packages exclude sage/graphs/bliss.pyx +# Exclude all__*.py files belonging to distributions related to optional packages +global-exclude all__sagemath_bliss.py +global-exclude all__sagemath_coxeter3.py +global-exclude all__sagemath_mcqd.py +global-exclude all__sagemath_meataxe.py +global-exclude all__sagemath_sirocco.py +global-exclude all__sagemath_tdlib.py + global-exclude __pycache__ global-exclude *.py[co] global-exclude *.bak From 2ce4a867f6b5a258846830afff3168823f1bca9f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 3 Aug 2023 17:10:37 -0700 Subject: [PATCH 83/87] src/MANIFEST.in: Exclude files shipped by sagemath-bliss etc. --- src/MANIFEST.in | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/MANIFEST.in b/src/MANIFEST.in index 02e05c34512..13e8d94917a 100644 --- a/src/MANIFEST.in +++ b/src/MANIFEST.in @@ -21,7 +21,6 @@ global-exclude *.cpp include sage/cpython/debugimpl.c include sage/graphs/base/boost_interface.cpp include sage/graphs/cliquer/cl.c -include sage/graphs/graph_decompositions/sage_tdlib.cpp include sage/libs/eclib/wrap.cpp include sage/libs/linkages/padics/relaxed/flint_helper.c include sage/misc/inherit_comparison_impl.c @@ -45,7 +44,13 @@ include sage/geometry/triangulation/data.cc include sage/geometry/triangulation/functions.cc # Exclude extension modules shipped by optional packages -exclude sage/graphs/bliss.pyx +exclude sage/graphs/bliss.p* +prune sage/graphs/bliss_cpp +prune sage/libs/coxeter3 +exclude sage/graphs/mcqd.p* +exclude sage/libs/meataxe.p* +exclude sage/matrix/matrix_gfpn_dense.p* +exclude sage/graphs/graph_decompositions/sage_tdlib.cpp # Exclude all__*.py files belonging to distributions related to optional packages global-exclude all__sagemath_bliss.py From cf02a4256ee8e630ec444452d1dfdd0dac7382cf Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 3 Aug 2023 17:33:09 -0700 Subject: [PATCH 84/87] src/MANIFEST.in: Exclude files shipped by sagemath-tdlib --- src/MANIFEST.in | 1 + src/sage/graphs/graph_decompositions/sage_tdlib.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/MANIFEST.in b/src/MANIFEST.in index 13e8d94917a..2a26ec02dba 100644 --- a/src/MANIFEST.in +++ b/src/MANIFEST.in @@ -51,6 +51,7 @@ exclude sage/graphs/mcqd.p* exclude sage/libs/meataxe.p* exclude sage/matrix/matrix_gfpn_dense.p* exclude sage/graphs/graph_decompositions/sage_tdlib.cpp +exclude sage/graphs/graph_decomposition/tdlib.p* # Exclude all__*.py files belonging to distributions related to optional packages global-exclude all__sagemath_bliss.py diff --git a/src/sage/graphs/graph_decompositions/sage_tdlib.cpp b/src/sage/graphs/graph_decompositions/sage_tdlib.cpp index ad1e3fb1f03..3644edf6ac7 100644 --- a/src/sage/graphs/graph_decompositions/sage_tdlib.cpp +++ b/src/sage/graphs/graph_decompositions/sage_tdlib.cpp @@ -1,3 +1,5 @@ +// sage.setup: distribution = sagemath-tdlib + #include #include From e57dacd2f5f01656a384e2734535da6af350604a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 4 Aug 2023 13:27:24 -0700 Subject: [PATCH 85/87] src/MANIFEST.in: Remove redundant 'exclude' --- src/MANIFEST.in | 1 - 1 file changed, 1 deletion(-) diff --git a/src/MANIFEST.in b/src/MANIFEST.in index 2a26ec02dba..bbed8838199 100644 --- a/src/MANIFEST.in +++ b/src/MANIFEST.in @@ -50,7 +50,6 @@ prune sage/libs/coxeter3 exclude sage/graphs/mcqd.p* exclude sage/libs/meataxe.p* exclude sage/matrix/matrix_gfpn_dense.p* -exclude sage/graphs/graph_decompositions/sage_tdlib.cpp exclude sage/graphs/graph_decomposition/tdlib.p* # Exclude all__*.py files belonging to distributions related to optional packages From 4d259d440db55d7065bc5e8109112b75bee4acbe Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 4 Aug 2023 17:03:12 -0700 Subject: [PATCH 86/87] src/sage/graphs/generators/smallgraphs.py: Fix up merge --- src/sage/graphs/generators/smallgraphs.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/graphs/generators/smallgraphs.py b/src/sage/graphs/generators/smallgraphs.py index ccc4610bb8c..e58248f05c8 100644 --- a/src/sage/graphs/generators/smallgraphs.py +++ b/src/sage/graphs/generators/smallgraphs.py @@ -4664,7 +4664,6 @@ def WienerArayaGraph(): False sage: g.delete_vertex(g.random_vertex()) sage: g.is_hamiltonian() # needs sage.numerical.mip ->>>>>>> 85d4a8d443 (./sage -fixdoctests --probe all --distribution 'sagemath-graphs[modules]' src/sage/graphs/generators/smallgraphs.py; ./sage -fixdoctests src/sage/graphs/generators/smallgraphs.py) True """ g = Graph(name="Wiener-Araya Graph") From 0fd596703c824a53f4ffb54556f336de436dde59 Mon Sep 17 00:00:00 2001 From: Release Manager Date: Sun, 6 Aug 2023 01:16:49 +0200 Subject: [PATCH 87/87] Updated SageMath version to 10.1.beta9 --- CITATION.cff | 4 ++-- VERSION.txt | 2 +- build/pkgs/configure/checksums.ini | 6 +++--- build/pkgs/configure/package-version.txt | 2 +- build/pkgs/sage_conf/install-requires.txt | 2 +- build/pkgs/sage_docbuild/install-requires.txt | 2 +- build/pkgs/sage_setup/install-requires.txt | 2 +- build/pkgs/sage_sws2rst/install-requires.txt | 2 +- build/pkgs/sagelib/install-requires.txt | 2 +- build/pkgs/sagemath_bliss/install-requires.txt | 2 +- build/pkgs/sagemath_categories/install-requires.txt | 2 +- build/pkgs/sagemath_coxeter3/install-requires.txt | 2 +- build/pkgs/sagemath_environment/install-requires.txt | 2 +- build/pkgs/sagemath_mcqd/install-requires.txt | 2 +- build/pkgs/sagemath_meataxe/install-requires.txt | 2 +- build/pkgs/sagemath_objects/install-requires.txt | 2 +- build/pkgs/sagemath_repl/install-requires.txt | 2 +- build/pkgs/sagemath_sirocco/install-requires.txt | 2 +- build/pkgs/sagemath_tdlib/install-requires.txt | 2 +- pkgs/sage-conf/VERSION.txt | 2 +- pkgs/sage-conf_pypi/VERSION.txt | 2 +- pkgs/sage-docbuild/VERSION.txt | 2 +- pkgs/sage-setup/VERSION.txt | 2 +- pkgs/sage-sws2rst/VERSION.txt | 2 +- pkgs/sagemath-bliss/VERSION.txt | 2 +- pkgs/sagemath-categories/VERSION.txt | 2 +- pkgs/sagemath-coxeter3/VERSION.txt | 2 +- pkgs/sagemath-environment/VERSION.txt | 2 +- pkgs/sagemath-mcqd/VERSION.txt | 2 +- pkgs/sagemath-meataxe/VERSION.txt | 2 +- pkgs/sagemath-objects/VERSION.txt | 2 +- pkgs/sagemath-repl/VERSION.txt | 2 +- pkgs/sagemath-sirocco/VERSION.txt | 2 +- pkgs/sagemath-tdlib/VERSION.txt | 2 +- src/VERSION.txt | 2 +- src/bin/sage-version.sh | 6 +++--- src/sage/version.py | 6 +++--- 37 files changed, 44 insertions(+), 44 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index 6f4f46a6d8a..8e536719607 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -4,8 +4,8 @@ title: SageMath abstract: SageMath is a free open-source mathematics software system. authors: - name: "The SageMath Developers" -version: 10.1.beta8 +version: 10.1.beta9 doi: 10.5281/zenodo.593563 -date-released: 2023-07-30 +date-released: 2023-08-05 repository-code: "https://github.com/sagemath/sage" url: "https://www.sagemath.org/" diff --git a/VERSION.txt b/VERSION.txt index d9562f0204a..3a158e5f21f 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 10.1.beta8, Release Date: 2023-07-30 +SageMath version 10.1.beta9, Release Date: 2023-08-05 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 4896e050f7a..ba8597088cd 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=5009fe65b14c7a831686bdfb450847e3d0529a05 -md5=4b37514c5f8aa7c5abdac9166f8971c6 -cksum=1917392583 +sha1=0c03cb79520ba7f484e811aeb10ce528b3ea97d5 +md5=499635417f054c55dc90c9aca9494d61 +cksum=3916950255 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 5348ab7e0b8..1d722817b70 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -6b849264a96717a5ecabbd2a63b2559c3ade2306 +ffdd9f8e55c138555338187b059d80ceecc2abaf diff --git a/build/pkgs/sage_conf/install-requires.txt b/build/pkgs/sage_conf/install-requires.txt index 308956090b6..76fd774f5f4 100644 --- a/build/pkgs/sage_conf/install-requires.txt +++ b/build/pkgs/sage_conf/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-conf ~= 10.1b8 +sage-conf ~= 10.1b9 diff --git a/build/pkgs/sage_docbuild/install-requires.txt b/build/pkgs/sage_docbuild/install-requires.txt index f2408da3bef..49a89420880 100644 --- a/build/pkgs/sage_docbuild/install-requires.txt +++ b/build/pkgs/sage_docbuild/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-docbuild ~= 10.1b8 +sage-docbuild ~= 10.1b9 diff --git a/build/pkgs/sage_setup/install-requires.txt b/build/pkgs/sage_setup/install-requires.txt index 3fb4f9bd897..c222b9cdd2f 100644 --- a/build/pkgs/sage_setup/install-requires.txt +++ b/build/pkgs/sage_setup/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-setup ~= 10.1b8 +sage-setup ~= 10.1b9 diff --git a/build/pkgs/sage_sws2rst/install-requires.txt b/build/pkgs/sage_sws2rst/install-requires.txt index 5705cd5cef9..4486a67ed75 100644 --- a/build/pkgs/sage_sws2rst/install-requires.txt +++ b/build/pkgs/sage_sws2rst/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-sws2rst ~= 10.1b8 +sage-sws2rst ~= 10.1b9 diff --git a/build/pkgs/sagelib/install-requires.txt b/build/pkgs/sagelib/install-requires.txt index 09ddf8e9f0e..74089ecdd65 100644 --- a/build/pkgs/sagelib/install-requires.txt +++ b/build/pkgs/sagelib/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-standard ~= 10.1b8 +sagemath-standard ~= 10.1b9 diff --git a/build/pkgs/sagemath_bliss/install-requires.txt b/build/pkgs/sagemath_bliss/install-requires.txt index 175856b245f..7e7c708066a 100644 --- a/build/pkgs/sagemath_bliss/install-requires.txt +++ b/build/pkgs/sagemath_bliss/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-bliss ~= 10.1b8 +sagemath-bliss ~= 10.1b9 diff --git a/build/pkgs/sagemath_categories/install-requires.txt b/build/pkgs/sagemath_categories/install-requires.txt index 2bc854cfebc..21f5efa6dd8 100644 --- a/build/pkgs/sagemath_categories/install-requires.txt +++ b/build/pkgs/sagemath_categories/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-categories ~= 10.1b8 +sagemath-categories ~= 10.1b9 diff --git a/build/pkgs/sagemath_coxeter3/install-requires.txt b/build/pkgs/sagemath_coxeter3/install-requires.txt index 7576be637d3..174264f9c2d 100644 --- a/build/pkgs/sagemath_coxeter3/install-requires.txt +++ b/build/pkgs/sagemath_coxeter3/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-coxeter3 ~= 10.1b8 +sagemath-coxeter3 ~= 10.1b9 diff --git a/build/pkgs/sagemath_environment/install-requires.txt b/build/pkgs/sagemath_environment/install-requires.txt index ac5083c4105..3a2a2e06ca5 100644 --- a/build/pkgs/sagemath_environment/install-requires.txt +++ b/build/pkgs/sagemath_environment/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-environment ~= 10.1b8 +sagemath-environment ~= 10.1b9 diff --git a/build/pkgs/sagemath_mcqd/install-requires.txt b/build/pkgs/sagemath_mcqd/install-requires.txt index 211e612c18e..5012bc30606 100644 --- a/build/pkgs/sagemath_mcqd/install-requires.txt +++ b/build/pkgs/sagemath_mcqd/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-mcqd ~= 10.1b8 +sagemath-mcqd ~= 10.1b9 diff --git a/build/pkgs/sagemath_meataxe/install-requires.txt b/build/pkgs/sagemath_meataxe/install-requires.txt index 1ca467ef1b7..d9c67ecdcb4 100644 --- a/build/pkgs/sagemath_meataxe/install-requires.txt +++ b/build/pkgs/sagemath_meataxe/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-meataxe ~= 10.1b8 +sagemath-meataxe ~= 10.1b9 diff --git a/build/pkgs/sagemath_objects/install-requires.txt b/build/pkgs/sagemath_objects/install-requires.txt index c8da8347647..cdaa97d1f23 100644 --- a/build/pkgs/sagemath_objects/install-requires.txt +++ b/build/pkgs/sagemath_objects/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-objects ~= 10.1b8 +sagemath-objects ~= 10.1b9 diff --git a/build/pkgs/sagemath_repl/install-requires.txt b/build/pkgs/sagemath_repl/install-requires.txt index da36117bd6e..d8fa592fcc2 100644 --- a/build/pkgs/sagemath_repl/install-requires.txt +++ b/build/pkgs/sagemath_repl/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-repl ~= 10.1b8 +sagemath-repl ~= 10.1b9 diff --git a/build/pkgs/sagemath_sirocco/install-requires.txt b/build/pkgs/sagemath_sirocco/install-requires.txt index 417fc0e71cf..743cd19995b 100644 --- a/build/pkgs/sagemath_sirocco/install-requires.txt +++ b/build/pkgs/sagemath_sirocco/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-sirocco ~= 10.1b8 +sagemath-sirocco ~= 10.1b9 diff --git a/build/pkgs/sagemath_tdlib/install-requires.txt b/build/pkgs/sagemath_tdlib/install-requires.txt index 949a775737d..40c4589d4b3 100644 --- a/build/pkgs/sagemath_tdlib/install-requires.txt +++ b/build/pkgs/sagemath_tdlib/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-tdlib ~= 10.1b8 +sagemath-tdlib ~= 10.1b9 diff --git a/pkgs/sage-conf/VERSION.txt b/pkgs/sage-conf/VERSION.txt index d06eca61e5a..6730b33848c 100644 --- a/pkgs/sage-conf/VERSION.txt +++ b/pkgs/sage-conf/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.beta9 diff --git a/pkgs/sage-conf_pypi/VERSION.txt b/pkgs/sage-conf_pypi/VERSION.txt index d06eca61e5a..6730b33848c 100644 --- a/pkgs/sage-conf_pypi/VERSION.txt +++ b/pkgs/sage-conf_pypi/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.beta9 diff --git a/pkgs/sage-docbuild/VERSION.txt b/pkgs/sage-docbuild/VERSION.txt index d06eca61e5a..6730b33848c 100644 --- a/pkgs/sage-docbuild/VERSION.txt +++ b/pkgs/sage-docbuild/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.beta9 diff --git a/pkgs/sage-setup/VERSION.txt b/pkgs/sage-setup/VERSION.txt index d06eca61e5a..6730b33848c 100644 --- a/pkgs/sage-setup/VERSION.txt +++ b/pkgs/sage-setup/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.beta9 diff --git a/pkgs/sage-sws2rst/VERSION.txt b/pkgs/sage-sws2rst/VERSION.txt index d06eca61e5a..6730b33848c 100644 --- a/pkgs/sage-sws2rst/VERSION.txt +++ b/pkgs/sage-sws2rst/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.beta9 diff --git a/pkgs/sagemath-bliss/VERSION.txt b/pkgs/sagemath-bliss/VERSION.txt index d06eca61e5a..6730b33848c 100644 --- a/pkgs/sagemath-bliss/VERSION.txt +++ b/pkgs/sagemath-bliss/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.beta9 diff --git a/pkgs/sagemath-categories/VERSION.txt b/pkgs/sagemath-categories/VERSION.txt index d06eca61e5a..6730b33848c 100644 --- a/pkgs/sagemath-categories/VERSION.txt +++ b/pkgs/sagemath-categories/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.beta9 diff --git a/pkgs/sagemath-coxeter3/VERSION.txt b/pkgs/sagemath-coxeter3/VERSION.txt index d06eca61e5a..6730b33848c 100644 --- a/pkgs/sagemath-coxeter3/VERSION.txt +++ b/pkgs/sagemath-coxeter3/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.beta9 diff --git a/pkgs/sagemath-environment/VERSION.txt b/pkgs/sagemath-environment/VERSION.txt index d06eca61e5a..6730b33848c 100644 --- a/pkgs/sagemath-environment/VERSION.txt +++ b/pkgs/sagemath-environment/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.beta9 diff --git a/pkgs/sagemath-mcqd/VERSION.txt b/pkgs/sagemath-mcqd/VERSION.txt index d06eca61e5a..6730b33848c 100644 --- a/pkgs/sagemath-mcqd/VERSION.txt +++ b/pkgs/sagemath-mcqd/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.beta9 diff --git a/pkgs/sagemath-meataxe/VERSION.txt b/pkgs/sagemath-meataxe/VERSION.txt index d06eca61e5a..6730b33848c 100644 --- a/pkgs/sagemath-meataxe/VERSION.txt +++ b/pkgs/sagemath-meataxe/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.beta9 diff --git a/pkgs/sagemath-objects/VERSION.txt b/pkgs/sagemath-objects/VERSION.txt index d06eca61e5a..6730b33848c 100644 --- a/pkgs/sagemath-objects/VERSION.txt +++ b/pkgs/sagemath-objects/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.beta9 diff --git a/pkgs/sagemath-repl/VERSION.txt b/pkgs/sagemath-repl/VERSION.txt index d06eca61e5a..6730b33848c 100644 --- a/pkgs/sagemath-repl/VERSION.txt +++ b/pkgs/sagemath-repl/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.beta9 diff --git a/pkgs/sagemath-sirocco/VERSION.txt b/pkgs/sagemath-sirocco/VERSION.txt index d06eca61e5a..6730b33848c 100644 --- a/pkgs/sagemath-sirocco/VERSION.txt +++ b/pkgs/sagemath-sirocco/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.beta9 diff --git a/pkgs/sagemath-tdlib/VERSION.txt b/pkgs/sagemath-tdlib/VERSION.txt index d06eca61e5a..6730b33848c 100644 --- a/pkgs/sagemath-tdlib/VERSION.txt +++ b/pkgs/sagemath-tdlib/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.beta9 diff --git a/src/VERSION.txt b/src/VERSION.txt index d06eca61e5a..6730b33848c 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -10.1.beta8 +10.1.beta9 diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 1800ec2771f..8c1a833ccb2 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -4,6 +4,6 @@ # which stops "setup.py develop" from rewriting it as a Python file. : # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='10.1.beta8' -SAGE_RELEASE_DATE='2023-07-30' -SAGE_VERSION_BANNER='SageMath version 10.1.beta8, Release Date: 2023-07-30' +SAGE_VERSION='10.1.beta9' +SAGE_RELEASE_DATE='2023-08-05' +SAGE_VERSION_BANNER='SageMath version 10.1.beta9, Release Date: 2023-08-05' diff --git a/src/sage/version.py b/src/sage/version.py index 4d55e0375ec..1dacd8c2bfe 100644 --- a/src/sage/version.py +++ b/src/sage/version.py @@ -1,5 +1,5 @@ # Sage version information for Python scripts # This file is auto-generated by the sage-update-version script, do not edit! -version = '10.1.beta8' -date = '2023-07-30' -banner = 'SageMath version 10.1.beta8, Release Date: 2023-07-30' +version = '10.1.beta9' +date = '2023-08-05' +banner = 'SageMath version 10.1.beta9, Release Date: 2023-08-05'