Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix slow doctests or mark # long time #35443

Merged
merged 12 commits into from
Apr 23, 2023
6 changes: 3 additions & 3 deletions src/sage/calculus/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@

Other examples that now (:trac:`27958`) work::

sage: integrate(log(x)*exp(-x^2), x)
sage: integrate(log(x)*exp(-x^2), x) # long time
1/2*sqrt(pi)*erf(x)*log(x) - x*hypergeometric((1/2, 1/2), (3/2, 3/2), -x^2)

sage: integrate(log(1+sqrt(1+4*x)/2)/x, x, 0, 1)
Expand Down Expand Up @@ -201,12 +201,12 @@
1/3*sqrt(3)*arctan(1/3*sqrt(3)*(2*x + 1)) - 1/6*log(x^2 + x + 1) + 1/3*log(x - 1)
sage: integrate(exp(-x^2), x)
1/2*sqrt(pi)*erf(x)
sage: integrate(exp(-x^2)*log(x), x)
sage: integrate(exp(-x^2)*log(x), x) # long time
1/2*sqrt(pi)*erf(x)*log(x) - x*hypergeometric((1/2, 1/2), (3/2, 3/2), -x^2)
sage: f = exp(-x^2)*log(x)
sage: f.nintegral(x, 0, 999)
(-0.87005772672831..., 7.5584...e-10, 567, 0)
sage: integral(1/sqrt(2*t^4 - 3*t^2 - 2), t, 2, 3) # todo: maple can do this
sage: integral(1/sqrt(2*t^4 - 3*t^2 - 2), t, 2, 3) # long time # todo: maple can do this
integrate(1/(sqrt(2*t^2 + 1)*sqrt(t^2 - 2)), t, 2, 3)
sage: integral(integral(x*y^2, x, 0, y), y, -2, 2)
32/5
Expand Down
4 changes: 2 additions & 2 deletions src/sage/categories/pushout.py
Original file line number Diff line number Diff line change
Expand Up @@ -1154,8 +1154,8 @@ def expand(self):
Traceback (most recent call last):
...
TypeError: unsupported operand parent(s) for +: 'Multivariate Polynomial Ring in x, y, z over Integer Ring' and 'Multivariate Polynomial Ring in y, s over Rational Field'
sage: R = PolynomialRing(ZZ, 'x', 500)
sage: S = PolynomialRing(GF(5), 'x', 200)
sage: R = PolynomialRing(ZZ, 'x', 50)
sage: S = PolynomialRing(GF(5), 'x', 20)
sage: R.gen(0) + S.gen(0)
2*x0
"""
Expand Down
13 changes: 7 additions & 6 deletions src/sage/combinat/crystals/affine_factorization.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ def __init__(self, w, n, x = None):
sage: W = WeylGroup(['A',3,1], prefix='s')
sage: w = W.from_reduced_word([2,3,2,1])
sage: B = crystals.AffineFactorization(w,3)
sage: TestSuite(B).run()
sage: TestSuite(B).run() # long time
"""
Parent.__init__(self, category = ClassicalCrystals())
self.n = n
Expand Down Expand Up @@ -407,7 +407,7 @@ def affine_factorizations(w, l, weight=None):
[[s1, s2, s1], [s2, s1, s2]]
sage: W = WeylGroup(['A',3], prefix='s')
sage: w0 = W.long_element()
sage: affine_factorizations(w0,6,(1,1,1,1,1,1))
sage: affine_factorizations(w0,6,(1,1,1,1,1,1)) # long time
[[s1, s2, s1, s3, s2, s1],
[s1, s2, s3, s1, s2, s1],
[s1, s2, s3, s2, s1, s2],
Expand Down Expand Up @@ -498,12 +498,13 @@ def is_isomorphism(self):

sage: W = WeylGroup(['A',4,1], prefix='s')
sage: w = W.from_reduced_word([2,1,3,2,4,3,2,1])
sage: B = crystals.AffineFactorization(w, 4)
sage: phi = B._tableaux_isomorphism
sage: all(phi(b).e(i) == phi(b.e(i)) and phi(b).f(i) == phi(b.f(i))
sage: B = crystals.AffineFactorization(w, 4) # long time
sage: phi = B._tableaux_isomorphism # long time
sage: all(phi(b).e(i) == phi(b.e(i)) and # long time
....: phi(b).f(i) == phi(b.f(i))
....: for b in B for i in B.index_set())
True
sage: set(phi(b) for b in B) == set(phi.codomain())
sage: set(phi(b) for b in B) == set(phi.codomain()) # long time
True
"""
return True
Expand Down
2 changes: 1 addition & 1 deletion src/sage/combinat/crystals/highest_weight_crystals.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ def HighestWeightCrystal(dominant_weight, model=None):

Check that the correct crystal is constructed for the fundamental weights::

sage: for ct in CartanType.samples(finite=True, crystallographic=True):
sage: for ct in CartanType.samples(finite=True, crystallographic=True): # long time
....: L = ct.root_system().weight_lattice()
....: La = L.fundamental_weights()
....: for model in ['Tableaux', 'NakajimaMonomials', 'AlcovePaths', 'RiggedConfigurations']:
Expand Down
4 changes: 2 additions & 2 deletions src/sage/combinat/designs/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -1658,8 +1658,8 @@ def OA_10_469():

sage: from sage.combinat.designs.designs_pyx import is_orthogonal_array
sage: from sage.combinat.designs.database import OA_10_469
sage: OA = OA_10_469()
sage: is_orthogonal_array(OA,10,469,2)
sage: OA = OA_10_469() # long time
sage: is_orthogonal_array(OA,10,469,2) # long time
True

The design is available from the general constructor::
Expand Down
4 changes: 2 additions & 2 deletions src/sage/combinat/k_regular_sequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -1112,7 +1112,7 @@ def from_recurrence(self, *args, **kwds):

TESTS::

sage: Seq2.from_recurrence([
sage: Seq2.from_recurrence([ # long time
....: f(4*n) == f(2*n),
....: f(4*n + 1) == f(2*n),
....: f(4*n + 2) == f(2*n),
Expand Down Expand Up @@ -1179,7 +1179,7 @@ def from_recurrence(self, *args, **kwds):
....: g(22) == 22, g(23) == 23, g(24) == 24, g(25) == 25,
....: g(26) == 26, g(27) == 27, g(28) == 28, g(29) == 29,
....: g(30) == 30, g(31) == 31], g, m, offset=8)
sage: (S - T).is_trivial_zero()
sage: (S - T).is_trivial_zero() # long time
True

Zero-sequence with non-zero initial values::
Expand Down
4 changes: 2 additions & 2 deletions src/sage/combinat/rsk.py
Original file line number Diff line number Diff line change
Expand Up @@ -2586,7 +2586,7 @@ class RuleStar(Rule):
....: for T in SemistandardTableaux(shape, max_entry=4)
....: if fc(row_reading(T.conjugate()))]
sage: Checks = []
sage: for T in FC_tabs:
sage: for T in FC_tabs: # long time
....: shape = T.shape().conjugate()
....: P = T.conjugate()
....: Checks += [all((P,Q) == tuple(RSK(*RSK_inverse(P, Q,
Expand All @@ -2596,7 +2596,7 @@ class RuleStar(Rule):
sage: all(Checks)
True
sage: Checks = []
sage: for T in FC_tabs:
sage: for T in FC_tabs: # long time
....: shape = T.shape().conjugate()
....: P = T.conjugate()
....: Checks += [all((P,Q) == tuple(RSK(RSK_inverse(P, Q,
Expand Down
20 changes: 13 additions & 7 deletions src/sage/combinat/words/paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -1614,38 +1614,44 @@ def animate(self):

sage: P = WordPaths('abAB')
sage: p = P('aaababbb')
sage: a = p.animate(); a # optional -- ImageMagick
sage: a = p.animate(); print(a)
Animation with 9 frames
sage: show(a) # optional -- ImageMagick
sage: a.gif(delay=35, iterations=3) # optional -- ImageMagick
sage: show(a) # long time # optional -- ImageMagick
sage: show(a, delay=35, iterations=3) # long time # optional -- ImageMagick

::

sage: P = WordPaths('abcdef',steps='triangle')
sage: p = P('abcdef')
sage: p.animate() # optional -- ImageMagick
sage: a = p.animate(); print(a)
Animation with 8 frames
sage: show(a) # long time # optional -- ImageMagick

If the path is closed, the plain polygon is added at the end of the
animation::

sage: P = WordPaths('abAB')
sage: p = P('ababAbABABaB')
sage: a = p.animate(); a # optional -- ImageMagick
sage: a = p.animate(); print(a)
Animation with 14 frames
sage: show(a) # long time # optional -- ImageMagick

Another example illustrating a Fibonacci tile::

sage: w = words.fibonacci_tile(2)
sage: show(w.animate()) # optional -- ImageMagick
sage: a = w.animate(); print(a)
Animation with 54 frames
sage: show(a) # long time # optional -- ImageMagick

The first 4 Fibonacci tiles in an animation::

sage: a = words.fibonacci_tile(0).animate()
sage: b = words.fibonacci_tile(1).animate()
sage: c = words.fibonacci_tile(2).animate()
sage: d = words.fibonacci_tile(3).animate()
sage: (a*b*c*d).show() # optional -- ImageMagick # long time
sage: print(a*b*c*d)
Animation with 296 frames
sage: show(a*b*c*d) # long time # optional -- ImageMagick

.. note::

Expand Down
3 changes: 2 additions & 1 deletion src/sage/crypto/lwe.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ def __init__(self, n, q, D, secret_dist='uniform', m=None):
sage: L = []
sage: def add_samples():
....: global L
....: L += [lwe() for _ in range(1000)]
....: L += [lwe() for _ in range(100)]
sage: add_samples()

To test the oracle, we use the internal secret to evaluate the samples
Expand All @@ -298,6 +298,7 @@ def __init__(self, n, q, D, secret_dist='uniform', m=None):

sage: from numpy import std
sage: while abs(std([e if e <= 200 else e-401 for e in S()]) - 3.0) > 0.01:
....: L = [] # reset L to avoid quadratic behaviour
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't the idea of this test that by increasing the number of samples, the error bound will be hit?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure. To be honest I'm not sure what is the role of this test, but the previous implementation exhibits quadratic behavior which is the cause of this test usually being ok but sometimes being very slow:

sage -t --warn-long --random-seed=110988274722243807127083377606682083581 src/sage/crypto/lwe.py
**********************************************************************
File "src/sage/crypto/lwe.py", line 300, in sage.crypto.lwe.LWE.__init__
Warning, slow doctest:
    while abs(std([e if e <= 200 else e-401 for e in S()]) - 3.0) > 0.01:
        add_samples()
Test ran for 16.66 s, check ran for 0.00 s
    [112 tests, 17.29 s]

vs.

sage -t --warn-long 0.4 --random-seed=1 src/sage/crypto/lwe.py
**********************************************************************
File "src/sage/crypto/lwe.py", line 300, in sage.crypto.lwe.LWE.__init__
Warning, slow doctest:
    while abs(std([e if e <= 200 else e-401 for e in S()]) - 3.0) > 0.01:
        add_samples()
Test ran for 0.47 s, check ran for 0.00 s
    [112 tests, 1.37 s]

As far as I understand, they want to show that these samples indeed have a normal distribution with standard deviation 3.0. They take 1000 samples and want the standard deviation of these to be close to 3.0. Otherwise they keep adding samples, etc. until the standard deviation of the samples is indeed close to 3.0.

However, the way this is implemented it becomes O(n^2) when they have to try 1000n samples.

With my change, instead of adding more samples, we take a new set of 1000 samples. In this way, trying 1000n samples is O(n). So, even if we have to try more times, this is better.

Moreover, now this is linear instead of quadratic, it's even faster too try a sample of 100.

Summary: the new way the test is done, it keeps computing the standard deviation of 100 samples until it's really close to 3.0.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know if you are happy with my explanation. Otherwise, I'll revert and place a # long time label (although I'd be more inclined to just nuke the test).

I think this was the only non-cosmetic objection you had (and the cosmetic ones are more or less all addressed).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I would be more comfortable if we just get rid of the while loop, compute and print the std and mark the result as random

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That said, your solution is of course fine.

....: add_samples()

If ``m`` is not ``None`` the number of available samples is restricted::
Expand Down
12 changes: 5 additions & 7 deletions src/sage/crypto/sbox.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -940,13 +940,11 @@ cdef class SBox(SageObject):
Check that :trac:`22453` is fixed::

sage: from sage.crypto.sboxes import AES
sage: aes_polys = AES.polynomials()
sage: p = aes_polys[0].parent("x3*y0 + x5*y0 + x7*y0 + x6*y1 + x2*y2"
....: " + x3*y2 + x4*y2 + x2*y3 + x3*y3 +"
....: " x5*y4 + x6*y4 + x3*y5 + x4*y5 + x4*y7"
....: " + x2 + x3 + y2 + y3 + y4 + 1")
sage: p in aes_polys
True
sage: aes_polys = AES.polynomials() # long time
sage: aes_polys[3] # long time
x3*y0 + x5*y0 + x7*y0 + x6*y1 + x2*y2 + x3*y2 + x4*y2
+ x2*y3 + x3*y3 + x5*y4 + x6*y4 + x3*y5 + x4*y5
+ x4*y7 + x2 + x3 + y2 + y3 + y4 + 1
"""
cdef Py_ssize_t m = self.m
cdef Py_ssize_t n = self.n
Expand Down
8 changes: 4 additions & 4 deletions src/sage/doctest/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -1083,7 +1083,7 @@ def cleanup(self, final=True):
sage: from sage.doctest.control import DocTestDefaults, DocTestController
sage: from sage.env import SAGE_SRC
sage: import os
sage: dirname = os.path.join(SAGE_SRC, 'sage', 'rings', 'infinity.py')
sage: dirname = os.path.join(SAGE_SRC, 'sage', 'rings', 'all.py')
sage: DD = DocTestDefaults()

sage: DC = DocTestController(DD, [dirname])
Expand All @@ -1097,7 +1097,7 @@ def cleanup(self, final=True):
sage: DC.run()
Running doctests with ID ...
Doctesting 1 file.
sage -t .../rings/infinity.py
sage -t .../rings/all.py
[... tests, ... s]
----------------------------------------------------------------------
All tests passed!
Expand Down Expand Up @@ -1402,10 +1402,10 @@ def run_doctests(module, options=None):

EXAMPLES::

sage: run_doctests(sage.rings.infinity)
sage: run_doctests(sage.rings.all)
Running doctests with ID ...
Doctesting 1 file.
sage -t .../sage/rings/infinity.py
sage -t .../sage/rings/all.py
[... tests, ... s]
----------------------------------------------------------------------
All tests passed!
Expand Down
30 changes: 16 additions & 14 deletions src/sage/dynamics/arithmetic_dynamics/projective_ds.py
Original file line number Diff line number Diff line change
Expand Up @@ -1219,9 +1219,9 @@ def arakelov_zhang_pairing(self, g, **kwds):
sage: f.arakelov_zhang_pairing(g)
0.326954667248466
sage: # Correct value should be = 0.323067...
sage: f.arakelov_zhang_pairing(g, n=9)
sage: f.arakelov_zhang_pairing(g, n=9) # long time
0.323091061918965
sage: _ - 0.323067
sage: _ - 0.323067 # long time
0.0000240619189654789

Also from Prop. 18 of Petsche, Szpiro and Tucker, includes places of bad reduction::
Expand All @@ -1232,11 +1232,13 @@ def arakelov_zhang_pairing(self, g, **kwds):
sage: a = 7/(b - 1)
sage: f = DynamicalSystem_projective([a*y^2 - (a*y - x)^2, y^2])
sage: g = DynamicalSystem_projective([x^2, y^2])
sage: # If all archimedean absolute values of a have modulus > 2,
sage: # then the pairing should be h(a).
sage: f.arakelov_zhang_pairing(g, n=6)

If all archimedean absolute values of a have modulus > 2,
then the pairing should be h(a).::

sage: f.arakelov_zhang_pairing(g, n=6) # long time
1.93846423207664
sage: _ - a.global_height()
sage: _ - a.global_height() # long time
-0.00744591697867292
"""
n = kwds.pop('n', 5)
Expand Down Expand Up @@ -4794,8 +4796,8 @@ def periodic_points(self, n, minimal=True, formal=False, R=None, algorithm='vari

sage: P.<x,y,z> = ProjectiveSpace(ZZ, 2)
sage: f = DynamicalSystem([x^2 - 2*y^2, y^2, z^2])
sage: X = f.periodic_points(2, minimal=False, formal=True, return_scheme=True)
sage: len(X.defining_polynomials())
sage: X = f.periodic_points(2, minimal=False, formal=True, return_scheme=True) # long time
sage: len(X.defining_polynomials()) # long time
19

TESTS::
Expand Down Expand Up @@ -5006,7 +5008,7 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur

sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
sage: f = DynamicalSystem_projective([x^2, z^2, y^2])
sage: f.multiplier_spectra(2, formal=True)
sage: f.multiplier_spectra(2, formal=True) # long time
[
[4 0] [4 0] [4 0] [4 0] [4 0] [4 0] [4 0] [4 0] [0 0] [0 0]
[0 4], [0 0], [0 0], [0 4], [0 4], [0 0], [0 0], [0 4], [0 0], [0 0],
Expand Down Expand Up @@ -5132,15 +5134,15 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur
sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
sage: f = DynamicalSystem_projective([x^2, z^2, y^2])
sage: g = f.change_ring(QQbar)
sage: f.multiplier_spectra(1) == g.multiplier_spectra(1)
sage: f.multiplier_spectra(1) == g.multiplier_spectra(1) # long time
True

::

sage: K.<w> = QuadraticField(5)
sage: P.<x,y,z> = ProjectiveSpace(K, 2)
sage: f = DynamicalSystem_projective([x^2 + w*x*y + y^2, y^2, z^2])
sage: f.multiplier_spectra(1)
sage: f.multiplier_spectra(1) # long time
[
[1.000000000000000? - 1.572302755514847?*I 0]
[1.000000000000000? - 1.572302755514847?*I 0.618033988749895? - 1.757887921270715?*I]
Expand Down Expand Up @@ -7480,8 +7482,8 @@ def conjugating_set(self, other, R=None, num_cpus=2):
sage: f = DynamicalSystem_projective([2*x + 12*y, 11*y+2*z, x+z])
sage: m1 = matrix(L, 3, 3, [1,4,v^2,0,2,1,1,1,1])
sage: g = f.conjugate(m1)
sage: m = f.conjugating_set(g)[0]
sage: f.conjugate(m) == g
sage: m = f.conjugating_set(g)[0] # long time
sage: f.conjugate(m) == g # long time
True

TESTS:
Expand Down Expand Up @@ -8191,7 +8193,7 @@ def potential_good_reduction(self, prime, return_conjugation=False):

sage: P.<x,y> = ProjectiveSpace(QQ, 1)
sage: system = DynamicalSystem_projective([3^5*x^3 + x^2*y - 3^5*x*y^2, -3^5*x^2*y + x*y^2 + 3^5*y^3])
sage: system.potential_good_reduction(3, return_conjugation=True)
sage: system.potential_good_reduction(3, return_conjugation=True) # long time
(False, None, None)

::
Expand Down
6 changes: 3 additions & 3 deletions src/sage/dynamics/complex_dynamics/mandel_julia.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,15 +167,15 @@ def mandelbrot_plot(f=None, **kwds):
sage: B.<c> = CC[]
sage: R.<z> = B[]
sage: f = z^5 + c
sage: mandelbrot_plot(f)
sage: mandelbrot_plot(f) # long time
500x500px 24-bit RGB image

When the polynomial is defined over a multivariate polynomial ring it is
necessary to specify the parameter variable (default parameter is ``c``)::

sage: R.<a,b> = CC[]
sage: f = a^2 + b^3
sage: mandelbrot_plot(f, parameter=b)
sage: mandelbrot_plot(f, parameter=b) # long time
500x500px 24-bit RGB image

Interact functionality is not implemented for general polynomial maps::
Expand Down Expand Up @@ -593,7 +593,7 @@ def julia_plot(f=None, **kwds):

sage: R.<z> = CC[]
sage: f = z^3 - z + 1
sage: julia_plot(f)
sage: julia_plot(f) # long time
500x500px 24-bit RGB image

To display an interactive plot of the Julia set in the Notebook,
Expand Down
4 changes: 2 additions & 2 deletions src/sage/geometry/polyhedron/base6.py
Original file line number Diff line number Diff line change
Expand Up @@ -1596,10 +1596,10 @@ def affine_hull_manifold(self, name=None, latex_name=None, start_index=0, ambien

sage: D = polytopes.dodecahedron() # optional - sage.rings.number_field
sage: E3 = EuclideanSpace(3) # optional - sage.rings.number_field # optional - sage.symbolic
sage: submanifolds = [ # optional - sage.rings.number_field # optional - sage.symbolic
sage: submanifolds = [ # long time # optional - sage.rings.number_field # optional - sage.symbolic
....: F.as_polyhedron().affine_hull_manifold(name=f'F{i}', orthogonal=True, ambient_space=E3)
....: for i, F in enumerate(D.facets())]
sage: sum(FM.plot({}, srange(-2, 2, 0.1), srange(-2, 2, 0.1), opacity=0.2) # not tested # optional - sage.symbolic # optional - sage.plot # optional - sage.rings.number_field
sage: sum(FM.plot({}, srange(-2, 2, 0.1), srange(-2, 2, 0.1), opacity=0.2) # not tested # long time # optional - sage.symbolic # optional - sage.plot # optional - sage.rings.number_field
....: for FM in submanifolds) + D.plot()
Graphics3d Object

Expand Down
2 changes: 1 addition & 1 deletion src/sage/graphs/generators/distance_regular.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -2305,7 +2305,7 @@ def pseudo_partition_graph(int m, int a):
EXAMPLES::

sage: from sage.graphs.generators.distance_regular import *
sage: pseudo_partition_graph(6, 1)
sage: pseudo_partition_graph(6, 1) # long time
Folded Johnson graph with parameters 12,6: Graph on 462 vertices

Not all graphs built with this function are pseudo partition graphs as
Expand Down
2 changes: 1 addition & 1 deletion src/sage/groups/libgap_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,7 @@ def character_table(self):
[ 1 1 -1]
[ 2 -1 0]
[ 1 1 1]
sage: MatrixGroup(SymmetricGroup(5)).character_table()
sage: MatrixGroup(SymmetricGroup(5)).character_table() # long time
[ 1 -1 -1 1 -1 1 1]
[ 4 0 1 -1 -2 1 0]
[ 5 1 -1 0 -1 -1 1]
Expand Down
Loading