From 0f22b6fecf87f03545b03cd4aaac671cdbe0c656 Mon Sep 17 00:00:00 2001 From: bbarros Date: Fri, 25 Aug 2017 17:07:04 -0500 Subject: [PATCH 001/340] 23720: Added mandelbrot_plot support for general polynomials --- .../dynamics/complex_dynamics/mandel_julia.py | 227 +++++++--- .../complex_dynamics/mandel_julia_helper.pyx | 414 ++++++++++++++++-- 2 files changed, 542 insertions(+), 99 deletions(-) diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia.py b/src/sage/dynamics/complex_dynamics/mandel_julia.py index 15249e4a754..b3e0251b8dc 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia.py +++ b/src/sage/dynamics/complex_dynamics/mandel_julia.py @@ -1,16 +1,17 @@ r""" Mandelbrot and Julia sets -Plots the Mandelbrot and Julia sets for the map `Q_c(z)=z^2+c` in the complex +Plots the Mandelbrot and Julia sets for general polynomial maps in the complex plane. -The Mandelbrot set is the set of complex numbers `c` for which the function -`Q_c(z)=z^2+c` does not diverge when iterated from `z = 0`. This set of complex +The Mandelbrot set is the set of complex numbers `c` for which the map +`f_c(z)` does not diverge when iterated from `z = 0`. This set of complex numbers can be visualized by plotting each value for `c` in the complex plane. -The Mandelbrot set is an example of a fractal when plotted in the complex plane. +The Mandelbrot set is often an example of a fractal when plotted in the complex +plane. -The Julia set for a given `c` is the set of complex numbers for which the -function `Q_c(z)=z^2+c` is bounded under iteration. +The Julia set for a given parameter `c` is the set of complex numbers for which +the function `f_c(z)` is bounded under iteration. AUTHORS: @@ -34,7 +35,8 @@ convert_to_pixels, get_line, fast_julia_plot, - julia_helper) + julia_helper, + polynomial_mandelbrot) from sagenb.notebook.interact import (interact, slider, input_box, @@ -49,21 +51,11 @@ from sage.schemes.projective.projective_space import ProjectiveSpace from sage.categories.homset import End from sage.misc.prandom import randint +from sage.calculus.var import var -def mandelbrot_plot(**kwds): +def mandelbrot_plot(f=None, **kwds): r""" - Interactive plot of the Mandelbrot set for the map `Q_c(z) = z^2 + c`. - - ALGORITHM: - - Let each pixel in the image be a point `c \in \mathbb{C}` and define the - map `Q_c(z) = z^2 + c`. If `|Q_{c}^{k}(c)| > 2` for some `k \geq 0`, it - follows that `Q_{c}^{n}(c) \to \infty`. Let `N` be the maximum number of - iterations. Compute the first `N` points on the orbit of `0` under `Q_c`. - If for any `k < N`, `|Q_{c}^{k}(0)| > 2`, we stop the iteration and assign - a color to the point `c` based on how quickly `0` escaped to infinity under - iteration of `Q_c`. If `|Q_{c}^{i}(0)| \leq 2` for all `i \leq N`, we assume - `c` is in the Mandelbrot set and assign the point `c` the color black. + Plot of the Mandelbrot set for a general polynomial map `f_c(z)`. REFERENCE: @@ -71,23 +63,38 @@ def mandelbrot_plot(**kwds): kwds: - - ``x_center`` -- double (optional - default: ``-1.0``), Real part of center point. + - ``f`` -- map (optional - default: ``z^2 + c``), polynomial map used to + plot the Mandelbrot set. + + - ``parameter`` -- variable (optional - default: ``c``), parameter variable + used to plot the Mandelbrot set. + + - ``x_center`` -- double (optional - default: ``-1.0``), Real part of center + point. - - ``y_center`` -- double (optional - default: ``0.0``), Imaginary part of center point. + - ``y_center`` -- double (optional - default: ``0.0``), Imaginary part of + center point. - - ``image_width`` -- double (optional - default: ``4.0``), width of image in the complex plane. + - ``image_width`` -- double (optional - default: ``4.0``), width of image + in the complex plane. - - ``max_iteration`` -- long (optional - default: ``500``), maximum number of iterations the map ``Q_c(z)``. + - ``max_iteration`` -- long (optional - default: ``500``), maximum number of + iterations the map ``Q_c(z)``. - - ``pixel_count`` -- long (optional - default: ``500``), side length of image in number of pixels. + - ``pixel_count`` -- long (optional - default: ``500``), side length of + image in number of pixels. - - ``base_color`` -- RGB color (optional - default: ``[40, 40, 40]``) color used to determine the coloring of set. + - ``base_color`` -- RGB color (optional - default: ``[40, 40, 40]``) color + used to determine the coloring of set. - - ``iteration_level`` -- long (optional - default: 1) number of iterations between each color level. + - ``iteration_level`` -- long (optional - default: 1) number of iterations + between each color level. - - ``number_of_colors`` -- long (optional - default: 30) number of colors used to plot image. + - ``number_of_colors`` -- long (optional - default: 30) number of colors + used to plot image. - - ``interact`` -- boolean (optional - default: ``False``), controls whether plot will have interactive functionality. + - ``interact`` -- boolean (optional - default: ``False``), controls whether + plot will have interactive functionality. OUTPUT: @@ -100,18 +107,14 @@ def mandelbrot_plot(**kwds): sage: mandelbrot_plot() # long time 500x500px 24-bit RGB image - :: - - sage: mandelbrot_plot(pixel_count=1000) # long time - 1000x1000px 24-bit RGB image - :: sage: mandelbrot_plot(x_center=-1.11, y_center=0.2283, image_width=1/128, # long time ....: max_iteration=2000, number_of_colors=500, base_color=[40, 100, 100]) 500x500px 24-bit RGB image - To display an interactive plot of the Mandelbrot set in the Notebook, set ``interact`` to ``True``:: + To display an interactive plot of the Mandelbrot in the Notebook, set + ``interact`` to ``True``. (This is only implemented for ``z^2 + c``):: sage: mandelbrot_plot(interact=True) ... @@ -121,35 +124,130 @@ def mandelbrot_plot(**kwds): sage: mandelbrot_plot(interact=True, x_center=-0.75, y_center=0.25, ....: image_width=1/2, number_of_colors=75) ... - """ - x_center = kwds.pop("x_center", -1.0) + Polynomial maps can be defined over a multivariate polynomial ring or a + univariate polynomial ring tower:: + + sage: R. = CC[] + sage: f = z^2 + c + sage: mandelbrot_plot(f) # not tested + 500x500px 24-bit RGB image + + :: + + sage: B. = CC[] + sage: R. = B[] + sage: f = z^5 + c + sage: mandelbrot_plot(f) # not tested + 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. = CC[] + sage: f = a^2 + b^3 + sage: mandelbrot_plot(f, parameter=b) # not tested + 500x500px 24-bit RGB image + + Interact functionality is not implemented for general polynomial maps:: + + sage: R. = CC[] + sage: f = z^3 + c + sage: mandelbrot_plot(f, interact=True) # not tested + NotImplementedError: Interact only implemented for z^2 + c + """ + parameter = kwds.pop("parameter", None) + x_center = kwds.pop("x_center", 0.0) y_center = kwds.pop("y_center", 0.0) image_width = kwds.pop("image_width", 4.0) - max_iteration = kwds.pop("max_iteration", 500) + max_iteration = kwds.pop("max_iteration", None) pixel_count = kwds.pop("pixel_count", 500) base_color = kwds.pop("base_color", [40, 40, 40]) iteration_level = kwds.pop("iteration_level", 1) number_of_colors = kwds.pop("number_of_colors", 30) interacts = kwds.pop("interact", False) - if interacts: - @interact(layout={'bottom':[['real_center'], ['im_center'], ['width']], - 'top':[['iterations'], ['level_sep'], ['color_num'], ['image_color']]}) - def _(real_center=input_box(x_center, 'Real'), - im_center=input_box(y_center, 'Imaginary'), - width=input_box(image_width, 'Width of Image'), - iterations=input_box(max_iteration, 'Max Number of Iterations'), - level_sep=input_box(iteration_level, 'Iterations between Colors'), - color_num=input_box(number_of_colors, 'Number of Colors'), - image_color=color_selector(default=Color([j/255 for j in base_color]), - label="Image Color", hide_box=True)): - return fast_mandelbrot_plot(real_center, im_center, width, - iterations, pixel_count, level_sep, color_num, image_color).show() + # Check if user specified maximum number of iterations + given_iterations = True + if max_iteration is None: + # Set default to 500 for z^2 + c map + max_iteration = 500 + given_iterations = False + + + if f is None: + # Quadratic map f = z^2 + c + if interacts: + @interact(layout={'bottom':[['real_center'], ['im_center'], ['width']], + 'top':[['iterations'], ['level_sep'], ['color_num'], ['image_color']]}) + def _(real_center=input_box(x_center, 'Real'), + im_center=input_box(y_center, 'Imaginary'), + width=input_box(image_width, 'Width of Image'), + iterations=input_box(max_iteration, 'Max Number of Iterations'), + level_sep=input_box(iteration_level, 'Iterations between Colors'), + color_num=input_box(number_of_colors, 'Number of Colors'), + image_color=color_selector(default=Color([j/255 for j in base_color]), + label="Image Color", hide_box=True)): + return fast_mandelbrot_plot(real_center, im_center, width, + iterations, pixel_count, level_sep, color_num, image_color).show() + + else: + return fast_mandelbrot_plot(x_center, y_center, image_width, + max_iteration, pixel_count, iteration_level, number_of_colors, + base_color) else: - return fast_mandelbrot_plot(x_center, y_center, image_width, max_iteration, - pixel_count, iteration_level, number_of_colors, base_color) + if parameter is None: + c = var('c') + parameter = c + + P = f.parent() + + if P.base() is CC: + gen_list = list(P.gens()) + parameter = gen_list.pop(gen_list.index(parameter)) + variable = gen_list.pop() + + elif P.base().base() is CC: + parameter = P.gen() + variable = P.base().gen() + + else: + raise ValueError + + if f == variable**2 + parameter: + # Quadratic map f = z^2 + c + if interacts: + @interact(layout={'bottom':[['real_center'], ['im_center'], ['width']], + 'top':[['iterations'], ['level_sep'], ['color_num'], ['image_color']]}) + def _(real_center=input_box(x_center, 'Real'), + im_center=input_box(y_center, 'Imaginary'), + width=input_box(image_width, 'Width of Image'), + iterations=input_box(max_iteration, 'Max Number of Iterations'), + level_sep=input_box(iteration_level, 'Iterations between Colors'), + color_num=input_box(number_of_colors, 'Number of Colors'), + image_color=color_selector(default=Color([j/255 for j in base_color]), + label="Image Color", hide_box=True)): + return fast_mandelbrot_plot(real_center, im_center, width, + iterations, pixel_count, level_sep, color_num, image_color).show() + + else: + return fast_mandelbrot_plot(x_center, y_center, image_width, + max_iteration, pixel_count, iteration_level, number_of_colors, + base_color) + else: + if interacts: + raise NotImplementedError("Interact only implemented for z^2 + c") + else: + # Set default of max_iteration to 50 for general polynomial maps + # This prevents the function from being very slow by default + if not given_iterations: + max_iteration = 50 + + # Mandelbrot of General Polynomial Map + return polynomial_mandelbrot(f, parameter, x_center, y_center, \ + image_width, max_iteration, pixel_count, iteration_level, \ + number_of_colors, base_color) def external_ray(theta, **kwds): r""" @@ -168,17 +266,28 @@ def external_ray(theta, **kwds): kwds: - - ``image`` -- 24-bit RGB image (optional - default: None) user specified image of Mandelbrot set. + - ``image`` -- 24-bit RGB image (optional - default: None) user specified + image of Mandelbrot set. - - ``D`` -- long (optional - default: ``25``) depth of the approximation. As ``D`` increases, the external ray gets closer to the boundary of the Mandelbrot set. If the ray doesn't reach the boundary of the Mandelbrot set, increase ``D``. + - ``D`` -- long (optional - default: ``25``) depth of the approximation. + As ``D`` increases, the external ray gets closer to the boundary of the + Mandelbrot set. If the ray doesn't reach the boundary of the Mandelbrot + set, increase ``D``. - - ``S`` -- long (optional - default: ``10``) sharpness of the approximation. Adjusts the number of points used to approximate the external ray (number of points is equal to ``S*D``). If ray looks jagged, increase ``S``. + - ``S`` -- long (optional - default: ``10``) sharpness of the approximation. + Adjusts the number of points used to approximate the external ray (number + of points is equal to ``S*D``). If ray looks jagged, increase ``S``. - - ``R`` -- long (optional - default: ``100``) radial parameter. If ``R`` is large, the external ray reaches sufficiently close to infinity. If ``R`` is too small, Newton's method may not converge to the correct ray. + - ``R`` -- long (optional - default: ``100``) radial parameter. If ``R`` is + large, the external ray reaches sufficiently close to infinity. If ``R`` is + too small, Newton's method may not converge to the correct ray. - - ``prec`` -- long (optional - default: ``300``) specifies the bits of precision used by the Complex Field when using Newton's method to compute points on the external ray. + - ``prec`` -- long (optional - default: ``300``) specifies the bits of + precision used by the Complex Field when using Newton's method to compute + points on the external ray. - - ``ray_color`` -- RGB color (optional - default: ``[255, 255, 255]``) color of the external ray(s). + - ``ray_color`` -- RGB color (optional - default: ``[255, 255, 255]``) color + of the external ray(s). OUTPUT: diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx index 85f1f3e4ef8..75f9dddceea 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +++ b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx @@ -27,22 +27,44 @@ from cysignals.signals cimport sig_check from sage.rings.complex_field import ComplexField from sage.functions.log import exp, log from sage.symbolic.constants import pi - -def fast_mandelbrot_plot(double x_center, double y_center, double image_width, - long max_iteration, long pixel_count, long level_sep, long color_num, base_color): - +from sage.symbolic.relation import solve +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.all import CC +from sage.rings.real_double import RDF +from sage.rings.complex_double import CDF +from sage.functions.other import sqrt +from sage.ext.fast_callable import fast_callable +from sage.calculus.all import symbolic_expression +from sage.calculus.var import var + +cpdef fast_mandelbrot_plot(double x_center, double y_center, + double image_width, long max_iteration, long pixel_count, + long level_sep, long color_num, base_color): r""" Plots the Mandelbrot set in the complex plane for the map `Q_c(z) = z^2 + c`. + ALGORITHM: + + Let each pixel in the image be a point `c \in \mathbb{C}` and define the + map `Q_c(z) = z^2 + c`. If `|Q_{c}^{k}(c)| > 2` for some `k \geq 0`, it + follows that `Q_{c}^{n}(c) \to \infty`. Let `N` be the maximum number of + iterations. Compute the first `N` points on the orbit of `0` under `Q_c`. + If for any `k < N`, `|Q_{c}^{k}(0)| > 2`, we stop the iteration and assign + a color to the point `c` based on how quickly `0` escaped to infinity under + iteration of `Q_c`. If `|Q_{c}^{i}(0)| \leq 2` for all `i \leq N`, we assume + `c` is in the Mandelbrot set and assign the point `c` the color black. + INPUT: - ``x_center`` -- double, real part of the center point in the complex plane. - - ``y_center`` -- double, imaginary part of the center point in the complex plane. + - ``y_center`` -- double, imaginary part of the center point in the complex + plane. - ``image_width`` -- double, width of the image in the complex plane. - - ``max_iteration`` -- long, maximum number of iterations the map `Q_c(z)` considered. + - ``max_iteration`` -- long, maximum number of iterations the map `Q_c(z)` + considered. - ``pixel_count`` -- long, side length of image in number of pixels. @@ -54,7 +76,7 @@ def fast_mandelbrot_plot(double x_center, double y_center, double image_width, OUTPUT: - 24-bit RGB image of the Mandelbrot set in the complex plane + 24-bit RGB image of the Mandelbrot set in the complex plane. EXAMPLES: @@ -71,9 +93,10 @@ def fast_mandelbrot_plot(double x_center, double y_center, double image_width, 500x500px 24-bit RGB image """ - cdef long i, j, col, row, level, color_value, iteration - cdef double k, x_corner, y_corner, step_size, x_coor, y_coor, new_x, new_y - cdef M, pixel, color_list + cdef: + M, pixel, color_list + long i, j, col, row, level, color_value, iteration + double k, x_corner, y_corner, step_size, x_coor, y_coor, new_x, new_y # Make sure image_width is positive image_width = abs(image_width) @@ -144,21 +167,30 @@ cpdef fast_external_ray(double theta, long D=30, long S=10, long R=100, - ``theta`` -- double, angle between 0 and 1 inclusive. - - ``D`` -- long (optional - default: ``25``) depth of the approximation. As ``D`` increases, the external ray gets closer to the boundary of the Mandelbrot set. + - ``D`` -- long (optional - default: ``25``) depth of the approximation. + As ``D`` increases, the external ray gets closer to the boundary of the + Mandelbrot set. - - ``S`` -- long (optional - default: ``10``) sharpness of the approximation. Adjusts the number of points used to approximate the external ray (number of points is equal to ``S*D``). + - ``S`` -- long (optional - default: ``10``) sharpness of the approximation. + Adjusts the number of points used to approximate the external ray (number + of points is equal to ``S*D``). - - ``R`` -- long (optional - default: ``100``) radial parameter. If ``R`` is sufficiently large, the external ray reaches enough close to infinity. + - ``R`` -- long (optional - default: ``100``) radial parameter. If ``R`` is + sufficiently large, the external ray reaches enough close to infinity. - - ``pixel_count`` -- long (optional - default: ``500``) side length of image in number of pixels. + - ``pixel_count`` -- long (optional - default: ``500``) side length of image + in number of pixels. - - ``image_width`` -- double (optional - default: ``4``) width of the image in the complex plane. + - ``image_width`` -- double (optional - default: ``4``) width of the image + in the complex plane. - - ``prec`` -- long (optional - default: ``300``) specifies the bits of precision used by the Complex Field when using Newton's method to compute points on the external ray. + - ``prec`` -- long (optional - default: ``300``) specifies the bits of + precision used by the Complex Field when using Newton's method to compute + points on the external ray. OUTPUT: - List of tuples of Real Interval Field Elements + List of tuples of Real Interval Field Elements. EXAMPLES:: @@ -371,23 +403,32 @@ cpdef fast_julia_plot(double c_real, double c_imag, - ``c_real`` -- double, Real part of `c` value that determines Julia set. - - ``c_imag`` -- double, Imaginary part of `c` value that determines Julia set. + - ``c_imag`` -- double, Imaginary part of `c` value that determines Julia + set. - - ``x_center`` -- double (optional - default: ``0.0``), Real part of center point. + - ``x_center`` -- double (optional - default: ``0.0``), Real part of center + point. - - ``y_center`` -- double (optional - default: ``0.0``), Imaginary part of center point. + - ``y_center`` -- double (optional - default: ``0.0``), Imaginary part of + center point. - - ``image_width`` -- double (optional - default: ``4.0``), width of image in the complex plane. + - ``image_width`` -- double (optional - default: ``4.0``), width of image + in the complex plane. - - ``max_iteration`` -- long (optional - default: ``500``), maximum number of iterations the map ``Q_c(z)``. + - ``max_iteration`` -- long (optional - default: ``500``), maximum number of + iterations the map ``Q_c(z)``. - - ``pixel_count`` -- long (optional - default: ``500``), side length of image in number of pixels. + - ``pixel_count`` -- long (optional - default: ``500``), side length of + image in number of pixels. - - ``level_sep`` -- long (optional - default: ``2``), number of iterations between each color level. + - ``level_sep`` -- long (optional - default: ``2``), number of iterations + between each color level. - - ``color_num`` -- long (optional - default: ``40``), number of colors used to plot image. + - ``color_num`` -- long (optional - default: ``40``), number of colors used + to plot image. - - ``base_color`` -- RGB color (optional - default: ``[50, 50, 50]``), color used to determine the coloring of set. + - ``base_color`` -- RGB color (optional - default: ``[50, 50, 50]``), color + used to determine the coloring of set. OUTPUT: @@ -408,9 +449,10 @@ cpdef fast_julia_plot(double c_real, double c_imag, 500x500px 24-bit RGB image """ - cdef long i, j, col, row, level, color_value, iteration - cdef double k, x_corner, y_corner, step_size, x_coor, y_coor, new_x, new_y - cdef M, pixel, color_list + cdef: + M, pixel, color_list + long i, j, col, row, level, color_value, iteration + double k, x_corner, y_corner, step_size, x_coor, y_coor, new_x, new_y # Make sure image_width is positive image_width = abs(image_width) @@ -477,7 +519,6 @@ cpdef julia_helper(double c_real, double c_imag, double x_center=0, double y_center=0, double image_width=4, long max_iteration=500, long pixel_count=500, long level_sep=2, long color_num=40, base_color=[50, 50, 50], point_color=[255, 0, 0]): - r""" Helper function that returns the image of a Julia set for a given `c` value side by side with the Mandelbrot set with a point denoting @@ -487,25 +528,35 @@ cpdef julia_helper(double c_real, double c_imag, double x_center=0, - ``c_real`` -- double, Real part of `c` value that determines Julia set. - - ``c_imag`` -- double, Imaginary part of `c` value that determines Julia set. + - ``c_imag`` -- double, Imaginary part of `c` value that determines Julia + set. - - ``x_center`` -- double (optional - default: ``0.0``), Real part of center point. + - ``x_center`` -- double (optional - default: ``0.0``), Real part of center + point. - - ``y_center`` -- double (optional - default: ``0.0``), Imaginary part of center point. + - ``y_center`` -- double (optional - default: ``0.0``), Imaginary part of + center point. - - ``image_width`` -- double (optional - default: ``4.0``), width of image in the complex plane. + - ``image_width`` -- double (optional - default: ``4.0``), width of image in + the complex plane. - - ``max_iteration`` -- long (optional - default: ``500``), maximum number of iterations the map ``Q_c(z)``. + - ``max_iteration`` -- long (optional - default: ``500``), maximum number of + iterations the map ``Q_c(z)``. - - ``pixel_count`` -- long (optional - default: ``500``), side length of image in number of pixels. + - ``pixel_count`` -- long (optional - default: ``500``), side length of + image in number of pixels. - - ``level_sep`` -- long (optional - default: ``2``), number of iterations between each color level. + - ``level_sep`` -- long (optional - default: ``2``), number of iterations + between each color level. - - ``color_num`` -- long (optional - default: ``40``), number of colors used to plot image. + - ``color_num`` -- long (optional - default: ``40``), number of colors used + to plot image. - - ``base_color`` -- RGB color (optional - default: ``[50, 50, 50]``), color used to determine the coloring of set. + - ``base_color`` -- RGB color (optional - default: ``[50, 50, 50]``), color + used to determine the coloring of set. - - ``point_color`` -- RGB color (optional - default: ``[255, 0, 0]``), color of the point `c` in the Mandelbrot set. + - ``point_color`` -- RGB color (optional - default: ``[255, 0, 0]``), color + of the point `c` in the Mandelbrot set. OUTPUT: @@ -566,3 +617,286 @@ cpdef julia_helper(double c_real, double c_imag, double x_center=0, Gp[CP[0][0]+pixel_count+1, CP[0][1]+i] = tuple(point_color) return G + +cpdef polynomial_mandelbrot(f, parameter=None, double x_center=0, + double y_center=0, image_width=4, int max_iteration=50, int pixel_count=500, + int level_sep=1, int color_num=30, base_color=[50,50,50]): + r""" + Plots the Mandelbrot set in the complex plane for a general polynomial map. + + INPUT: + + - ``f`` -- polynomial map defined over the multivariate polynomial ring in + z, c over the Complex field. + + - ``parameter`` -- designates which variable is used as the parameter. + If no parameter is provided, ``c`` will be used as the parameter. + + - ``x_center`` -- double, real part of the center point in the complex plane. + + - ``y_center`` -- double, imaginary part of the center point in the complex + plane. + + - ``image_width`` -- double, width of the image in the complex plane. + + - ``max_iteration`` -- long, maximum number of iterations the map `f(z)` + considered. + + - ``pixel_count`` -- long, side length of image in number of pixels. + + - ``level_sep`` -- long, number of iterations between each color level. + + - ``color_num`` -- long, number of colors used to plot image. + + - ``base_color`` -- list, RGB color used to determine the coloring of set. + + OUTPUT: + + 24-bit RGB image of a Mandelbrot set in the complex plane. + + EXAMPLES:: + + sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import polynomial_mandelbrot + sage: R. = CC[] + sage: f = z^5 + c + sage: polynomial_mandelbrot(f, pixel_count=100) + 100x100px 24-bit RGB image + + :: + + sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import polynomial_mandelbrot + sage: B. = CC[] + sage: R. = B[] + sage: f = z^4 - z + c + sage: polynomial_mandelbrot(f, pixel_count=100) + 100x100px 24-bit RGB image + """ + + cdef: + z, c, x, y, w, cr, ci, J, M, S, S2, R, P, phi, t, im, re, a_n, df + pt, c_pts, cp_real, cp_imag, pixel, color_list, critical_pts + f_real, f_imag, f_temp, escape_time, cf_list, cf + int i, j, d, k, col, row, iteration + double C, L, Rad, x_corner, y_corner, x_coor, y_coor, \ + step_size, new_x, new_y + I = CDF.gen() + constant_c = True + + if parameter is None: + c = var('c') + parameter = c + + P = f.parent() + + if P.base() is CC: + gen_list = list(P.gens()) + parameter = gen_list.pop(gen_list.index(parameter)) + variable = gen_list.pop() + + elif P.base().base() is CC: + parameter = P.gen() + variable = P.base().gen() + + else: + return ValueError + + + # Make sure image_width is positive + image_width = abs(image_width) + + # Initialize an image to the color black and access the pixels + M = Image("RGB", (pixel_count,pixel_count), 'black') + pixel = M.pixels() + + # Take the given base color and create a list of evenly spaced + # colors between the given base color and white. The number of + # colors in the list depends on the variable color_num. + if type(base_color) == Color: + # Convert Color to RGB list + base_color = [int(k*255) for k in base_color] + color_list = [] + for i in range(color_num): + sig_check() + color_list.append(copy(base_color)) + for j in range(3): + color_list[i][j] += i * (255 - color_list[i][j]) // color_num + color_list[i] = tuple(color_list[i]) + + # Split function into real and imaginary parts + R = PolynomialRing(CC, [variable,parameter]) + z, c = R.gens() + f = R(f) + S = PolynomialRing(f.base_ring(), 'x,y,J,cr,ci') + x,y,J,cr,ci = S.gens() + S2 = S.quotient_ring(J**2+1) + phi = R.hom([x+y*J, cr+ci*J], S2) + t = phi(f).lift() + im = t.coefficient(J) + re = t - im*J + + f_real = fast_callable(re, vars=[x,y,cr,ci,J], domain=RDF) + f_imag = fast_callable(im, vars=[x,y,cr,ci,J], domain=RDF) + + # Compute critical points + try: + df = f.derivative(z).univariate_polynomial() + critical_pts = df.roots(multiplicities=False) + + except: + constant_c = False + + # If c is in the constant term of the polynomial, then the critical points + # will be independent of c. + if constant_c: + c_pts = [] + for pt in critical_pts: + c_pts.append([pt.real(), pt.imag()]) + + # Calculate escape condition + d = f.degree(z) + cf_list = f.coefficients() + a_n = cf_list.pop(0).abs() + C = 0 + for cf in cf_list: + C += cf.abs() + L = 1.00000000000001 + if d >= 2: + Rad = max(1, 2*C / a_n, (2*L / a_n**(1/(d-1)))) + else: + Rad = max(1, 2*C / a_n) + + # First, we determine the complex coordinates of the point in the top + # left corner of the image. Then, we loop through each pixel in the + # image and assign it complex coordinates relative to the image's top + # left corner. + x_corner = x_center - image_width/2 + y_corner = y_center + image_width/2 + step_size = image_width*1.0 / pixel_count + for col in range(pixel_count): + x_coor = x_corner + col*step_size + for row in range(pixel_count): + sig_check() + y_coor = y_corner - row*step_size + + # Initialize escape_time to be maximum number of iterations. + escape_time = max_iteration + + # Loop though each critical point. If all of the critical + # points are bounded for a particular c value, then c is in + # the mandelbrot set. + for pt in c_pts: + cp_real = pt[0] + cp_imag = pt[1] + + # Iterate the map f using the critical point as the initial + # value. + new_x, new_y = cp_real, cp_imag + iteration = 0 + while new_x**2 + new_y**2 <= Rad**2 and iteration < escape_time: + sig_check() + new_x, new_y = f_real(new_x, new_y, x_coor, y_coor,1), \ + f_imag(new_x, new_y, x_coor, y_coor,1) + iteration += 1 + + # For each point, we take the minimum number of iterations + # over all the critical points and use this minimum to + # color the point. + if iteration < escape_time: + escape_time = iteration + + # If the point escapes to infinity, assign the point a color + # based on how fast it escapes. The more iterations it takes for + # a point to escape to infinity, the lighter its color will be. + # Otherwise, assume the point is in the Mandelbrot set and leave + # it black. + if iteration != max_iteration: + # Assign each point a level based on its number of iterations. + level = iteration // level_sep + # Assign the pixel a color based on it's level. If we run out + # of colors, assign it the last color in the list. + if level < color_num: + pixel[col,row] = color_list[level] + else: + pixel[col,row] = color_list[-1] + + # If the critical points of f depend on c, we must compute the different + # critical points for each c. + else: + # Solve for critical points symbollically. + w = var('w') + df = f.derivative(z).polynomial(z).subs({z:w}) + critical_pts = solve(symbolic_expression(df)==0, w) + c_pts = [] + for pt in critical_pts: + c_pts.append(fast_callable(pt.rhs(), vars=[c], domain=CDF)) + + # Calculate degree of f + d = f.degree(z) + + # First, we determine the complex coordinates of the point in the top + # left corner of the image. Then, we loop through each pixel in the + # image and assign it complex coordinates relative to the image's top + # left corner. + x_corner = x_center - image_width/2 + y_corner = y_center + image_width/2 + step_size = image_width*1.0 / pixel_count + for col in range(pixel_count): + x_coor = x_corner + col*step_size + for row in range(pixel_count): + + sig_check() + y_coor = y_corner - row*step_size + + # Initialize escape time to be maximum number of iterations + escape_time = max_iteration + + # Calculate escape condition for each c value + f_temp = f.subs({c:x_coor+y_coor*I}) + cf_list = f_temp.coefficients() + a_n = cf_list.pop(0).abs() + C = 0 + for cf in cf_list: + C += cf.abs() + L = 1.00000000000001 + if d >= 2: + Rad = max(1, 2*C / a_n, (2*L / a_n**(1/(d-1)))) + else: + Rad = max(1, 2*C / a_n) + + for f_cp in c_pts: + + # Compute real and imaginary critical point + cp_real = f_cp(x_coor + y_coor*I).real() + cp_imag = f_cp(x_coor + y_coor*I).imag() + + # Iterate the map f using the critical point as the initial + # value. + new_x, new_y = cp_real, cp_imag + iteration = 0 + while new_x**2 + new_y**2 <= Rad**2 and iteration < escape_time: + sig_check() + new_x, new_y = f_real(new_x, new_y, x_coor, y_coor,1), \ + f_imag(new_x, new_y, x_coor, y_coor,1) + iteration += 1 + + # For each point, we take the minimum number of iterations + # over all the critical points and use this minimum to + # color the point. + if iteration < escape_time: + escape_time = iteration + + # If the point escapes to infinity, assign the point a color + # based on how fast it escapes. The more iterations it takes for + # a point to escape to infinity, the lighter its color will be. + # Otherwise, assume the point is in the Mandelbrot set and leave + # it black. + if iteration != max_iteration: + # Assign each point a level based on its number of iterations. + level = iteration // level_sep + # Assign the pixel a color based on it's level. If we run out + # of colors, assign it the last color in the list. + if level < color_num: + pixel[col,row] = color_list[level] + else: + pixel[col,row] = color_list[-1] + return M From c141f070ac00807dd11e098f3c4a8f2e9c8bd028 Mon Sep 17 00:00:00 2001 From: bbarros Date: Fri, 25 Aug 2017 20:18:02 -0500 Subject: [PATCH 002/340] 23720: Fixed bug in external_ray function --- src/sage/dynamics/complex_dynamics/mandel_julia.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia.py b/src/sage/dynamics/complex_dynamics/mandel_julia.py index b3e0251b8dc..801d56c6f84 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia.py +++ b/src/sage/dynamics/complex_dynamics/mandel_julia.py @@ -346,7 +346,7 @@ def external_ray(theta, **kwds): ray_color = kwds.get("ray_color", [255]*3) image = kwds.get("image", None) if image is None: - image = mandelbrot_plot(**kwds) + image = mandelbrot_plot(x_center=x_0, **kwds) # Make a copy of the bitmap image. # M = copy(image) From 70f3b587a494c72ee062a559ea853367496ed553 Mon Sep 17 00:00:00 2001 From: bbarros Date: Mon, 28 Aug 2017 16:27:30 -0500 Subject: [PATCH 003/340] 23740: Added helper function for plotting of Julia sets for polynomials --- .../dynamics/complex_dynamics/mandel_julia.py | 2 + .../complex_dynamics/mandel_julia_helper.pyx | 92 +++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia.py b/src/sage/dynamics/complex_dynamics/mandel_julia.py index 801d56c6f84..98f681bfce4 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia.py +++ b/src/sage/dynamics/complex_dynamics/mandel_julia.py @@ -395,6 +395,8 @@ def external_ray(theta, **kwds): pixel[int(k[0]), int(k[1])] = tuple(ray_color) return M +#TODO: Update julia_plot to work for general polynomials. + def julia_plot(c=-1, **kwds): r""" Plots the Julia set of a given complex `c` value. Users can specify whether diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx index 75f9dddceea..4960e764ebb 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +++ b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx @@ -900,3 +900,95 @@ cpdef polynomial_mandelbrot(f, parameter=None, double x_center=0, else: pixel[col,row] = color_list[-1] return M + +cpdef general_julia(f, double x_center=0, double y_center=0, image_width=4, + int max_iteration=50, int pixel_count=500, int level_sep=1, int color_num=30, + base_color=[50,50,50]): + r""" + Plots Julia sets for General Polynomials + TODO: Add documentation + """ + + cdef: + M, pixel, color_list, R, z, S, x, y, S2, phi, t, im, re, a_n, df, + critical_pts, f_real, f_imag, J + int i, j, d, k, col, row, iteration, ii + double C, L, Rad, x_corner, y_corner, x_coor, y_coor, step_size, new_x, new_y + I = CDF.gen() + + # Make sure image_width is positive + image_width = abs(image_width) + + # Initialize an image to the color black and access the pixels + M = Image("RGB", (pixel_count,pixel_count), 'black') + pixel = M.pixels() + + # Take the given base color and create a list of evenly spaced + # colors between the given base color and white. The number of + # colors in the list depends on the variable color_num. + if type(base_color) == Color: + # Convert Color to RGB list + base_color = [int(k*255) for k in base_color] + color_list = [] + for i in range(color_num): + sig_check() + color_list.append(copy(base_color)) + for j in range(3): + color_list[i][j] += i * (255 - color_list[i][j]) // color_num + color_list[i] = tuple(color_list[i]) + + z = f.variables()[0] + f_fast = fast_callable(f, vars=[z], domain=CDF) + + # Calculate escape condition for each c value + d = f.degree(z) + cf_list = f.coefficients(sparse=False) + a_n = cf_list.pop(-1).abs() + C = 0 + for cf in cf_list: + C += cf.abs() + L = 1.00000000000001 + if d >= 2: + Rad = max(1, 2*C / a_n, (2*L / a_n**(1/(d-1)))) + else: + Rad = max(1, 2*C / a_n) + + # First, we determine the complex coordinates of the point in the top left + # corner of the image. Then, we loop through each pixel in the image and + # assign it complex coordinates relative to the image's top left corner. + x_corner = x_center - image_width/2 + y_corner = y_center + image_width/2 + step_size = image_width*1.0 / pixel_count + for col in range(pixel_count): + x_coor = x_corner + col*step_size + for row in range(pixel_count): + sig_check() + y_coor = y_corner - row*step_size + + # We compute the orbit of c under the map f + # until we either reach the maximum number of iterations + # or find a point in the orbit with modulus greater than + # some the escape condition (Rad) + + new_z = x_coor + y_coor*I + iteration = 0 + while new_z.abs() <= Rad**2 and iteration < max_iteration: + sig_check() + new_z = f_fast(new_z) + iteration += 1 + + # If the point escapes to infinity, assign the point a color + # based on how fast it escapes. The more iterations it takes for + # a point to escape to infinity, the lighter its color will be. + # Otherwise, assume the point is in the Mandelbrot set and leave + # it black. + if iteration != max_iteration: + # Assign each point a level based on its number of iterations. + level = iteration // level_sep + # Assign the pixel a color based on it's level. If we run out + # of colors, assign it the last color in the list. + if level < color_num: + pixel[col,row] = color_list[level] + else: + pixel[col,row] = color_list[-1] + return M From 1d8a9b63c1b5671904ff9a92684980b9bdf511bd Mon Sep 17 00:00:00 2001 From: Adam Towsley Date: Sat, 9 Sep 2017 11:27:25 -0500 Subject: [PATCH 004/340] 23813 Implemented matrix actions on scheme morphisms --- .../dynamics/arithmetic_dynamics/affine_ds.py | 49 +++++++ .../arithmetic_dynamics/projective_ds.py | 7 + src/sage/matrix/action.pxd | 5 + src/sage/matrix/action.pyx | 120 +++++++++++++++++- src/sage/matrix/matrix_space.py | 6 + .../schemes/projective/projective_morphism.py | 88 +++++++++++++ 6 files changed, 273 insertions(+), 2 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/affine_ds.py b/src/sage/dynamics/arithmetic_dynamics/affine_ds.py index 2f720113129..11d5b981f37 100644 --- a/src/sage/dynamics/arithmetic_dynamics/affine_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/affine_ds.py @@ -791,6 +791,55 @@ def multiplier(self, P, n, check=True): Q = R return l + def conjugate(self, M): + r""" + Conjugate this dynamical system by ``M``, i.e. `M^{-1} \circ f \circ M`. + + If possible the new map will be defined over the same space. + Otherwise, will try to coerce to the base ring of ``M``. + + INPUT: + + - ``M`` -- a square invertible matrix + + OUTPUT: + + An affine dynamical system + + Examples:: + + sage: A. = AffineSpace(QQ, 1) + sage: f = DynamicalSystem_affine([x^2+1]) + sage: f.conjugate(matrix([[1,2], [0,1]])) + Dynamical System of Affine Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x) to + (x^2 + 4*x + 3) + + :: + + sage: A. = AffineSpace(ZZ,2) + sage: f = DynamicalSystem_affine([x^3+y^3,y^2]) + sage: f.conjugate(matrix([[1,2,3], [0,1,2], [0,0,1]])) + Dynamical System of Affine Space of dimension 2 over Integer Ring + Defn: Defined on coordinates by sending (x, y) to + (x^3 + 6*x^2*y + 12*x*y^2 + 9*y^3 + 9*x^2 + 36*x*y + 40*y^2 + 27*x + 58*y + 28, y^2 + 4*y + 2) + + :: + + sage: R. = PolynomialRing(QQ) + sage: K. = NumberField(x^2+1) + sage: A. = AffineSpace(ZZ,1) + sage: f = DynamicalSystem_affine([x^3+2*x^2+3]) + sage: f.conjugate(matrix([[i,i], [0,-i]])) + Dynamical System of Affine Space of dimension 1 over Integer Ring + Defn: Defined on coordinates by sending (x) to + (x^3 + x^2 - x - 5) + + """ + d = self.codomain().ngens() + f = self.homogenize(d).conjugate(M) + return f.dehomogenize(d) + class DynamicalSystem_affine_field(DynamicalSystem_affine, SchemeMorphism_polynomial_affine_space_field): @cached_method diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 99599ac5a32..e1c4cb76fa0 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -1511,6 +1511,13 @@ def conjugate(self, M): Dynamical System of Projective Space of dimension 1 over Number Field in i with defining polynomial x^2 + 1 Defn: Defined on coordinates by sending (x : y) to ((1/3*i)*x^2 + (1/2*i)*y^2 : (-i)*y^2) + + .. TODO:: + + Use the left and right action functionality to replace the code below with + #return DynamicalSystem_projective(M.inverse()*self*M, domain=self.codomain()) + once there is a function to pass to the smallest field of definition. + """ if not (M.is_square() == 1 and M.determinant() != 0 and M.ncols() == self.domain().ambient_space().dimension_relative() + 1): diff --git a/src/sage/matrix/action.pxd b/src/sage/matrix/action.pxd index 1c6905e3d30..a438807a4b4 100644 --- a/src/sage/matrix/action.pxd +++ b/src/sage/matrix/action.pxd @@ -15,3 +15,8 @@ cdef class MatrixVectorAction(MatrixMulAction): cdef class VectorMatrixAction(MatrixMulAction): pass +cdef class MatrixPolymapAction(MatrixMulAction): + pass + +cdef class PolymapMatrixAction(MatrixMulAction): + pass \ No newline at end of file diff --git a/src/sage/matrix/action.pyx b/src/sage/matrix/action.pyx index 76131fae1e6..b2bf0baba3e 100644 --- a/src/sage/matrix/action.pyx +++ b/src/sage/matrix/action.pyx @@ -78,8 +78,10 @@ cdef class MatrixMulAction(Action): base = G.base_ring() Action.__init__(self, G, S, is_left, operator.mul) self._codomain = self._create_codomain(base) - self.fix_sparseness = G.is_sparse() != S.is_sparse() - + try: + self.fix_sparseness = G.is_sparse() != S.is_sparse() + except AttributeError: + pass def codomain(self): return self._codomain @@ -355,3 +357,117 @@ cdef class VectorMatrixAction(MatrixMulAction): v = v.dense_vector() return (A)._vector_times_matrix_(v) # v * A +cdef class MatrixPolymapAction(MatrixMulAction): + def __init__(self, G, S): + """ + Examples:: + sage: from sage.matrix.action import MatrixPolymapAction + sage: M = MatrixSpace(QQ,2,2) + sage: P. = ProjectiveSpace(QQ,1) + sage: H = Hom(P,P) + sage: A = MatrixPolymapAction(M,H) + sage: A + Left action by Full MatrixSpace of 2 by 2 dense matrices over Rational + Field on Set of morphisms + From: Projective Space of dimension 1 over Rational Field + To: Projective Space of dimension 1 over Rational Field + """ + from sage.schemes.generic.homset import SchemeHomset_generic + if not isinstance(S,SchemeHomset_generic): + raise TypeError("not a scheme polynomial morphism: %s"% S) + MatrixMulAction.__init__(self, G, S, True) + + def _create_codomain(self,base): + """ + Examples:: + + sage: from sage.matrix.action import MatrixPolymapAction + sage: M = MatrixSpace(QQ,2,2) + sage: P. = ProjectiveSpace(QQ,1) + sage: H = Hom(P,P) + sage: A = MatrixPolymapAction(M,H) + sage: A.codomain() + Set of morphisms + From: Projective Space of dimension 1 over Rational Field + To: Projective Space of dimension 1 over Rational Field + """ + from sage.categories.homset import Hom + return Hom(self.underlying_set().domain().change_ring(base),self.underlying_set().codomain().change_ring(base)) + + cpdef _call_(self, mat, f): + """ + Examples:: + + sage: from sage.matrix.action import MatrixPolymapAction + sage: M = MatrixSpace(QQ, 2, 2) + sage: P. = ProjectiveSpace(QQ, 1) + sage: H = Hom(P, P) + sage: f = H([x^2 + y^2, y^2]) + sage: A = MatrixPolymapAction(M, H) + sage: m = matrix([[1,1], [0,1]]) + sage: A._call_(m, f) + Scheme morphism: + From: Projective Space of dimension 1 over Rational Field + To: Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (x^2 + 2*y^2 : y^2) + """ + return f._matrix_times_polymap_(mat, self._codomain) + +cdef class PolymapMatrixAction(MatrixMulAction): + def __init__(self, G, S): + """ + Examples:: + + sage: from sage.matrix.action import PolymapMatrixAction + sage: M = MatrixSpace(QQ,2,2) + sage: P. = ProjectiveSpace(QQ,1) + sage: H = Hom(P,P) + sage: A = PolymapMatrixAction(M,H) + sage: A + Right action by Full MatrixSpace of 2 by 2 dense matrices over Rational + Field on Set of morphisms + From: Projective Space of dimension 1 over Rational Field + To: Projective Space of dimension 1 over Rational Field + """ + from sage.schemes.generic.homset import SchemeHomset_generic + if not isinstance(S,SchemeHomset_generic): + raise TypeError("not a scheme polynomial morphism: %s"% S) + MatrixMulAction.__init__(self, G, S, False ) + + def _create_codomain(self,base): + """ + Examples:: + + sage: from sage.matrix.action import PolymapMatrixAction + sage: M = MatrixSpace(QQ,2,2) + sage: P. = ProjectiveSpace(QQ,1) + sage: H = Hom(P,P) + sage: A = PolymapMatrixAction(M,H) + sage: A.codomain() + Set of morphisms + From: Projective Space of dimension 1 over Rational Field + To: Projective Space of dimension 1 over Rational Field + """ + from sage.categories.homset import Hom + return Hom(self.underlying_set().domain().change_ring(base),self.underlying_set().codomain().change_ring(base)) + + cpdef _call_(self, f, mat): + """ + Examples:: + + sage: from sage.matrix.action import PolymapMatrixAction + sage: M = MatrixSpace(QQ, 2, 2) + sage: P. = ProjectiveSpace(QQ, 1) + sage: H = Hom(P, P) + sage: f = H([x^2 + y^2, y^2]) + sage: A = PolymapMatrixAction(M, H) + sage: m = matrix([[1,1], [0,1]]) + sage: A._call_(f, m) + Scheme morphism: + From: Projective Space of dimension 1 over Rational Field + To: Projective Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x : y) to + (x^2 + 2*x*y + 2*y^2 : y^2) + """ + return f._polymap_times_matrix_(mat, self._codomain) \ No newline at end of file diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index 4c37d6cf1bb..f8285fe227b 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -617,6 +617,8 @@ def construction(self): def get_action_impl(self, S, op, self_on_left): try: + from sage.schemes.generic.algebraic_scheme import AlgebraicScheme + from sage.schemes.generic.homset import SchemeHomset_generic if op is operator.mul: from . import action as matrix_action if self_on_left: @@ -624,12 +626,16 @@ def get_action_impl(self, S, op, self_on_left): return matrix_action.MatrixMatrixAction(self, S) elif sage.modules.free_module.is_FreeModule(S): return matrix_action.MatrixVectorAction(self, S) + elif isinstance(S,SchemeHomset_generic): + return matrix_action.MatrixPolymapAction(self, S) else: # action of base ring return sage.structure.coerce.RightModuleAction(S, self) else: if sage.modules.free_module.is_FreeModule(S): return matrix_action.VectorMatrixAction(self, S) + elif isinstance(S,SchemeHomset_generic): + return matrix_action.PolymapMatrixAction(self, S) else: # action of base ring return sage.structure.coerce.LeftModuleAction(S, self) diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index 816c0267e5e..b1cc8860f35 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -510,6 +510,94 @@ def __ne__(self, right): return True return False + def _matrix_times_polymap_(self, mat, h): + """ + Multiplies the morphism on the left by a matrix ``mat``. + + INPUT: + + - ``mat`` -- a matrix + + OUTPUT: a scheme morphism given by ``self*mat`` + + EXAMPLES:: + + sage: P. = ProjectiveSpace(ZZ, 1) + sage: H = Hom(P,P) + sage: f = H([x^2 + y^2, y^2]) + sage: matrix([[1,2], [0,1]]) * f + Scheme morphism: + From: Projective Space of dimension 1 over Integer Ring + To: Projective Space of dimension 1 over Integer Ring + Defn: Defined on coordinates by sending (x : y) to + (x^2 + 3*y^2 : y^2) + + :: + + sage: R. = PolynomialRing(QQ) + sage: K. = NumberField(x^2+1) + sage: P. = ProjectiveSpace(QQ, 1) + sage: H = Hom(P,P) + sage: f = H([1/3*x^2 + 1/2*y^2, y^2]) + sage: matrix([[i,0], [0,i]]) * f + Scheme morphism: + From: Projective Space of dimension 1 over Number Field in i with defining polynomial x^2 + 1 + To: Projective Space of dimension 1 over Number Field in i with defining polynomial x^2 + 1 + Defn: Defined on coordinates by sending (x : y) to + ((1/3*i)*x^2 + (1/2*i)*y^2 : (i)*y^2) + + """ + from sage.modules.free_module_element import vector + if mat.ncols() != len(vector(self)): + raise ValueError("matrix size is incompatible") + F = mat * vector(list(self)) + return(h(list(F))) + + def _polymap_times_matrix_(self, mat, h): + """ + Multiplies the morphism on the right by a matrix ``mat``. + + INPUT: + + - ``mat`` -- a matrix + + OUTPUT: a scheme morphism given by ``mat*self`` + + EXAMPLES:: + + sage: P. = ProjectiveSpace(ZZ, 1) + sage: H = Hom(P, P) + sage: f = H([x^2 + y^2, y^2]) + sage: f * matrix([[1,2], [0,1]]) + Scheme morphism: + From: Projective Space of dimension 1 over Integer Ring + To: Projective Space of dimension 1 over Integer Ring + Defn: Defined on coordinates by sending (x : y) to + (x^2 + 4*x*y + 5*y^2 : y^2) + + :: + + sage: R. = PolynomialRing(QQ) + sage: K. = NumberField(x^2+1) + sage: P. = ProjectiveSpace(QQ, 1) + sage: H = Hom(P,P) + sage: f = H([1/3*x^2 + 1/2*y^2, y^2]) + sage: f * matrix([[i,0], [0,i]]) + Scheme morphism: + From: Projective Space of dimension 1 over Number Field in i with defining polynomial x^2 + 1 + To: Projective Space of dimension 1 over Number Field in i with defining polynomial x^2 + 1 + Defn: Defined on coordinates by sending (x : y) to + (-1/3*x^2 - 1/2*y^2 : -y^2) + + """ + from sage.modules.free_module_element import vector + if mat.nrows() != len(vector(self)): + raise ValueError("matrix size is incompatible") + X = mat * vector(self[0].parent().gens()) + F = vector(self._polys) + F = F(list(X)) + return(h(list(F))) + def as_dynamical_system(self): """ Return this endomorpism as a :class:`DynamicalSystem_projective`. From 52c966ffaab05c800011763772f3a0675ed3e50e Mon Sep 17 00:00:00 2001 From: Adam Towsley Date: Sat, 9 Sep 2017 14:11:36 -0500 Subject: [PATCH 005/340] 23813 Fixes from review by bhutz --- src/sage/matrix/action.pyx | 77 +++++++++++-------- src/sage/matrix/matrix_space.py | 4 +- .../schemes/projective/projective_morphism.py | 36 ++++----- 3 files changed, 65 insertions(+), 52 deletions(-) diff --git a/src/sage/matrix/action.pyx b/src/sage/matrix/action.pyx index b2bf0baba3e..27e37ddfefc 100644 --- a/src/sage/matrix/action.pyx +++ b/src/sage/matrix/action.pyx @@ -66,22 +66,28 @@ import operator from .matrix_space import MatrixSpace, is_MatrixSpace from sage.modules.free_module import FreeModule, is_FreeModule from sage.structure.element cimport coercion_model +from sage.categories.homset import Hom, End +from sage.schemes.generic.homset import SchemeHomset_generic cdef class MatrixMulAction(Action): def __init__(self, G, S, is_left): if not is_MatrixSpace(G): raise TypeError("Not a matrix space: %s" % G) - if G.base_ring() is not S.base_ring(): - base = coercion_model.common_parent(G.base_ring(), S.base_ring()) + if isinstance(S, SchemeHomset_generic): + if G.base_ring() is not S.domain().base_ring(): + base = coercion_model.common_parent(G.base_ring(), S.domain().base_ring()) + else: + base = G.base_ring() else: - base = G.base_ring() + if G.base_ring() is not S.base_ring(): + base = coercion_model.common_parent(G.base_ring(), S.base_ring()) + else: + base = G.base_ring() + self.fix_sparseness = G.is_sparse() != S.is_sparse() Action.__init__(self, G, S, is_left, operator.mul) self._codomain = self._create_codomain(base) - try: - self.fix_sparseness = G.is_sparse() != S.is_sparse() - except AttributeError: - pass + def codomain(self): return self._codomain @@ -360,7 +366,8 @@ cdef class VectorMatrixAction(MatrixMulAction): cdef class MatrixPolymapAction(MatrixMulAction): def __init__(self, G, S): """ - Examples:: + EXAMPLES:: + sage: from sage.matrix.action import MatrixPolymapAction sage: M = MatrixSpace(QQ,2,2) sage: P. = ProjectiveSpace(QQ,1) @@ -372,31 +379,33 @@ cdef class MatrixPolymapAction(MatrixMulAction): From: Projective Space of dimension 1 over Rational Field To: Projective Space of dimension 1 over Rational Field """ - from sage.schemes.generic.homset import SchemeHomset_generic - if not isinstance(S,SchemeHomset_generic): + if not isinstance(S, SchemeHomset_generic): raise TypeError("not a scheme polynomial morphism: %s"% S) MatrixMulAction.__init__(self, G, S, True) - def _create_codomain(self,base): + def _create_codomain(self, base): """ - Examples:: + EXAMPLES:: sage: from sage.matrix.action import MatrixPolymapAction sage: M = MatrixSpace(QQ,2,2) sage: P. = ProjectiveSpace(QQ,1) - sage: H = Hom(P,P) + sage: H = End(P) sage: A = MatrixPolymapAction(M,H) sage: A.codomain() Set of morphisms From: Projective Space of dimension 1 over Rational Field To: Projective Space of dimension 1 over Rational Field + sage: A.codomain().is_endomorphism_set() + True """ - from sage.categories.homset import Hom - return Hom(self.underlying_set().domain().change_ring(base),self.underlying_set().codomain().change_ring(base)) + if self.underlying_set().is_endomorphism_set(): + return End(self.underlying_set().domain().change_ring(base)) + return Hom(self.underlying_set().domain().change_ring(base), self.underlying_set().codomain().change_ring(base)) cpdef _call_(self, mat, f): """ - Examples:: + EXAMPLES:: sage: from sage.matrix.action import MatrixPolymapAction sage: M = MatrixSpace(QQ, 2, 2) @@ -406,9 +415,7 @@ cdef class MatrixPolymapAction(MatrixMulAction): sage: A = MatrixPolymapAction(M, H) sage: m = matrix([[1,1], [0,1]]) sage: A._call_(m, f) - Scheme morphism: - From: Projective Space of dimension 1 over Rational Field - To: Projective Space of dimension 1 over Rational Field + Scheme endomorphism of Projective Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x : y) to (x^2 + 2*y^2 : y^2) """ @@ -417,7 +424,9 @@ cdef class MatrixPolymapAction(MatrixMulAction): cdef class PolymapMatrixAction(MatrixMulAction): def __init__(self, G, S): """ - Examples:: + Initialize the action. + + EXAMPLES:: sage: from sage.matrix.action import PolymapMatrixAction sage: M = MatrixSpace(QQ,2,2) @@ -430,31 +439,37 @@ cdef class PolymapMatrixAction(MatrixMulAction): From: Projective Space of dimension 1 over Rational Field To: Projective Space of dimension 1 over Rational Field """ - from sage.schemes.generic.homset import SchemeHomset_generic - if not isinstance(S,SchemeHomset_generic): + if not isinstance(S, SchemeHomset_generic): raise TypeError("not a scheme polynomial morphism: %s"% S) MatrixMulAction.__init__(self, G, S, False ) - def _create_codomain(self,base): + def _create_codomain(self, base): """ - Examples:: + Create the codomain. + + EXAMPLES:: sage: from sage.matrix.action import PolymapMatrixAction sage: M = MatrixSpace(QQ,2,2) sage: P. = ProjectiveSpace(QQ,1) - sage: H = Hom(P,P) + sage: H = End(P) sage: A = PolymapMatrixAction(M,H) sage: A.codomain() Set of morphisms From: Projective Space of dimension 1 over Rational Field To: Projective Space of dimension 1 over Rational Field + sage: A.codomain().is_endomorphism_set() + True """ - from sage.categories.homset import Hom - return Hom(self.underlying_set().domain().change_ring(base),self.underlying_set().codomain().change_ring(base)) + if self.underlying_set().is_endomorphism_set(): + return End(self.underlying_set().domain().change_ring(base)) + return Hom(self.underlying_set().domain().change_ring(base), self.underlying_set().codomain().change_ring(base)) cpdef _call_(self, f, mat): """ - Examples:: + Call the action. + + EXAMPLES:: sage: from sage.matrix.action import PolymapMatrixAction sage: M = MatrixSpace(QQ, 2, 2) @@ -464,10 +479,8 @@ cdef class PolymapMatrixAction(MatrixMulAction): sage: A = PolymapMatrixAction(M, H) sage: m = matrix([[1,1], [0,1]]) sage: A._call_(f, m) - Scheme morphism: - From: Projective Space of dimension 1 over Rational Field - To: Projective Space of dimension 1 over Rational Field + Scheme endomorphism of Projective Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x : y) to (x^2 + 2*x*y + 2*y^2 : y^2) """ - return f._polymap_times_matrix_(mat, self._codomain) \ No newline at end of file + return f._polymap_times_matrix_(mat, self._codomain) diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index f8285fe227b..1b1037a4507 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -626,7 +626,7 @@ def get_action_impl(self, S, op, self_on_left): return matrix_action.MatrixMatrixAction(self, S) elif sage.modules.free_module.is_FreeModule(S): return matrix_action.MatrixVectorAction(self, S) - elif isinstance(S,SchemeHomset_generic): + elif isinstance(S, SchemeHomset_generic): return matrix_action.MatrixPolymapAction(self, S) else: # action of base ring @@ -634,7 +634,7 @@ def get_action_impl(self, S, op, self_on_left): else: if sage.modules.free_module.is_FreeModule(S): return matrix_action.VectorMatrixAction(self, S) - elif isinstance(S,SchemeHomset_generic): + elif isinstance(S, SchemeHomset_generic): return matrix_action.PolymapMatrixAction(self, S) else: # action of base ring diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index b1cc8860f35..9fda97ac9fc 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -526,9 +526,7 @@ def _matrix_times_polymap_(self, mat, h): sage: H = Hom(P,P) sage: f = H([x^2 + y^2, y^2]) sage: matrix([[1,2], [0,1]]) * f - Scheme morphism: - From: Projective Space of dimension 1 over Integer Ring - To: Projective Space of dimension 1 over Integer Ring + Scheme endomorphism of Projective Space of dimension 1 over Integer Ring Defn: Defined on coordinates by sending (x : y) to (x^2 + 3*y^2 : y^2) @@ -540,18 +538,20 @@ def _matrix_times_polymap_(self, mat, h): sage: H = Hom(P,P) sage: f = H([1/3*x^2 + 1/2*y^2, y^2]) sage: matrix([[i,0], [0,i]]) * f - Scheme morphism: - From: Projective Space of dimension 1 over Number Field in i with defining polynomial x^2 + 1 - To: Projective Space of dimension 1 over Number Field in i with defining polynomial x^2 + 1 + Scheme endomorphism of Projective Space of dimension 1 over Number Field in i with defining polynomial x^2 + 1 Defn: Defined on coordinates by sending (x : y) to ((1/3*i)*x^2 + (1/2*i)*y^2 : (i)*y^2) - """ from sage.modules.free_module_element import vector - if mat.ncols() != len(vector(self)): + from sage.dynamics.arithmetic_dynamics.generic_ds import DynamicalSystem + if not mat.is_square(): + raise ValueError("matrix must be square") + if mat.ncols() != self.codomain().ngens(): raise ValueError("matrix size is incompatible") F = mat * vector(list(self)) - return(h(list(F))) + if isinstance(self, DynamicalSystem): + return h(list(F)).as_dynamical_system() + return h(list(F)) def _polymap_times_matrix_(self, mat, h): """ @@ -569,9 +569,7 @@ def _polymap_times_matrix_(self, mat, h): sage: H = Hom(P, P) sage: f = H([x^2 + y^2, y^2]) sage: f * matrix([[1,2], [0,1]]) - Scheme morphism: - From: Projective Space of dimension 1 over Integer Ring - To: Projective Space of dimension 1 over Integer Ring + Scheme endomorphism of Projective Space of dimension 1 over Integer Ring Defn: Defined on coordinates by sending (x : y) to (x^2 + 4*x*y + 5*y^2 : y^2) @@ -583,20 +581,22 @@ def _polymap_times_matrix_(self, mat, h): sage: H = Hom(P,P) sage: f = H([1/3*x^2 + 1/2*y^2, y^2]) sage: f * matrix([[i,0], [0,i]]) - Scheme morphism: - From: Projective Space of dimension 1 over Number Field in i with defining polynomial x^2 + 1 - To: Projective Space of dimension 1 over Number Field in i with defining polynomial x^2 + 1 + Scheme endomorphism of Projective Space of dimension 1 over Number Field in i with defining polynomial x^2 + 1 Defn: Defined on coordinates by sending (x : y) to (-1/3*x^2 - 1/2*y^2 : -y^2) - """ from sage.modules.free_module_element import vector - if mat.nrows() != len(vector(self)): + from sage.dynamics.arithmetic_dynamics.generic_ds import DynamicalSystem + if not mat.is_square(): + raise ValueError("matrix must be square") + if mat.nrows() != self.domain().ngens(): raise ValueError("matrix size is incompatible") X = mat * vector(self[0].parent().gens()) F = vector(self._polys) F = F(list(X)) - return(h(list(F))) + if isinstance(self, DynamicalSystem): + return h(list(F)).as_dynamical_system() + return h(list(F)) def as_dynamical_system(self): """ From 4eefffc45543cec5625c8063b78110dc50ba6d21 Mon Sep 17 00:00:00 2001 From: Adam Towsley Date: Sat, 9 Sep 2017 15:50:40 -0500 Subject: [PATCH 006/340] 23813 Added matrix actions for affine morphisms --- src/sage/schemes/affine/affine_morphism.py | 80 ++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/src/sage/schemes/affine/affine_morphism.py b/src/sage/schemes/affine/affine_morphism.py index 204f0ab145e..d6d0767d154 100644 --- a/src/sage/schemes/affine/affine_morphism.py +++ b/src/sage/schemes/affine/affine_morphism.py @@ -797,6 +797,86 @@ def multiplier(self, P, n, check=True): deprecation(23479, "use sage.dynamics.arithmetic_dynamics.affine_ds.multiplier instead") return self.as_dynamical_system().multiplier(P, n, check) + def _matrix_times_polymap_(self, mat, h): + """ + Multiplies the morphism on the left by a matrix ``mat``. + + INPUT: + + - ``mat`` -- a matrix + + OUTPUT: a scheme morphism given by ``self*mat`` + + EXAMPLES:: + + sage: A. = AffineSpace(ZZ, 1) + sage: H = Hom(A, A) + sage: f = H([x^2 + 1]) + sage: matrix([[1,2], [0,1]]) * f + Scheme endomorphism of Affine Space of dimension 1 over Integer Ring + Defn: Defined on coordinates by sending (x) to + (x^2 + 3) + + :: + + sage: A1 = AffineSpace(ZZ,1) + sage: A2 = AffineSpace(ZZ,2) + sage: H = Hom(A1, A2) + sage: f = H([x^2+1,x^2-1]) + sage: matrix([[1,2,3], [0,1,2], [0,0,1]]) * f + Scheme morphism: + From: Affine Space of dimension 1 over Integer Ring + To: Affine Space of dimension 2 over Integer Ring + Defn: Defined on coordinates by sending (x) to + (3*x^2 + 2, x^2 + 1) + """ + if self.is_endomorphism(): + d = self.domain().ngens() + else: + d = (self.domain().ngens(),self.codomain().ngens()) + f = mat*self.homogenize(d) + return f.dehomogenize(d) + + def _polymap_times_matrix_(self, mat, h): + """ + Multiplies the morphism on the right by a matrix ``mat``. + + INPUT: + + - ``mat`` -- a matrix + + OUTPUT: a scheme morphism given by ``mat*self`` + + EXAMPLES:: + + sage: A. = AffineSpace(ZZ, 1) + sage: H = Hom(A, A) + sage: f = H([x^2 + 1]) + sage: f * matrix([[1,2], [0,1]]) + Scheme endomorphism of Affine Space of dimension 1 over Integer Ring + Defn: Defined on coordinates by sending (x) to + (x^2 + 4*x + 5) + + :: + + sage: A1 = AffineSpace(ZZ,1) + sage: A2 = AffineSpace(ZZ,2) + sage: H = Hom(A1, A2) + sage: f = H([x^2+1,x^2-1]) + sage: f * matrix([[1,2], [0,1]]) + Scheme morphism: + From: Affine Space of dimension 1 over Integer Ring + To: Affine Space of dimension 2 over Integer Ring + Defn: Defined on coordinates by sending (x) to + (x^2 + 4*x + 5, x^2 + 4*x + 3) + """ + if self.is_endomorphism(): + d = self.domain().ngens() + else: + d = (self.domain().ngens(),self.codomain().ngens()) + f = self.homogenize(d)*mat + return f.dehomogenize(d) + class SchemeMorphism_polynomial_affine_space_field(SchemeMorphism_polynomial_affine_space): @cached_method From 86ab06aeee2ad614da02d28e8ba7f49c5b7e2fe7 Mon Sep 17 00:00:00 2001 From: Adam Towsley Date: Sat, 9 Sep 2017 16:23:45 -0500 Subject: [PATCH 007/340] 23813 fixed dehomogenize --- src/sage/schemes/projective/projective_morphism.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index 9fda97ac9fc..37ccfa4e410 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -1026,7 +1026,7 @@ def dehomogenize(self, n): else: Aff_domain = PS_domain.affine_patch(ind[0]) S = Aff_domain.ambient_space().coordinate_ring() - N = A_domain.dimension_relative() + N = self.codomain().ambient_space().dimension_relative() R = A_domain.coordinate_ring() phi = R.hom([S.gen(j) for j in range(0, ind[0])] + [1] + [S.gen(j) for j in range(ind[0], N)], S) F = [] From 3ebecc9f11cca4837f69839f43b5d9d2fd8c342e Mon Sep 17 00:00:00 2001 From: Adam Towsley Date: Sat, 9 Sep 2017 16:40:05 -0500 Subject: [PATCH 008/340] 23813 Added examples, fixed dehomogenize again. --- src/sage/schemes/affine/affine_morphism.py | 14 ++++++++++++++ .../schemes/projective/projective_morphism.py | 16 +++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/sage/schemes/affine/affine_morphism.py b/src/sage/schemes/affine/affine_morphism.py index d6d0767d154..d4d161e1d0e 100644 --- a/src/sage/schemes/affine/affine_morphism.py +++ b/src/sage/schemes/affine/affine_morphism.py @@ -869,6 +869,20 @@ def _polymap_times_matrix_(self, mat, h): To: Affine Space of dimension 2 over Integer Ring Defn: Defined on coordinates by sending (x) to (x^2 + 4*x + 5, x^2 + 4*x + 3) + + :: + + sage: P. = AffineSpace(QQ, 2) + sage: P2. = AffineSpace(QQ,3) + sage: H = Hom(P2, P) + sage: f = H([u^2 + v^2, w^2]) + sage: m = matrix([[1,1,1], [1,0,1],[0,0,1]]) + sage: m*f + Scheme morphism: + From: Affine Space of dimension 3 over Rational Field + To: Affine Space of dimension 2 over Rational Field + Defn: Defined on coordinates by sending (x0, x1, x2) to + (x0^2 + x1^2 + x2^2 + 1, x0^2 + x1^2 + 1) """ if self.is_endomorphism(): d = self.domain().ngens() diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index 37ccfa4e410..5ebb58d6fd8 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -1006,6 +1006,19 @@ def dehomogenize(self, n): sage: f = H([x^2 - 2*x*y, y^2]) sage: f.dehomogenize(0).homogenize(0) == f True + + :: + + sage: P1. = ProjectiveSpace(QQ,1) + sage: P2. = ProjectiveSpace(QQ,2) + sage: H = Hom(P2,P1) + sage: f = H([u^2,v^2]) + sage: f.dehomogenize((2,1)) + Scheme morphism: + From: Affine Space of dimension 2 over Rational Field + To: Affine Space of dimension 1 over Rational Field + Defn: Defined on coordinates by sending (x0, x1) to + (x0^2/x1^2) """ #the dehomogenizations are stored for future use. try: @@ -1026,9 +1039,10 @@ def dehomogenize(self, n): else: Aff_domain = PS_domain.affine_patch(ind[0]) S = Aff_domain.ambient_space().coordinate_ring() + M = A_domain.dimension_relative() N = self.codomain().ambient_space().dimension_relative() R = A_domain.coordinate_ring() - phi = R.hom([S.gen(j) for j in range(0, ind[0])] + [1] + [S.gen(j) for j in range(ind[0], N)], S) + phi = R.hom([S.gen(j) for j in range(0, ind[0])] + [1] + [S.gen(j) for j in range(ind[0], M)], S) F = [] G = phi(self._polys[ind[1]]) for i in range(0, N + 1): From e0a20571c69a99dd511c4a6e3e635c14bc98512f Mon Sep 17 00:00:00 2001 From: Ben Hutz Date: Sat, 9 Sep 2017 17:52:41 -0500 Subject: [PATCH 009/340] 23816: implement matrix action on scheme points --- src/sage/matrix/action.pxd | 5 +- src/sage/matrix/action.pyx | 61 ++++++++++++++++++- src/sage/matrix/matrix_space.py | 3 + src/sage/schemes/affine/affine_point.py | 47 ++++++++++++++ .../schemes/projective/projective_point.py | 56 +++++++++++++++++ 5 files changed, 170 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/action.pxd b/src/sage/matrix/action.pxd index a438807a4b4..d50965dc8f5 100644 --- a/src/sage/matrix/action.pxd +++ b/src/sage/matrix/action.pxd @@ -19,4 +19,7 @@ cdef class MatrixPolymapAction(MatrixMulAction): pass cdef class PolymapMatrixAction(MatrixMulAction): - pass \ No newline at end of file + pass + +cdef class MatrixSchemePointAction(MatrixMulAction): + pass diff --git a/src/sage/matrix/action.pyx b/src/sage/matrix/action.pyx index 27e37ddfefc..940838d0c2e 100644 --- a/src/sage/matrix/action.pyx +++ b/src/sage/matrix/action.pyx @@ -67,7 +67,7 @@ from .matrix_space import MatrixSpace, is_MatrixSpace from sage.modules.free_module import FreeModule, is_FreeModule from sage.structure.element cimport coercion_model from sage.categories.homset import Hom, End -from sage.schemes.generic.homset import SchemeHomset_generic +from sage.schemes.generic.homset import SchemeHomset_generic, SchemeHomset_points cdef class MatrixMulAction(Action): @@ -484,3 +484,62 @@ cdef class PolymapMatrixAction(MatrixMulAction): (x^2 + 2*x*y + 2*y^2 : y^2) """ return f._polymap_times_matrix_(mat, self._codomain) + +cdef class MatrixSchemePointAction(MatrixMulAction): + r""" + Action class for left multiplication of schemes points by matricies. + """ + def __init__(self, G, S): + """ + Initialization of action class. + + EXAMPLES:: + + sage: from sage.matrix.action import MatrixSchemePointAction + sage: M = MatrixSpace(QQ, 2, 2) + sage: P. = ProjectiveSpace(QQ, 1) + sage: A = MatrixSchemePointAction(M, P(QQ)) + sage: A + Left action by Full MatrixSpace of 2 by 2 dense matrices over + Rational Field on Set of rational points of Projective Space + of dimension 1 over Rational Field + """ + if not isinstance(S, SchemeHomset_points): + raise TypeError("not a homset of scheme points: %s"% S) + MatrixMulAction.__init__(self, G, S, True) + + def _create_codomain(self, base): + """ + Create the point homset for the resulting point. + + EXAMPLES:: + + sage: from sage.matrix.action import MatrixSchemePointAction + sage: P. = ProjectiveSpace(QQ, 1) + sage: M = MatrixSpace(QQ, 2, 2) + sage: A = MatrixSchemePointAction(M, P(QQ)) + sage: A.codomain() + Set of rational points of Projective Space of dimension 1 over Rational Field + """ + #need to extend the base of the ambient space + #and return the set of point over the base + amb = self.underlying_set().codomain() + return amb.change_ring(base)(base) + + cpdef _call_(self, mat, P): + """ + Action of matrices on scheme points. + + EXAMPLES:: + + sage: from sage.matrix.action import MatrixSchemePointAction + sage: P. = ProjectiveSpace(QQ, 1) + sage: Q = P(1,1) + sage: M = MatrixSpace(QQ, 2, 2) + sage: A = MatrixSchemePointAction(M, Q.parent()) + sage: m = matrix([[1,1], [0,1]]) + sage: A._call_(m, Q) + (2 : 1) + """ + return P._matrix_times_point_(mat, self._codomain) + diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index 1b1037a4507..a79b8410a4c 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -619,6 +619,7 @@ def get_action_impl(self, S, op, self_on_left): try: from sage.schemes.generic.algebraic_scheme import AlgebraicScheme from sage.schemes.generic.homset import SchemeHomset_generic + from sage.schemes.generic.homset import SchemeHomset_points if op is operator.mul: from . import action as matrix_action if self_on_left: @@ -626,6 +627,8 @@ def get_action_impl(self, S, op, self_on_left): return matrix_action.MatrixMatrixAction(self, S) elif sage.modules.free_module.is_FreeModule(S): return matrix_action.MatrixVectorAction(self, S) + elif isinstance(S, SchemeHomset_points): + return matrix_action.MatrixSchemePointAction(self, S) elif isinstance(S, SchemeHomset_generic): return matrix_action.MatrixPolymapAction(self, S) else: diff --git a/src/sage/schemes/affine/affine_point.py b/src/sage/schemes/affine/affine_point.py index e31ffa01f31..89abac93e6b 100644 --- a/src/sage/schemes/affine/affine_point.py +++ b/src/sage/schemes/affine/affine_point.py @@ -90,6 +90,53 @@ def __init__(self, X, v, check=True): X.extended_codomain()._check_satisfies_equations(v) self._coords = tuple(v) + def _matrix_times_point_(self, mat, dom): + r""" + Multiplies the point on the left by a matrix ``mat``. + + INPUT: + + - ``mat`` -- a matrix + + - ``dom`` -- (unused) needed for consistent function call with projective + + OUTPUT: a scheme point given by ``mat*self`` + + EXAMPLES:: + + sage: P = AffineSpace(QQ,2) + sage: Q = P(1,2) + sage: m = matrix(ZZ, 3, 3, [0,1,1,0,0,1,1,1,1]) + sage: m*Q + (3/4, 1/4) + + :: + + sage: P = AffineSpace(QQ,1) + sage: Q = P(0) + sage: m = matrix(RR, 2, 2, [0,1,1,0]) + sage: m*Q + Traceback (most recent call last): + ... + ValueError: resulting point not affine + + :: + + sage: P = AffineSpace(QQ,2) + sage: Q = P(1,1) + sage: m = matrix(RR, 2, 2, [0,1,1,0]) + sage: m*Q + Traceback (most recent call last): + ... + ValueError: matrix size is incompatible + """ + #input checking done in projective implementation + d = self.codomain().ngens() + P = mat*self.homogenize(d) + if P[-1] == 0: + raise ValueError("resulting point not affine") + return P.dehomogenize(d) + def nth_iterate(self, f, n): r""" Returns the point `f^n(self)` diff --git a/src/sage/schemes/projective/projective_point.py b/src/sage/schemes/projective/projective_point.py index 96453bf1825..161a56a80b2 100644 --- a/src/sage/schemes/projective/projective_point.py +++ b/src/sage/schemes/projective/projective_point.py @@ -408,6 +408,62 @@ def __hash__(self): #a constant value return hash(self.codomain()) + def _matrix_times_point_(self, mat, dom): + r""" + Multiplies the point by a matrix ``mat`` on the left. + + INPUT: + + - ``mat`` -- a matrix + + - ``dom`` -- point set of the resulting point + + OUTPUT: a scheme point given by ``mat*self`` + + EXAMPLES:: + + sage: P = ProjectiveSpace(QQ,1) + sage: Q = P(1,1) + sage: m = matrix(QQ, 2, 2, [1,1,0,1]) + sage: m*Q + (2 : 1) + + :: + + sage: P. = ProjectiveSpace(QQ,2) + sage: X = P.subscheme(x-y) + sage: Q = X(1,1) + sage: m = matrix(CC, 3, 3, [1,CC.0,0,CC.0,1,0,1,1,1]) + sage: m*Q + (0.333333333333333 + 0.333333333333333*I : 0.333333333333333 + + 0.333333333333333*I : 1.00000000000000) + + :: + + sage: P = ProjectiveSpace(QQbar,1) + sage: Q = P(QQbar(sqrt(2)),1) + sage: m = matrix(ZZ, 2, 2, [1,-1,0,1]) + sage: m*Q + (0.4142135623730951? : 1) + + :: + + sage: P = ProjectiveSpace(QQ,1) + sage: Q = P(1,1) + sage: m = matrix(QQ, 3, 2, [1,1,0,1,1,1]) + sage: m*Q + Traceback (most recent call last): + ... + ValueError: matrix must be square + """ + from sage.modules.free_module_element import vector + if not mat.is_square(): + raise ValueError("matrix must be square") + if mat.ncols() != self.codomain().ngens(): + raise ValueError("matrix size is incompatible") + X = mat * vector(list(self)) + return dom.codomain()(list(X)) + def scale_by(self,t): """ Scale the coordinates of the point by ``t``. From afbc43853d508da64b588be17df828d5d2106775 Mon Sep 17 00:00:00 2001 From: bbarros Date: Sat, 10 Feb 2018 17:44:08 -0600 Subject: [PATCH 010/340] 23720: Bug, documentation fixes --- .../dynamics/complex_dynamics/mandel_julia.py | 28 +++++++++---------- .../complex_dynamics/mandel_julia_helper.pyx | 5 +++- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia.py b/src/sage/dynamics/complex_dynamics/mandel_julia.py index dcbb0c09f4b..63c95bfcee5 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia.py +++ b/src/sage/dynamics/complex_dynamics/mandel_julia.py @@ -65,37 +65,37 @@ def mandelbrot_plot(f=None, **kwds): kwds: - ``f`` -- map (optional - default: ``z^2 + c``), polynomial map used to - plot the Mandelbrot set. + plot the Mandelbrot set. - ``parameter`` -- variable (optional - default: ``c``), parameter variable - used to plot the Mandelbrot set. + used to plot the Mandelbrot set. - ``x_center`` -- double (optional - default: ``-1.0``), Real part of center - point. + point. - ``y_center`` -- double (optional - default: ``0.0``), Imaginary part of - center point. + center point. - ``image_width`` -- double (optional - default: ``4.0``), width of image - in the complex plane. + in the complex plane. - ``max_iteration`` -- long (optional - default: ``500``), maximum number of - iterations the map ``Q_c(z)``. + iterations the map ``Q_c(z)``. - ``pixel_count`` -- long (optional - default: ``500``), side length of - image in number of pixels. + image in number of pixels. - ``base_color`` -- RGB color (optional - default: ``[40, 40, 40]``) color - used to determine the coloring of set. + used to determine the coloring of set. - ``iteration_level`` -- long (optional - default: 1) number of iterations - between each color level. + between each color level. - ``number_of_colors`` -- long (optional - default: 30) number of colors - used to plot image. + used to plot image. - ``interact`` -- boolean (optional - default: ``False``), controls whether - plot will have interactive functionality. + plot will have interactive functionality. OUTPUT: @@ -204,17 +204,17 @@ def _(real_center=input_box(x_center, 'Real'), P = f.parent() - if P.base() is CC: + if P.base_ring() is CC or P.base_ring() is CDF: gen_list = list(P.gens()) parameter = gen_list.pop(gen_list.index(parameter)) variable = gen_list.pop() - elif P.base().base() is CC: + elif P.base_ring().base_ring() is CC or P.base_ring().base_ring() is CDF: parameter = P.gen() variable = P.base().gen() else: - raise ValueError + raise ValueError("Base ring must be a complex field") if f == variable**2 + parameter: # Quadratic map f = z^2 + c diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx index 75f9dddceea..8fa3d370d84 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +++ b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx @@ -682,6 +682,7 @@ cpdef polynomial_mandelbrot(f, parameter=None, double x_center=0, I = CDF.gen() constant_c = True + # Is this needed in cython file also? This parsing is done in python file. if parameter is None: c = var('c') parameter = c @@ -698,7 +699,7 @@ cpdef polynomial_mandelbrot(f, parameter=None, double x_center=0, variable = P.base().gen() else: - return ValueError + return ValueError("Base ring must be a complex field.") # Make sure image_width is positive @@ -724,6 +725,8 @@ cpdef polynomial_mandelbrot(f, parameter=None, double x_center=0, # Split function into real and imaginary parts R = PolynomialRing(CC, [variable,parameter]) + if len(R.gens()) > 2: + return NotImplementedError("Base ring must have only 2 variables") z, c = R.gens() f = R(f) S = PolynomialRing(f.base_ring(), 'x,y,J,cr,ci') From d8ae5e216190f013001529f28a1d03d9cf86c879 Mon Sep 17 00:00:00 2001 From: Ralf Stephan Date: Thu, 1 Mar 2018 17:10:25 +0100 Subject: [PATCH 011/340] 24398: Document function initialization parameters --- src/doc/en/reference/functions/callable.rst | 1 + src/doc/en/reference/functions/function.rst | 1 + .../reference/functions/function_factory.rst | 1 + src/doc/en/reference/functions/index.rst | 13 +++ src/sage/symbolic/function.pyx | 81 +++++++++++++++++++ 5 files changed, 97 insertions(+) create mode 100644 src/doc/en/reference/functions/callable.rst create mode 100644 src/doc/en/reference/functions/function.rst create mode 100644 src/doc/en/reference/functions/function_factory.rst diff --git a/src/doc/en/reference/functions/callable.rst b/src/doc/en/reference/functions/callable.rst new file mode 100644 index 00000000000..0a7d2156955 --- /dev/null +++ b/src/doc/en/reference/functions/callable.rst @@ -0,0 +1 @@ +.. include:: ../calculus/sage/symbolic/callable.rst diff --git a/src/doc/en/reference/functions/function.rst b/src/doc/en/reference/functions/function.rst new file mode 100644 index 00000000000..b815a14bd68 --- /dev/null +++ b/src/doc/en/reference/functions/function.rst @@ -0,0 +1 @@ +.. include:: ../calculus/sage/symbolic/function.rst diff --git a/src/doc/en/reference/functions/function_factory.rst b/src/doc/en/reference/functions/function_factory.rst new file mode 100644 index 00000000000..365c614fa61 --- /dev/null +++ b/src/doc/en/reference/functions/function_factory.rst @@ -0,0 +1 @@ +.. include:: ../calculus/sage/symbolic/function_factory.rst diff --git a/src/doc/en/reference/functions/index.rst b/src/doc/en/reference/functions/index.rst index f33b8da08a6..fe863260fe6 100644 --- a/src/doc/en/reference/functions/index.rst +++ b/src/doc/en/reference/functions/index.rst @@ -1,6 +1,9 @@ Functions ========= +Built-in Functions +================== + .. toctree:: :maxdepth: 2 @@ -24,4 +27,14 @@ Functions sage/functions/prime_pi sage/functions/min_max +Developer documentation +======================= + +.. toctree:: + :maxdepth: 2 + + function + function_factory + callable + .. include:: ../footer.txt diff --git a/src/sage/symbolic/function.pyx b/src/sage/symbolic/function.pyx index 64af0fd8e8c..579e69c641c 100644 --- a/src/sage/symbolic/function.pyx +++ b/src/sage/symbolic/function.pyx @@ -1,5 +1,86 @@ r""" Classes for symbolic functions + +To enable their usage as part of symbolic expressions, symbolic function +classes are derived from one of the subclasses of :class:`Function`: + + * :class:`BuiltinFunction`: the code of these functions is written in Python; many special functions are of this type, see :doc + * :class:`GinacFunction`: the code of these functions is written in C++ and part of the Pynac support library; most elementary functions are of this type + * :class:`SymbolicFunction`: symbolic functions defined on the Sage command line are of this type + +Sage uses ``BuiltinFunction`` and ``GinacFunction`` for its symbolic builtin functions. Users can define any other additional ``SymbolicFunction`` through the ``function()`` factory, see :doc:`function_factory` + +Several parameters are supported by the superclass' ``__init__()`` method. Examples follow below. + + * ``nargs``: the number of arguments + * ``name``: the string that is printed on the CLI; the name of the member functions that are attempted for evaluation of Sage element arguments; also the name of the Pynac function that is associated with a ``GinacFunction`` + * ``alt_name``: the second name of the member functions that are attempted for evaluation of Sage element arguments + * ``latex_name``: what is printed when ``latex(f(...))`` is called + * ``conversions``: a dict containing the function's name in other CAS + * ``evalf_params_first``: if ``False``, when floating-point evaluating the expression do not evaluate function arguments before calling the ``_evalf_()`` member of the function + * ``preserved_arg``: if nonzero, the index (starting with ``1``) of the function argument that determines the return type. Note that, e.g, ``atan2()`` uses both arguments to determine return type, through a different mechanism + +Function classes can define the following Python member functions: + + * ``_eval_(*args)``: the only mandatory member function, evaluating the argument and returning the result; if ``None`` is returned the expression stays unevaluated + * ``_eval_numpy_(*args)``: evaluation of ``f(args)`` with arguments of numpy type + * ``_evalf_(*args, **kwds)``: called when the expression is floating-point evaluated; may receive a ``parent`` keyword specifying the expected parent of the result. If not defined an attempt is made to convert the result of ``_eval_()``. + * ``_conjugate_(*args)``, ``_real_part_(*args)``, ``_imag_part_(*args)``: return conjugate, real part, imaginary part of the expression ``f(args)`` + * ``_derivative_(*args, index)``: return derivative with respect to the parameter indexed by ``index`` (starting with 0) of ``f(args)`` + * ``_tderivative_()``: same as ``_derivative_()`` but don't apply chain rule; only one of the two functions may be defined + * ``_power_(*args, expo)``: return f(args)^expo + * ``_series_(*args, **kwds)``: return the power series at ``at`` up to ``order`` with respect to ``var`` of ``f(args)``; these three values are received in ``kwds``. If not defined the series is attempted to be computed by differentiation. + * ``print(*args)``: return what should be printed on the CLI with ``f(args)`` + * ``print_latex(*args)``: return what should be output with ``latex(f(args))`` + +The following examples are intended for Sage developers. Users can define functions interactively through the ``function()`` factory, see :doc:`function_factory` + +EXAMPLES: + +The simplest example is a function returning nothing, it practically behaves +like a symbol. Setting ``nargs=0`` allows any number of arguments:: + + sage: from sage.symbolic.function import BuiltinFunction + sage: class Test1(BuiltinFunction): + ....: def __init__(self): + ....: BuiltinFunction.__init__(self, 'test', nargs=0) + ....: def _eval_(self, *args): + ....: pass + sage: f = Test1() + sage: f() + test() + sage: f(1,2,3)*f(1,2,3) + test(1, 2, 3)^2 + +In the following the ``sin`` function of ``CBF(0)`` is called because with +floating point arguments the ``CBF`` element's ``my_sin()`` member function +is attempted, and after that ``sin()`` which succeeds:: + + sage: class Test2(BuiltinFunction): + ....: def __init__(self): + ....: BuiltinFunction.__init__(self, 'my_sin', alt_name='sin', + ....: latex_name=r'\SIN', nargs=1) + ....: def _eval_(self, x): + ....: return 5 + ....: def _evalf_(self, x, **kwds): + ....: return 3.5 + sage: f = Test2() + sage: f(0) + 5 + sage: f(0, hold=True) + my_sin(0) + sage: f(0, hold=True).n() + 3.50000000000000 + sage: f(CBF(0)) + 0 + + sage: latex(f(0, hold=True)) + \SIN\left(0\right) + sage: f(1,2) + Traceback (most recent call last): + ... + TypeError: Symbolic function my_sin takes exactly 1 arguments (2 given) + """ #***************************************************************************** From 3cd27de951bfb26282570a24bc80ea401ef1cbc2 Mon Sep 17 00:00:00 2001 From: Ralf Stephan Date: Sun, 4 Mar 2018 07:32:45 +0100 Subject: [PATCH 012/340] 24398: remove include of other documents --- src/doc/en/reference/functions/callable.rst | 1 - src/doc/en/reference/functions/function.rst | 1 - src/doc/en/reference/functions/function_factory.rst | 1 - src/doc/en/reference/functions/index.rst | 11 ++--------- 4 files changed, 2 insertions(+), 12 deletions(-) delete mode 100644 src/doc/en/reference/functions/callable.rst delete mode 100644 src/doc/en/reference/functions/function.rst delete mode 100644 src/doc/en/reference/functions/function_factory.rst diff --git a/src/doc/en/reference/functions/callable.rst b/src/doc/en/reference/functions/callable.rst deleted file mode 100644 index 0a7d2156955..00000000000 --- a/src/doc/en/reference/functions/callable.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../calculus/sage/symbolic/callable.rst diff --git a/src/doc/en/reference/functions/function.rst b/src/doc/en/reference/functions/function.rst deleted file mode 100644 index b815a14bd68..00000000000 --- a/src/doc/en/reference/functions/function.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../calculus/sage/symbolic/function.rst diff --git a/src/doc/en/reference/functions/function_factory.rst b/src/doc/en/reference/functions/function_factory.rst deleted file mode 100644 index 365c614fa61..00000000000 --- a/src/doc/en/reference/functions/function_factory.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../calculus/sage/symbolic/function_factory.rst diff --git a/src/doc/en/reference/functions/index.rst b/src/doc/en/reference/functions/index.rst index fe863260fe6..40e45791dfa 100644 --- a/src/doc/en/reference/functions/index.rst +++ b/src/doc/en/reference/functions/index.rst @@ -27,14 +27,7 @@ Built-in Functions sage/functions/prime_pi sage/functions/min_max -Developer documentation -======================= - -.. toctree:: - :maxdepth: 2 - - function - function_factory - callable +Please find extensive developer documentation for creating new functions +in the symbolic calculus module. .. include:: ../footer.txt From 8477ba8e0f1ae70f1a990b568e032ea3f1d2287b Mon Sep 17 00:00:00 2001 From: raghukul01 Date: Fri, 27 Jul 2018 20:03:50 +0530 Subject: [PATCH 013/340] 23701: Product Sieve Added --- .../product_projective/rational_point.py | 251 ++++++++++++++++++ 1 file changed, 251 insertions(+) diff --git a/src/sage/schemes/product_projective/rational_point.py b/src/sage/schemes/product_projective/rational_point.py index 54d38d6181d..194b39a069b 100644 --- a/src/sage/schemes/product_projective/rational_point.py +++ b/src/sage/schemes/product_projective/rational_point.py @@ -58,6 +58,13 @@ from sage.schemes.generic.scheme import is_Scheme from sage.schemes.product_projective.space import is_ProductProjectiveSpaces from sage.misc.mrange import xmrange +from sage.misc.all import prod +from sage.arith.all import gcd, srange, next_prime, previous_prime, crt +from sage.rings.all import ZZ, RR +from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF +from sage.parallel.ncpus import ncpus +from sage.parallel.use_fork import p_iter_fork +from sage.matrix.constructor import matrix def enum_product_projective_rational_field(X, B): r""" @@ -291,3 +298,247 @@ def enum_product_projective_finite_field(X): pts.sort() return pts + +def sieve(X, bound): + r""" + Returns the list of all product projective, rational points on scheme ``X`` of + height up to ``bound``. + + Height of a product projective point X = (x_1, x_2,..., x_n) is given by + H_X = max(y_1, y_2,..., y_n), where H_X is height of point X and y_i's + are the normalized coordinates such that all y_i are integers and + gcd(y_1, y_2,..., y_n) = 1. + + ALGORITHM: + + Main idea behind the algorithm is to find points modulo primes + and then reconstruct them using chinese remainder theorem. + We find modulo primes parallely and then lift them and apply + LLL in parallel. LLL reduction is applied for each component + projective space, and finally result is merged and converted + to product projective point. + + For the algorithm to work correctly, sufficient primes need + to be present, these are calculated using the bound given in + this([Hutz2015]_) paper. + + INPUT: + + - ``X`` - a scheme with ambient space defined over projective space + + - ``bound`` - a positive integer bound + + OUTPUT: + + - a list containing the projective rational points of ``X`` of height + up to ``bound``, sorted + + EXAMPLES:: + + sage: from sage.schemes.product_projective.rational_point import sieve + sage: PP. = ProductProjectiveSpaces([2,1], QQ) + sage: X = PP.subscheme([x^2 + y^2 - x*z, u*u-v*u]) + sage: sieve(X,2) + [(0 : 0 : 1 , 0 : 1), (0 : 0 : 1 , 1 : 1), (1/2 : -1/2 : 1 , 0 : 1), + (1/2 : -1/2 : 1 , 1 : 1), (1/2 : 1/2 : 1 , 0 : 1), (1/2 : 1/2 : 1 , 1 : 1), + (1 : 0 : 1 , 0 : 1), (1 : 0 : 1 , 1 : 1)] + + """ + + if bound < 1: + return [] + + modulo_points = [] + len_modulo_points = [] + primes_list = [] + + P = X.ambient_space() + N = P.ngens() + dim_scheme = X.dimension() + + num_comp = P.num_components() + comp_dim_relative = [P[i].dimension_relative() + 1 for i in range(num_comp)] + + dim_prefix = [0, comp_dim_relative[0]] # prefixes dim list + for i in range(1, len(comp_dim_relative)): + dim_prefix.append(dim_prefix[i] + comp_dim_relative[i]) + + dim_max = max(P[i].dimension() for i in range(num_comp)) + B = RR(2**(dim_max/4+1)*bound**2*(dim_max+1).sqrt()) + m = [] + + def sufficient_primes(x): + r""" + Returns a list of primes whose product is > `x` + """ + small_primes = [2,3] + prod_primes = 6 + + while prod_primes < x: + p = next_prime(small_primes[-1]) + small_primes.append(p) + prod_primes *= p + return small_primes + + def good_primes(B): + r""" + Given the bound returns the prime whose product is greater than ``B`` + and which would take least amount of time to run main sieve algorithm + + Complexity of finding points modulo primes is assumed to be N^2 * P_max^{N}. + Complexity of lifting points and LLL() function is assumed to + be close to (N^5) * (alpha^dim_scheme / P_max). + where alpha is product of all primes, and P_max is largest prime in list. + """ + + M = dict() # stores optimal list of primes, corresponding to list size + small_primes = sufficient_primes(B) + max_length = len(small_primes) + M[max_length] = small_primes + current_count = max_length - 1 + + while current_count > 1: + current_list = [] # stores prime which are bigger than least + updated_list = [] + best_list = [] + + least = (RR(B)**(1.00/current_count)).floor() + for i in range(current_count): + current_list.append(next_prime(least)) + least = current_list[-1] + # improving list of primes by taking prime less than least + # this part of algorithm is used to centralize primes around `least` + prod_prime = prod(current_list) + least = current_list[0] + while least != 2 and prod_prime > B and len(updated_list) < current_count: + best_list = updated_list + current_list[:current_count - len(updated_list)] + updated_list.append(previous_prime(least)) + least = updated_list[-1] + + removed_prime = current_list[current_count - len(updated_list)] + prod_prime = (prod_prime * least) / removed_prime + + M[current_count] = sorted(best_list) + current_count = current_count - 1 + + best_size = 2 + best_time = (N**2)*M[2][-1]**(N) + (N**5 * RR(prod(M[2])**dim_scheme / M[2][-1]) ) + for i in range(2, max_length + 1): + current_time = (N**2)*M[i][-1]**(N) + (N**5 * RR(prod(M[i])**dim_scheme / M[i][-1]) ) + if current_time < best_time: + best_size = i + best_time = current_time + + return M[best_size] + + def parallel_function(X, p): + r""" + Function used in parallel computation, computes a list of + all rational points in modulo ring. + """ + Xp = X.change_ring(GF(p)) + L = Xp.rational_points() + + return [list(_) for _ in L] + + def points_modulo_primes(X, primes): + r""" + Return a list of rational points modulo all `p` in primes, + computed parallely. + """ + normalized_input = [] + for p in primes_list: + normalized_input.append(((X, p, ), {})) + p_iter = p_iter_fork(ncpus()) + + points_pair = list(p_iter(parallel_function, normalized_input)) + points_pair.sort() + modulo_points = [] + for pair in points_pair: + modulo_points.append(pair[1]) + + return modulo_points + + def parallel_function_combination(point_p_max): + r""" + Function used in parallel computation, computes rational + points lifted. + """ + rat_points = set() + for tupl in xmrange(len_modulo_points): + point = [] + for k in range(N): + # lift all coordinates of given point using chinese remainder theorem + L = [modulo_points[j][tupl[j]][k].lift() for j in range(len_primes - 1)] + L.append(point_p_max[k].lift()) + point.append( crt(L, primes_list) ) + + for i in range(num_comp): + for j in range(comp_dim_relative[i]): + m[i][j] = point[dim_prefix[i] + j] + + # generating matrix to compute LLL reduction for each component + M = [matrix(ZZ, comp_dim_relative[i] + 1, comp_dim_relative[i], m[i]) \ + for i in range(num_comp)] + A = [M[i].LLL() for i in range(num_comp)] + point = [] + for i in range(num_comp): + point.extend(A[i][1]) + + # check if all coordinates of this point satisfy height bound + bound_satisfied = True + for coordinate in point: + if coordinate.abs() > bound: + bound_satisfied = False + break + if not bound_satisfied: + continue + + try: + rat_points.add(X(point)) # checks if this point lies on X or not + except: + pass + + return [list(_) for _ in rat_points] + + def lift_all_points(): + r""" + Returns list of all rational points lifted parallely. + """ + normalized_input = [] + points = modulo_points.pop() # remove the list of points corresponding to largest prime + len_modulo_points.pop() + + for point in points: + normalized_input.append(( (point, ), {})) + p_iter = p_iter_fork(ncpus()) + points_satisfying = list(p_iter(parallel_function_combination, normalized_input)) + + lifted_points = set() + for pair in points_satisfying: + L = pair[1] + for point in L: + lifted_points.add(X(tuple(point))) + + return list(lifted_points) + + primes_list = good_primes(B.ceil()) + modulo_points = points_modulo_primes(X, primes_list) + len_modulo_points = [len(_) for _ in modulo_points] + len_primes = len(primes_list) + prod_primes = prod(primes_list) + + # construct m for each component projective space + for i in range(num_comp): + dim = comp_dim_relative[i] + temp = [0 for _ in range(dim)] + for j in range(dim): + w = [0 for _ in range(dim)] + w[j] = prod_primes + temp.extend(w) + m.append(temp) + + rat_points = lift_all_points() + + return sorted(rat_points) + From cc156842d39b23ec7332f814ff9e25defd4f88d6 Mon Sep 17 00:00:00 2001 From: raghukul01 Date: Tue, 14 Aug 2018 00:12:25 +0530 Subject: [PATCH 014/340] 25701: Some improvement in complexity estimate --- .../schemes/product_projective/rational_point.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sage/schemes/product_projective/rational_point.py b/src/sage/schemes/product_projective/rational_point.py index 194b39a069b..5e7839bd384 100644 --- a/src/sage/schemes/product_projective/rational_point.py +++ b/src/sage/schemes/product_projective/rational_point.py @@ -338,7 +338,7 @@ def sieve(X, bound): sage: from sage.schemes.product_projective.rational_point import sieve sage: PP. = ProductProjectiveSpaces([2,1], QQ) sage: X = PP.subscheme([x^2 + y^2 - x*z, u*u-v*u]) - sage: sieve(X,2) + sage: sieve(X, 2) [(0 : 0 : 1 , 0 : 1), (0 : 0 : 1 , 1 : 1), (1/2 : -1/2 : 1 , 0 : 1), (1/2 : -1/2 : 1 , 1 : 1), (1/2 : 1/2 : 1 , 0 : 1), (1/2 : 1/2 : 1 , 1 : 1), (1 : 0 : 1 , 0 : 1), (1 : 0 : 1 , 1 : 1)] @@ -387,8 +387,10 @@ def good_primes(B): Complexity of finding points modulo primes is assumed to be N^2 * P_max^{N}. Complexity of lifting points and LLL() function is assumed to - be close to (N^5) * (alpha^dim_scheme / P_max). - where alpha is product of all primes, and P_max is largest prime in list. + be close to (dim_max^5) * (alpha / P_max)^dim_scheme. + where alpha is product of all primes, P_max is largest prime in list, + dim_max is the max of dimension of all components, and N is dimension + of ambient space. """ M = dict() # stores optimal list of primes, corresponding to list size @@ -396,6 +398,7 @@ def good_primes(B): max_length = len(small_primes) M[max_length] = small_primes current_count = max_length - 1 + dim = X.ambient_space().dimension() while current_count > 1: current_list = [] # stores prime which are bigger than least @@ -422,9 +425,9 @@ def good_primes(B): current_count = current_count - 1 best_size = 2 - best_time = (N**2)*M[2][-1]**(N) + (N**5 * RR(prod(M[2])**dim_scheme / M[2][-1]) ) + best_time = (dim**2)*M[2][-1]**(dim) + (dim_max**5 * (prod(M[2])/M[2][-1])**dim_scheme) for i in range(2, max_length + 1): - current_time = (N**2)*M[i][-1]**(N) + (N**5 * RR(prod(M[i])**dim_scheme / M[i][-1]) ) + current_time = (dim**2)*M[i][-1]**(dim) + (dim_max**5 * (prod(M[i])/M[i][-1])**dim_scheme) if current_time < best_time: best_size = i best_time = current_time From 94517d2079f53af11e60e1dc0a67dcd2038506d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Fri, 2 Nov 2018 21:06:26 +1300 Subject: [PATCH 015/340] basic suitsparse spkg --- build/pkgs/suitesparse/SPKG.txt | 940 ++++++++++++++++++ build/pkgs/suitesparse/checksums.ini | 4 + build/pkgs/suitesparse/dependencies | 1 + build/pkgs/suitesparse/package-version.txt | 1 + .../patches/01-no_cmake_project.patch | 40 + .../suitesparse/patches/02-darwin_blas.patch | 16 + build/pkgs/suitesparse/spkg-install | 7 + build/pkgs/suitesparse/type | 1 + 8 files changed, 1010 insertions(+) create mode 100644 build/pkgs/suitesparse/SPKG.txt create mode 100644 build/pkgs/suitesparse/checksums.ini create mode 100644 build/pkgs/suitesparse/dependencies create mode 100644 build/pkgs/suitesparse/package-version.txt create mode 100644 build/pkgs/suitesparse/patches/01-no_cmake_project.patch create mode 100644 build/pkgs/suitesparse/patches/02-darwin_blas.patch create mode 100644 build/pkgs/suitesparse/spkg-install create mode 100644 build/pkgs/suitesparse/type diff --git a/build/pkgs/suitesparse/SPKG.txt b/build/pkgs/suitesparse/SPKG.txt new file mode 100644 index 00000000000..445759392d9 --- /dev/null +++ b/build/pkgs/suitesparse/SPKG.txt @@ -0,0 +1,940 @@ +==> AMD/Doc/License.txt <== + + AMD, Copyright (c), 1996-2015, Timothy A. Davis, + Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved. + + Availability: + + http://www.suitesparse.com + + ------------------------------------------------------------------------------- + AMD License: BSD 3-clause: + ------------------------------------------------------------------------------- + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organizations to which the authors are + affiliated, nor the names of its contributors may be used to endorse + or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. + +==> BTF/Doc/License.txt <== + BTF, Copyright (C) 2004-2013, University of Florida + by Timothy A. Davis and Ekanathan Palamadai. + BTF is also available under other licenses; contact authors for details. + http://www.suitesparse.com + + -------------------------------------------------------------------------------- + + BTF is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + BTF is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this Module; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +==> CAMD/Doc/License.txt <== + + CAMD, Copyright (c) by Timothy A. Davis, + Yanqing Chen, + Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved. + CAMD is available under alternate licenses, contact T. Davis for details. + + CAMD License: BSD 3-clause + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organizations to which the authors are + affiliated, nor the names of its contributors may be used to endorse + or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. + + Availability: + + http://www.suitesparse.com + +==> CCOLAMD/Doc/License.txt <== + + CCOLAMD: constrained column approximate minimum degree ordering + Copyright (C) 2005-2016, Univ. of Florida. Authors: Timothy A. Davis, + Sivasankaran Rajamanickam, and Stefan Larimore. Closely based on COLAMD by + Davis, Stefan Larimore, in collaboration with Esmond Ng, and John Gilbert. + http://www.suitesparse.com + + -------------------------------------------------------------------------------- + + CCOLAMD license: BSD 3-clause: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organizations to which the authors are + affiliated, nor the names of its contributors may be used to endorse + or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. + + -------------------------------------------------------------------------------- + +==> CHOLMOD/Doc/License.txt <== + -------------------------------------------------------------------------------- + ==> Check/License.txt <== + -------------------------------------------------------------------------------- + + CHOLMOD/Check Module. Copyright (C) 2005-2006, Timothy A. Davis CHOLMOD is + also available under other licenses; contact authors for details. + http://www.suitesparse.com + + Note that this license is for the CHOLMOD/Check module only. + All CHOLMOD modules are licensed separately. + + ---------------------------------------------------------------------------- + + This Module is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This Module is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this Module; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + -------------------------------------------------------------------------------- + ==> Cholesky/License.txt <== + -------------------------------------------------------------------------------- + + CHOLMOD/Cholesky module, Copyright (C) 2005-2006, Timothy A. Davis. + CHOLMOD is also available under other licenses; contact authors for + details. http://www.suitesparse.com + + Note that this license is for the CHOLMOD/Cholesky module only. + All CHOLMOD modules are licensed separately. + + ---------------------------------------------------------------------------- + + + This Module is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This Module is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this Module; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + -------------------------------------------------------------------------------- + ==> Core/License.txt <== + -------------------------------------------------------------------------------- + + CHOLMOD/Core Module. Copyright (C) 2005-2006, Univ. of Florida. Author: + Timothy A. Davis. CHOLMOD is also available under other licenses; contact + authors for details. http://www.suitesparse.com + + Note that this license is for the CHOLMOD/Core module only. + All CHOLMOD modules are licensed separately. + + + ---------------------------------------------------------------------------- + + + This Module is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This Module is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this Module; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + -------------------------------------------------------------------------------- + ==> Demo/License.txt <== + -------------------------------------------------------------------------------- + + CHOLMOD/Demo Module. Copyright (C) 2005-2006, Timothy A. Davis. CHOLMOD + is also available under other licenses; contact authors for details. + http://www.suitesparse.com + + Note that this license is for the CHOLMOD/Demo module only. + All CHOLMOD modules are licensed separately. + + + ---------------------------------------------------------------------------- + + + This Module is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This Module is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this Module; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + + -------------------------------------------------------------------------------- + ==> Include/License.txt <== + -------------------------------------------------------------------------------- + + CHOLMOD/Include/* files. Copyright (C) 2005-2006, either Univ. of Florida + or T. Davis, depending on the file. + + Each file is licensed separately, according to the Module for which it + contains definitions and prototypes: + + Include/cholmod.h LGPL + Include/cholmod_blas.h LGPL + Include/cholmod_camd.h part of Partition module + Include/cholmod_check.h part of Check module + Include/cholmod_cholesky.h part of Cholesky module + Include/cholmod_complexity.h LGPL + Include/cholmod_config.h LGPL + Include/cholmod_core.h part of Core module + Include/cholmod_function.h no license; freely usable, no restrictions + Include/cholmod_gpu.h part of GPU module + Include/cholmod_gpu_kernels.h part of GPU module + Include/cholmod_internal.h LGPL + Include/cholmod_io64.h LGPL + Include/cholmod_matrixops.h part of MatrixOps module + Include/cholmod_modify.h part of Modify module + Include/cholmod_partition.h part of Partition module + Include/cholmod_supernodal.h part of Supernodal module + Include/cholmod_template.h LGPL + + -------------------------------------------------------------------------------- + ==> MATLAB/License.txt <== + -------------------------------------------------------------------------------- + + CHOLMOD/MATLAB Module. Copyright (C) 2005-2006, Timothy A. Davis. CHOLMOD + is also available under other licenses; contact authors for details. + MATLAB(tm) is a Registered Trademark of The MathWorks, Inc. + http://www.suitesparse.com + + Note that this license is for the CHOLMOD/MATLAB module only. + All CHOLMOD modules are licensed separately. + + ---------------------------------------------------------------------------- + + + This Module is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This Module is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this Module; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + + -------------------------------------------------------------------------------- + ==> MatrixOps/License.txt <== + -------------------------------------------------------------------------------- + + CHOLMOD/MatrixOps Module. Copyright (C) 2005-2006, Timothy A. Davis. + CHOLMOD is also available under other licenses; contact authors for + details. http://www.suitesparse.com + + Note that this license is for the CHOLMOD/MatrixOps module only. + All CHOLMOD modules are licensed separately. + + + ---------------------------------------------------------------------------- + + + This Module is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This Module is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this Module; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + + -------------------------------------------------------------------------------- + ==> Modify/License.txt <== + -------------------------------------------------------------------------------- + + CHOLMOD/Modify Module. Copyright (C) 2005-2006, Timothy A. Davis and + William W. Hager. CHOLMOD is also available under other licenses; contact + authors for details. http://www.suitesparse.com + + Note that this license is for the CHOLMOD/Modify module only. + All CHOLMOD modules are licensed separately. + + + ---------------------------------------------------------------------------- + + + This Module is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This Module is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this Module; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + + -------------------------------------------------------------------------------- + ==> Partition/License.txt <== + -------------------------------------------------------------------------------- + + CHOLMOD/Partition Module. + Copyright (C) 2005-2006, Univ. of Florida. Author: Timothy A. Davis + CHOLMOD is also available under other licenses; contact authors for details. + http://www.suitesparse.com + + Note that this license is for the CHOLMOD/Partition module only. + All CHOLMOD modules are licensed separately. + + + ---------------------------------------------------------------------------- + + + This Module is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This Module is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this Module; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + -------------------------------------------------------------------------------- + ==> Supernodal/License.txt <== + -------------------------------------------------------------------------------- + + CHOLMOD/Supernodal Module. + Copyright (C) 2005-2006, Timothy A. Davis + CHOLMOD is also available under other licenses; contact authors for details. + http://www.suitesparse.com + + Note that this license is for the CHOLMOD/Supernodal module only. + All CHOLMOD modules are licensed separately. + + + ---------------------------------------------------------------------------- + + + This Module is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This Module is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this Module; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + + -------------------------------------------------------------------------------- + ==> Tcov/License.txt <== + -------------------------------------------------------------------------------- + + CHOLMOD/Tcov Module. Copyright (C) 2005-2006, Timothy A. Davis + CHOLMOD is also available under other licenses; contact authors for details. + http://www.suitesparse.com + + Note that this license is for the CHOLMOD/Tcov module only. + All CHOLMOD modules are licensed separately. + + + ---------------------------------------------------------------------------- + + + This Module is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This Module is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this Module; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + + -------------------------------------------------------------------------------- + ==> Valgrind/License.txt <== + -------------------------------------------------------------------------------- + + CHOLMOD/Valgrind Module. Copyright (C) 2005-2006, Timothy A. Davis. + CHOLMOD is also available under other licenses; contact authors for details. + http://www.suitesparse.com + + Note that this license is for the CHOLMOD/Valgrind module only. + All CHOLMOD modules are licensed separately. + + + ---------------------------------------------------------------------------- + + + This Module is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This Module is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this Module; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + +==> COLAMD/Doc/License.txt <== + COLAMD, Copyright 1998-2016, Timothy A. Davis. http://www.suitesparse.com + http://www.suitesparse.com + + COLAMD License: BSD 3-clause + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organizations to which the authors are + affiliated, nor the names of its contributors may be used to endorse + or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. + +==> CSparse/Doc/License.txt <== + CSparse: a Concise Sparse matrix package. + Copyright (c) 2006, Timothy A. Davis. + http://www.suitesparse.com + + -------------------------------------------------------------------------------- + + CSparse is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + CSparse is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this Module; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +==> CXSparse/Doc/License.txt <== + CXSparse: a Concise Sparse matrix package - Extended. + Copyright (c) 2006, Timothy A. Davis. + http://www.suitesparse.com + + -------------------------------------------------------------------------------- + + CXSparse is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + CXSparse is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this Module; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +==> CXSparse_newfiles/Doc/License.txt <== + CXSparse: a Concise Sparse matrix package - Extended. + Copyright (c) 2006, Timothy A. Davis. + http://www.suitesparse.com + + -------------------------------------------------------------------------------- + + CXSparse is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + CXSparse is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this Module; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +==> GPUQREngine/Doc/License.txt <== + GPUQREngine Copyright (c) 2013, Timothy A. Davis, Sencer Nuri Yeralan, + and Sanjay Ranka. + http://www.suitesparse.com + + GPUQREngine is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free Software + Foundation; either version 2 of the License, or (at your option) any later + version. + + GPUQREngine is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + this Module; if not, write to the Free Software Foundation, Inc., 51 Franklin + Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +==> KLU/Doc/License.txt <== + KLU, Copyright (C) 2004-2013, University of Florida + by Timothy A. Davis and Ekanathan Palamadai. + KLU is also available under other licenses; contact authors for details. + http://www.suitesparse.com + + -------------------------------------------------------------------------------- + + KLU is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + KLU is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this Module; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +==> LDL/Doc/License.txt <== + LDL Copyright (c) 2005-2013 by Timothy A. Davis. + LDL is also available under other licenses; contact the author for details. + http://www.suitesparse.com + + -------------------------------------------------------------------------------- + + LDL is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + LDL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this Module; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +==> MATLAB_Tools/Doc/License.txt <== + The MATLAB_Tools collection of packages is + Copyright (c), Timothy A. Davis, All Rights Reserved, + with the exception of the spqr_rank package, which is + Copyright (c), Timothy A. Davis and Les Foster, All Rights Reserved, + + All packages are available under alternative licenses. + Contact the authors for details. + + -------------------------------------------------------------------------------- + MATLAB_Tools License, with the exception of SSMULT and SuiteSparseCollection: + -------------------------------------------------------------------------------- + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organizations to which the authors are + affiliated, nor the names of its contributors may be used to endorse + or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. + + -------------------------------------------------------------------------------- + SuiteSparseCollection License: + -------------------------------------------------------------------------------- + + SuiteSparseCollection is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + SuiteSparseCollection is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this package; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + -------------------------------------------------------------------------------- + SSMULT License: + -------------------------------------------------------------------------------- + + SSMULT, Copyright (c) 2007-2011, Timothy A. Davis, + http://www.suitesparse.com. + + SSMULT is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 2 of the License, or (at your option) any later + version. + + SSMULT is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + + You should have received a copy of the GNU General Public License along + with this package; if not, write to the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +==> RBio/Doc/License.txt <== + RBio toolbox. Copyright (C) 2006-2009, Timothy A. Davis + RBio is also available under other licenses; contact authors for details. + http://www.suitesparse.com + + -------------------------------------------------------------------------------- + + RBio is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + RBio is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this Module; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +==> SPQR/Doc/License.txt <== + SPQR, Copyright 2008-2016 by Timothy A. Davis. + All Rights Reserved. + SPQR is available under alternate licenses, contact T. Davis for details. + + SPQR License: + + Your use or distribution of SPQR or any modified version of + SPQR implies that you agree to this License. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA + + Permission is hereby granted to use or copy this program under the + terms of the GNU GPL, provided that the Copyright, this License, + and the Availability of the original version is retained on all copies. + User documentation of any code that uses this code or any modified + version of this code must cite the Copyright, this License, the + Availability note, and "Used by permission." Permission to modify + the code and to distribute modified code is granted, provided the + Copyright, this License, and the Availability note are retained, + and a notice that the code was modified is included. + + Availability: + + http://www.suitesparse.com + + +==> SuiteSparse_GPURuntime/Doc/License.txt <== + SuiteSparse_GPURuntime Copyright (c) 2013-2016, Timothy A. Davis, + Sencer Nuri Yeralan, and Sanjay Ranka. http://www.suitesparse.com + + -------------------------------------------------------------------------------- + + SuiteSparse_GPURuntime is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) any + later version. + + SuiteSparse_GPURuntime is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + + You should have received a copy of the GNU General Public License along with + this Module; if not, write to the Free Software Foundation, Inc., 51 Franklin + Street, Fifth Floor, Boston, MA 02110-1301, USA. + +==> ssget/Doc/License.txt <== + Copyright (c), 2009-2016, Timothy A. Davis, All Rights Reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organizations to which the authors are + affiliated, nor the names of its contributors may be used to endorse + or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. + + +==> UMFPACK/Doc/License.txt <== + UMFPACK, Copyright 1995-2009 by Timothy A. Davis. + All Rights Reserved. + UMFPACK is available under alternate licenses, contact T. Davis for details. + + UMFPACK License: + + Your use or distribution of UMFPACK or any modified version of + UMFPACK implies that you agree to this License. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA + + Permission is hereby granted to use or copy this program under the + terms of the GNU GPL, provided that the Copyright, this License, + and the Availability of the original version is retained on all copies. + User documentation of any code that uses this code or any modified + version of this code must cite the Copyright, this License, the + Availability note, and "Used by permission." Permission to modify + the code and to distribute modified code is granted, provided the + Copyright, this License, and the Availability note are retained, + and a notice that the code was modified is included. + + Availability: + + http://www.suitesparse.com + + +==> CSparse/MATLAB/ssget/Doc/License.txt <== + Copyright (c), 2009-2016, Timothy A. Davis, All Rights Reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organizations to which the authors are + affiliated, nor the names of its contributors may be used to endorse + or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. + + +==> CXSparse/MATLAB/ssget/Doc/License.txt <== + Copyright (c), 2009-2016, Timothy A. Davis, All Rights Reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the organizations to which the authors are + affiliated, nor the names of its contributors may be used to endorse + or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. + +==> GraphBLAS/Doc/License.txt <== + SuiteSparse:GraphBLAS, Copyright 2017, Timothy A. Davis + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use SuiteSparse:GraphBLAS except in compliance with the + License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +==> Mongoose License <== + Mongoose, Copyright 2018, Timothy A. Davis, Scott P. Kolodziej, + William W. Hager, S. Nuri Yeralan + Licensed under the GNU GENERAL PUBLIC LICENSE, Version 3, 29 June 2007 + + diff --git a/build/pkgs/suitesparse/checksums.ini b/build/pkgs/suitesparse/checksums.ini new file mode 100644 index 00000000000..4ff8609fb98 --- /dev/null +++ b/build/pkgs/suitesparse/checksums.ini @@ -0,0 +1,4 @@ +tarball=SuiteSparse-VERSION.tar.gz +sha1=2c484c8dfacfbb46b1af00c187e369c7a85d2ede +md5=d638a4369f3df0ca9e64b019af658a38 +cksum=4147428121 diff --git a/build/pkgs/suitesparse/dependencies b/build/pkgs/suitesparse/dependencies new file mode 100644 index 00000000000..7580ea8e60f --- /dev/null +++ b/build/pkgs/suitesparse/dependencies @@ -0,0 +1 @@ +$(BLAS) gfortran diff --git a/build/pkgs/suitesparse/package-version.txt b/build/pkgs/suitesparse/package-version.txt new file mode 100644 index 00000000000..03f488b076a --- /dev/null +++ b/build/pkgs/suitesparse/package-version.txt @@ -0,0 +1 @@ +5.3.0 diff --git a/build/pkgs/suitesparse/patches/01-no_cmake_project.patch b/build/pkgs/suitesparse/patches/01-no_cmake_project.patch new file mode 100644 index 00000000000..0884058370c --- /dev/null +++ b/build/pkgs/suitesparse/patches/01-no_cmake_project.patch @@ -0,0 +1,40 @@ +diff --git a/Makefile b/Makefile +index 6a2ddc6..bf4b5e9 100644 +--- a/Makefile ++++ b/Makefile +@@ -12,8 +12,6 @@ include SuiteSparse_config/SuiteSparse_config.mk + # Compile the default rules for each package + go: metis + ( cd SuiteSparse_config && $(MAKE) ) +- ( cd GraphBLAS && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' ) +- ( cd Mongoose && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' ) + ( cd AMD && $(MAKE) ) + ( cd BTF && $(MAKE) ) + ( cd CAMD && $(MAKE) ) +@@ -38,8 +36,6 @@ endif + # (note that CSparse is not installed; CXSparse is installed instead) + install: metisinstall + ( cd SuiteSparse_config && $(MAKE) install ) +- ( cd GraphBLAS && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' install ) +- ( cd Mongoose && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' install ) + ( cd AMD && $(MAKE) install ) + ( cd BTF && $(MAKE) install ) + ( cd CAMD && $(MAKE) install ) +@@ -116,8 +112,6 @@ endif + # the static library + library: metis + ( cd SuiteSparse_config && $(MAKE) ) +- ( cd GraphBLAS && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' library ) +- ( cd Mongoose && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' library ) + ( cd AMD && $(MAKE) library ) + ( cd BTF && $(MAKE) library ) + ( cd CAMD && $(MAKE) library ) +@@ -143,8 +137,6 @@ endif + # both the dynamic and static libraries. + static: metis + ( cd SuiteSparse_config && $(MAKE) static ) +- ( cd GraphBLAS && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' static ) +- ( cd Mongoose && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' static ) + ( cd AMD && $(MAKE) static ) + ( cd BTF && $(MAKE) static ) + ( cd CAMD && $(MAKE) static ) diff --git a/build/pkgs/suitesparse/patches/02-darwin_blas.patch b/build/pkgs/suitesparse/patches/02-darwin_blas.patch new file mode 100644 index 00000000000..ed719bc8bfd --- /dev/null +++ b/build/pkgs/suitesparse/patches/02-darwin_blas.patch @@ -0,0 +1,16 @@ +diff --git a/SuiteSparse_config/SuiteSparse_config.mk b/SuiteSparse_config/SuiteSparse_config.mk +index f991b7a..59ae6da 100644 +--- a/SuiteSparse_config/SuiteSparse_config.mk ++++ b/SuiteSparse_config/SuiteSparse_config.mk +@@ -360,8 +360,8 @@ SUITESPARSE_VERSION = 5.3.0 + # command line in the Terminal, before doing 'make': + # xcode-select --install + CF += -fno-common +- BLAS = -framework Accelerate +- LAPACK = -framework Accelerate ++ #BLAS = -framework Accelerate ++ #LAPACK = -framework Accelerate + # OpenMP is not yet supported by default in clang + CFOPENMP = + endif + diff --git a/build/pkgs/suitesparse/spkg-install b/build/pkgs/suitesparse/spkg-install new file mode 100644 index 00000000000..2ddb9e913ad --- /dev/null +++ b/build/pkgs/suitesparse/spkg-install @@ -0,0 +1,7 @@ +cd src + +echo "print configuration" +$MAKE MY_METIS_LIB=none CHOLMOD_CONFIG=-DNPARTITION BLAS="$(pkg-config --libs blas)" LAPACK="$(pkg-config --libs lapack)" config INSTALL="$SAGE_LOCAL" +# build and install +$MAKE MY_METIS_LIB=none CHOLMOD_CONFIG=-DNPARTITION BLAS="$(pkg-config --libs blas)" LAPACK="$(pkg-config --libs lapack)" install INSTALL="$SAGE_LOCAL" + diff --git a/build/pkgs/suitesparse/type b/build/pkgs/suitesparse/type new file mode 100644 index 00000000000..a6a7b9cd726 --- /dev/null +++ b/build/pkgs/suitesparse/type @@ -0,0 +1 @@ +standard From 903741fb9d61bddf187f517fb8bdb1d60d18a73e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Fri, 2 Nov 2018 21:34:40 +1300 Subject: [PATCH 016/340] initial update to cvxopt 1.2.2 --- build/pkgs/cvxopt/checksums.ini | 6 +- build/pkgs/cvxopt/package-version.txt | 2 +- build/pkgs/cvxopt/patches/cvxopt.h.patch | 21 ------ build/pkgs/cvxopt/patches/setup.py.patch | 92 ------------------------ build/pkgs/cvxopt/spkg-install | 27 +++++++ 5 files changed, 31 insertions(+), 117 deletions(-) delete mode 100644 build/pkgs/cvxopt/patches/cvxopt.h.patch delete mode 100644 build/pkgs/cvxopt/patches/setup.py.patch diff --git a/build/pkgs/cvxopt/checksums.ini b/build/pkgs/cvxopt/checksums.ini index e38d96990f1..09ead57ae93 100644 --- a/build/pkgs/cvxopt/checksums.ini +++ b/build/pkgs/cvxopt/checksums.ini @@ -1,4 +1,4 @@ tarball=cvxopt-VERSION.tar.gz -sha1=6b6da47c80e5b8fb678bc0ebdc38bddeaa83cc74 -md5=b17c75117b4412b33ea31a47b7e5655e -cksum=4043372127 +sha1=725ce85fe122cd0fcda9d1b1a45ae43adf6fea2c +md5=ef9ab5f939380e9488e57b113103d96a +cksum=4099798435 diff --git a/build/pkgs/cvxopt/package-version.txt b/build/pkgs/cvxopt/package-version.txt index f3ec750738c..23aa8390630 100644 --- a/build/pkgs/cvxopt/package-version.txt +++ b/build/pkgs/cvxopt/package-version.txt @@ -1 +1 @@ -1.1.8.p2 +1.2.2 diff --git a/build/pkgs/cvxopt/patches/cvxopt.h.patch b/build/pkgs/cvxopt/patches/cvxopt.h.patch deleted file mode 100644 index c7c5ef12ef4..00000000000 --- a/build/pkgs/cvxopt/patches/cvxopt.h.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff -ru src/src/C/cvxopt.h b/src/C/cvxopt.h ---- src/src/C/cvxopt.h 2013-04-22 08:44:28.000000000 +0200 -+++ b/src/C/cvxopt.h 2013-05-14 17:00:12.402407091 +0200 -@@ -28,8 +28,16 @@ - /* ANSI99 complex is disabled during build of CHOLMOD */ - - #ifndef NO_ANSI99_COMPLEX --#include "complex.h" -+#include - #define MAT_BUFZ(O) ((double complex *)((matrix *)O)->buffer) -+ -+/* The header of Solaris 10 defines I in a way that GCC -+ * doesn't understand. Redefine I like in glibc. */ -+#if defined(__sun__) && defined(__GNUC__) -+ #undef I -+ #define I (__extension__ 1.0iF) -+#endif -+ - #endif - - #ifndef __CVXOPT__ diff --git a/build/pkgs/cvxopt/patches/setup.py.patch b/build/pkgs/cvxopt/patches/setup.py.patch deleted file mode 100644 index 34d2c4657e4..00000000000 --- a/build/pkgs/cvxopt/patches/setup.py.patch +++ /dev/null @@ -1,92 +0,0 @@ ---- a/setup.py 2015-09-22 07:26:00.000000000 +0200 -+++ b/setup.py 2016-02-27 18:01:10.582251583 +0100 -@@ -6,12 +6,28 @@ - import os - - # Modifiy this if BLAS and LAPACK libraries are not in /usr/lib. --BLAS_LIB_DIR = '/usr/lib' -+import pkgconfig -+ -+blas_pc = pkgconfig.parse('blas') -+lapack_pc = pkgconfig.parse('lapack') -+gsl_pc = pkgconfig.parse('gsl') -+ -+SAGE_LIB = os.path.join(os.environ['SAGE_LOCAL'], 'lib') -+SAGE_INCLUDE = os.path.join(os.environ['SAGE_LOCAL'], 'include') - - # Default names of BLAS and LAPACK libraries --BLAS_LIB = ['blas'] --LAPACK_LIB = ['lapack'] -+LAPACK_LIB = list(lapack_pc['libraries']) -+ - BLAS_EXTRA_LINK_ARGS = [] -+if os.environ['UNAME'] == 'CYGWIN': -+ BLAS_LIB =['blas', 'gfortran'] -+ BLAS_LIB_DIR = '/usr/lib' -+else: -+ BLAS_LIB = list(blas_pc['libraries']) -+ try: -+ BLAS_LIB_DIR = next(iter(blas_pc['library_dirs'])) -+ except StopIteration: -+ BLAS_LIB_DIR = SAGE_LIB - - # Set environment variable BLAS_NOUNDERSCORES=1 if your BLAS/LAPACK do - # not use trailing underscores -@@ -19,13 +35,19 @@ - - # Set to 1 if you are using the random number generators in the GNU - # Scientific Library. --BUILD_GSL = 0 -+BUILD_GSL = 1 - - # Directory containing libgsl (used only when BUILD_GSL = 1). --GSL_LIB_DIR = '/usr/lib' -+try: -+ GSL_LIB_DIR = next(iter(gsl_pc['library_dirs'])) -+except StopIteration: -+ GSL_LIB_DIR = SAGE_LIB - - # Directory containing the GSL header files (used only when BUILD_GSL = 1). --GSL_INC_DIR = '/usr/include/gsl' -+try: -+ GSL_INC_DIR = next(iter(gsl_pc['include_dirs'])) -+except StopIteration: -+ GSL_INC_DIR = SAGE_INCLUDE - - # Set to 1 if you are installing the fftw module. - BUILD_FFTW = 0 -@@ -37,13 +59,13 @@ - FFTW_INC_DIR = '/usr/include' - - # Set to 1 if you are installing the glpk module. --BUILD_GLPK = 0 -+BUILD_GLPK = 1 - - # Directory containing libglpk (used only when BUILD_GLPK = 1). --GLPK_LIB_DIR = '/usr/lib' -+GLPK_LIB_DIR = SAGE_LIB - - # Directory containing glpk.h (used only when BUILD_GLPK = 1). --GLPK_INC_DIR = '/usr/include' -+GLPK_INC_DIR = SAGE_INCLUDE - - # Set to 1 if you are installing the DSDP module. - BUILD_DSDP = 0 -@@ -114,7 +136,7 @@ - extmods += [fftw]; - - if BUILD_GLPK: -- glpk = Extension('glpk', libraries = ['glpk'], -+ glpk = Extension('glpk', libraries = ['glpk', 'gmp', 'z'], - include_dirs = [ GLPK_INC_DIR ], - library_dirs = [ GLPK_LIB_DIR ], - sources = ['src/C/glpk.c'] ) -@@ -213,7 +235,7 @@ - amd = Extension('amd', - include_dirs = [ 'src/C/SuiteSparse/AMD/Include', - 'src/C/SuiteSparse/SuiteSparse_config' ], -- define_macros = MACROS, -+ define_macros = MACROS + [('NTIMER', '1')], # this will be in upstream at some point - sources = [ 'src/C/amd.c', 'src/C/SuiteSparse/SuiteSparse_config/SuiteSparse_config.c'] + - glob('src/C/SuiteSparse/AMD/Source/*.c') ) - diff --git a/build/pkgs/cvxopt/spkg-install b/build/pkgs/cvxopt/spkg-install index ec928f1eeb4..47a2d68a103 100644 --- a/build/pkgs/cvxopt/spkg-install +++ b/build/pkgs/cvxopt/spkg-install @@ -5,6 +5,33 @@ if [ "$UNAME" = FreeBSD ]; then export CPPFLAGS="$CPPFLAGS -I$SAGE_LOCAL/include" fi +# Stolen from Gentoo +pkg_libs() { + pkg-config --libs-only-l $* | \ + sed -e 's:[ ]-l*\(pthread\|m\)\([ ]\|$\)::g' -e 's:[ ]*$::' | \ + tr ' ' '\n' | sort -u | sed -e "s:^-l\(.*\):\1:g" | \ + tr '\n' ';' | sed -e 's:;$::' +} + + +# configure cvxopt by variables +# Note that *_INC_DIR variables have to be non-empty. +# Compilers don't like "-I ". +export CVXOPT_BLAS_LIB="$(pkg_libs blas)" +export CVXOPT_BLAS_LIB_DIR="${SAGE_LOCAL}" +export CVXOPT_LAPACK_LIB="$(pkg_libs lapack)" + +export CVXOPT_SUITESPARSE_LIB_DIR="${SAGE_LOCAL}" +export CVXOPT_SUITESPARSE_INC_DIR="${SAGE_LOCAL}/include" + +export CVXOPT_BUILD_GLPK=1 +export CVXOPT_GLPK_LIB_DIR="${SAGE_LOCAL}" +export CVXOPT_GLPK_INC_DIR="${SAGE_LOCAL}/include" + +export CVXOPT_BUILD_GSL=1 +export CVXOPT_GSL_LIB_DIR="${SAGE_LOCAL}" +export CVXOPT_GSL_INC_DIR="${SAGE_LOCAL}/include" + sdh_pip_install . if [ "x$SAGE_SPKG_INSTALL_DOCS" = xyes ] ; then From 32e028e9d3b2a048cfe8db6b56212afbfe2321c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Fri, 2 Nov 2018 21:36:13 +1300 Subject: [PATCH 017/340] add suitesparse to cvxopt dependencies --- build/pkgs/cvxopt/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/cvxopt/dependencies b/build/pkgs/cvxopt/dependencies index 1fcae0585c2..df63b3adf76 100644 --- a/build/pkgs/cvxopt/dependencies +++ b/build/pkgs/cvxopt/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) numpy $(BLAS) gsl glpk | pkgconfig pip matplotlib +$(PYTHON) numpy $(BLAS) gsl glpk suitesparse | pkgconfig pip matplotlib matplotlib is needed to test cvxopt (i.e., if SAGE_CHECK=yes). See #12742. From 21e7280425f0e37e07265563b97dfc527332c548 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Sat, 3 Nov 2018 07:44:02 +1300 Subject: [PATCH 018/340] fix cvxopt checksum --- build/pkgs/cvxopt/checksums.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/pkgs/cvxopt/checksums.ini b/build/pkgs/cvxopt/checksums.ini index 09ead57ae93..ca0ae05037d 100644 --- a/build/pkgs/cvxopt/checksums.ini +++ b/build/pkgs/cvxopt/checksums.ini @@ -1,4 +1,4 @@ tarball=cvxopt-VERSION.tar.gz -sha1=725ce85fe122cd0fcda9d1b1a45ae43adf6fea2c -md5=ef9ab5f939380e9488e57b113103d96a -cksum=4099798435 +sha1=43113a138e5e8f3ba42dc53ccb8c3c7501d5576b +md5=fc2546fdba2faa6c4996e9b40fce5269 +cksum=3288957477 From 87f00486d061445a8fa83ddaf9133cd7be0aaca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Sat, 3 Nov 2018 11:34:02 +1300 Subject: [PATCH 019/340] Flesh out SPKG.txt --- build/pkgs/suitesparse/SPKG.txt | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/build/pkgs/suitesparse/SPKG.txt b/build/pkgs/suitesparse/SPKG.txt index 445759392d9..ff1fa1ca2f2 100644 --- a/build/pkgs/suitesparse/SPKG.txt +++ b/build/pkgs/suitesparse/SPKG.txt @@ -1,3 +1,30 @@ +SuiteSpare is a collection of software to deal with sparse matrix. +It is hosted at http://faculty.cse.tamu.edu/davis/suitesparse.html + +This spkg does a minimal install of suitesparse disabling the following +* metis +* GraphBLAS (need cmake) +* Mongoose (need cmake) + +An external metis package can be used but we just disable its use. + +Patches: +* The first patch disable the building of package using cmake. +* The second patch make sure we use sage's blas/lapack on OS X. By default +suitesparse discard any configurations to use the accelerate framework. + +The building of metis is diabled by passing +MY_METIS_LIB=none to make (any value would have done) +We also configure cholmod so it doesn't require metis by +passing +CHOLMOD_CONFIG=-DNPARTITION to make. + +Other configurations are self explanatory. + +License: because SuiteSparse is a collection, it comes with a variety +of licenses. Find below a copy of the "LICENSES.txt" shipped with +SuiteSparse. + ==> AMD/Doc/License.txt <== AMD, Copyright (c), 1996-2015, Timothy A. Davis, From eed989369d086451145434d9e9b49841ce745332 Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Mon, 3 Dec 2018 18:02:33 +0100 Subject: [PATCH 020/340] Trac 26816: allow specifying subgroups of Galois groups using generators --- src/sage/rings/number_field/galois_group.py | 38 +++++++++++++++---- .../rings/number_field/number_field_ideal.py | 6 +-- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/sage/rings/number_field/galois_group.py b/src/sage/rings/number_field/galois_group.py index 2e5d65983ec..f7b4846488f 100644 --- a/src/sage/rings/number_field/galois_group.py +++ b/src/sage/rings/number_field/galois_group.py @@ -390,11 +390,30 @@ def subgroup(self, elts): sage: G = NumberField(x^3 - x - 1, 'a').galois_closure('b').galois_group() sage: G.subgroup([ G(1), G([(1,2,3),(4,5,6)]), G([(1,3,2),(4,6,5)]) ]) Subgroup [(), (1,2,3)(4,5,6), (1,3,2)(4,6,5)] of Galois group of Number Field in b with defining polynomial x^6 - 6*x^4 + 9*x^2 + 23 + + Subgroups can be specified using generators (:trac:`26816`):: + + sage: K. = NumberField(x^6 - 6*x^4 + 9*x^2 + 23) + sage: G = K.galois_group() + sage: list(G) + [(), + (1,2,3)(4,5,6), + (1,3,2)(4,6,5), + (1,4)(2,6)(3,5), + (1,5)(2,4)(3,6), + (1,6)(2,5)(3,4)] + sage: g = G[1] + sage: h = G[3] + sage: list(G.subgroup([])) + [()] + sage: list(G.subgroup([g])) + [(), (1,2,3)(4,5,6), (1,3,2)(4,6,5)] + sage: list(G.subgroup([h])) + [(), (1,4)(2,6)(3,5)] + sage: list(G.subgroup([g,h])) == list(G) + True """ - if len(elts) == self.order(): - return self - else: - return GaloisGroup_subgroup(self, elts) + return GaloisGroup_subgroup(self, elts) # Proper number theory starts here. All the functions below make no sense # unless the field is Galois. @@ -523,7 +542,7 @@ def inertia_group(self, P): sage: K. = NumberField(x^2 - 3,'a') sage: G = K.galois_group() sage: G.inertia_group(K.primes_above(2)[0]) - Galois group of Number Field in b with defining polynomial x^2 - 3 + Subgroup [(), (1,2)] of Galois group of Number Field in b with defining polynomial x^2 - 3 sage: G.inertia_group(K.primes_above(5)[0]) Subgroup [()] of Galois group of Number Field in b with defining polynomial x^2 - 3 """ @@ -605,8 +624,11 @@ class GaloisGroup_subgroup(GaloisGroup_v2): def __init__(self, ambient, elts): r""" - Create a subgroup of a Galois group with the given elements. It is generally better to - use the subgroup() method of the parent group. + Return the subgroup of this Galois group generated by the + given elements. + + It is generally better to use the :meth:`subgroup` method of + the parent group. EXAMPLES:: @@ -637,7 +659,7 @@ def __init__(self, ambient, elts): self._pari_data = ambient._pari_data self._pari_gc = ambient._pari_gc self._gc_map = ambient._gc_map - self._elts = elts + self._elts = sorted(self.iteration()) def fixed_field(self): r""" diff --git a/src/sage/rings/number_field/number_field_ideal.py b/src/sage/rings/number_field/number_field_ideal.py index a90c12665a3..4e17e6ac732 100644 --- a/src/sage/rings/number_field/number_field_ideal.py +++ b/src/sage/rings/number_field/number_field_ideal.py @@ -1420,7 +1420,7 @@ def decomposition_group(self): EXAMPLES:: sage: QuadraticField(-23, 'w').primes_above(7)[0].decomposition_group() - Galois group of Number Field in w with defining polynomial x^2 + 23 + Subgroup [(), (1,2)] of Galois group of Number Field in w with defining polynomial x^2 + 23 """ return self.number_field().galois_group().decomposition_group(self) @@ -1436,7 +1436,7 @@ def ramification_group(self, v): EXAMPLES:: sage: QuadraticField(-23, 'w').primes_above(23)[0].ramification_group(0) - Galois group of Number Field in w with defining polynomial x^2 + 23 + Subgroup [(), (1,2)] of Galois group of Number Field in w with defining polynomial x^2 + 23 sage: QuadraticField(-23, 'w').primes_above(23)[0].ramification_group(1) Subgroup [()] of Galois group of Number Field in w with defining polynomial x^2 + 23 """ @@ -1454,7 +1454,7 @@ def inertia_group(self): EXAMPLES:: sage: QuadraticField(-23, 'w').primes_above(23)[0].inertia_group() - Galois group of Number Field in w with defining polynomial x^2 + 23 + Subgroup [(), (1,2)] of Galois group of Number Field in w with defining polynomial x^2 + 23 """ return self.ramification_group(0) From 9545ec7da42286552422f245a2d9b4f99393beeb Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Tue, 4 Dec 2018 12:12:02 +0100 Subject: [PATCH 021/340] Trac 26817: always return an embedding in GaloisGroup_subgroup.fixed_field() --- src/sage/rings/number_field/galois_group.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/number_field/galois_group.py b/src/sage/rings/number_field/galois_group.py index 2e5d65983ec..eb5a5120057 100644 --- a/src/sage/rings/number_field/galois_group.py +++ b/src/sage/rings/number_field/galois_group.py @@ -655,10 +655,16 @@ def fixed_field(self): To: Number Field in a with defining polynomial x^4 + 1 Defn: a0 |--> a^3 + a) - """ - if self.order() == 1: - return self._galois_closure # work around a silly error + An embedding is returned also if the subgroup is trivial + (:trac:`26817`):: + sage: H = G.subgroup([G.identity()]) + sage: H.fixed_field() + (Number Field in a0 with defining polynomial x^4 + 1, Ring morphism: + From: Number Field in a0 with defining polynomial x^4 + 1 + To: Number Field in a with defining polynomial x^4 + 1 + Defn: a0 |--> a) + """ vecs = [pari(g.domain()).Vecsmall() for g in self._elts] v = self._ambient._pari_data.galoisfixedfield(vecs) x = self._galois_closure(v[1]) From d7c974d6572b7887e8da6f9f711654c8b4cad4b9 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sun, 27 Jan 2019 23:15:16 +0100 Subject: [PATCH 022/340] speed up Burge --- src/sage/combinat/growth.py | 98 +++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 52 deletions(-) diff --git a/src/sage/combinat/growth.py b/src/sage/combinat/growth.py index 5767f89d568..5a9e683bae0 100644 --- a/src/sage/combinat/growth.py +++ b/src/sage/combinat/growth.py @@ -471,7 +471,7 @@ # http://www.gnu.org/licenses/ #**************************************************************************** - +from six.moves import zip_longest from sage.structure.sage_object import SageObject from sage.structure.unique_representation import UniqueRepresentation from sage.combinat.posets.posets import Poset @@ -488,6 +488,9 @@ from copy import copy from sage.graphs.digraph import DiGraph +def _make_partition(l): + return _Partitions.element_class(_Partitions, l) + class GrowthDiagram(SageObject): r""" A generalized Schensted growth diagram in the sense of Fomin. @@ -1891,7 +1894,7 @@ class RuleShiftedShapes(Rule): sage: list(Shifted(labels=G.out_labels())) == list(G) True """ - zero = _Partitions([]) + zero = _make_partition([]) has_multiple_edges = True def normalize_vertex(self, v): @@ -1904,7 +1907,7 @@ def normalize_vertex(self, v): sage: Shifted.normalize_vertex([3,1]).parent() Partitions """ - return _Partitions(v) + return _make_partition(v) def vertices(self, n): r""" @@ -2029,7 +2032,7 @@ def P_symbol(self, P_chain): for c in range(mu[r], la[r]): T[r][c] = i - skew = _Partitions([row.count(None) for row in T]) + skew = _make_partition([row.count(None) for row in T]) T = [[e for e in row if e is not None] for row in T] return ShiftedPrimedTableau(T, skew=skew) @@ -2085,7 +2088,7 @@ def Q_symbol(self, Q_chain): for c in range(mu[r], la[r]): T[r][c] = i - prime - skew = _Partitions([row.count(None) for row in T]) + skew = _make_partition([row.count(None) for row in T]) T = [[e for e in row if e is not None] for row in T] return ShiftedPrimedTableau(T, skew=skew) @@ -2153,9 +2156,9 @@ def forward_rule(self, y, e, t, f, x, content): g, z = 0, x elif content == 1: if len(x) == 0: - g, z = 1, _Partitions(x).add_cell(0) # black + g, z = 1, _make_partition(x).add_cell(0) # black else: - g, z = 2, _Partitions(x).add_cell(0) # blue + g, z = 2, _make_partition(x).add_cell(0) # blue else: raise NotImplementedError elif content != 0: @@ -2170,13 +2173,13 @@ def forward_rule(self, y, e, t, f, x, content): else: if x != y: row = SkewPartition([x, t]).cells()[0][0] - g, z = f, _Partitions(y).add_cell(row) + g, z = f, _make_partition(y).add_cell(row) elif x == y != t and f == 2: # blue row = 1+SkewPartition([x, t]).cells()[0][0] if row == len(y): - g, z = 1, _Partitions(y).add_cell(row) # black + g, z = 1, _make_partition(y).add_cell(row) # black else: - g, z = 2, _Partitions(y).add_cell(row) # blue + g, z = 2, _make_partition(y).add_cell(row) # blue elif x == y != t and f in [1, 3]: # black or red c = SkewPartition([x, t]).cells()[0] col = c[0] + c[1] + 1 @@ -2188,7 +2191,7 @@ def forward_rule(self, y, e, t, f, x, content): g = 3 else: raise NotImplementedError - return g, _Partitions(z), h + return g, _make_partition(z), h def backward_rule(self, y, g, z, h, x): r""" @@ -2258,11 +2261,11 @@ def backward_rule(self, y, g, z, h, x): else: if x != y: row = SkewPartition([z, x]).cells()[0][0] - return (0, _Partitions(y).remove_cell(row), g, 0) + return (0, _make_partition(y).remove_cell(row), g, 0) else: row, col = SkewPartition([z, x]).cells()[0] if row > 0 and g in [1, 2]: # black or blue - return (0, _Partitions(y).remove_cell(row-1), 2, 0) + return (0, _make_partition(y).remove_cell(row-1), 2, 0) elif row == 0 and g in [1, 2]: # black or blue return (0, y, 0, 1) else: @@ -3596,7 +3599,7 @@ class RulePartitions(Rule): ValueError: can only determine the shape of the growth diagram if ranks of successive labels differ """ - zero = _Partitions([]) + zero = _make_partition([]) def vertices(self, n): r""" @@ -3620,7 +3623,7 @@ def normalize_vertex(self, v): sage: RSK.normalize_vertex([3,1]).parent() Partitions """ - return _Partitions(v) + return _make_partition(v) def rank(self, v): r""" @@ -3824,7 +3827,7 @@ def backward_rule(self, y, z, x): t = [min(row1, row3) - carry] + t carry = z[i-1] - max(row1, row3) i = i-1 - return (_Partitions(t), carry) + return (_make_partition(t), carry) class RuleBurge(RulePartitions): r""" @@ -3906,30 +3909,23 @@ def forward_rule(self, y, t, x, content): sage: Burge.forward_rule([1],[],[2],2) [2, 1, 1, 1] """ + # n is the maximal length of longest decreasing chain by + # Kleitman-Greene's theorem + n = content + len(x) + len(y) + x += [0]*(n-len(x)) + y += [0]*(n-len(y)) + t += [0]*(n-len(t)) + z = [0]*n carry = content - z = [] - while True: - if x == []: - row1 = 0 - else: - row1 = x[0] - if t == []: - row2 = 0 - else: - row2 = t[0] - if y == []: - row3 = 0 + for i, (row1, row2, row3) in enumerate(zip(x, t, y)): + s = min(int(row1 == row2 == row3), carry) + new_part = max(row1, row3) + s + if new_part: + z[i] = new_part + carry += -s + min(row1, row3) - row2 else: - row3 = y[0] - newPart = max(row1, row3) + min(int(row1 == row2 == row3), carry) - if newPart == 0: - return _Partitions(z[::-1]) - else: - z = [newPart] + z - carry = carry - min(int(row1 == row2 == row3), carry) + min(row1, row3) - row2 - x = x[1:] - t = t[1:] - y = y[1:] + break + return _make_partition(z) def backward_rule(self, y, z, x): r""" @@ -3965,18 +3961,17 @@ def backward_rule(self, y, z, x): sage: GrowthDiagram(Burge, labels=G._out_labels).to_word() == w # indirect doctest True """ + t = [0]*len(z) # z must be the longest partition + mu = [0]*(len(z)-len(x)) + x[::-1] + nu = [0]*(len(z)-len(y)) + y[::-1] + la = z[::-1] carry = 0 - t = [] - i = len(z) - while i > 0: - mu_i = 0 if len(x) < i else x[i-1] - la_i = 0 if len(z) < i else z[i-1] - nu_i = 0 if len(y) < i else y[i-1] - - t = [min(mu_i, nu_i) - min(int(mu_i == nu_i == la_i), carry)] + t - carry = carry - min(int(mu_i == nu_i == la_i), carry) + la_i - max(mu_i, nu_i) - i = i - 1 - return (_Partitions(t), carry) + for i, (mu_i, la_i, nu_i) in enumerate(zip(mu, la, nu)): + s = min(int(mu_i == nu_i == la_i), carry) + t[i] = min(mu_i, nu_i) - s + carry += -s + la_i - max(mu_i, nu_i) + t.reverse() + return (_make_partition(t), carry) class RuleDomino(Rule): r""" @@ -4089,7 +4084,7 @@ class RuleDomino(Rule): ValueError: [1] has smaller rank than [2, 1] but is not covered by it in P """ r = 2 - zero = _Partitions([]) + zero = _make_partition([]) def normalize_vertex(self, v): """ @@ -4101,7 +4096,7 @@ def normalize_vertex(self, v): sage: Domino.normalize_vertex([3,1]).parent() Partitions """ - return _Partitions(v) + return _make_partition(v) def vertices(self, n): r""" @@ -4246,7 +4241,6 @@ def union(la, mu): r""" Return the union of the two partitions. """ - from six.moves import zip_longest return [max(p,q) for (p,q) in zip_longest(la, mu, fillvalue=0)] if content not in [0,1,-1]: From fc42aa0137dd50fac68100dd84167df05f9f3739 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Sun, 3 Mar 2019 18:06:10 +0100 Subject: [PATCH 023/340] trac #27408: first trial of edge view --- src/doc/en/reference/graphs/index.rst | 2 +- src/sage/graphs/views.py | 419 ++++++++++++++++++++++++++ 2 files changed, 420 insertions(+), 1 deletion(-) create mode 100644 src/sage/graphs/views.py diff --git a/src/doc/en/reference/graphs/index.rst b/src/doc/en/reference/graphs/index.rst index d221dbb7ef2..3a63a38247f 100644 --- a/src/doc/en/reference/graphs/index.rst +++ b/src/doc/en/reference/graphs/index.rst @@ -14,7 +14,7 @@ Graph objects and methods sage/graphs/graph sage/graphs/digraph sage/graphs/bipartite_graph - + sage/graphs/views.py Constructors and databases -------------------------- diff --git a/src/sage/graphs/views.py b/src/sage/graphs/views.py new file mode 100644 index 00000000000..94240cc7544 --- /dev/null +++ b/src/sage/graphs/views.py @@ -0,0 +1,419 @@ +r""" +View classes + +This module implements views for vertices (:class:`VertexView`) and edges +(:class:`EdgeView`) of (di)graphs. A view is a read-only iterable container +enabling operations like ``for e in E`` and ``e in E``. It is updated as the +graph is updated. Hence, the graph should not be updated while iterating through +a view. Views can be iterated multiple times. + +""" +# **************************************************************************** +# Copyright (C) 2019 David Coudert +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from __future__ import print_function, absolute_import + +from sage.structure.sage_object import SageObject +from itertools import chain + + +class EdgeView(SageObject): + r""" + EdgeView class. + + This class implements a read-only iterable container of edges enabling + operations like ``for e in E`` and ``e in E``. An :class:`EdgeView` can be + iterated multiple times, and checking membership is done in constant + time. It avoids the construction of edge lists and so consumes little + memory. It is updated as the graph is updated. Hence, the graph should not + be updated while iterating through an :class:`EdgeView`. + + INPUT: + + - ``G`` -- a (di)graph + + - ``vertices`` -- object (default: ``None``); a vertex, an iterable + container of vertices or ``None``. When set, consider only edges incident + to specified vertices. + + - ``labels`` -- boolean (default: ``True``); if ``False``, each edge is + simply a pair ``(u, v)`` of vertices + + - ``ignore_direction`` -- boolean (default: ``False``); only applies to + directed graphs. If ``True``, searches across edges in either direction. + + - ``sort`` -- boolean (default: ``True``); if ``True``, edges are sorted + according to the default ordering + + - ``key`` -- a function (default: ``None``); a function that takes an edge + (a pair or a triple, according to the ``labels`` keyword) as its one + argument and returns a value that can be used for comparisons in the + sorting algorithm. This parameter is ignored when ``sort = False``. + + .. WARNING:: + + Since any object may be a vertex, there is no guarantee that any two + vertices will be comparable, and thus no guarantee how two edges may + compare. With default objects for vertices (all integers), or when all + the vertices are of the same simple type, then there should not be a + problem with how the vertices will be sorted. However, if you need to + guarantee a total order for the sorting of the edges, use the ``key`` + argument, as illustrated in the examples below. + + EXAMPLES:: + + sage: G = Graph([(0, 1, 'C'), (0, 2, 'A'), (1, 2, 'B')]) + sage: E = EdgeView(G); E + [(0, 1, 'C'), (0, 2, 'A'), (1, 2, 'B')] + sage: (1, 2) in E + False + sage: (1, 2, 'B') in E + True + sage: E = EdgeView(G, labels=False); E + [(0, 1), (0, 2), (1, 2)] + sage: (1, 2) in E + True + sage: (1, 2, 'B') in E + False + sage: [e for e in E] + [(0, 1), (0, 2), (1, 2)] + + An :class:`EdgeView` can be iterated multiple times:: + + sage: G = graphs.CycleGraph(3) + sage: print(E) + [(0, 1), (0, 2), (1, 2)] + sage: print(E) + [(0, 1), (0, 2), (1, 2)] + sage: for e in E: + ....: for ee in E: + ....: print(e, ee) + ((0, 1), (0, 1)) + ((0, 1), (0, 2)) + ((0, 1), (1, 2)) + ((0, 2), (0, 1)) + ((0, 2), (0, 2)) + ((0, 2), (1, 2)) + ((1, 2), (0, 1)) + ((1, 2), (0, 2)) + ((1, 2), (1, 2)) + + We can check if a view is empty:: + + sage: E = EdgeView(graphs.CycleGraph(3)) + sage: if E: + ....: print('not empty') + not empty + sage: E = EdgeView(Graph()) + sage: if not E: + ....: print('empty') + empty + + When ``sort`` is ``True``, edges are sorted by default in the default + fashion:: + + sage: G = Graph([(0, 1, 'C'), (0, 2, 'A'), (1, 2, 'B')]) + sage: E = EdgeView(G, sort=True); E + [(0, 1, 'C'), (0, 2, 'A'), (1, 2, 'B')] + + This can be overridden by specifying a key function. This first example just + ignores the labels in the third component of the triple:: + + sage: G = Graph([(0, 1, 'C'), (0, 2, 'A'), (1, 2, 'B')]) + sage: E = EdgeView(G, sort=True, key=lambda x: (x[1], -x[0])); E + [(0, 1, 'C'), (1, 2, 'B'), (0, 2, 'A')] + + We can also sort according to the labels:: + + sage: G = Graph([(0, 1, 'C'), (0, 2, 'A'), (1, 2, 'B')]) + sage: E = EdgeView(G, sort=True, key=lambda x: x[2]); E + [(0, 2, 'A'), (1, 2, 'B'), (0, 1, 'C')] + + With a directed graph:: + + sage: G = digraphs.DeBruijn(2, 2) + sage: E = EdgeView(G, labels=False, sort=True); E + [('00', '00'), ('00', '01'), ('01', '10'), ('01', '11'), + ('10', '00'), ('10', '01'), ('11', '10'), ('11', '11')] + sage: E = EdgeView(G, labels=False, sort=True, key=lambda e:(e[1], e[0])); E + [('00', '00'), ('10', '00'), ('00', '01'), ('10', '01'), + ('01', '10'), ('11', '10'), ('01', '11'), ('11', '11')] + + We can consider only edges incident to a specified set of vertices:: + + sage: G = graphs.CycleGraph(5) + sage: E = EdgeView(G, vertices=[0, 1], labels=False, sort=True); E + [(0, 1), (0, 4), (1, 2)] + sage: E = EdgeView(G, vertices=0, labels=False, sort=True); E + [(0, 1), (0, 4)] + sage: E = EdgeView(G, vertices=None, labels=False, sort=True); E + [(0, 1), (0, 4), (1, 2), (2, 3), (3, 4)] + + sage: G = digraphs.Circuit(5) + sage: E = EdgeView(G, vertices=[0, 1], labels=False, sort=True); E + [(0, 1), (1, 2)] + + We can ignore the direction of the edges of a directed graph, in which case + we search accross edges in either direction:: + + sage: G = digraphs.Circuit(5) + sage: E = EdgeView(G, vertices=[0, 1], labels=False, sort=True, ignore_direction=False); E + [(0, 1), (1, 2)] + sage: (1, 0) in E + False + sage: E = EdgeView(G, vertices=[0, 1], labels=False, sort=True, ignore_direction=True); E + [(0, 1), (0, 1), (1, 2), (4, 0)] + sage: (1, 0) in E + True + sage: G.has_edge(1, 0) + False + + A view is updated as the graph is updated:: + + sage: G = Graph() + sage: E = EdgeView(G, vertices=[0, 3], labels=False); E + [] + sage: G.add_edges([(0, 1), (1, 2)]) + sage: E + [(0, 1)] + sage: G.add_edge(2, 3) + sage: E + [(0, 1), (2, 3)] + + Hence, the graph should not be updated while iterating through a view:: + + sage: G = Graph([('a', 'b'), ('b', 'c')]) + sage: E = EdgeView(G, labels=False, sort=False); E + [('a', 'b'), ('b', 'c')] + sage: for u, v in E: + ....: G.add_edge(u + u, v + v) + Traceback (most recent call last): + ... + RuntimeError: dictionary changed size during iteration + """ + + def __init__(self, G, vertices=None, labels=True, ignore_direction=False, + sort=True, key=None): + """ + Construction of this :class:`EdgeView`. + + EXAMPLES:: + + sage: G = Graph([(0, 1, 'C'), (0, 2, 'A'), (1, 2, 'B')]) + sage: E = EdgeView(G); E + [(0, 1, 'C'), (0, 2, 'A'), (1, 2, 'B')] + + TESTS:: + + sage: EdgeView(Graph(), sort=False, key=lambda x:0) + Traceback (most recent call last): + ... + ValueError: sort keyword is False, yet a key function is given + """ + self.graph = G + self.directed = G._directed + + if vertices is None: + self.vertices = G + self.vertex_set = G + elif vertices in G: + self.vertices = [vertices] + self.vertex_set = self.vertices + else: + self.vertices = list(vertices) + self.vertex_set = frozenset(self.vertices) + + # None and 0 are interpreted as False, 1 as True + self.labels = True if labels else False + self.ignore_direction = True if ignore_direction else False + self.sort_edges = True if sort else False + if not sort and key: + raise ValueError('sort keyword is False, yet a key function is given') + self.sort_edges_key = key + + def __len__(self): + """ + Return the number of edges in ``self``. + + EXAMPLES:: + + sage: G = graphs.HouseGraph() + sage: E = EdgeView(G) + sage: len(E) + 6 + sage: len(E) == G.size() + True + sage: E = EdgeView(G, vertices=0, labels=False); E + [(0, 1), (0, 2)] + sage: len(E) + 2 + """ + if self.vertices is self.graph: + return self.graph.size() + else: + return sum(1 for _ in self) + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: G = graphs.HouseGraph() + sage: E = EdgeView(G, labels=False) + sage: repr(E) + '[(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)]' + sage: E + [(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)] + """ + return "[%s]" % ', '.join(map(repr, self)) + + def __iter__(self): + """ + Iterator over the edges in ``self``. + + EXAMPLES:: + + sage: G = graphs.HouseGraph() + sage: E = EdgeView(G, labels=False) + sage: list(E) + [(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)] + sage: sum(1 for e in E for ee in E) = len(E) * len(E) + True + """ + if self.directed: + if self.ignore_direction: + edges = chain(self.graph._backend.iterator_out_edges(self.vertices, self.labels), + self.graph._backend.iterator_in_edges(self.vertices, self.labels)) + else: + edges = self.graph._backend.iterator_out_edges(self.vertices, self.labels) + else: + edges = self.graph._backend.iterator_edges(self.vertices, self.labels) + + if self.sort_edges: + edges = sorted(list(edges), key=self.sort_edges_key) + for e in edges: + yield e + + def __eq__(self, other): + """ + Check whether ``self`` and ``other`` are equal. + + Do not call this method directly. That is, for ``E1.__eq__(E2)`` write + ``E1 == E2``. + + Two :class:`EdgeView` are considered equal if the following hold: + - they report either both directed, or both undirected edges; + - they have the same settings for ``ignore_direction``; + - they have the same settings for ``labels``; + - they report the same edges in the same order. + + EXAMPLES:: + + sage: G = graphs.HouseGraph() + sage: EG = EdgeView(G) + sage: H = Graph(list(G.edge_iterator())) + sage: EH = EdgeView(H) + sage: EG == EH + True + sage: G.add_edge(0, 10) + sage: EG = EdgeView(G) + sage: EG == EH + False + sage: H.add_edge(0, 10) + sage: EH = EdgeView(H) + sage: EG == EH + True + sage: H = G.strong_orientation() + sage: EH = EdgeView(H) + sage: EG == EH + False + """ + if not isinstance(other, EdgeView): + return False + if self is other: + return True + # Check parameters + if (self.directed != other.directed or + self.ignore_direction != other.ignore_direction or + self.labels != other.labels): + return False + # Check that the same edges are reported in the same order + return all(es == eo for es, eo in zip(self, other)) + + def __contains__(self, e): + """ + Check whether edge ``e`` is part of ``self``. + + INPUT: + + - ``e`` -- tuple; when ``self.labels`` is ``True``, the expected form is + ``(u, v, label)``, while when ``self.labels`` is ``False``, the + expected form is ``(u, v)`` + + EXAMPLES:: + + sage: G = Graph([(0, 1)]) + sage: E = EdgeView(G, labels=False) + sage: print(E) + [(0, 1)] + sage: (0, 1) in E + True + sage: (0, 1, None) in E + False + sage: E = EdgeView(G, labels=True) + sage: print(E) + [(0, 1, None)] + sage: (0, 1) in E + False + sage: (0, 1, None) in E + True + """ + if self.labels: + try: + u, v, label = e + except Exception: + return False + else: + try: + u, v = e + except Exception: + return False + label = None + if (self.vertex_set is not self.graph + and u not in self.vertex_set and v not in self.vertex_set): + return False + if self.directed and self.ignore_direction: + return (self.graph._backend.has_edge(u, v, label) + or self.graph._backend.has_edge(v, u, label)) + return self.graph._backend.has_edge(u, v, label) + + +class VertexView(SageObject): + r""" + VertexView class. + + This class implements a read-only iterable container of vertices enabling + operations like ``for v in V`` and ``v in V``. It is updated as the graph is + updated. Hence, the graph should not be updated while iterating through a + :class:`VertexView`. A :class:`VertexView` can be iterated multiple times. + + INPUT: + + - ``G`` -- a (di)graph + + """ + + def __init__(self, G): + """ + Construction of this :class:`VertexView`. + """ + raise NotImplementedError() + From 79b426bc235a76cbf87aad906de449f81db214f9 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Sun, 3 Mar 2019 18:11:11 +0100 Subject: [PATCH 024/340] trac #27408: fix doctests in views.py --- src/sage/graphs/views.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/views.py b/src/sage/graphs/views.py index 94240cc7544..8003d677f0f 100644 --- a/src/sage/graphs/views.py +++ b/src/sage/graphs/views.py @@ -69,6 +69,7 @@ class EdgeView(SageObject): EXAMPLES:: + sage: from sage.graphs.views import EdgeView sage: G = Graph([(0, 1, 'C'), (0, 2, 'A'), (1, 2, 'B')]) sage: E = EdgeView(G); E [(0, 1, 'C'), (0, 2, 'A'), (1, 2, 'B')] @@ -94,7 +95,7 @@ class EdgeView(SageObject): [(0, 1), (0, 2), (1, 2)] sage: for e in E: ....: for ee in E: - ....: print(e, ee) + ....: print((e, ee)) ((0, 1), (0, 1)) ((0, 1), (0, 2)) ((0, 1), (1, 2)) @@ -206,6 +207,7 @@ def __init__(self, G, vertices=None, labels=True, ignore_direction=False, EXAMPLES:: + sage: from sage.graphs.views import EdgeView sage: G = Graph([(0, 1, 'C'), (0, 2, 'A'), (1, 2, 'B')]) sage: E = EdgeView(G); E [(0, 1, 'C'), (0, 2, 'A'), (1, 2, 'B')] @@ -244,6 +246,7 @@ def __len__(self): EXAMPLES:: + sage: from sage.graphs.views import EdgeView sage: G = graphs.HouseGraph() sage: E = EdgeView(G) sage: len(E) @@ -266,6 +269,7 @@ def _repr_(self): EXAMPLES:: + sage: from sage.graphs.views import EdgeView sage: G = graphs.HouseGraph() sage: E = EdgeView(G, labels=False) sage: repr(E) @@ -281,11 +285,12 @@ def __iter__(self): EXAMPLES:: + sage: from sage.graphs.views import EdgeView sage: G = graphs.HouseGraph() sage: E = EdgeView(G, labels=False) sage: list(E) [(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)] - sage: sum(1 for e in E for ee in E) = len(E) * len(E) + sage: sum(1 for e in E for ee in E) == len(E) * len(E) True """ if self.directed: @@ -317,6 +322,7 @@ def __eq__(self, other): EXAMPLES:: + sage: from sage.graphs.views import EdgeView sage: G = graphs.HouseGraph() sage: EG = EdgeView(G) sage: H = Graph(list(G.edge_iterator())) @@ -360,6 +366,7 @@ def __contains__(self, e): EXAMPLES:: + sage: from sage.graphs.views import EdgeView sage: G = Graph([(0, 1)]) sage: E = EdgeView(G, labels=False) sage: print(E) From 0e4961bc7fdff131f6d28ea346bd6df7439ca0e2 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Sun, 3 Mar 2019 20:01:04 +0100 Subject: [PATCH 025/340] trac #27408: fix issues in graph module --- src/sage/graphs/base/graph_backends.pyx | 4 ++- .../graphs/base/static_sparse_backend.pyx | 2 +- src/sage/graphs/comparability.pyx | 2 +- src/sage/graphs/connectivity.pyx | 8 +++--- src/sage/graphs/digraph.py | 12 ++++---- src/sage/graphs/generic_graph.py | 28 ++++++++----------- src/sage/graphs/graph.py | 18 ++++++------ .../graph_decompositions/graph_products.pyx | 2 +- src/sage/graphs/graph_generators.py | 2 +- src/sage/graphs/orientations.py | 2 +- src/sage/graphs/spanning_tree.pyx | 2 +- src/sage/graphs/tutte_polynomial.py | 17 ++++++----- 12 files changed, 50 insertions(+), 49 deletions(-) diff --git a/src/sage/graphs/base/graph_backends.pyx b/src/sage/graphs/base/graph_backends.pyx index 090bf6c6fdc..25ad072d04c 100644 --- a/src/sage/graphs/base/graph_backends.pyx +++ b/src/sage/graphs/base/graph_backends.pyx @@ -703,7 +703,9 @@ cdef class GenericGraphBackend(SageObject): No problems with loops and multiple edges, with Labels:: sage: g = Graph(multiedges=True, loops=True) - sage: g.add_edges(2 * graphs.PetersenGraph().edges(sort=False)) + sage: E = graphs.PetersenGraph().edges(sort=False) + sage: g.add_edges(E) + sage: g.add_edges(E) sage: g.add_edge(0, 0) sage: g.add_edge(1, 1, "a label") sage: g.add_edges([(0, 1, "labellll"), (0, 1, "labellll"), (0, 1, "LABELLLL")]) diff --git a/src/sage/graphs/base/static_sparse_backend.pyx b/src/sage/graphs/base/static_sparse_backend.pyx index f3948a3be55..ece2de4a02a 100644 --- a/src/sage/graphs/base/static_sparse_backend.pyx +++ b/src/sage/graphs/base/static_sparse_backend.pyx @@ -393,7 +393,7 @@ cdef class StaticSparseBackend(CGraphBackend): sage: g = DiGraph(digraphs.DeBruijn(4, 3), data_structure="static_sparse") sage: gi = DiGraph(g, data_structure="static_sparse") - sage: gi.edges()[0] + sage: list(gi.edges())[0] ('000', '000', '0') sage: sorted(gi.edges_incident('111')) [('111', '110', '0'), diff --git a/src/sage/graphs/comparability.pyx b/src/sage/graphs/comparability.pyx index 0306ea0350c..c294672ab1b 100644 --- a/src/sage/graphs/comparability.pyx +++ b/src/sage/graphs/comparability.pyx @@ -707,7 +707,7 @@ def is_permutation(g, algorithm="greedy", certificate=False, check=True, return False, co_certif # Building the two orderings - tmp = co_certif.edges(labels=False, sort=False) + tmp = list(co_certif.edge_iterator(labels=False)) for u,v in certif.edge_iterator(labels=False): co_certif.add_edge(v,u) certif.add_edges(tmp) diff --git a/src/sage/graphs/connectivity.pyx b/src/sage/graphs/connectivity.pyx index 0567b9457da..bedc03ae3d9 100644 --- a/src/sage/graphs/connectivity.pyx +++ b/src/sage/graphs/connectivity.pyx @@ -2114,9 +2114,9 @@ def cleave(G, cut_vertices=None, virtual_edges=True, solver=None, verbose=0): # is needed. cocycles = Graph([cut_vertices, []], multiedges=True) if K.size(): - cocycles.add_edges(K.edges(sort=False) * (len(cut_sides) + 1)) + cocycles.add_edges(list(K.edge_iterator()) * (len(cut_sides) + 1)) if virtual_edges and virtual_cut_graph: - cocycles.add_edges(virtual_cut_graph.edges(sort=False) * len(cut_sides)) + cocycles.add_edges(list(virtual_cut_graph.edge_iterator()) * len(cut_sides)) return cut_sides, cocycles, virtual_cut_graph @@ -2255,7 +2255,7 @@ def spqr_tree(G, algorithm="Hopcroft_Tarjan", solver=None, verbose=0): sage: T = G.spqr_tree(algorithm="cleave") sage: Counter(u[0] for u in T) Counter({'R': 1}) - sage: for u,v in G.edges(labels=False, sort=False): + sage: for u,v in list(G.edge_iterator(labels=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()) @@ -2263,7 +2263,7 @@ def spqr_tree(G, algorithm="Hopcroft_Tarjan", solver=None, verbose=0): sage: T = G.spqr_tree(algorithm="cleave") sage: sorted(Counter(u[0] for u in T).items()) [('P', 15), ('R', 1), ('S', 15)] - sage: for u,v in G.edges(labels=False, sort=False): + sage: for u,v in list(G.edge_iterator(labels=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()) diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index 2066cfa223d..7679bff256c 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -166,6 +166,7 @@ import sage.graphs.generic_graph_pyx as generic_graph_pyx from sage.graphs.generic_graph import GenericGraph from sage.graphs.dot2tex_utils import have_dot2tex +from sage.graphs.views import EdgeView class DiGraph(GenericGraph): @@ -659,9 +660,10 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if (format is None and isinstance(data, list) and len(data) == 2 and - isinstance(data[0], list) and # a list of two lists, the second of - isinstance(data[1], list) and # which contains iterables (the edges) - (not data[1] or callable(getattr(data[1][0], "__iter__", None)))): + isinstance(data[0], list) and # a list of two lists, the second of + ((isinstance(data[1], list) and # which contains iterables (the edges) + (not data[1] or callable(getattr(data[1][0], "__iter__", None)))) or + (isinstance(data[1], EdgeView)))): format = "vertices_and_edges" if format is None and isinstance(data, dict): @@ -697,8 +699,8 @@ def __init__(self, data=None, pos=None, loops=None, format=None, format = 'int' data = 0 - # Input is a list of edges - if format is None and isinstance(data,list): + # Input is a list of edges or an EdgeView + if format is None and isinstance(data, (list, EdgeView)): format = "list_of_edges" if weighted is None: weighted = False diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 41bbfe01624..93196238c98 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -71,7 +71,7 @@ :meth:`~GenericGraph.delete_multiedge` | Delete all edges from ``u`` to ``v``. :meth:`~GenericGraph.set_edge_label` | Set the edge label of a given edge. :meth:`~GenericGraph.has_edge` | Check whether ``(u, v)`` is an edge of the (di)graph. - :meth:`~GenericGraph.edges` | Return a list of edges. + :meth:`~GenericGraph.edges` | Return a :class:`~EdgeView` of edges. :meth:`~GenericGraph.edge_boundary` | Return a list of edges ``(u,v,l)`` with ``u`` in ``vertices1`` :meth:`~GenericGraph.edge_iterator` | Return an iterator over edges. :meth:`~GenericGraph.edges_incident` | Return incident edges to some vertices. @@ -420,6 +420,7 @@ from copy import copy +from sage.graphs.views import EdgeView from .generic_graph_pyx import GenericGraph_pyx, spring_layout_fast from .dot2tex_utils import assert_have_dot2tex @@ -4278,7 +4279,7 @@ def min_spanning_tree(self, v = next(self.vertex_iterator()) else: v = starting_vertex - sorted_edges = self.edges(key=wfunction_float) + sorted_edges = list(self.edges(key=wfunction_float)) tree = set([v]) edges = [] for _ in range(self.order() - 1): @@ -7580,9 +7581,9 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, else: if self.allows_multiple_edges() and len(self.edge_label(uu, vv)) > 1: if maximize: - edges = self.edges(key=weight)[-2:] + edges = list(self.edges(key=weight))[-2:] else: - edges = self.edges(key=weight)[:2] + edges = list(self.edges(key=weight))[:2] answer = self.subgraph(edges=edges, immutable=self.is_immutable()) answer.set_pos(self.get_pos()) answer.name("TSP from "+self.name()) @@ -10990,7 +10991,7 @@ def has_edge(self, u, v=None, label=None): def edges(self, labels=True, sort=True, key=None): r""" - Return a list of edges. + Return a :class:`~EdgeView` of edges. Each edge is a triple ``(u, v, l)`` where ``u`` and ``v`` are vertices and ``l`` is a label. If the parameter ``labels`` is ``False`` then a @@ -11010,7 +11011,7 @@ def edges(self, labels=True, sort=True, key=None): one argument and returns a value that can be used for comparisons in the sorting algorithm - OUTPUT: A list of tuples. It is safe to change the returned list. + OUTPUT: A :class:`~EdgeView`. .. WARNING:: @@ -11078,12 +11079,7 @@ def edges(self, labels=True, sort=True, key=None): sage: G.edges() [(0, 1, [8]), (0, 2, [7])] """ - if (not sort) and key: - raise ValueError('sort keyword is False, yet a key function is given') - L = list(self.edge_iterator(labels=labels)) - if sort: - L.sort(key=key) - return L + return EdgeView(self, labels=labels, sort=sort, key=key) def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False): r""" @@ -15995,9 +15991,9 @@ def weight_function(e): else: # Needed to remove labels. if self.is_directed(): - G = networkx.DiGraph(self.edges(labels=False, sort=False)) + G = networkx.DiGraph(list(self.edge_iterator(labels=False))) else: - G = networkx.Graph(self.edges(labels=False, sort=False)) + G = networkx.Graph(list(self.edge_iterator(labels=False))) G.add_nodes_from(self) return networkx.single_source_dijkstra_path(G, u) @@ -16218,9 +16214,9 @@ def weight_function(e): else: # Needed to remove labels. if self.is_directed(): - G = networkx.DiGraph(self.edges(labels=False, sort=False)) + G = networkx.DiGraph(list(self.edge_iterator(labels=False))) else: - G = networkx.Graph(self.edges(labels=False, sort=False)) + G = networkx.Graph(list(self.edge_iterator(labels=False))) G.add_nodes_from(self) return networkx.single_source_dijkstra_path_length(G, u) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index f487479ad07..61acf625503 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -416,6 +416,7 @@ from sage.graphs.digraph import DiGraph from sage.graphs.independent_sets import IndependentSets from sage.misc.rest_index_of_methods import doc_index, gen_thematic_rest_table_index +from sage.graphs.views import EdgeView class Graph(GenericGraph): @@ -1059,9 +1060,10 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if (format is None and isinstance(data, list) and len(data) == 2 and - isinstance(data[0], list) and # a list of two lists, the second of - isinstance(data[1], list) and # which contains iterables (the edges) - (not data[1] or callable(getattr(data[1][0], "__iter__", None)))): + isinstance(data[0], list) and # a list of two lists, the second of + ((isinstance(data[1], list) and # which contains iterables (the edges) + (not data[1] or callable(getattr(data[1][0], "__iter__", None)))) or + (isinstance(data[1], EdgeView)))): format = "vertices_and_edges" if format is None and isinstance(data, dict): @@ -1069,7 +1071,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, format = 'dict_of_dicts' else: val = next(iter(data.values())) - if isinstance(val, list): + if isinstance(val, (list, EdgeView)): format = 'dict_of_lists' elif isinstance(val, dict): format = 'dict_of_dicts' @@ -1097,8 +1099,8 @@ def __init__(self, data=None, pos=None, loops=None, format=None, format = 'int' data = 0 - # Input is a list of edges - if format is None and isinstance(data, list): + # Input is a list of edges or an EdgeView + if format is None and isinstance(data, (list, EdgeView)): format = "list_of_edges" if weighted is None: weighted = False @@ -7831,7 +7833,7 @@ def kirchhoff_symanzik_polynomial(self, name='t'): from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - edges = self.edges() + edges = list(self.edge_iterator()) cycles = self.cycle_basis(output='edge') edge2int = {e: j for j, e in enumerate(edges)} @@ -7990,7 +7992,7 @@ def ihara_zeta_function_inverse(self): from sage.matrix.constructor import matrix H = self.subgraph(vertices=self.cores(k=2)[1]) - E = H.edges() + E = list(H.edge_iterator()) m = len(E) # compute (Hashimoto) edge matrix T T = matrix(ZZ, 2 * m, 2 * m, 0) diff --git a/src/sage/graphs/graph_decompositions/graph_products.pyx b/src/sage/graphs/graph_decompositions/graph_products.pyx index e4ebe69547e..7881c25a325 100644 --- a/src/sage/graphs/graph_decompositions/graph_products.pyx +++ b/src/sage/graphs/graph_decompositions/graph_products.pyx @@ -300,7 +300,7 @@ def is_cartesian_product(g, certificate=False, relabeling=False): # Edges uv and u'v' such that d(u,u')+d(v,v') != d(u,v')+d(v,u') are also # equivalent - cdef list edges = g_int.edges(labels=False, sort=False) + cdef list edges = list(g_int.edge_iterator(labels=False)) cdef dict d = g_int.distance_all_pairs() cdef int uu, vv for i, (u, v) in enumerate(edges): diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index 99ae990b789..64343519da4 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -2513,7 +2513,7 @@ def canaug_traverse_edge(g, aut_gens, property, dig=False, loops=False, implemen for ii in range(n): relabel_inverse[canonical_relabeling[ii]] = ii z_can = z.relabel(canonical_relabeling, inplace=False) - cut_edge_can = z_can.edges(labels=False, sort=True)[-1] + cut_edge_can = list(z_can.edges(labels=False, sort=True))[-1] cut_edge = [relabel_inverse[cut_edge_can[0]], relabel_inverse[cut_edge_can[1]]] if dig: cut_edge = tuple(cut_edge) diff --git a/src/sage/graphs/orientations.py b/src/sage/graphs/orientations.py index a6c2dafddfa..5b68e2b8a0e 100644 --- a/src/sage/graphs/orientations.py +++ b/src/sage/graphs/orientations.py @@ -196,7 +196,7 @@ def _strong_orientations_of_a_mixed_graph(Dg, V, E): sage: from sage.graphs.orientations import _strong_orientations_of_a_mixed_graph sage: g = graphs.CycleGraph(5) sage: Dg = DiGraph(g) # all edges of g will be doubly oriented - sage: it = _strong_orientations_of_a_mixed_graph(Dg, g.vertices(), g.edges(labels=False)) + sage: it = _strong_orientations_of_a_mixed_graph(Dg, list(g), list(g.edge_iterator(labels=False))) sage: len(list(it)) # there are two orientations of this multigraph 2 """ diff --git a/src/sage/graphs/spanning_tree.pyx b/src/sage/graphs/spanning_tree.pyx index 2992f9fa9b7..d88c326e336 100644 --- a/src/sage/graphs/spanning_tree.pyx +++ b/src/sage/graphs/spanning_tree.pyx @@ -433,7 +433,7 @@ cpdef boruvka(G, wfunction=None, bint check=False, bint by_weight=True): If the input graph is a tree, then return its edges:: sage: T = graphs.RandomTree(randint(1, 10)) - sage: T.edges() == sorted(boruvka(T, check=True)) + sage: list(T.edges(sort=True)) == sorted(boruvka(T, check=True)) True Check if the weight of MST returned by Prim's and Boruvka's is the same:: diff --git a/src/sage/graphs/tutte_polynomial.py b/src/sage/graphs/tutte_polynomial.py index 9b94881dd04..23ac1ab4d86 100644 --- a/src/sage/graphs/tutte_polynomial.py +++ b/src/sage/graphs/tutte_polynomial.py @@ -448,10 +448,9 @@ def __call__(self, graph): (0, 1, None) """ degrees = dict(graph.degree_iterator(labels=True)) - edges = graph.edges(labels=True) - edges.sort(key=lambda x: degrees[x[0]]+degrees[x[1]]) # Sort by degree - for e in edges: - return e + edges = graph.edges(labels=True, sort=False) + if edges: + return min(edges, key=lambda x: degrees[x[0]] + degrees[x[1]]) raise RuntimeError("no edges left to select") @@ -463,15 +462,15 @@ def __call__(self, graph): sage: from sage.graphs.tutte_polynomial import MaximizeDegree sage: G = graphs.PathGraph(6) sage: MaximizeDegree()(G) - (3, 4, None) + (1, 2, None) """ degrees = dict(graph.degree_iterator(labels=True)) - edges = graph.edges(labels=True) - edges.sort(key=lambda x: degrees[x[0]]+degrees[x[1]]) # Sort by degree - for e in reversed(edges): - return e + edges = graph.edges(labels=True, sort=False) + if edges: + return max(edges, key=lambda x: degrees[x[0]] + degrees[x[1]]) raise RuntimeError("no edges left to select") + ########### # Caching # ########### From 01579875c3b76eaf76421decbdc89c4fde53793a Mon Sep 17 00:00:00 2001 From: David Coudert Date: Sun, 3 Mar 2019 22:10:43 +0100 Subject: [PATCH 026/340] trac #27408: fix issues in other modules --- src/sage/combinat/cluster_algebra_quiver/quiver.py | 3 ++- src/sage/combinat/root_system/type_C.py | 2 +- src/sage/matroids/utilities.py | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver.py b/src/sage/combinat/cluster_algebra_quiver/quiver.py index 99eca0e1127..b44a510f715 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver.py @@ -44,6 +44,7 @@ from copy import copy from sage.rings.all import ZZ, CC, infinity from sage.graphs.all import Graph, DiGraph +from sage.graphs.views import EdgeView from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import QuiverMutationType, QuiverMutationType_Irreducible, QuiverMutationType_Reducible, _edge_list_to_matrix from sage.combinat.cluster_algebra_quiver.mutation_class import _principal_part, _digraph_mutate, _matrix_to_digraph, _dg_canonical_form, _mutation_class_iter, _digraph_to_dig6, _dig6_to_matrix from sage.combinat.cluster_algebra_quiver.mutation_type import _connected_mutation_type, _mutation_type_from_data, is_mutation_finite @@ -454,7 +455,7 @@ def __init__(self, data, frozen=None, user_labels=None): # if data is a list of edges, the appropriate digraph is constructed. - elif isinstance(data, list) and all(isinstance(x, (list,tuple)) for x in data): + elif isinstance(data, (list, EdgeView)) and all(isinstance(x, (list,tuple)) for x in data): dg = DiGraph(data) self.__init__(data=dg, frozen=frozen) diff --git a/src/sage/combinat/root_system/type_C.py b/src/sage/combinat/root_system/type_C.py index 60643bd6cc7..b170d9eed2a 100644 --- a/src/sage/combinat/root_system/type_C.py +++ b/src/sage/combinat/root_system/type_C.py @@ -221,7 +221,7 @@ def dynkin_diagram(self): O---O=<=O 1 2 3 C3 - sage: e = c.edges(); e.sort(); e + sage: c.edges(sort=True) [(1, 2, 1), (2, 1, 1), (2, 3, 1), (3, 2, 2)] sage: b = CartanType(['C',1]).dynkin_diagram() diff --git a/src/sage/matroids/utilities.py b/src/sage/matroids/utilities.py index 5c8ffcac830..45da7793493 100644 --- a/src/sage/matroids/utilities.py +++ b/src/sage/matroids/utilities.py @@ -300,8 +300,8 @@ def make_regular_matroid_from_matroid(matroid): for f in C.difference([e]): A[dB[f], dNB[e]] = 1 # Change some entries from -1 to 1 - entries = BipartiteGraph(A.transpose()).edges(labels=False) - while len(entries) > 0: + entries = list(BipartiteGraph(A.transpose()).edge_iterator(labels=False)) + while entries: L = [G.shortest_path(u, v) for u, v in entries] mindex, minval = min(enumerate(L), key=lambda x: len(x[1])) From 5cf8344cd92ff982bae5644340644556b0788ab5 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Mon, 4 Mar 2019 11:19:58 +0100 Subject: [PATCH 027/340] trac #27408: various corrections --- src/doc/en/reference/graphs/index.rst | 2 +- src/sage/graphs/views.py | 58 ++++++++++++++------------- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/doc/en/reference/graphs/index.rst b/src/doc/en/reference/graphs/index.rst index 3a63a38247f..e975fe6d650 100644 --- a/src/doc/en/reference/graphs/index.rst +++ b/src/doc/en/reference/graphs/index.rst @@ -14,7 +14,7 @@ Graph objects and methods sage/graphs/graph sage/graphs/digraph sage/graphs/bipartite_graph - sage/graphs/views.py + sage/graphs/views Constructors and databases -------------------------- diff --git a/src/sage/graphs/views.py b/src/sage/graphs/views.py index 8003d677f0f..9c383fa7d27 100644 --- a/src/sage/graphs/views.py +++ b/src/sage/graphs/views.py @@ -1,12 +1,13 @@ r""" View classes -This module implements views for vertices (:class:`VertexView`) and edges -(:class:`EdgeView`) of (di)graphs. A view is a read-only iterable container -enabling operations like ``for e in E`` and ``e in E``. It is updated as the -graph is updated. Hence, the graph should not be updated while iterating through -a view. Views can be iterated multiple times. +This module implements views for (di)graphs. A view is a read-only iterable +container enabling operations like ``for e in E`` and ``e in E``. It is updated +as the graph is updated. Hence, the graph should not be updated while iterating +through a view. Views can be iterated multiple times. +Classes +------- """ # **************************************************************************** # Copyright (C) 2019 David Coudert @@ -198,6 +199,30 @@ class EdgeView(SageObject): Traceback (most recent call last): ... RuntimeError: dictionary changed size during iteration + + Two :class:`EdgeView` are considered equal if they report either both + directed, or both undirected edges, they have the same settings for + ``ignore_direction``, they have the same settings for ``labels``, and they + report the same edges in the same order:: + + sage: G = graphs.HouseGraph() + sage: EG = EdgeView(G) + sage: H = Graph(list(G.edge_iterator())) + sage: EH = EdgeView(H) + sage: EG == EH + True + sage: G.add_edge(0, 10) + sage: EG = EdgeView(G) + sage: EG == EH + False + sage: H.add_edge(0, 10) + sage: EH = EdgeView(H) + sage: EG == EH + True + sage: H = G.strong_orientation() + sage: EH = EdgeView(H) + sage: EG == EH + False """ def __init__(self, G, vertices=None, labels=True, ignore_direction=False, @@ -401,26 +426,3 @@ def __contains__(self, e): return (self.graph._backend.has_edge(u, v, label) or self.graph._backend.has_edge(v, u, label)) return self.graph._backend.has_edge(u, v, label) - - -class VertexView(SageObject): - r""" - VertexView class. - - This class implements a read-only iterable container of vertices enabling - operations like ``for v in V`` and ``v in V``. It is updated as the graph is - updated. Hence, the graph should not be updated while iterating through a - :class:`VertexView`. A :class:`VertexView` can be iterated multiple times. - - INPUT: - - - ``G`` -- a (di)graph - - """ - - def __init__(self, G): - """ - Construction of this :class:`VertexView`. - """ - raise NotImplementedError() - From b3f6f4b5dae864c21afd0aadc8c416326a2a1003 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Mon, 4 Mar 2019 11:43:14 +0100 Subject: [PATCH 028/340] trac #27408: start internal variables with _ --- src/sage/graphs/views.py | 63 ++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/src/sage/graphs/views.py b/src/sage/graphs/views.py index 9c383fa7d27..d1f9f462c9d 100644 --- a/src/sage/graphs/views.py +++ b/src/sage/graphs/views.py @@ -244,26 +244,25 @@ def __init__(self, G, vertices=None, labels=True, ignore_direction=False, ... ValueError: sort keyword is False, yet a key function is given """ - self.graph = G - self.directed = G._directed + self._graph = G if vertices is None: - self.vertices = G - self.vertex_set = G + self._vertices = G + self._vertex_set = G elif vertices in G: - self.vertices = [vertices] - self.vertex_set = self.vertices + self._vertices = [vertices] + self._vertex_set = self._vertices else: - self.vertices = list(vertices) - self.vertex_set = frozenset(self.vertices) + self._vertices = list(vertices) + self._vertex_set = frozenset(self._vertices) # None and 0 are interpreted as False, 1 as True - self.labels = True if labels else False - self.ignore_direction = True if ignore_direction else False - self.sort_edges = True if sort else False + self._labels = True if labels else False + self._ignore_direction = True if ignore_direction else False + self._sort_edges = True if sort else False if not sort and key: raise ValueError('sort keyword is False, yet a key function is given') - self.sort_edges_key = key + self._sort_edges_key = key def __len__(self): """ @@ -283,8 +282,8 @@ def __len__(self): sage: len(E) 2 """ - if self.vertices is self.graph: - return self.graph.size() + if self._vertices is self._graph: + return self._graph.size() else: return sum(1 for _ in self) @@ -318,17 +317,17 @@ def __iter__(self): sage: sum(1 for e in E for ee in E) == len(E) * len(E) True """ - if self.directed: - if self.ignore_direction: - edges = chain(self.graph._backend.iterator_out_edges(self.vertices, self.labels), - self.graph._backend.iterator_in_edges(self.vertices, self.labels)) + if self._graph._directed: + if self._ignore_direction: + edges = chain(self._graph._backend.iterator_out_edges(self._vertices, self._labels), + self._graph._backend.iterator_in_edges(self._vertices, self._labels)) else: - edges = self.graph._backend.iterator_out_edges(self.vertices, self.labels) + edges = self._graph._backend.iterator_out_edges(self._vertices, self._labels) else: - edges = self.graph._backend.iterator_edges(self.vertices, self.labels) + edges = self._graph._backend.iterator_edges(self._vertices, self._labels) - if self.sort_edges: - edges = sorted(list(edges), key=self.sort_edges_key) + if self._sort_edges: + edges = sorted(edges, key=self._sort_edges_key) for e in edges: yield e @@ -372,9 +371,9 @@ def __eq__(self, other): if self is other: return True # Check parameters - if (self.directed != other.directed or - self.ignore_direction != other.ignore_direction or - self.labels != other.labels): + if (self._graph._directed != other._graph._directed or + self._ignore_direction != other._ignore_direction or + self._labels != other._labels): return False # Check that the same edges are reported in the same order return all(es == eo for es, eo in zip(self, other)) @@ -408,7 +407,7 @@ def __contains__(self, e): sage: (0, 1, None) in E True """ - if self.labels: + if self._labels: try: u, v, label = e except Exception: @@ -419,10 +418,10 @@ def __contains__(self, e): except Exception: return False label = None - if (self.vertex_set is not self.graph - and u not in self.vertex_set and v not in self.vertex_set): + if (self._vertex_set is not self._graph + and u not in self._vertex_set and v not in self._vertex_set): return False - if self.directed and self.ignore_direction: - return (self.graph._backend.has_edge(u, v, label) - or self.graph._backend.has_edge(v, u, label)) - return self.graph._backend.has_edge(u, v, label) + if self._graph._directed and self._ignore_direction: + return (self._graph._backend.has_edge(u, v, label) + or self._graph._backend.has_edge(v, u, label)) + return self._graph._backend.has_edge(u, v, label) From 367534f70e81daab2d36aa68eb0dad0f29efdad7 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Tue, 5 Mar 2019 14:31:51 +0100 Subject: [PATCH 029/340] trac #27408: move to Cython file --- src/module_list.py | 3 +++ src/sage/graphs/{views.py => views.pyx} | 5 +++++ 2 files changed, 8 insertions(+) rename src/sage/graphs/{views.py => views.pyx} (99%) diff --git a/src/module_list.py b/src/module_list.py index 90294b7e3e4..0373dd2c5de 100644 --- a/src/module_list.py +++ b/src/module_list.py @@ -417,6 +417,9 @@ def uname_specific(name, value, alternative): Extension('sage.graphs.base.boost_graph', sources = ['sage/graphs/base/boost_graph.pyx']), + Extension('sage.graphs.views', + sources = ['sage/graphs/views.pyx']), + ################################ ## ## sage.groups diff --git a/src/sage/graphs/views.py b/src/sage/graphs/views.pyx similarity index 99% rename from src/sage/graphs/views.py rename to src/sage/graphs/views.pyx index d1f9f462c9d..413f78d3507 100644 --- a/src/sage/graphs/views.py +++ b/src/sage/graphs/views.pyx @@ -6,6 +6,11 @@ as the graph is updated. Hence, the graph should not be updated while iterating through a view. Views can be iterated multiple times. +.. TODO:: + + - View of neighborhood to get open/close neighborhood of a vertex/set of + vertices, and also the vertex boundary + Classes ------- """ From c68e5d147be78ac10598bdab73ec1b2d1b953149 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Tue, 5 Mar 2019 15:08:08 +0100 Subject: [PATCH 030/340] trac #27408: rename EdgesView and revert some edges/edge_iterator --- .../combinat/cluster_algebra_quiver/quiver.py | 4 +- src/sage/graphs/comparability.pyx | 2 +- src/sage/graphs/connectivity.pyx | 8 +- src/sage/graphs/digraph.py | 8 +- src/sage/graphs/generic_graph.py | 18 ++-- src/sage/graphs/graph.py | 14 +-- .../graph_decompositions/graph_products.pyx | 2 +- src/sage/graphs/orientations.py | 2 +- src/sage/graphs/views.pyx | 102 +++++++++--------- src/sage/matroids/utilities.py | 2 +- 10 files changed, 81 insertions(+), 81 deletions(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver.py b/src/sage/combinat/cluster_algebra_quiver/quiver.py index b44a510f715..2b709d3918e 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver.py @@ -44,7 +44,7 @@ from copy import copy from sage.rings.all import ZZ, CC, infinity from sage.graphs.all import Graph, DiGraph -from sage.graphs.views import EdgeView +from sage.graphs.views import EdgesView from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import QuiverMutationType, QuiverMutationType_Irreducible, QuiverMutationType_Reducible, _edge_list_to_matrix from sage.combinat.cluster_algebra_quiver.mutation_class import _principal_part, _digraph_mutate, _matrix_to_digraph, _dg_canonical_form, _mutation_class_iter, _digraph_to_dig6, _dig6_to_matrix from sage.combinat.cluster_algebra_quiver.mutation_type import _connected_mutation_type, _mutation_type_from_data, is_mutation_finite @@ -455,7 +455,7 @@ def __init__(self, data, frozen=None, user_labels=None): # if data is a list of edges, the appropriate digraph is constructed. - elif isinstance(data, (list, EdgeView)) and all(isinstance(x, (list,tuple)) for x in data): + elif isinstance(data, (list, EdgesView)) and all(isinstance(x, (list,tuple)) for x in data): dg = DiGraph(data) self.__init__(data=dg, frozen=frozen) diff --git a/src/sage/graphs/comparability.pyx b/src/sage/graphs/comparability.pyx index c294672ab1b..2d9e41bbefe 100644 --- a/src/sage/graphs/comparability.pyx +++ b/src/sage/graphs/comparability.pyx @@ -707,7 +707,7 @@ def is_permutation(g, algorithm="greedy", certificate=False, check=True, return False, co_certif # Building the two orderings - tmp = list(co_certif.edge_iterator(labels=False)) + tmp = list(co_certif.edges(labels=False, sort=False)) for u,v in certif.edge_iterator(labels=False): co_certif.add_edge(v,u) certif.add_edges(tmp) diff --git a/src/sage/graphs/connectivity.pyx b/src/sage/graphs/connectivity.pyx index bedc03ae3d9..f8544cb1939 100644 --- a/src/sage/graphs/connectivity.pyx +++ b/src/sage/graphs/connectivity.pyx @@ -2114,9 +2114,9 @@ def cleave(G, cut_vertices=None, virtual_edges=True, solver=None, verbose=0): # is needed. cocycles = Graph([cut_vertices, []], multiedges=True) if K.size(): - cocycles.add_edges(list(K.edge_iterator()) * (len(cut_sides) + 1)) + cocycles.add_edges(list(K.edges(sort=False)) * (len(cut_sides) + 1)) if virtual_edges and virtual_cut_graph: - cocycles.add_edges(list(virtual_cut_graph.edge_iterator()) * len(cut_sides)) + cocycles.add_edges(list(virtual_cut_graph.edges(sort=False)) * len(cut_sides)) return cut_sides, cocycles, virtual_cut_graph @@ -2255,7 +2255,7 @@ def spqr_tree(G, algorithm="Hopcroft_Tarjan", solver=None, verbose=0): sage: T = G.spqr_tree(algorithm="cleave") sage: Counter(u[0] for u in T) Counter({'R': 1}) - sage: for u,v in list(G.edge_iterator(labels=False)): + 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()) @@ -2263,7 +2263,7 @@ def spqr_tree(G, algorithm="Hopcroft_Tarjan", solver=None, verbose=0): sage: T = G.spqr_tree(algorithm="cleave") sage: sorted(Counter(u[0] for u in T).items()) [('P', 15), ('R', 1), ('S', 15)] - sage: for u,v in list(G.edge_iterator(labels=False)): + 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()) diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index 7679bff256c..1ead02d2331 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -166,7 +166,7 @@ import sage.graphs.generic_graph_pyx as generic_graph_pyx from sage.graphs.generic_graph import GenericGraph from sage.graphs.dot2tex_utils import have_dot2tex -from sage.graphs.views import EdgeView +from sage.graphs.views import EdgesView class DiGraph(GenericGraph): @@ -663,7 +663,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, isinstance(data[0], list) and # a list of two lists, the second of ((isinstance(data[1], list) and # which contains iterables (the edges) (not data[1] or callable(getattr(data[1][0], "__iter__", None)))) or - (isinstance(data[1], EdgeView)))): + (isinstance(data[1], EdgesView)))): format = "vertices_and_edges" if format is None and isinstance(data, dict): @@ -699,8 +699,8 @@ def __init__(self, data=None, pos=None, loops=None, format=None, format = 'int' data = 0 - # Input is a list of edges or an EdgeView - if format is None and isinstance(data, (list, EdgeView)): + # Input is a list of edges or an EdgesView + if format is None and isinstance(data, (list, EdgesView)): format = "list_of_edges" if weighted is None: weighted = False diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 93196238c98..958c2cb1a85 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -71,7 +71,7 @@ :meth:`~GenericGraph.delete_multiedge` | Delete all edges from ``u`` to ``v``. :meth:`~GenericGraph.set_edge_label` | Set the edge label of a given edge. :meth:`~GenericGraph.has_edge` | Check whether ``(u, v)`` is an edge of the (di)graph. - :meth:`~GenericGraph.edges` | Return a :class:`~EdgeView` of edges. + :meth:`~GenericGraph.edges` | Return a :class:`~EdgesView` of edges. :meth:`~GenericGraph.edge_boundary` | Return a list of edges ``(u,v,l)`` with ``u`` in ``vertices1`` :meth:`~GenericGraph.edge_iterator` | Return an iterator over edges. :meth:`~GenericGraph.edges_incident` | Return incident edges to some vertices. @@ -420,7 +420,7 @@ from copy import copy -from sage.graphs.views import EdgeView +from sage.graphs.views import EdgesView from .generic_graph_pyx import GenericGraph_pyx, spring_layout_fast from .dot2tex_utils import assert_have_dot2tex @@ -10991,7 +10991,7 @@ def has_edge(self, u, v=None, label=None): def edges(self, labels=True, sort=True, key=None): r""" - Return a :class:`~EdgeView` of edges. + Return a :class:`~EdgesView` of edges. Each edge is a triple ``(u, v, l)`` where ``u`` and ``v`` are vertices and ``l`` is a label. If the parameter ``labels`` is ``False`` then a @@ -11011,7 +11011,7 @@ def edges(self, labels=True, sort=True, key=None): one argument and returns a value that can be used for comparisons in the sorting algorithm - OUTPUT: A :class:`~EdgeView`. + OUTPUT: A :class:`~EdgesView`. .. WARNING:: @@ -11079,7 +11079,7 @@ def edges(self, labels=True, sort=True, key=None): sage: G.edges() [(0, 1, [8]), (0, 2, [7])] """ - return EdgeView(self, labels=labels, sort=sort, key=key) + return EdgesView(self, labels=labels, sort=sort, key=key) def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False): r""" @@ -15991,9 +15991,9 @@ def weight_function(e): else: # Needed to remove labels. if self.is_directed(): - G = networkx.DiGraph(list(self.edge_iterator(labels=False))) + G = networkx.DiGraph(list(self.edges(labels=False, sort=False))) else: - G = networkx.Graph(list(self.edge_iterator(labels=False))) + G = networkx.Graph(list(self.edges(labels=False, sort=False))) G.add_nodes_from(self) return networkx.single_source_dijkstra_path(G, u) @@ -16214,9 +16214,9 @@ def weight_function(e): else: # Needed to remove labels. if self.is_directed(): - G = networkx.DiGraph(list(self.edge_iterator(labels=False))) + G = networkx.DiGraph(list(self.edges(labels=False, sort=False))) else: - G = networkx.Graph(list(self.edge_iterator(labels=False))) + G = networkx.Graph(list(self.edges(labels=False, sort=False))) G.add_nodes_from(self) return networkx.single_source_dijkstra_path_length(G, u) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 61acf625503..87e177fd10c 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -416,7 +416,7 @@ from sage.graphs.digraph import DiGraph from sage.graphs.independent_sets import IndependentSets from sage.misc.rest_index_of_methods import doc_index, gen_thematic_rest_table_index -from sage.graphs.views import EdgeView +from sage.graphs.views import EdgesView class Graph(GenericGraph): @@ -1063,7 +1063,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, isinstance(data[0], list) and # a list of two lists, the second of ((isinstance(data[1], list) and # which contains iterables (the edges) (not data[1] or callable(getattr(data[1][0], "__iter__", None)))) or - (isinstance(data[1], EdgeView)))): + (isinstance(data[1], EdgesView)))): format = "vertices_and_edges" if format is None and isinstance(data, dict): @@ -1071,7 +1071,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, format = 'dict_of_dicts' else: val = next(iter(data.values())) - if isinstance(val, (list, EdgeView)): + if isinstance(val, (list, EdgesView)): format = 'dict_of_lists' elif isinstance(val, dict): format = 'dict_of_dicts' @@ -1099,8 +1099,8 @@ def __init__(self, data=None, pos=None, loops=None, format=None, format = 'int' data = 0 - # Input is a list of edges or an EdgeView - if format is None and isinstance(data, (list, EdgeView)): + # Input is a list of edges or an EdgesView + if format is None and isinstance(data, (list, EdgesView)): format = "list_of_edges" if weighted is None: weighted = False @@ -7833,7 +7833,7 @@ def kirchhoff_symanzik_polynomial(self, name='t'): from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - edges = list(self.edge_iterator()) + edges = list(self.edges(sort=False)) cycles = self.cycle_basis(output='edge') edge2int = {e: j for j, e in enumerate(edges)} @@ -7992,7 +7992,7 @@ def ihara_zeta_function_inverse(self): from sage.matrix.constructor import matrix H = self.subgraph(vertices=self.cores(k=2)[1]) - E = list(H.edge_iterator()) + E = list(H.edges(sort=False)) m = len(E) # compute (Hashimoto) edge matrix T T = matrix(ZZ, 2 * m, 2 * m, 0) diff --git a/src/sage/graphs/graph_decompositions/graph_products.pyx b/src/sage/graphs/graph_decompositions/graph_products.pyx index 7881c25a325..e567c9b485e 100644 --- a/src/sage/graphs/graph_decompositions/graph_products.pyx +++ b/src/sage/graphs/graph_decompositions/graph_products.pyx @@ -300,7 +300,7 @@ def is_cartesian_product(g, certificate=False, relabeling=False): # Edges uv and u'v' such that d(u,u')+d(v,v') != d(u,v')+d(v,u') are also # equivalent - cdef list edges = list(g_int.edge_iterator(labels=False)) + cdef list edges = list(g_int.edges(labels=False, sort=False)) cdef dict d = g_int.distance_all_pairs() cdef int uu, vv for i, (u, v) in enumerate(edges): diff --git a/src/sage/graphs/orientations.py b/src/sage/graphs/orientations.py index 5b68e2b8a0e..fd05c5b08d9 100644 --- a/src/sage/graphs/orientations.py +++ b/src/sage/graphs/orientations.py @@ -196,7 +196,7 @@ def _strong_orientations_of_a_mixed_graph(Dg, V, E): sage: from sage.graphs.orientations import _strong_orientations_of_a_mixed_graph sage: g = graphs.CycleGraph(5) sage: Dg = DiGraph(g) # all edges of g will be doubly oriented - sage: it = _strong_orientations_of_a_mixed_graph(Dg, list(g), list(g.edge_iterator(labels=False))) + sage: it = _strong_orientations_of_a_mixed_graph(Dg, list(g), list(g.edges(labels=False, sort=False))) sage: len(list(it)) # there are two orientations of this multigraph 2 """ diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index 413f78d3507..264ea911046 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -30,16 +30,16 @@ from sage.structure.sage_object import SageObject from itertools import chain -class EdgeView(SageObject): +class EdgesView(SageObject): r""" - EdgeView class. + EdgesView class. This class implements a read-only iterable container of edges enabling - operations like ``for e in E`` and ``e in E``. An :class:`EdgeView` can be + operations like ``for e in E`` and ``e in E``. An :class:`EdgesView` can be iterated multiple times, and checking membership is done in constant time. It avoids the construction of edge lists and so consumes little memory. It is updated as the graph is updated. Hence, the graph should not - be updated while iterating through an :class:`EdgeView`. + be updated while iterating through an :class:`EdgesView`. INPUT: @@ -75,15 +75,15 @@ class EdgeView(SageObject): EXAMPLES:: - sage: from sage.graphs.views import EdgeView + sage: from sage.graphs.views import EdgesView sage: G = Graph([(0, 1, 'C'), (0, 2, 'A'), (1, 2, 'B')]) - sage: E = EdgeView(G); E + sage: E = EdgesView(G); E [(0, 1, 'C'), (0, 2, 'A'), (1, 2, 'B')] sage: (1, 2) in E False sage: (1, 2, 'B') in E True - sage: E = EdgeView(G, labels=False); E + sage: E = EdgesView(G, labels=False); E [(0, 1), (0, 2), (1, 2)] sage: (1, 2) in E True @@ -92,7 +92,7 @@ class EdgeView(SageObject): sage: [e for e in E] [(0, 1), (0, 2), (1, 2)] - An :class:`EdgeView` can be iterated multiple times:: + An :class:`EdgesView` can be iterated multiple times:: sage: G = graphs.CycleGraph(3) sage: print(E) @@ -114,11 +114,11 @@ class EdgeView(SageObject): We can check if a view is empty:: - sage: E = EdgeView(graphs.CycleGraph(3)) + sage: E = EdgesView(graphs.CycleGraph(3)) sage: if E: ....: print('not empty') not empty - sage: E = EdgeView(Graph()) + sage: E = EdgesView(Graph()) sage: if not E: ....: print('empty') empty @@ -127,55 +127,55 @@ class EdgeView(SageObject): fashion:: sage: G = Graph([(0, 1, 'C'), (0, 2, 'A'), (1, 2, 'B')]) - sage: E = EdgeView(G, sort=True); E + sage: E = EdgesView(G, sort=True); E [(0, 1, 'C'), (0, 2, 'A'), (1, 2, 'B')] This can be overridden by specifying a key function. This first example just ignores the labels in the third component of the triple:: sage: G = Graph([(0, 1, 'C'), (0, 2, 'A'), (1, 2, 'B')]) - sage: E = EdgeView(G, sort=True, key=lambda x: (x[1], -x[0])); E + sage: E = EdgesView(G, sort=True, key=lambda x: (x[1], -x[0])); E [(0, 1, 'C'), (1, 2, 'B'), (0, 2, 'A')] We can also sort according to the labels:: sage: G = Graph([(0, 1, 'C'), (0, 2, 'A'), (1, 2, 'B')]) - sage: E = EdgeView(G, sort=True, key=lambda x: x[2]); E + sage: E = EdgesView(G, sort=True, key=lambda x: x[2]); E [(0, 2, 'A'), (1, 2, 'B'), (0, 1, 'C')] With a directed graph:: sage: G = digraphs.DeBruijn(2, 2) - sage: E = EdgeView(G, labels=False, sort=True); E + sage: E = EdgesView(G, labels=False, sort=True); E [('00', '00'), ('00', '01'), ('01', '10'), ('01', '11'), ('10', '00'), ('10', '01'), ('11', '10'), ('11', '11')] - sage: E = EdgeView(G, labels=False, sort=True, key=lambda e:(e[1], e[0])); E + sage: E = EdgesView(G, labels=False, sort=True, key=lambda e:(e[1], e[0])); E [('00', '00'), ('10', '00'), ('00', '01'), ('10', '01'), ('01', '10'), ('11', '10'), ('01', '11'), ('11', '11')] We can consider only edges incident to a specified set of vertices:: sage: G = graphs.CycleGraph(5) - sage: E = EdgeView(G, vertices=[0, 1], labels=False, sort=True); E + sage: E = EdgesView(G, vertices=[0, 1], labels=False, sort=True); E [(0, 1), (0, 4), (1, 2)] - sage: E = EdgeView(G, vertices=0, labels=False, sort=True); E + sage: E = EdgesView(G, vertices=0, labels=False, sort=True); E [(0, 1), (0, 4)] - sage: E = EdgeView(G, vertices=None, labels=False, sort=True); E + sage: E = EdgesView(G, vertices=None, labels=False, sort=True); E [(0, 1), (0, 4), (1, 2), (2, 3), (3, 4)] sage: G = digraphs.Circuit(5) - sage: E = EdgeView(G, vertices=[0, 1], labels=False, sort=True); E + sage: E = EdgesView(G, vertices=[0, 1], labels=False, sort=True); E [(0, 1), (1, 2)] We can ignore the direction of the edges of a directed graph, in which case we search accross edges in either direction:: sage: G = digraphs.Circuit(5) - sage: E = EdgeView(G, vertices=[0, 1], labels=False, sort=True, ignore_direction=False); E + sage: E = EdgesView(G, vertices=[0, 1], labels=False, sort=True, ignore_direction=False); E [(0, 1), (1, 2)] sage: (1, 0) in E False - sage: E = EdgeView(G, vertices=[0, 1], labels=False, sort=True, ignore_direction=True); E + sage: E = EdgesView(G, vertices=[0, 1], labels=False, sort=True, ignore_direction=True); E [(0, 1), (0, 1), (1, 2), (4, 0)] sage: (1, 0) in E True @@ -185,7 +185,7 @@ class EdgeView(SageObject): A view is updated as the graph is updated:: sage: G = Graph() - sage: E = EdgeView(G, vertices=[0, 3], labels=False); E + sage: E = EdgesView(G, vertices=[0, 3], labels=False); E [] sage: G.add_edges([(0, 1), (1, 2)]) sage: E @@ -197,7 +197,7 @@ class EdgeView(SageObject): Hence, the graph should not be updated while iterating through a view:: sage: G = Graph([('a', 'b'), ('b', 'c')]) - sage: E = EdgeView(G, labels=False, sort=False); E + sage: E = EdgesView(G, labels=False, sort=False); E [('a', 'b'), ('b', 'c')] sage: for u, v in E: ....: G.add_edge(u + u, v + v) @@ -205,27 +205,27 @@ class EdgeView(SageObject): ... RuntimeError: dictionary changed size during iteration - Two :class:`EdgeView` are considered equal if they report either both + Two :class:`EdgesView` are considered equal if they report either both directed, or both undirected edges, they have the same settings for ``ignore_direction``, they have the same settings for ``labels``, and they report the same edges in the same order:: sage: G = graphs.HouseGraph() - sage: EG = EdgeView(G) + sage: EG = EdgesView(G) sage: H = Graph(list(G.edge_iterator())) - sage: EH = EdgeView(H) + sage: EH = EdgesView(H) sage: EG == EH True sage: G.add_edge(0, 10) - sage: EG = EdgeView(G) + sage: EG = EdgesView(G) sage: EG == EH False sage: H.add_edge(0, 10) - sage: EH = EdgeView(H) + sage: EH = EdgesView(H) sage: EG == EH True sage: H = G.strong_orientation() - sage: EH = EdgeView(H) + sage: EH = EdgesView(H) sage: EG == EH False """ @@ -233,18 +233,18 @@ class EdgeView(SageObject): def __init__(self, G, vertices=None, labels=True, ignore_direction=False, sort=True, key=None): """ - Construction of this :class:`EdgeView`. + Construction of this :class:`EdgesView`. EXAMPLES:: - sage: from sage.graphs.views import EdgeView + sage: from sage.graphs.views import EdgesView sage: G = Graph([(0, 1, 'C'), (0, 2, 'A'), (1, 2, 'B')]) - sage: E = EdgeView(G); E + sage: E = EdgesView(G); E [(0, 1, 'C'), (0, 2, 'A'), (1, 2, 'B')] TESTS:: - sage: EdgeView(Graph(), sort=False, key=lambda x:0) + sage: EdgesView(Graph(), sort=False, key=lambda x:0) Traceback (most recent call last): ... ValueError: sort keyword is False, yet a key function is given @@ -275,14 +275,14 @@ class EdgeView(SageObject): EXAMPLES:: - sage: from sage.graphs.views import EdgeView + sage: from sage.graphs.views import EdgesView sage: G = graphs.HouseGraph() - sage: E = EdgeView(G) + sage: E = EdgesView(G) sage: len(E) 6 sage: len(E) == G.size() True - sage: E = EdgeView(G, vertices=0, labels=False); E + sage: E = EdgesView(G, vertices=0, labels=False); E [(0, 1), (0, 2)] sage: len(E) 2 @@ -298,9 +298,9 @@ class EdgeView(SageObject): EXAMPLES:: - sage: from sage.graphs.views import EdgeView + sage: from sage.graphs.views import EdgesView sage: G = graphs.HouseGraph() - sage: E = EdgeView(G, labels=False) + sage: E = EdgesView(G, labels=False) sage: repr(E) '[(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)]' sage: E @@ -314,9 +314,9 @@ class EdgeView(SageObject): EXAMPLES:: - sage: from sage.graphs.views import EdgeView + sage: from sage.graphs.views import EdgesView sage: G = graphs.HouseGraph() - sage: E = EdgeView(G, labels=False) + sage: E = EdgesView(G, labels=False) sage: list(E) [(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)] sage: sum(1 for e in E for ee in E) == len(E) * len(E) @@ -343,7 +343,7 @@ class EdgeView(SageObject): Do not call this method directly. That is, for ``E1.__eq__(E2)`` write ``E1 == E2``. - Two :class:`EdgeView` are considered equal if the following hold: + Two :class:`EdgesView` are considered equal if the following hold: - they report either both directed, or both undirected edges; - they have the same settings for ``ignore_direction``; - they have the same settings for ``labels``; @@ -351,27 +351,27 @@ class EdgeView(SageObject): EXAMPLES:: - sage: from sage.graphs.views import EdgeView + sage: from sage.graphs.views import EdgesView sage: G = graphs.HouseGraph() - sage: EG = EdgeView(G) + sage: EG = EdgesView(G) sage: H = Graph(list(G.edge_iterator())) - sage: EH = EdgeView(H) + sage: EH = EdgesView(H) sage: EG == EH True sage: G.add_edge(0, 10) - sage: EG = EdgeView(G) + sage: EG = EdgesView(G) sage: EG == EH False sage: H.add_edge(0, 10) - sage: EH = EdgeView(H) + sage: EH = EdgesView(H) sage: EG == EH True sage: H = G.strong_orientation() - sage: EH = EdgeView(H) + sage: EH = EdgesView(H) sage: EG == EH False """ - if not isinstance(other, EdgeView): + if not isinstance(other, EdgesView): return False if self is other: return True @@ -395,16 +395,16 @@ class EdgeView(SageObject): EXAMPLES:: - sage: from sage.graphs.views import EdgeView + sage: from sage.graphs.views import EdgesView sage: G = Graph([(0, 1)]) - sage: E = EdgeView(G, labels=False) + sage: E = EdgesView(G, labels=False) sage: print(E) [(0, 1)] sage: (0, 1) in E True sage: (0, 1, None) in E False - sage: E = EdgeView(G, labels=True) + sage: E = EdgesView(G, labels=True) sage: print(E) [(0, 1, None)] sage: (0, 1) in E diff --git a/src/sage/matroids/utilities.py b/src/sage/matroids/utilities.py index 45da7793493..fc92e05715a 100644 --- a/src/sage/matroids/utilities.py +++ b/src/sage/matroids/utilities.py @@ -300,7 +300,7 @@ def make_regular_matroid_from_matroid(matroid): for f in C.difference([e]): A[dB[f], dNB[e]] = 1 # Change some entries from -1 to 1 - entries = list(BipartiteGraph(A.transpose()).edge_iterator(labels=False)) + entries = list(BipartiteGraph(A.transpose()).edges(labels=False, sort=False)) while entries: L = [G.shortest_path(u, v) for u, v in entries] mindex, minval = min(enumerate(L), key=lambda x: len(x[1])) From 5f9cae862e30c338b6a7045c402e9218b589ed23 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Tue, 5 Mar 2019 15:24:29 +0100 Subject: [PATCH 031/340] trac #27408: use yield from in __iter__ --- src/sage/graphs/views.pyx | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index 264ea911046..39e4fe7d443 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -26,11 +26,7 @@ Classes from __future__ import print_function, absolute_import -from sage.structure.sage_object import SageObject -from itertools import chain - - -class EdgesView(SageObject): +class EdgesView(): r""" EdgesView class. @@ -265,7 +261,7 @@ class EdgesView(SageObject): self._labels = True if labels else False self._ignore_direction = True if ignore_direction else False self._sort_edges = True if sort else False - if not sort and key: + if not sort and key is not None: raise ValueError('sort keyword is False, yet a key function is given') self._sort_edges_key = key @@ -292,7 +288,7 @@ class EdgesView(SageObject): else: return sum(1 for _ in self) - def _repr_(self): + def __repr__(self): """ Return a string representation of ``self``. @@ -322,19 +318,17 @@ class EdgesView(SageObject): sage: sum(1 for e in E for ee in E) == len(E) * len(E) True """ - if self._graph._directed: - if self._ignore_direction: - edges = chain(self._graph._backend.iterator_out_edges(self._vertices, self._labels), - self._graph._backend.iterator_in_edges(self._vertices, self._labels)) - else: - edges = self._graph._backend.iterator_out_edges(self._vertices, self._labels) - else: - edges = self._graph._backend.iterator_edges(self._vertices, self._labels) - if self._sort_edges: - edges = sorted(edges, key=self._sort_edges_key) - for e in edges: - yield e + self._sort_edges = False + yield from sorted(self, key=self._sort_edges_key) + self._sort_edges = True + else: + if self._graph._directed: + yield from self._graph._backend.iterator_out_edges(self._vertices, self._labels) + if self._ignore_direction: + yield from self._graph._backend.iterator_in_edges(self._vertices, self._labels) + else: + yield from self._graph._backend.iterator_edges(self._vertices, self._labels) def __eq__(self, other): """ From 5ba0c3fa4b856e98aad4bbecf74c28db9e795973 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Tue, 5 Mar 2019 16:34:07 +0100 Subject: [PATCH 032/340] trac #27408: add __mul__, __rmul__, __getitem__, __add__ --- src/sage/graphs/base/graph_backends.pyx | 4 +- .../graphs/base/static_sparse_backend.pyx | 2 +- src/sage/graphs/graph_generators.py | 2 +- src/sage/graphs/views.pyx | 183 +++++++++++++++++- 4 files changed, 185 insertions(+), 6 deletions(-) diff --git a/src/sage/graphs/base/graph_backends.pyx b/src/sage/graphs/base/graph_backends.pyx index 25ad072d04c..090bf6c6fdc 100644 --- a/src/sage/graphs/base/graph_backends.pyx +++ b/src/sage/graphs/base/graph_backends.pyx @@ -703,9 +703,7 @@ cdef class GenericGraphBackend(SageObject): No problems with loops and multiple edges, with Labels:: sage: g = Graph(multiedges=True, loops=True) - sage: E = graphs.PetersenGraph().edges(sort=False) - sage: g.add_edges(E) - sage: g.add_edges(E) + sage: g.add_edges(2 * graphs.PetersenGraph().edges(sort=False)) sage: g.add_edge(0, 0) sage: g.add_edge(1, 1, "a label") sage: g.add_edges([(0, 1, "labellll"), (0, 1, "labellll"), (0, 1, "LABELLLL")]) diff --git a/src/sage/graphs/base/static_sparse_backend.pyx b/src/sage/graphs/base/static_sparse_backend.pyx index ece2de4a02a..f3948a3be55 100644 --- a/src/sage/graphs/base/static_sparse_backend.pyx +++ b/src/sage/graphs/base/static_sparse_backend.pyx @@ -393,7 +393,7 @@ cdef class StaticSparseBackend(CGraphBackend): sage: g = DiGraph(digraphs.DeBruijn(4, 3), data_structure="static_sparse") sage: gi = DiGraph(g, data_structure="static_sparse") - sage: list(gi.edges())[0] + sage: gi.edges()[0] ('000', '000', '0') sage: sorted(gi.edges_incident('111')) [('111', '110', '0'), diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index 64343519da4..99ae990b789 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -2513,7 +2513,7 @@ def canaug_traverse_edge(g, aut_gens, property, dig=False, loops=False, implemen for ii in range(n): relabel_inverse[canonical_relabeling[ii]] = ii z_can = z.relabel(canonical_relabeling, inplace=False) - cut_edge_can = list(z_can.edges(labels=False, sort=True))[-1] + cut_edge_can = z_can.edges(labels=False, sort=True)[-1] cut_edge = [relabel_inverse[cut_edge_can[0]], relabel_inverse[cut_edge_can[1]]] if dig: cut_edge = tuple(cut_edge) diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index 39e4fe7d443..b97da8ac9b6 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -208,7 +208,7 @@ class EdgesView(): sage: G = graphs.HouseGraph() sage: EG = EdgesView(G) - sage: H = Graph(list(G.edge_iterator())) + sage: H = Graph(EG) sage: EH = EdgesView(H) sage: EG == EH True @@ -224,6 +224,47 @@ class EdgesView(): sage: EH = EdgesView(H) sage: EG == EH False + + The sum of two :class:`EdgesView` is a list containing the edges in both + :class:`EdgesView`:: + + sage: E1 = EdgesView(Graph([(0, 1)]), labels=False) + sage: E2 = EdgesView(Graph([(2, 3)]), labels=False) + sage: E1 + E2 + [(0, 1), (2, 3)] + sage: E2 + E1 + [(2, 3), (0, 1)] + + Recall that a :class:`EdgesView` is read-only and that this method + returns a list:: + + sage: E1 += E2 + sage: type(E1) is list + True + + It is also possible to get the sum a :class:`EdgesView` with itself `n` + times:: + + sage: E = EdgesView(Graph([(0, 1), (2, 3)]), labels=False) + sage: E * 3 + [(0, 1), (2, 3), (0, 1), (2, 3), (0, 1), (2, 3)] + sage: 3 * E + [(0, 1), (2, 3), (0, 1), (2, 3), (0, 1), (2, 3)] + + Recall that a :class:`EdgesView` is read-only and that this method + returns a list:: + + sage: E *= 2 + sage: type(E) is list + True + + We can ask for the `i`-th edge:: + + sage: E = EdgesView(graphs.HouseGraph(), labels=False) + sage: E[0] + (0, 1) + sage: E[2] + (1, 3) """ def __init__(self, G, vertices=None, labels=True, ignore_direction=False, @@ -424,3 +465,143 @@ class EdgesView(): return (self._graph._backend.has_edge(u, v, label) or self._graph._backend.has_edge(v, u, label)) return self._graph._backend.has_edge(u, v, label) + + def __getitem__(self, i): + r""" + Return the `i`-th edge in ``self``. + + This method takes time `O(i)`. When several calls to this method are + done, prefer making ``list`` from ``self`` before querying items. + + INPUT: + + - ``i`` -- nonnegative integer + + EXAMPLES:: + + sage: from sage.graphs.views import EdgesView + sage: E = EdgesView(graphs.HouseGraph(), labels=False) + sage: E[0] + (0, 1) + sage: E[2] + (1, 3) + + TESTS:: + + sage: from sage.graphs.views import EdgesView + sage: E = EdgesView(graphs.HouseGraph(), labels=False) + sage: E[-1] + Traceback (most recent call last): + ... + IndexError: index out of range + sage: E[10] + Traceback (most recent call last): + ... + IndexError: index out of range + """ + if i < 0: + raise IndexError('index out of range') + cdef Py_ssize_t j + for j, e in enumerate(self): + if i == j: + return e + raise IndexError('index out of range') + + def __add__(self, other): + """ + Return a list containing the edges of ``self`` and ``other``. + + The returned list contains the edges of ``self`` with prescribed order + followed by the edges of ``other`` in prescribed order. + + INPUT: + + - ``other`` -- :class:`EdgesView` + + EXAMPLES:: + + sage: from sage.graphs.views import EdgesView + sage: E1 = EdgesView(Graph([(0, 1)]), labels=False) + sage: E2 = EdgesView(Graph([(2, 3)]), labels=False) + sage: E1 + E2 + [(0, 1), (2, 3)] + sage: E2 + E1 + [(2, 3), (0, 1)] + + Recall that a :class:`EdgesView` is read-only and that this method + returns a list:: + + sage: E1 += E2 + sage: type(E1) is list + True + + TESTS:: + + sage: from sage.graphs.views import EdgesView + sage: E = EdgesView(graphs.HouseGraph()) + sage: E + 'foo' + Traceback (most recent call last): + ... + TypeError: other is not a EdgesView + """ + if not isinstance(other, EdgesView): + raise TypeError('other is not a EdgesView') + cdef list L = list(self) + L.extend(other) + return L + + def __mul__(self, n): + r""" + Return the sum of ``self`` with itself ``n`` times. + + INPUT: + + - ``n`` -- integer + + EXAMPLES:: + + sage: from sage.graphs.views import EdgesView + sage: E = EdgesView(Graph([(0, 1), (2, 3)]), labels=False) + sage: E * 3 + [(0, 1), (2, 3), (0, 1), (2, 3), (0, 1), (2, 3)] + + Recall that a :class:`EdgesView` is read-only and that this method + returns a list:: + + sage: E *= 2 + sage: type(E) is list + True + + TESTS:: + + sage: from sage.graphs.views import EdgesView + sage: E = EdgesView(Graph([(0, 1)])) + sage: E * (-1) + Traceback (most recent call last): + ... + TypeError: multiplication of a EdgesView and a nonpositive integer is not defined + sage: E * 1.5 + Traceback (most recent call last): + ... + TypeError: can't multiply sequence by non-int of type 'sage.rings.real_mpfr.RealLiteral' + """ + if n < 1: + raise TypeError('multiplication of a EdgesView and a nonpositive integer is not defined') + return list(self) * n + + def __rmul__(self, n): + r""" + Return the sum of ``self`` with itself ``n`` times. + + INPUT: + + - ``n`` -- integer + + EXAMPLES:: + + sage: from sage.graphs.views import EdgesView + sage: E = EdgesView(Graph([(0, 1), (2, 3)]), labels=False) + sage: 3 * E + [(0, 1), (2, 3), (0, 1), (2, 3), (0, 1), (2, 3)] + """ + return self.__mul__(n) From d9736595c4bac3224a0afb8394d25e1965c82e4a Mon Sep 17 00:00:00 2001 From: David Coudert Date: Tue, 5 Mar 2019 17:41:49 +0100 Subject: [PATCH 033/340] trac #27408: better getitem and various fix --- src/sage/graphs/connectivity.pyx | 4 +-- src/sage/graphs/generic_graph.py | 4 +-- src/sage/graphs/graph.py | 9 ++++--- src/sage/graphs/views.pyx | 43 +++++++++++++++++++------------- 4 files changed, 34 insertions(+), 26 deletions(-) diff --git a/src/sage/graphs/connectivity.pyx b/src/sage/graphs/connectivity.pyx index f8544cb1939..d596494643d 100644 --- a/src/sage/graphs/connectivity.pyx +++ b/src/sage/graphs/connectivity.pyx @@ -2114,9 +2114,9 @@ def cleave(G, cut_vertices=None, virtual_edges=True, solver=None, verbose=0): # is needed. cocycles = Graph([cut_vertices, []], multiedges=True) if K.size(): - cocycles.add_edges(list(K.edges(sort=False)) * (len(cut_sides) + 1)) + cocycles.add_edges(K.edges(sort=False) * (len(cut_sides) + 1)) if virtual_edges and virtual_cut_graph: - cocycles.add_edges(list(virtual_cut_graph.edges(sort=False)) * len(cut_sides)) + cocycles.add_edges(virtual_cut_graph.edges(sort=False) * len(cut_sides)) return cut_sides, cocycles, virtual_cut_graph diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 958c2cb1a85..c614c1e2ec0 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -7581,9 +7581,9 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, else: if self.allows_multiple_edges() and len(self.edge_label(uu, vv)) > 1: if maximize: - edges = list(self.edges(key=weight))[-2:] + edges = self.edges(key=weight)[-2:] else: - edges = list(self.edges(key=weight))[:2] + edges = self.edges(key=weight)[:2] answer = self.subgraph(edges=edges, immutable=self.is_immutable()) answer.set_pos(self.get_pos()) answer.name("TSP from "+self.name()) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 87e177fd10c..901c1efd2b0 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -7809,14 +7809,14 @@ def kirchhoff_symanzik_polynomial(self, name='t'): sage: G = Graph([(0,2,'a'),(0,2,'b'),(0,1,'c'),(1,2,'d')], multiedges=True) sage: G.kirchhoff_symanzik_polynomial() - t0*t1 + t0*t2 + t1*t2 + t1*t3 + t2*t3 + t0*t1 + t1*t2 + t0*t3 + t1*t3 + t2*t3 For the complete graph with 4 vertices:: sage: G = graphs.CompleteGraph(4) sage: G.kirchhoff_symanzik_polynomial() - 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 + t0*t1*t2 + t0*t1*t3 + t0*t2*t3 + t0*t1*t4 + t0*t2*t4 + t1*t2*t4 + + t1*t3*t4 + t2*t3*t4 + t0*t2*t5 + t1*t2*t5 + t0*t3*t5 + t1*t3*t5 + t2*t3*t5 + t0*t4*t5 + t1*t4*t5 + t3*t4*t5 REFERENCES: @@ -7833,7 +7833,8 @@ def kirchhoff_symanzik_polynomial(self, name='t'): from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - edges = list(self.edges(sort=False)) + # The order of the vertices in each tuple matters, so we freeze edges + edges = frozenset(self.edges(sort=False)) cycles = self.cycle_basis(output='edge') edge2int = {e: j for j, e in enumerate(edges)} diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index b97da8ac9b6..62f49ab5bcb 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -73,13 +73,13 @@ class EdgesView(): sage: from sage.graphs.views import EdgesView sage: G = Graph([(0, 1, 'C'), (0, 2, 'A'), (1, 2, 'B')]) - sage: E = EdgesView(G); E + sage: E = EdgesView(G, sort=True); E [(0, 1, 'C'), (0, 2, 'A'), (1, 2, 'B')] sage: (1, 2) in E False sage: (1, 2, 'B') in E True - sage: E = EdgesView(G, labels=False); E + sage: E = EdgesView(G, labels=False, sort=True); E [(0, 1), (0, 2), (1, 2)] sage: (1, 2) in E True @@ -181,7 +181,7 @@ class EdgesView(): A view is updated as the graph is updated:: sage: G = Graph() - sage: E = EdgesView(G, vertices=[0, 3], labels=False); E + sage: E = EdgesView(G, vertices=[0, 3], labels=False, sort=True); E [] sage: G.add_edges([(0, 1), (1, 2)]) sage: E @@ -245,7 +245,7 @@ class EdgesView(): It is also possible to get the sum a :class:`EdgesView` with itself `n` times:: - sage: E = EdgesView(Graph([(0, 1), (2, 3)]), labels=False) + sage: E = EdgesView(Graph([(0, 1), (2, 3)]), labels=False, sort=True) sage: E * 3 [(0, 1), (2, 3), (0, 1), (2, 3), (0, 1), (2, 3)] sage: 3 * E @@ -258,13 +258,17 @@ class EdgesView(): sage: type(E) is list True - We can ask for the `i`-th edge:: + We can ask for the `i`-th edge, or a subset of the edges as a list:: - sage: E = EdgesView(graphs.HouseGraph(), labels=False) + sage: E = EdgesView(graphs.HouseGraph(), labels=False, sort=True) sage: E[0] (0, 1) sage: E[2] (1, 3) + sage: E[-1] + (3, 4) + sage: E[1:-1] + [(0, 2), (1, 3), (2, 3), (2, 4)] """ def __init__(self, G, vertices=None, labels=True, ignore_direction=False, @@ -276,7 +280,7 @@ class EdgesView(): sage: from sage.graphs.views import EdgesView sage: G = Graph([(0, 1, 'C'), (0, 2, 'A'), (1, 2, 'B')]) - sage: E = EdgesView(G); E + sage: E = EdgesView(G, sort=True); E [(0, 1, 'C'), (0, 2, 'A'), (1, 2, 'B')] TESTS:: @@ -319,7 +323,7 @@ class EdgesView(): 6 sage: len(E) == G.size() True - sage: E = EdgesView(G, vertices=0, labels=False); E + sage: E = EdgesView(G, vertices=0, labels=False, sort=True); E [(0, 1), (0, 2)] sage: len(E) 2 @@ -353,11 +357,14 @@ class EdgesView(): sage: from sage.graphs.views import EdgesView sage: G = graphs.HouseGraph() - sage: E = EdgesView(G, labels=False) + sage: E = EdgesView(G, labels=False, sort=True) sage: list(E) [(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)] sage: sum(1 for e in E for ee in E) == len(E) * len(E) True + sage: E = EdgesView(G, labels=False) + sage: sum(1 for e in E for ee in E) == G.size() * G.size() + True """ if self._sort_edges: self._sort_edges = False @@ -389,7 +396,7 @@ class EdgesView(): sage: from sage.graphs.views import EdgesView sage: G = graphs.HouseGraph() sage: EG = EdgesView(G) - sage: H = Graph(list(G.edge_iterator())) + sage: H = Graph(EG) sage: EH = EdgesView(H) sage: EG == EH True @@ -485,22 +492,22 @@ class EdgesView(): (0, 1) sage: E[2] (1, 3) + sage: E[1:-1] + [(0, 2), (1, 3), (2, 3), (2, 4)] + sage: E[-1] + (3, 4) TESTS:: sage: from sage.graphs.views import EdgesView sage: E = EdgesView(graphs.HouseGraph(), labels=False) - sage: E[-1] - Traceback (most recent call last): - ... - IndexError: index out of range sage: E[10] Traceback (most recent call last): ... IndexError: index out of range """ - if i < 0: - raise IndexError('index out of range') + if isinstance(i, slice) or i < 0: + return list(self).__getitem__(i) cdef Py_ssize_t j for j, e in enumerate(self): if i == j: @@ -561,7 +568,7 @@ class EdgesView(): EXAMPLES:: sage: from sage.graphs.views import EdgesView - sage: E = EdgesView(Graph([(0, 1), (2, 3)]), labels=False) + sage: E = EdgesView(Graph([(0, 1), (2, 3)]), labels=False, sort=True) sage: E * 3 [(0, 1), (2, 3), (0, 1), (2, 3), (0, 1), (2, 3)] @@ -600,7 +607,7 @@ class EdgesView(): EXAMPLES:: sage: from sage.graphs.views import EdgesView - sage: E = EdgesView(Graph([(0, 1), (2, 3)]), labels=False) + sage: E = EdgesView(Graph([(0, 1), (2, 3)]), labels=False, sort=True) sage: 3 * E [(0, 1), (2, 3), (0, 1), (2, 3), (0, 1), (2, 3)] """ From 711be0b9788a32164f83dadb287ec5c8333b0f0f Mon Sep 17 00:00:00 2001 From: David Coudert Date: Tue, 5 Mar 2019 18:55:44 +0100 Subject: [PATCH 034/340] trac #27408: set default sort to None by default and add deprecation warning --- src/sage/graphs/generic_graph.py | 4 +-- src/sage/graphs/graph.py | 10 +++--- src/sage/graphs/views.pyx | 53 ++++++++++++++++++++++++-------- 3 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index c614c1e2ec0..154ed200d6c 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -4279,7 +4279,7 @@ def min_spanning_tree(self, v = next(self.vertex_iterator()) else: v = starting_vertex - sorted_edges = list(self.edges(key=wfunction_float)) + sorted_edges = sorted(self.edges(sort=False), key=wfunction_float) tree = set([v]) edges = [] for _ in range(self.order() - 1): @@ -11070,7 +11070,7 @@ def edges(self, labels=True, sort=True, key=None): sage: P.edges(sort=False, key=lambda x: x) Traceback (most recent call last): ... - ValueError: sort keyword is False, yet a key function is given + ValueError: sort keyword is not True, yet a key function is given sage: G = Graph() sage: G.add_edge(0, 1, [7]) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 901c1efd2b0..cebfc16764c 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -7809,14 +7809,14 @@ def kirchhoff_symanzik_polynomial(self, name='t'): sage: G = Graph([(0,2,'a'),(0,2,'b'),(0,1,'c'),(1,2,'d')], multiedges=True) sage: G.kirchhoff_symanzik_polynomial() - t0*t1 + t1*t2 + t0*t3 + t1*t3 + t2*t3 + 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() - t0*t1*t2 + t0*t1*t3 + t0*t2*t3 + t0*t1*t4 + t0*t2*t4 + t1*t2*t4 - + t1*t3*t4 + t2*t3*t4 + t0*t2*t5 + t1*t2*t5 + t0*t3*t5 + t1*t3*t5 + 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 REFERENCES: @@ -7833,8 +7833,8 @@ def kirchhoff_symanzik_polynomial(self, name='t'): from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - # The order of the vertices in each tuple matters, so we freeze edges - edges = frozenset(self.edges(sort=False)) + # The order of the vertices in each tuple matters, so use a list + edges = list(self.edges(sort=False)) cycles = self.cycle_basis(output='edge') edge2int = {e: j for j, e in enumerate(edges)} diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index 62f49ab5bcb..795a188b4b7 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -26,6 +26,8 @@ Classes from __future__ import print_function, absolute_import +from sage.misc.superseded import deprecation + class EdgesView(): r""" EdgesView class. @@ -51,8 +53,18 @@ class EdgesView(): - ``ignore_direction`` -- boolean (default: ``False``); only applies to directed graphs. If ``True``, searches across edges in either direction. - - ``sort`` -- boolean (default: ``True``); if ``True``, edges are sorted - according to the default ordering + - ``sort`` -- boolean (default: ``None``); whether to sort edges + + - if ``None``, sort edges according to the default ordering and give a + deprecation warning as sorting will be set to ``False`` by default in + the future + + - if ``True``, edges are sorted according the ordering specified with + parameter ``key`` + + - if ``False``, edges are not sorted. This is the fastest and less memory + consuming method for iterating over edges. This will become the default + behavior in the future. - ``key`` -- a function (default: ``None``); a function that takes an edge (a pair or a triple, according to the ``labels`` keyword) as its one @@ -110,7 +122,7 @@ class EdgesView(): We can check if a view is empty:: - sage: E = EdgesView(graphs.CycleGraph(3)) + sage: E = EdgesView(graphs.CycleGraph(3), sort=False) sage: if E: ....: print('not empty') not empty @@ -258,7 +270,7 @@ class EdgesView(): sage: type(E) is list True - We can ask for the `i`-th edge, or a subset of the edges as a list:: + We can ask for the `i`-th edge, or a slice of the edges as a list:: sage: E = EdgesView(graphs.HouseGraph(), labels=False, sort=True) sage: E[0] @@ -269,10 +281,12 @@ class EdgesView(): (3, 4) sage: E[1:-1] [(0, 2), (1, 3), (2, 3), (2, 4)] + sage: E[::-1] + [(3, 4), (2, 4), (2, 3), (1, 3), (0, 2), (0, 1)] """ def __init__(self, G, vertices=None, labels=True, ignore_direction=False, - sort=True, key=None): + sort=None, key=None): """ Construction of this :class:`EdgesView`. @@ -288,7 +302,7 @@ class EdgesView(): sage: EdgesView(Graph(), sort=False, key=lambda x:0) Traceback (most recent call last): ... - ValueError: sort keyword is False, yet a key function is given + ValueError: sort keyword is not True, yet a key function is given """ self._graph = G @@ -303,11 +317,13 @@ class EdgesView(): self._vertex_set = frozenset(self._vertices) # None and 0 are interpreted as False, 1 as True - self._labels = True if labels else False - self._ignore_direction = True if ignore_direction else False - self._sort_edges = True if sort else False + self._labels = labels + self._ignore_direction = ignore_direction + if sort is None: + deprecation(27408, "parameter 'sort' will be set to False by default in the future") + self._sort_edges = sort if not sort and key is not None: - raise ValueError('sort keyword is False, yet a key function is given') + raise ValueError('sort keyword is not True, yet a key function is given') self._sort_edges_key = key def __len__(self): @@ -366,9 +382,20 @@ class EdgesView(): sage: sum(1 for e in E for ee in E) == G.size() * G.size() True """ - if self._sort_edges: + if self._sort_edges is True: self._sort_edges = False - yield from sorted(self, key=self._sort_edges_key) + # use try / except to restore _sort_edges + try: + yield from sorted(self, key=self._sort_edges_key) + except Exception as msg: + raise TypeError("the edges cannot be sorted due to " + msg) + self._sort_edges = True + elif self._sort_edges is None: + self._sort_edges = False + try: + yield from sorted(self) + except Exception as msg: + raise TypeError("the edges cannot be sorted due to " + msg) self._sort_edges = True else: if self._graph._directed: @@ -482,7 +509,7 @@ class EdgesView(): INPUT: - - ``i`` -- nonnegative integer + - ``i`` -- integer or slice EXAMPLES:: From a1701f80d0a80c7a94a7407b6952e23fa1025e76 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Tue, 5 Mar 2019 20:03:58 +0100 Subject: [PATCH 035/340] trac #27408: some care for Python 3 --- src/sage/graphs/graph.py | 14 ++++++-------- src/sage/graphs/views.pyx | 25 +++++++++++++++++-------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index cebfc16764c..68a518095a6 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -405,6 +405,7 @@ from __future__ import absolute_import import six from six.moves import range +import itertools from copy import copy from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -1200,9 +1201,8 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if weighted is None: weighted = False self.allow_loops(loops, check=False) self.allow_multiple_edges(True if multiedges else False, check=False) - from itertools import combinations self.add_vertices(verts) - self.add_edges(e for e in combinations(verts,2) if f(*e)) + self.add_edges(e for e in itertools.combinations(verts,2) if f(*e)) if loops: self.add_edges((v,v) for v in verts if f(v,v)) @@ -2816,8 +2816,8 @@ def treewidth(self, k=None, certificate=False, algorithm=None): return all(cc.treewidth(k) for cc in g.connected_components_subgraphs()) else: T = [cc.treewidth(certificate=True) for cc in g.connected_components_subgraphs()] - tree = Graph([sum([list(t) for t in T], []), - sum([t.edges(labels=False, sort=False) for t in T], [])], + tree = Graph([list(itertools.chain(*T)), + list(itertools.chain(*[t.edges(labels=False, sort=False) for t in T]))], format='vertices_and_edges', name="Tree decomposition") v = next(T[0].vertex_iterator()) for t in T[1:]: @@ -3854,11 +3854,10 @@ def orientations(self, implementation='c_graph', data_structure=None, sparse=Non yield D return - from itertools import product E = [[(u,v,label), (v,u,label)] if u != v else [(u,v,label)] for u,v,label in self.edge_iterator()] verts = self.vertices() - for edges in product(*E): + for edges in itertools.product(*E): D = DiGraph(data=[verts, edges], format='vertices_and_edges', name=name, @@ -5508,10 +5507,9 @@ def seidel_switching(self, s, inplace=True): sage: G == H True """ - from itertools import product G = self if inplace else copy(self) boundary = self.edge_boundary(s) - G.add_edges(product(s, set(self).difference(s))) + G.add_edges(itertools.product(s, set(self).difference(s))) G.delete_edges(boundary) if not inplace: return G diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index 795a188b4b7..4346bf4d4cc 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -126,7 +126,7 @@ class EdgesView(): sage: if E: ....: print('not empty') not empty - sage: E = EdgesView(Graph()) + sage: E = EdgesView(Graph(), sort=False) sage: if not E: ....: print('empty') empty @@ -219,29 +219,29 @@ class EdgesView(): report the same edges in the same order:: sage: G = graphs.HouseGraph() - sage: EG = EdgesView(G) + sage: EG = EdgesView(G, sort=False) sage: H = Graph(EG) - sage: EH = EdgesView(H) + sage: EH = EdgesView(H, sort=False) sage: EG == EH True sage: G.add_edge(0, 10) - sage: EG = EdgesView(G) + sage: EG = EdgesView(G, sort=False) sage: EG == EH False sage: H.add_edge(0, 10) - sage: EH = EdgesView(H) + sage: EH = EdgesView(H, sort=False) sage: EG == EH True sage: H = G.strong_orientation() - sage: EH = EdgesView(H) + sage: EH = EdgesView(H, sort=False) sage: EG == EH False The sum of two :class:`EdgesView` is a list containing the edges in both :class:`EdgesView`:: - sage: E1 = EdgesView(Graph([(0, 1)]), labels=False) - sage: E2 = EdgesView(Graph([(2, 3)]), labels=False) + sage: E1 = EdgesView(Graph([(0, 1)]), labels=False, sort=False) + sage: E2 = EdgesView(Graph([(2, 3)]), labels=False, sort=False) sage: E1 + E2 [(0, 1), (2, 3)] sage: E2 + E1 @@ -283,6 +283,15 @@ class EdgesView(): [(0, 2), (1, 3), (2, 3), (2, 4)] sage: E[::-1] [(3, 4), (2, 4), (2, 3), (1, 3), (0, 2), (0, 1)] + + TESTS: + + Deprecation warning for ``sort=None`` (:trac:`27408`):: + + sage: G = graphs.HouseGraph() + sage: EG = EdgesView(G, sort=None) + doctest:...: DeprecationWarning: parameter 'sort' will be set to False by default in the future + See https://trac.sagemath.org/27408 for details. """ def __init__(self, G, vertices=None, labels=True, ignore_direction=False, From 890530982e496ddd4b893eb616bfe8c1c8e888ab Mon Sep 17 00:00:00 2001 From: David Coudert Date: Wed, 6 Mar 2019 00:05:13 +0100 Subject: [PATCH 036/340] trac #27408: improve getitem --- src/sage/graphs/views.pyx | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index 4346bf4d4cc..fb65fb84317 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -27,6 +27,8 @@ Classes from __future__ import print_function, absolute_import from sage.misc.superseded import deprecation +from itertools import islice +from sys import maxsize as sys_maxsize class EdgesView(): r""" @@ -542,13 +544,20 @@ class EdgesView(): ... IndexError: index out of range """ - if isinstance(i, slice) or i < 0: - return list(self).__getitem__(i) - cdef Py_ssize_t j - for j, e in enumerate(self): - if i == j: - return e - raise IndexError('index out of range') + cdef Py_ssize_t start, stop, step + if isinstance(i, slice): + start, stop, step = i.start or 0, i.stop or sys_maxsize, i.step or 1 + if start >= 0 and stop >= 0 and step >= 0: + return list(islice(self, i.start, i.stop, i.end)) + else: + return list(self)[i] + elif i < 0: + return list(self)[i] + else: + try: + return next(islice(self, i, i + 1, 1)) + except StopIteration: + raise IndexError('index out of range') def __add__(self, other): """ From e27645bffae04b1b04e39efe41a19e6ac85e5193 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Wed, 6 Mar 2019 08:56:55 +0100 Subject: [PATCH 037/340] trac #27408: it's .step, not .end --- src/sage/graphs/views.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index fb65fb84317..7e9db381eaf 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -548,7 +548,7 @@ class EdgesView(): if isinstance(i, slice): start, stop, step = i.start or 0, i.stop or sys_maxsize, i.step or 1 if start >= 0 and stop >= 0 and step >= 0: - return list(islice(self, i.start, i.stop, i.end)) + return list(islice(self, i.start, i.stop, i.step)) else: return list(self)[i] elif i < 0: From 8d7bd05b4a60909cc1bf694dc8990fe3d9cae4c2 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Wed, 6 Mar 2019 09:00:40 +0100 Subject: [PATCH 038/340] trac #27408: better like that --- src/sage/graphs/views.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index 7e9db381eaf..6206633988f 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -548,7 +548,7 @@ class EdgesView(): if isinstance(i, slice): start, stop, step = i.start or 0, i.stop or sys_maxsize, i.step or 1 if start >= 0 and stop >= 0 and step >= 0: - return list(islice(self, i.start, i.stop, i.step)) + return list(islice(self, start, stop, step)) else: return list(self)[i] elif i < 0: From 132284fc54db27855167d6643fa009340067f218 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Wed, 6 Mar 2019 13:41:08 +0100 Subject: [PATCH 039/340] trac #27408: correction of len --- src/sage/graphs/views.pyx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index 6206633988f..a8c0191925a 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -354,8 +354,15 @@ class EdgesView(): [(0, 1), (0, 2)] sage: len(E) 2 + sage: G = digraphs.Circuit(4) + sage: len(EdgesView(G, ignore_direction=False, sort=False)) + 4 + sage: len(EdgesView(G, ignore_direction=True, sort=False)) + 8 """ if self._vertices is self._graph: + if self._graph._directed and self._ignore_direction: + return 2 * self._graph.size() return self._graph.size() else: return sum(1 for _ in self) From bbbb824d1535e76d5ae28ff22f679c8991ddfdf2 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Sun, 10 Mar 2019 10:37:06 +0100 Subject: [PATCH 040/340] trac #27408: fix __mul__ --- src/sage/graphs/views.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index a8c0191925a..1869b110540 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -663,4 +663,4 @@ class EdgesView(): sage: 3 * E [(0, 1), (2, 3), (0, 1), (2, 3), (0, 1), (2, 3)] """ - return self.__mul__(n) + return self * n From 0aa8c01e4ebea09d471565c7bca922df9dcd8afe Mon Sep 17 00:00:00 2001 From: David Coudert Date: Tue, 9 Apr 2019 16:19:23 +0200 Subject: [PATCH 041/340] trac #27408: avoid vertices=single vertex --- src/sage/graphs/views.pyx | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index 1869b110540..c29f871f500 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -45,9 +45,9 @@ class EdgesView(): - ``G`` -- a (di)graph - - ``vertices`` -- object (default: ``None``); a vertex, an iterable - container of vertices or ``None``. When set, consider only edges incident - to specified vertices. + - ``vertices`` -- list (default: ``None``); an iterable container of + vertices or ``None``. When set, consider only edges incident to specified + vertices. - ``labels`` -- boolean (default: ``True``); if ``False``, each edge is simply a pair ``(u, v)`` of vertices @@ -168,7 +168,7 @@ class EdgesView(): sage: G = graphs.CycleGraph(5) sage: E = EdgesView(G, vertices=[0, 1], labels=False, sort=True); E [(0, 1), (0, 4), (1, 2)] - sage: E = EdgesView(G, vertices=0, labels=False, sort=True); E + sage: E = EdgesView(G, vertices=[0], labels=False, sort=True); E [(0, 1), (0, 4)] sage: E = EdgesView(G, vertices=None, labels=False, sort=True); E [(0, 1), (0, 4), (1, 2), (2, 3), (3, 4)] @@ -320,9 +320,6 @@ class EdgesView(): if vertices is None: self._vertices = G self._vertex_set = G - elif vertices in G: - self._vertices = [vertices] - self._vertex_set = self._vertices else: self._vertices = list(vertices) self._vertex_set = frozenset(self._vertices) @@ -350,7 +347,7 @@ class EdgesView(): 6 sage: len(E) == G.size() True - sage: E = EdgesView(G, vertices=0, labels=False, sort=True); E + sage: E = EdgesView(G, vertices=[0], labels=False, sort=True); E [(0, 1), (0, 2)] sage: len(E) 2 From 7287f14b26832c0958fe1a4d8024909724085d1a Mon Sep 17 00:00:00 2001 From: David Coudert Date: Tue, 9 Apr 2019 16:44:35 +0200 Subject: [PATCH 042/340] trac #27408: most reviewers comment #54 --- src/sage/graphs/views.pyx | 49 +++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index c29f871f500..3e24dd688e0 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -30,7 +30,7 @@ from sage.misc.superseded import deprecation from itertools import islice from sys import maxsize as sys_maxsize -class EdgesView(): +class EdgesView: r""" EdgesView class. @@ -364,6 +364,22 @@ class EdgesView(): else: return sum(1 for _ in self) + def __bool__(self): + """ + Check whether ``self`` is empty. + + EXAMPLES:: + + sage: from sage.graphs.views import EdgesView + sage: E = EdgesView(Graph()) + sage: bool(E) + False + sage: E = EdgesView(graphs.HouseGraph()) + sage: bool(E) + True + """ + return len(self) > 0 + def __repr__(self): """ Return a string representation of ``self``. @@ -399,18 +415,11 @@ class EdgesView(): """ if self._sort_edges is True: self._sort_edges = False - # use try / except to restore _sort_edges - try: - yield from sorted(self, key=self._sort_edges_key) - except Exception as msg: - raise TypeError("the edges cannot be sorted due to " + msg) + yield from sorted(self, key=self._sort_edges_key) self._sort_edges = True elif self._sort_edges is None: self._sort_edges = False - try: - yield from sorted(self) - except Exception as msg: - raise TypeError("the edges cannot be sorted due to " + msg) + yield from sorted(self) self._sort_edges = True else: if self._graph._directed: @@ -454,9 +463,19 @@ class EdgesView(): sage: EH = EdgesView(H) sage: EG == EH False + + TESTS:: + + sage: from sage.graphs.views import EdgesView + sage: G = graphs.HouseGraph() + sage: E = EdgesView(G) + sage: E == G + False + sage: G == E + False """ if not isinstance(other, EdgesView): - return False + return NotImplemented if self is other: return True # Check parameters @@ -559,7 +578,7 @@ class EdgesView(): return list(self)[i] else: try: - return next(islice(self, i, i + 1, 1)) + return next(islice(self, i, i + 1, 1)) except StopIteration: raise IndexError('index out of range') @@ -633,16 +652,12 @@ class EdgesView(): sage: from sage.graphs.views import EdgesView sage: E = EdgesView(Graph([(0, 1)])) sage: E * (-1) - Traceback (most recent call last): - ... - TypeError: multiplication of a EdgesView and a nonpositive integer is not defined + [] sage: E * 1.5 Traceback (most recent call last): ... TypeError: can't multiply sequence by non-int of type 'sage.rings.real_mpfr.RealLiteral' """ - if n < 1: - raise TypeError('multiplication of a EdgesView and a nonpositive integer is not defined') return list(self) * n def __rmul__(self, n): From 38cdcedfa0401260abb147e02bd95e7b39aa1854 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Wed, 10 Apr 2019 14:26:33 +0200 Subject: [PATCH 043/340] trac #27408: cdef class EdgesView --- src/sage/graphs/views.pyx | 55 ++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index 3e24dd688e0..8737d7bf0be 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -29,8 +29,9 @@ from __future__ import print_function, absolute_import from sage.misc.superseded import deprecation from itertools import islice from sys import maxsize as sys_maxsize +from sage.graphs.generic_graph_pyx cimport GenericGraph_pyx -class EdgesView: +cdef class EdgesView: r""" EdgesView class. @@ -295,6 +296,13 @@ class EdgesView: doctest:...: DeprecationWarning: parameter 'sort' will be set to False by default in the future See https://trac.sagemath.org/27408 for details. """ + cdef readonly GenericGraph_pyx _graph + cdef list _vertices + cdef frozenset _vertex_set + cdef readonly bint _labels + cdef readonly bint _ignore_direction + cdef bint _sort_edges + cdef _sort_edges_key def __init__(self, G, vertices=None, labels=True, ignore_direction=False, sort=None, key=None): @@ -315,11 +323,11 @@ class EdgesView: ... ValueError: sort keyword is not True, yet a key function is given """ - self._graph = G + self._graph = G if vertices is None: - self._vertices = G - self._vertex_set = G + self._vertices = None + self._vertex_set = None else: self._vertices = list(vertices) self._vertex_set = frozenset(self._vertices) @@ -329,7 +337,7 @@ class EdgesView: self._ignore_direction = ignore_direction if sort is None: deprecation(27408, "parameter 'sort' will be set to False by default in the future") - self._sort_edges = sort + self._sort_edges = False if sort is False else True if not sort and key is not None: raise ValueError('sort keyword is not True, yet a key function is given') self._sort_edges_key = key @@ -422,12 +430,16 @@ class EdgesView: yield from sorted(self) self._sort_edges = True else: + if self._vertices is None: + vertices = self._graph + else: + vertices = self._vertices if self._graph._directed: - yield from self._graph._backend.iterator_out_edges(self._vertices, self._labels) + yield from self._graph._backend.iterator_out_edges(vertices, self._labels) if self._ignore_direction: - yield from self._graph._backend.iterator_in_edges(self._vertices, self._labels) + yield from self._graph._backend.iterator_in_edges(vertices, self._labels) else: - yield from self._graph._backend.iterator_edges(self._vertices, self._labels) + yield from self._graph._backend.iterator_edges(vertices, self._labels) def __eq__(self, other): """ @@ -526,7 +538,7 @@ class EdgesView: except Exception: return False label = None - if (self._vertex_set is not self._graph + if (self._vertex_set is not None and u not in self._vertex_set and v not in self._vertex_set): return False if self._graph._directed and self._ignore_direction: @@ -639,6 +651,8 @@ class EdgesView: sage: E = EdgesView(Graph([(0, 1), (2, 3)]), labels=False, sort=True) sage: E * 3 [(0, 1), (2, 3), (0, 1), (2, 3), (0, 1), (2, 3)] + sage: 3 * E + [(0, 1), (2, 3), (0, 1), (2, 3), (0, 1), (2, 3)] Recall that a :class:`EdgesView` is read-only and that this method returns a list:: @@ -658,21 +672,8 @@ class EdgesView: ... TypeError: can't multiply sequence by non-int of type 'sage.rings.real_mpfr.RealLiteral' """ - return list(self) * n - - def __rmul__(self, n): - r""" - Return the sum of ``self`` with itself ``n`` times. - - INPUT: - - - ``n`` -- integer - - EXAMPLES:: - - sage: from sage.graphs.views import EdgesView - sage: E = EdgesView(Graph([(0, 1), (2, 3)]), labels=False, sort=True) - sage: 3 * E - [(0, 1), (2, 3), (0, 1), (2, 3), (0, 1), (2, 3)] - """ - return self * n + if isinstance(self, EdgesView): + return list(self) * n + else: + # Case __rmul__ + return list(n) * self From 2fa2823e1b36e066ebecd6b4265b48a0af2a263c Mon Sep 17 00:00:00 2001 From: David Coudert Date: Wed, 10 Apr 2019 14:59:33 +0200 Subject: [PATCH 044/340] trac #27408: improve __eq__ --- src/sage/graphs/views.pyx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index 8737d7bf0be..adacba7f879 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -441,9 +441,9 @@ cdef class EdgesView: else: yield from self._graph._backend.iterator_edges(vertices, self._labels) - def __eq__(self, other): + def __eq__(self, right): """ - Check whether ``self`` and ``other`` are equal. + Check whether ``self`` and ``right`` are equal. Do not call this method directly. That is, for ``E1.__eq__(E2)`` write ``E1 == E2``. @@ -481,13 +481,16 @@ cdef class EdgesView: sage: from sage.graphs.views import EdgesView sage: G = graphs.HouseGraph() sage: E = EdgesView(G) + sage: E == E + True sage: E == G False sage: G == E False """ - if not isinstance(other, EdgesView): + if not isinstance(right, EdgesView): return NotImplemented + cdef EdgesView other = right if self is other: return True # Check parameters From 74219866a2d11f535d35c611930cb7c5a3f30197 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Wed, 10 Apr 2019 15:39:34 +0200 Subject: [PATCH 045/340] trac #27408: further improvements --- src/sage/graphs/generic_graph.py | 12 +++++++++- src/sage/graphs/views.pyx | 40 +++++++++++--------------------- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 97e4b09065b..5463890c756 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -11152,7 +11152,18 @@ def edges(self, labels=True, sort=True, key=None): sage: G.edge_label(0, 1)[0] += 1 sage: G.edges() [(0, 1, [8]), (0, 2, [7])] + + Deprecation warning for ``sort=None`` (:trac:`27408`):: + + sage: G = graphs.HouseGraph() + sage: G.edges(sort=None) + doctest:...: DeprecationWarning: parameter 'sort' will be set to False by default in the future + See https://trac.sagemath.org/27408 for details. + [(0, 1, None), (0, 2, None), (1, 3, None), (2, 3, None), (2, 4, None), (3, 4, None)] """ + if sort is None: + deprecation(27408, "parameter 'sort' will be set to False by default in the future") + sort = True return EdgesView(self, labels=labels, sort=sort, key=key) def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False): @@ -17320,7 +17331,6 @@ def depth_first_search(self, start, ignore_direction=False, [0, 2, 1] """ - from sage.misc.superseded import deprecation if distance is not None: deprecation(19227, "Parameter 'distance' is broken. Do not use.") diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index adacba7f879..0549d744d7a 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -26,7 +26,6 @@ Classes from __future__ import print_function, absolute_import -from sage.misc.superseded import deprecation from itertools import islice from sys import maxsize as sys_maxsize from sage.graphs.generic_graph_pyx cimport GenericGraph_pyx @@ -286,15 +285,6 @@ cdef class EdgesView: [(0, 2), (1, 3), (2, 3), (2, 4)] sage: E[::-1] [(3, 4), (2, 4), (2, 3), (1, 3), (0, 2), (0, 1)] - - TESTS: - - Deprecation warning for ``sort=None`` (:trac:`27408`):: - - sage: G = graphs.HouseGraph() - sage: EG = EdgesView(G, sort=None) - doctest:...: DeprecationWarning: parameter 'sort' will be set to False by default in the future - See https://trac.sagemath.org/27408 for details. """ cdef readonly GenericGraph_pyx _graph cdef list _vertices @@ -323,7 +313,7 @@ cdef class EdgesView: ... ValueError: sort keyword is not True, yet a key function is given """ - self._graph = G + self._graph = G if vertices is None: self._vertices = None @@ -335,9 +325,7 @@ cdef class EdgesView: # None and 0 are interpreted as False, 1 as True self._labels = labels self._ignore_direction = ignore_direction - if sort is None: - deprecation(27408, "parameter 'sort' will be set to False by default in the future") - self._sort_edges = False if sort is False else True + self._sort_edges = sort if not sort and key is not None: raise ValueError('sort keyword is not True, yet a key function is given') self._sort_edges_key = key @@ -597,7 +585,7 @@ cdef class EdgesView: except StopIteration: raise IndexError('index out of range') - def __add__(self, other): + def __add__(left, right): """ Return a list containing the edges of ``self`` and ``other``. @@ -632,21 +620,21 @@ cdef class EdgesView: sage: E + 'foo' Traceback (most recent call last): ... - TypeError: other is not a EdgesView + TypeError: right is not a EdgesView """ - if not isinstance(other, EdgesView): - raise TypeError('other is not a EdgesView') - cdef list L = list(self) - L.extend(other) + if not isinstance(right, EdgesView): + raise TypeError('right is not a EdgesView') + cdef list L = list(left) + L.extend(right) return L - def __mul__(self, n): + def __mul__(left, right): r""" - Return the sum of ``self`` with itself ``n`` times. + Return the sum of ``left`` with itself ``right`` times. INPUT: - - ``n`` -- integer + - ``right`` -- integer EXAMPLES:: @@ -675,8 +663,8 @@ cdef class EdgesView: ... TypeError: can't multiply sequence by non-int of type 'sage.rings.real_mpfr.RealLiteral' """ - if isinstance(self, EdgesView): - return list(self) * n + if isinstance(left, EdgesView): + return list(left) * right else: # Case __rmul__ - return list(n) * self + return list(right) * left From 4e8684663116fc45a1d402a22b1b44977c1a8db6 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Wed, 10 Apr 2019 16:20:25 +0200 Subject: [PATCH 046/340] trac #27408: return NotImplemented --- src/sage/graphs/views.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index 0549d744d7a..c577d673483 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -620,10 +620,10 @@ cdef class EdgesView: sage: E + 'foo' Traceback (most recent call last): ... - TypeError: right is not a EdgesView + TypeError: unsupported operand type(s) for +: 'sage.graphs.views.EdgesView' and 'str' """ if not isinstance(right, EdgesView): - raise TypeError('right is not a EdgesView') + return NotImplemented cdef list L = list(left) L.extend(right) return L From 578315e5ed3210af5343a5333e5e1b1d970ae106 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Wed, 10 Apr 2019 18:28:45 +0200 Subject: [PATCH 047/340] trac #27408: better iterator over edges --- src/sage/graphs/views.pyx | 44 +++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index c577d673483..6bb10f5c5e6 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -392,6 +392,25 @@ cdef class EdgesView: """ return "[%s]" % ', '.join(map(repr, self)) + def _iter_unsorted(self, vertices): + """ + Iterator over the unsorted edges in ``self``. + + EXAMPLES:: + + sage: from sage.graphs.views import EdgesView + sage: G = graphs.HouseGraph() + sage: E = EdgesView(G, labels=False, sort=False) + sage: list(E) + [(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)] + """ + if self._graph._directed: + yield from self._graph._backend.iterator_out_edges(vertices, self._labels) + if self._ignore_direction: + yield from self._graph._backend.iterator_in_edges(vertices, self._labels) + else: + yield from self._graph._backend.iterator_edges(vertices, self._labels) + def __iter__(self): """ Iterator over the edges in ``self``. @@ -409,25 +428,14 @@ cdef class EdgesView: sage: sum(1 for e in E for ee in E) == G.size() * G.size() True """ - if self._sort_edges is True: - self._sort_edges = False - yield from sorted(self, key=self._sort_edges_key) - self._sort_edges = True - elif self._sort_edges is None: - self._sort_edges = False - yield from sorted(self) - self._sort_edges = True + if self._vertices is None: + vertices = self._graph else: - if self._vertices is None: - vertices = self._graph - else: - vertices = self._vertices - if self._graph._directed: - yield from self._graph._backend.iterator_out_edges(vertices, self._labels) - if self._ignore_direction: - yield from self._graph._backend.iterator_in_edges(vertices, self._labels) - else: - yield from self._graph._backend.iterator_edges(vertices, self._labels) + vertices = self._vertices + if self._sort_edges: + yield from sorted(self._iter_unsorted(vertices), key=self._sort_edges_key) + else: + yield from self._iter_unsorted(vertices) def __eq__(self, right): """ From 5044e460c8ab0841404a5e097b19d1811cc49593 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Wed, 10 Apr 2019 18:31:12 +0200 Subject: [PATCH 048/340] trac #27408: more tests in __add__ --- src/sage/graphs/views.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index 6bb10f5c5e6..723715b5c49 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -630,7 +630,7 @@ cdef class EdgesView: ... TypeError: unsupported operand type(s) for +: 'sage.graphs.views.EdgesView' and 'str' """ - if not isinstance(right, EdgesView): + if not isinstance(right, EdgesView) or not isinstance(right, EdgesView): return NotImplemented cdef list L = list(left) L.extend(right) From 96d87bb88cf274a8526e61779b23461027a1b1fa Mon Sep 17 00:00:00 2001 From: David Coudert Date: Fri, 12 Apr 2019 14:53:10 +0200 Subject: [PATCH 049/340] trac #27408: fix __add__ --- src/sage/graphs/views.pyx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index 723715b5c49..b3f7354205a 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -595,14 +595,14 @@ cdef class EdgesView: def __add__(left, right): """ - Return a list containing the edges of ``self`` and ``other``. + Return a list containing the edges of ``left`` and ``right``. - The returned list contains the edges of ``self`` with prescribed order - followed by the edges of ``other`` in prescribed order. + The returned list contains the edges of ``left`` with prescribed order + followed by the edges of ``right`` in prescribed order. INPUT: - - ``other`` -- :class:`EdgesView` + - ``left,right`` -- :class:`EdgesView` or list of edges EXAMPLES:: @@ -613,6 +613,8 @@ cdef class EdgesView: [(0, 1), (2, 3)] sage: E2 + E1 [(2, 3), (0, 1)] + sage: E1 + E2 + E1 + [(0, 1), (2, 3), (0, 1)] Recall that a :class:`EdgesView` is read-only and that this method returns a list:: @@ -630,7 +632,7 @@ cdef class EdgesView: ... TypeError: unsupported operand type(s) for +: 'sage.graphs.views.EdgesView' and 'str' """ - if not isinstance(right, EdgesView) or not isinstance(right, EdgesView): + if not isinstance(left, (list, EdgesView)) or not isinstance(right, (list, EdgesView)): return NotImplemented cdef list L = list(left) L.extend(right) From 4db22e28da77e5f85898809ae435c734dc215073 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Mon, 6 May 2019 18:41:05 +0200 Subject: [PATCH 050/340] trac #27408: fix a doctest in matroids/utilities.py --- src/sage/matroids/utilities.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/matroids/utilities.py b/src/sage/matroids/utilities.py index a17dfb1a9a5..6b75f98a68b 100644 --- a/src/sage/matroids/utilities.py +++ b/src/sage/matroids/utilities.py @@ -752,13 +752,13 @@ def split_vertex(G, u, v=None, edges=None): sage: from sage.matroids.utilities import split_vertex sage: G = graphs.BullGraph() - sage: split_vertex(G, u = 1, v = 'a', edges = [(1, 3)]) + sage: split_vertex(G, u = 1, v = 55, edges = [(1, 3)]) Traceback (most recent call last): ... ValueError: the edges are not all incident with u - sage: split_vertex(G, u = 1, v = 'a', edges = [(1, 3, None)]) - sage: G.edges() - [(0, 1, None), (0, 2, None), (1, 2, None), (2, 4, None), (3, 'a', None)] + sage: split_vertex(G, u = 1, v = 55, edges = [(1, 3, None)]) + sage: list(G.edges(sort=False)) + [(0, 1, None), (0, 2, None), (1, 2, None), (2, 4, None), (3, 55, None)] """ if v is None: From 2b26bc454ddbf132ab5c41ef90b86d713735a1ad Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Fri, 7 Jun 2019 15:07:57 +0200 Subject: [PATCH 051/340] Trac 26817: fix doctest --- src/sage/rings/number_field/galois_group.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/number_field/galois_group.py b/src/sage/rings/number_field/galois_group.py index 157df5e8275..eccf1a6033a 100644 --- a/src/sage/rings/number_field/galois_group.py +++ b/src/sage/rings/number_field/galois_group.py @@ -661,8 +661,9 @@ def fixed_field(self): sage: H = G.subgroup([G.identity()]) sage: H.fixed_field() - (Number Field in a0 with defining polynomial x^4 + 1, Ring morphism: - From: Number Field in a0 with defining polynomial x^4 + 1 + (Number Field in a0 with defining polynomial x^4 + 1 with a0 = a, + Ring morphism: + From: Number Field in a0 with defining polynomial x^4 + 1 with a0 = a To: Number Field in a with defining polynomial x^4 + 1 Defn: a0 |--> a) """ From d145dca112b3d8e37fdafec5e1d3df1921847cb1 Mon Sep 17 00:00:00 2001 From: leopoldmayer Date: Thu, 11 Jul 2019 10:52:26 -0400 Subject: [PATCH 052/340] 28170 - enhance several functions using field_of_definition functions --- .../arithmetic_dynamics/projective_ds.py | 140 ++++++++++++------ 1 file changed, 97 insertions(+), 43 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index f2278824722..fd8ccd9eda7 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -2980,11 +2980,14 @@ def is_postcritically_finite(self, err=0.01, embedding=None): point is preperiodic. The optional parameter ``err`` is passed into ``is_preperiodic()`` as part of the preperiodic check. + If ``embedding`` is ``None`` the function will use the minimal extension + containing all the critical points, as found by ``field_of_definition_critical``. + INPUT: - ``err`` -- (default: 0.01) positive real number - - ``embedding`` -- embedding of base ring into `\QQbar` + - ``embedding`` -- (default: None) embedding of base ring into `\QQbar` OUTPUT: boolean @@ -3028,9 +3031,8 @@ def is_postcritically_finite(self, err=0.01, embedding=None): raise NotImplementedError("must be over a number field or a number field order or QQbar") if embedding is None: - F = self.change_ring(QQbar) - else: - F = self.change_ring(embedding) + embedding = self.field_of_definition_critical(return_embedding=True)[1] + F = self.change_ring(embedding) crit_points = F.critical_points() pcf = True i = 0 @@ -3051,9 +3053,9 @@ def critical_point_portrait(self, check=True, embedding=None): INPUT: - - ``check`` -- boolean + - ``check`` -- boolean (default: True) - - ``embedding`` -- embedding of base ring into `\QQbar` + - ``embedding`` -- embedding of base ring into `\QQbar` (default: None) OUTPUT: a digraph @@ -3087,9 +3089,8 @@ def critical_point_portrait(self, check=True, embedding=None): if not self.is_postcritically_finite(): raise TypeError("map must be post-critically finite") if embedding is None: - F = self.change_ring(QQbar) - else: - F = self.change_ring(embedding) + embedding = self.field_of_definition_critical(return_embedding=True)[1] + F = self.change_ring(embedding) crit_points = F.critical_points() N = len(crit_points) for i in range(N): @@ -3423,7 +3424,7 @@ def multiplier_spectra(self, n, formal=False, embedding=None, type='point'): User can also specify to compute the ``n`` multiplier spectra instead which includes the multipliers of all periodic points of period ``n``. The map must be defined over - projective space of dimension 1 over a number field. + projective space of dimension 1 over a number field or finite field. INPUT: @@ -3447,10 +3448,18 @@ def multiplier_spectra(self, n, formal=False, embedding=None, type='point'): sage: f = DynamicalSystem_projective([4608*x^10 - 2910096*x^9*y + 325988068*x^8*y^2 + 31825198932*x^7*y^3 - 4139806626613*x^6*y^4\ - 44439736715486*x^5*y^5 + 2317935971590902*x^4*y^6 - 15344764859590852*x^3*y^7 + 2561851642765275*x^2*y^8\ + 113578270285012470*x*y^9 - 150049940203963800*y^10, 4608*y^10]) - sage: f.multiplier_spectra(1) - [0, -7198147681176255644585/256, 848446157556848459363/19683, -3323781962860268721722583135/35184372088832, - 529278480109921/256, -4290991994944936653/2097152, 1061953534167447403/19683, -3086380435599991/9, - 82911372672808161930567/8192, -119820502365680843999, 3553497751559301575157261317/8192] + sage: sorted(f.multiplier_spectra(1)) + [-119820502365680843999, + -7198147681176255644585/256, + -3086380435599991/9, + -3323781962860268721722583135/35184372088832, + -4290991994944936653/2097152, + 0, + 529278480109921/256, + 1061953534167447403/19683, + 848446157556848459363/19683, + 82911372672808161930567/8192, + 3553497751559301575157261317/8192] :: @@ -3459,19 +3468,19 @@ def multiplier_spectra(self, n, formal=False, embedding=None, type='point'): sage: K. = NumberField(z^4 - 4*z^2 + 1,'z') sage: P. = ProjectiveSpace(K,1) sage: f = DynamicalSystem_projective([x^2 - w/4*y^2, y^2]) - sage: f.multiplier_spectra(2, formal=False, embedding=K.embeddings(QQbar)[0], type='cycle') + sage: sorted(f.multiplier_spectra(2, formal=False, embedding=K.embeddings(QQbar)[0], type='cycle')) [0, - 5.931851652578137? + 0.?e-49*I, 0.0681483474218635? - 1.930649271699173?*I, - 0.0681483474218635? + 1.930649271699173?*I] + 0.0681483474218635? + 1.930649271699173?*I, + 5.931851652578137? + 0.?e-49*I] :: sage: P. = ProjectiveSpace(QQ,1) sage: f = DynamicalSystem_projective([x^2 - 3/4*y^2, y^2]) - sage: f.multiplier_spectra(2, formal=False, type='cycle') + sage: sorted(f.multiplier_spectra(2, formal=False, type='cycle')) [0, 1, 1, 9] - sage: f.multiplier_spectra(2, formal=False, type='point') + sage: sorted(f.multiplier_spectra(2, formal=False, type='point')) [0, 1, 1, 1, 9] :: @@ -3483,12 +3492,20 @@ def multiplier_spectra(self, n, formal=False, embedding=None, type='point'): sage: f.multiplier_spectra(3, formal=True, type='point') [1, 1, 1, 1, 1, 1] - :: + TESTS:: sage: P. = ProjectiveSpace(QQ,1) sage: f = DynamicalSystem_projective([x^2 + y^2, x*y]) sage: f.multiplier_spectra(1) [1, 1, 1] + + :: + + sage: F. = GF(7) + sage: P.=ProjectiveSpace(F,1) + sage: f = DynamicalSystem_projective([x^2 + y^2, y^2]) + sage: sorted(f.multiplier_spectra(1)) + [0, 3, 6] """ PS = self.domain() n = Integer(n) @@ -3499,13 +3516,10 @@ def multiplier_spectra(self, n, formal=False, embedding=None, type='point'): raise NotImplementedError("not implemented for subschemes") if (PS.dimension_relative() > 1): raise NotImplementedError("only implemented for dimension 1") - if not PS.base_ring() in NumberFields() and not PS.base_ring() is QQbar: - raise NotImplementedError("self must be a map over a number field") if embedding is None: - f = self.change_ring(QQbar) - else: - f = self.change_ring(embedding) + embedding = self.field_of_definition_periodic(n, return_embedding=True)[1] + f = self.change_ring(embedding) PS = f.domain() @@ -3514,17 +3528,9 @@ def multiplier_spectra(self, n, formal=False, embedding=None, type='point'): F = G[0]*PS.gens()[1] - G[1]*PS.gens()[0] else: # periodic points of formal period n are the roots of the nth dynatomic polynomial - K = f._number_field_from_algebraics().as_dynamical_system() - F = K.dynatomic_polynomial(n) - if K.domain().base_ring() != QQ: # need to coerce F to poly over QQbar. This is only needed if base ring is not QQ - abspoly = K.domain().base_ring().absolute_polynomial() - phi = K.domain().base_ring().hom(QQbar.polynomial_root(abspoly,abspoly.any_root(CIF)),QQbar) - Kx = K.coordinate_ring() - QQbarx = QQbar[Kx.variable_names()] - phix = Kx.hom(phi,QQbarx) - F = phix(F) - - other_roots = F.parent()(F([(f.domain().gens()[0]),1])).univariate_polynomial().roots(ring=QQbar) + F = f.dynatomic_polynomial(n) + + other_roots = F.parent()(F([(f.domain().gens()[0]),1])).univariate_polynomial().roots(ring=f.base_ring()) points = [] @@ -5643,9 +5649,57 @@ def normal_form(self, return_conjugation=False): class DynamicalSystem_projective_finite_field(DynamicalSystem_projective_field, SchemeMorphism_polynomial_projective_space_finite_field): + + def is_postcritically_finite(self): + r""" + Every point is postcritically finite in a finite field. + + OUTPUT: the boolean ``True`` + + EXAMPLES:: + + sage: P. = ProjectiveSpace(GF(5),2) + sage: f = DynamicalSystem_projective([x^2 + y^2,y^2, z^2 + y*z], domain=P) + sage: f.is_postcritically_finite() + True + """ + return True + + def _is_preperiodic(self, P, return_period=False): + r""" + Every point in a finite field is preperiodic. + + INPUT: + + - ``P`` -- a point in the domain of this map + + - ``return_period`` -- (default: ``False``) boolean; controls if + the period is returned + + OUTPUT: the boolean ``True`` or a tuple ``(m,n)`` of integers + + EXAMPLES:: + + sage: P. = ProjectiveSpace(GF(5),2) + sage: f = DynamicalSystem_projective([x^2 + y^2,y^2, z^2 + y*z], domain=P) + sage: f._is_preperiodic(P(2,1,2)) + True + + :: + + sage: P. = ProjectiveSpace(GF(5),2) + sage: f = DynamicalSystem_projective([x^2 + y^2,y^2, z^2 + y*z], domain=P) + sage: f._is_preperiodic(P(2,1,2), return_period=True) + (0, 6) + """ + if return_period: + return self.orbit_structure(P) + else: + return True + def orbit_structure(self, P): r""" - Return the pair ``[m,n]``, where ``m`` is the preperiod and ``n`` + Return the pair ``(m,n)``, where ``m`` is the preperiod and ``n`` is the period of the point ``P`` by this dynamical system. Every point is preperiodic over a finite field so every point @@ -5655,14 +5709,14 @@ def orbit_structure(self, P): - ``P`` -- a point in the domain of this map - OUTPUT: a list ``[m,n]`` of integers + OUTPUT: a tuple ``(m,n)`` of integers EXAMPLES:: sage: P. = ProjectiveSpace(GF(5),2) sage: f = DynamicalSystem_projective([x^2 + y^2,y^2, z^2 + y*z], domain=P) sage: f.orbit_structure(P(2,1,2)) - [0, 6] + (0, 6) :: @@ -5670,14 +5724,14 @@ def orbit_structure(self, P): sage: X = P.subscheme(x^2-y^2) sage: f = DynamicalSystem_projective([x^2, y^2, z^2], domain=X) sage: f.orbit_structure(X(1,1,2)) - [0, 2] + (0, 2) :: sage: P. = ProjectiveSpace(GF(13),1) sage: f = DynamicalSystem_projective([x^2 - y^2, y^2], domain=P) sage: f.orbit_structure(P(3,4)) - [2, 3] + (2, 3) :: @@ -5685,7 +5739,7 @@ def orbit_structure(self, P): sage: P. = ProjectiveSpace(R,1) sage: f = DynamicalSystem_projective([x^2 - y^2, y^2], domain=P) sage: f.orbit_structure(P(t, 4)) - [11, 6] + (11, 6) """ orbit = [] index = 1 @@ -5699,7 +5753,7 @@ def orbit_structure(self, P): Q.normalize_coordinates() index += 1 I = orbit.index(Q) - return([I, index-I-1]) + return (I, index-I-1) def cyclegraph(self): r""" From 575420c70b6e04e3c6df1505aa0e760b4802066b Mon Sep 17 00:00:00 2001 From: David Coudert Date: Sun, 14 Jul 2019 14:07:27 +0200 Subject: [PATCH 053/340] trac #27408: improve method __bool__ --- src/sage/graphs/views.pyx | 45 +++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index b3f7354205a..22e82619b1e 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -360,22 +360,6 @@ cdef class EdgesView: else: return sum(1 for _ in self) - def __bool__(self): - """ - Check whether ``self`` is empty. - - EXAMPLES:: - - sage: from sage.graphs.views import EdgesView - sage: E = EdgesView(Graph()) - sage: bool(E) - False - sage: E = EdgesView(graphs.HouseGraph()) - sage: bool(E) - True - """ - return len(self) > 0 - def __repr__(self): """ Return a string representation of ``self``. @@ -437,6 +421,35 @@ cdef class EdgesView: else: yield from self._iter_unsorted(vertices) + def __bool__(self): + """ + Check whether ``self`` is empty. + + EXAMPLES:: + + sage: from sage.graphs.views import EdgesView + sage: E = EdgesView(Graph()) + sage: bool(E) + False + sage: E = EdgesView(graphs.HouseGraph()) + sage: bool(E) + True + """ + if self._vertices is None: + vertices = self._graph + else: + vertices = self._vertices + if self._graph._directed: + for _ in self._graph._backend.iterator_out_edges(vertices, False): + return True + if self._ignore_direction: + for _ in self._graph._backend.iterator_in_edges(vertices, False): + return True + else: + for _ in self._graph._backend.iterator_edges(vertices, False): + return True + return False + def __eq__(self, right): """ Check whether ``self`` and ``right`` are equal. From e22128573720f571abece85d8614e1ea70cf9ea2 Mon Sep 17 00:00:00 2001 From: EnderWannabe Date: Thu, 18 Jul 2019 10:50:50 -0400 Subject: [PATCH 054/340] started deprecation --- .../arithmetic_dynamics/projective_ds.py | 67 +++++++++++++++++-- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index f2278824722..8db3c8fe07d 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -4761,6 +4761,65 @@ def rational_preperiodic_points(self, **kwds): sage: PS. = ProjectiveSpace(1,QQ) sage: f = DynamicalSystem_projective([x^2 -y^2, 3*x*y]) sage: sorted(f.rational_preperiodic_points()) + DeprecationWarning + [(-2 : 1), (-1 : 1), (-1/2 : 1), (0 : 1), (1/2 : 1), (1 : 0), (1 : 1), + (2 : 1)] + """ + from sage.misc.superseded import deprecation + deprecation(28213, "use sage.dynamics.arithmetic_dynamics.projective_ds.all_preperiodic_points instead") + return self.all_preperiodic_points(**kwds) + + def all_preperiodic_points(self, **kwds): + r""" + Determine the set of rational preperiodic points for + this dynamical system. + + The map must be defined over `\QQ` and be an endomorphism of + projective space. If the map is a polynomial endomorphism of + `\mathbb{P}^1`, i.e. has a totally ramified fixed point, then + the base ring can be an absolute number field. + This is done by passing to the Weil restriction. + + The default parameter values are typically good choices for + `\mathbb{P}^1`. If you are having trouble getting a particular + map to finish, try first computing the possible periods, then + try various different values for ``lifting_prime``. + + ALGORITHM: + + - Determines the list of possible periods. + + - Determines the rational periodic points from the possible periods. + + - Determines the rational preperiodic points from the rational + periodic points by determining rational preimages. + + INPUT: + + kwds: + + - ``prime_bound`` -- (default: ``[1, 20]``) a pair (list or tuple) + of positive integers that represent the limits of primes to use + in the reduction step or an integer that represents the upper bound + + - ``lifting_prime`` -- (default: 23) a prime integer; specifies + modulo which prime to try and perform the lifting + + - ``periods`` -- (optional) a list of positive integers that is + the list of possible periods + + - ``bad_primes`` -- (optional) a list or tuple of integer primes; + the primes of bad reduction + + - ``ncpus`` -- (default: all cpus) number of cpus to use in parallel + + OUTPUT: a list of rational points in projective space + + EXAMPLES:: + + sage: PS. = ProjectiveSpace(1,QQ) + sage: f = DynamicalSystem_projective([x^2 -y^2, 3*x*y]) + sage: sorted(f.all_preperiodic_points()) [(-2 : 1), (-1 : 1), (-1/2 : 1), (0 : 1), (1/2 : 1), (1 : 0), (1 : 1), (2 : 1)] @@ -4768,14 +4827,14 @@ def rational_preperiodic_points(self, **kwds): sage: PS. = ProjectiveSpace(1,QQ) sage: f = DynamicalSystem_projective([5*x^3 - 53*x*y^2 + 24*y^3, 24*y^3]) - sage: sorted(f.rational_preperiodic_points(prime_bound=10)) + sage: sorted(f.all_preperiodic_points(prime_bound=10)) [(-1 : 1), (0 : 1), (1 : 0), (1 : 1), (3 : 1)] :: sage: PS. = ProjectiveSpace(2,QQ) sage: f = DynamicalSystem_projective([x^2 - 21/16*z^2, y^2-2*z^2, z^2]) - sage: sorted(f.rational_preperiodic_points(prime_bound=[1,8], lifting_prime=7, periods=[2])) # long time + sage: sorted(f.all_preperiodic_points(prime_bound=[1,8], lifting_prime=7, periods=[2])) # long time [(-5/4 : -2 : 1), (-5/4 : -1 : 1), (-5/4 : 0 : 1), (-5/4 : 1 : 1), (-5/4 : 2 : 1), (-1/4 : -2 : 1), (-1/4 : -1 : 1), (-1/4 : 0 : 1), (-1/4 : 1 : 1), (-1/4 : 2 : 1), (1/4 : -2 : 1), (1/4 : -1 : 1), (1/4 : 0 : 1), (1/4 @@ -4787,7 +4846,7 @@ def rational_preperiodic_points(self, **kwds): sage: K. = QuadraticField(33) sage: PS. = ProjectiveSpace(K,1) sage: f = DynamicalSystem_projective([x^2-71/48*y^2, y^2]) - sage: sorted(f.rational_preperiodic_points()) # long time + sage: sorted(f.all_preperiodic_points()) # long time [(-1/12*w - 1 : 1), (-1/6*w - 1/4 : 1), (-1/12*w - 1/2 : 1), @@ -4832,7 +4891,7 @@ def rational_preperiodic_points(self, **kwds): G = g.weil_restriction() F = G.homogenize(d) #find the QQ rational preperiodic points for the weil restriction - Fpre = F.rational_preperiodic_points(**kwds) + Fpre = F.all_preperiodic_points(**kwds) for P in Fpre: #take the 'good' points in the weil restriction and find the #associated number field points. From 0c5f507bcf59768145b02024a923876187635644 Mon Sep 17 00:00:00 2001 From: EnderWannabe Date: Thu, 18 Jul 2019 10:54:49 -0400 Subject: [PATCH 055/340] finished deprecation --- src/sage/dynamics/arithmetic_dynamics/projective_ds.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 8db3c8fe07d..0df0ab59905 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -4761,7 +4761,8 @@ def rational_preperiodic_points(self, **kwds): sage: PS. = ProjectiveSpace(1,QQ) sage: f = DynamicalSystem_projective([x^2 -y^2, 3*x*y]) sage: sorted(f.rational_preperiodic_points()) - DeprecationWarning + doctest:warning + ... [(-2 : 1), (-1 : 1), (-1/2 : 1), (0 : 1), (1/2 : 1), (1 : 0), (1 : 1), (2 : 1)] """ @@ -5003,7 +5004,7 @@ def rational_preperiodic_graph(self, **kwds): Looped digraph on 5 vertices """ #input checking done in .rational_preperiodic_points() - preper = self.rational_preperiodic_points(**kwds) + preper = self.all_preperiodic_points(**kwds) g = self._preperiodic_points_to_cyclegraph(preper) return g From dcb67000b03a2e9f9150c658e9237b893ebd0d1d Mon Sep 17 00:00:00 2001 From: ckelln Date: Thu, 18 Jul 2019 11:06:15 -0400 Subject: [PATCH 056/340] 23720: Fixed (most) color inconsistencies and updated interact feature to work for jupyter notebooks. --- .../dynamics/complex_dynamics/mandel_julia.py | 89 ++++++++++--------- .../complex_dynamics/mandel_julia_helper.pyx | 2 +- 2 files changed, 46 insertions(+), 45 deletions(-) diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia.py b/src/sage/dynamics/complex_dynamics/mandel_julia.py index 0120d79e010..77f709c522e 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia.py +++ b/src/sage/dynamics/complex_dynamics/mandel_julia.py @@ -38,6 +38,11 @@ polynomial_mandelbrot, julia_helper) from sage.dynamics.arithmetic_dynamics.generic_ds import DynamicalSystem +from sagenb.notebook.interact import (interact, + slider, + input_box, + color_selector, + checkbox) from sage.plot.colors import Color from sage.repl.image import Image from sage.functions.log import logb @@ -77,15 +82,15 @@ def mandelbrot_plot(f=None, **kwds): in the complex plane. - ``max_iteration`` -- long (optional - default: ``500``), maximum number of - iterations the map ``Q_c(z)``. + iterations the map ``f_c(z)``. - ``pixel_count`` -- long (optional - default: ``500``), side length of image in number of pixels. - - ``base_color`` -- RGB color (optional - default: ``[40, 40, 40]``) color + - ``base_color`` -- Hex color (optional - default: ``tomato``) color used to determine the coloring of set. - - ``iteration_level`` -- long (optional - default: 1) number of iterations + - ``level_sep`` -- long (optional - default: 1) number of iterations between each color level. - ``number_of_colors`` -- long (optional - default: 30) number of colors @@ -120,7 +125,7 @@ def mandelbrot_plot(f=None, **kwds): ``interact`` to ``True``. (This is only implemented for ``z^2 + c``):: sage: mandelbrot_plot(interact=True) - interactive(children=(FloatSlider(value=-1.0, description=u'Real center'... + ... :: @@ -165,11 +170,10 @@ def mandelbrot_plot(f=None, **kwds): image_width = kwds.pop("image_width", 4.0) max_iteration = kwds.pop("max_iteration", None) pixel_count = kwds.pop("pixel_count", 500) - base_color = kwds.pop("base_color", [40, 40, 40]) - iteration_level = kwds.pop("iteration_level", 1) + level_sep = kwds.pop("level_sep", 1) number_of_colors = kwds.pop("number_of_colors", 30) interacts = kwds.pop("interact", False) - + base_color = kwds.pop("base_color", Color('tomato')) # Check if user specified maximum number of iterations given_iterations = True if max_iteration is None: @@ -177,26 +181,35 @@ def mandelbrot_plot(f=None, **kwds): max_iteration = 500 given_iterations = False - + from ipywidgets.widgets import FloatSlider, IntSlider, ColorPicker, interact + widgets = dict( + x_center = FloatSlider(min=-1.0, max=1.0, step=EPS, + value=x_center, description="Real center"), + y_center = FloatSlider(min=-1.0, max=1.0, step=EPS, + value=y_center, description="Imag center"), + image_width = FloatSlider(min=EPS, max=4.0, step=EPS, + value=image_width, description="Zoom"), + max_iteration = IntSlider(min=0, max=600, + value=max_iteration, description="Iterations"), + pixel_count = IntSlider(min=10, max=600, + value=pixel_count, description="Pixels"), + level_sep = IntSlider(min=1, max=20, + value=level_sep, description="Color sep"), + color_num = IntSlider(min=1, max=100, + value=number_of_colors, description="# Colors"), + base_color = ColorPicker(value=Color(base_color).html_color(), + description="Base color"), + ) + if f is None: # Quadratic map f = z^2 + c + if interacts: - @interact(layout={'bottom':[['real_center'], ['im_center'], ['width']], - 'top':[['iterations'], ['level_sep'], ['color_num'], ['image_color']]}) - def _(real_center=input_box(x_center, 'Real'), - im_center=input_box(y_center, 'Imaginary'), - width=input_box(image_width, 'Width of Image'), - iterations=input_box(max_iteration, 'Max Number of Iterations'), - level_sep=input_box(iteration_level, 'Iterations between Colors'), - color_num=input_box(number_of_colors, 'Number of Colors'), - image_color=color_selector(default=Color([j/255 for j in base_color]), - label="Image Color", hide_box=True)): - return fast_mandelbrot_plot(real_center, im_center, width, - iterations, pixel_count, level_sep, color_num, image_color).show() - + return interact(**widgets).widget(fast_mandelbrot_plot) + else: return fast_mandelbrot_plot(x_center, y_center, image_width, - max_iteration, pixel_count, iteration_level, number_of_colors, + max_iteration, pixel_count, level_sep, number_of_colors, base_color) else: @@ -221,22 +234,11 @@ def _(real_center=input_box(x_center, 'Real'), if f == variable**2 + parameter: # Quadratic map f = z^2 + c if interacts: - @interact(layout={'bottom':[['real_center'], ['im_center'], ['width']], - 'top':[['iterations'], ['level_sep'], ['color_num'], ['image_color']]}) - def _(real_center=input_box(x_center, 'Real'), - im_center=input_box(y_center, 'Imaginary'), - width=input_box(image_width, 'Width of Image'), - iterations=input_box(max_iteration, 'Max Number of Iterations'), - level_sep=input_box(iteration_level, 'Iterations between Colors'), - color_num=input_box(number_of_colors, 'Number of Colors'), - image_color=color_selector(default=Color([j/255 for j in base_color]), - label="Image Color", hide_box=True)): - return fast_mandelbrot_plot(real_center, im_center, width, - iterations, pixel_count, level_sep, color_num, image_color).show() + return interact(**widgets).widget(fast_mandelbrot_plot) else: return fast_mandelbrot_plot(x_center, y_center, image_width, - max_iteration, pixel_count, iteration_level, number_of_colors, + max_iteration, pixel_count, level_sep, number_of_colors, base_color) else: if interacts: @@ -249,7 +251,7 @@ def _(real_center=input_box(x_center, 'Real'), # Mandelbrot of General Polynomial Map return polynomial_mandelbrot(f, parameter, x_center, y_center, \ - image_width, max_iteration, pixel_count, iteration_level, \ + image_width, max_iteration, pixel_count, level_sep, \ number_of_colors, base_color) def external_ray(theta, **kwds): @@ -352,7 +354,6 @@ def external_ray(theta, **kwds): image = mandelbrot_plot(x_center=x_0, **kwds) # Make a copy of the bitmap image. - # M = copy(image) old_pixel = image.pixels() M = Image('RGB', (pixel_width, pixel_width)) pixel = M.pixels() @@ -407,7 +408,7 @@ def julia_plot(c=-1, max_iteration=500, pixel_count=500, base_color='steelblue', - iteration_level=1, + level_sep=1, number_of_colors=50, point_color='yellow', interact=False, @@ -463,10 +464,10 @@ def julia_plot(c=-1, - ``pixel_count`` -- long (optional - default: ``500``), side length of image in number of pixels. - - ``base_color`` -- RGB color (optional - default: ``'steelblue'``), color + - ``base_color`` -- hex color (optional - default: ``'steelblue'``), color used to determine the coloring of set (any valid input for Color). - - ``iteration_level`` -- long (optional - default: 1), number of iterations + - ``level_sep`` -- long (optional - default: 1), number of iterations between each color level. - ``number_of_colors`` -- long (optional - default: 30), number of colors @@ -540,13 +541,13 @@ def julia_plot(c=-1, y_center = FloatSlider(min=-1.0, max=1.0, step=EPS, value=y_center, description="Imag center"), image_width = FloatSlider(min=EPS, max=4.0, step=EPS, - value=image_width, description="Image width"), + value=image_width, description="Zoom"), max_iteration = IntSlider(min=0, max=600, value=max_iteration, description="Iterations"), pixel_count = IntSlider(min=10, max=600, value=pixel_count, description="Pixels"), level_sep = IntSlider(min=1, max=20, - value=iteration_level, description="Color sep"), + value=level_sep, description="Color sep"), color_num = IntSlider(min=1, max=100, value=number_of_colors, description="# Colors"), base_color = ColorPicker(value=base_color.html_color(), @@ -562,11 +563,11 @@ def julia_plot(c=-1, if mandelbrot: return julia_helper(c_real, c_imag, x_center, y_center, image_width, max_iteration, pixel_count, - iteration_level, + level_sep, number_of_colors, base_color, point_color) else: return fast_julia_plot(c_real, c_imag, x_center, y_center, image_width, max_iteration, pixel_count, - iteration_level, + level_sep, number_of_colors, base_color) diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx index 016a0161127..c048b944883 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +++ b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx @@ -621,7 +621,7 @@ cpdef julia_helper(double c_real, double c_imag, double x_center=0, cpdef polynomial_mandelbrot(f, parameter=None, double x_center=0, double y_center=0, image_width=4, int max_iteration=50, int pixel_count=500, - int level_sep=1, int color_num=30, base_color=[50,50,50]): + int level_sep=1, int color_num=30, base_color='red'): r""" Plots the Mandelbrot set in the complex plane for a general polynomial map. From 1981d8e34a549183cce64f91385f5854d6fe124a Mon Sep 17 00:00:00 2001 From: = <=> Date: Thu, 18 Jul 2019 11:18:32 -0400 Subject: [PATCH 057/340] 23816: Fix missed merge issue --- src/sage/matrix/action.pyx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/sage/matrix/action.pyx b/src/sage/matrix/action.pyx index 1ce61d651ab..849b4f78410 100644 --- a/src/sage/matrix/action.pyx +++ b/src/sage/matrix/action.pyx @@ -65,15 +65,9 @@ import operator from .matrix_space import MatrixSpace, is_MatrixSpace from sage.modules.free_module import FreeModule, is_FreeModule -<<<<<<< HEAD from sage.structure.coerce cimport coercion_model from sage.categories.homset import Hom, End -from sage.schemes.generic.homset import SchemeHomset_generic -======= -from sage.structure.element cimport coercion_model -from sage.categories.homset import Hom, End from sage.schemes.generic.homset import SchemeHomset_generic, SchemeHomset_points ->>>>>>> adfc69204b75d0ba2f5e3ebe6b50fb0b45d732d6 cdef class MatrixMulAction(Action): From addbcf027760d16ff477764184124060c59d99b9 Mon Sep 17 00:00:00 2001 From: = <=> Date: Thu, 18 Jul 2019 11:21:49 -0400 Subject: [PATCH 058/340] 23816: Update _call_ in MatrixSchemePointAction to _act_ --- src/sage/matrix/action.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/action.pyx b/src/sage/matrix/action.pyx index 849b4f78410..8c310a72099 100644 --- a/src/sage/matrix/action.pyx +++ b/src/sage/matrix/action.pyx @@ -559,7 +559,7 @@ cdef class MatrixSchemePointAction(MatrixMulAction): amb = self.underlying_set().codomain() return amb.change_ring(base)(base) - cpdef _call_(self, mat, P): + cpdef _act_(self, mat, P): """ Action of matrices on scheme points. @@ -571,7 +571,7 @@ cdef class MatrixSchemePointAction(MatrixMulAction): sage: M = MatrixSpace(QQ, 2, 2) sage: A = MatrixSchemePointAction(M, Q.parent()) sage: m = matrix([[1,1], [0,1]]) - sage: A._call_(m, Q) + sage: A._act_(m, Q) (2 : 1) """ return P._matrix_times_point_(mat, self._codomain) From f9e3ab05d0fe5bf6f37a80fcc56edd5ab9c5b042 Mon Sep 17 00:00:00 2001 From: = <=> Date: Thu, 18 Jul 2019 11:32:23 -0400 Subject: [PATCH 059/340] 23816: Fix very minor test failure --- src/sage/schemes/affine/affine_morphism.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/schemes/affine/affine_morphism.py b/src/sage/schemes/affine/affine_morphism.py index 999d56a6672..4315f3403ac 100644 --- a/src/sage/schemes/affine/affine_morphism.py +++ b/src/sage/schemes/affine/affine_morphism.py @@ -899,8 +899,8 @@ def _polymap_times_matrix_(self, mat, h): Scheme morphism: From: Affine Space of dimension 3 over Rational Field To: Affine Space of dimension 2 over Rational Field - Defn: Defined on coordinates by sending (x0, x1, x2) to - (x0^2 + x1^2 + x2^2 + 1, x0^2 + x1^2 + 1) + Defn: Defined on coordinates by sending (u, v, w) to + (u^2 + v^2 + w^2 + 1, u^2 + v^2 + 1) """ if self.is_endomorphism(): d = self.domain().ngens() From f53180dc48833fa60f7206d1ce9620d33f9d163b Mon Sep 17 00:00:00 2001 From: joey Date: Thu, 18 Jul 2019 11:44:35 -0400 Subject: [PATCH 060/340] 28214: initial commit --- .../arithmetic_dynamics/projective_ds.py | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index f2278824722..bdd6a03ca6f 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -2233,6 +2233,66 @@ def _multipliermod(self, P, n, p, k): Q = R return(l) + def nth_preimage_tree(self, Q, n, numerical=False, diplay_labels=True, display_complex=False): + r""" + Return the ``n``-th pre-image tree rooted at ``Q`` + + This map must be an endomorphism of the projective line defined + over a number field or finite field. + + INPUT: + + - ``Q`` -- a point on domain of this map + + - ``n`` -- a positive integer, the depth of the pre-image tree + + - ``numerical`` -- (default: ``False``) boolean; calculate pre-images numerically + + - ``display_labels`` -- (default: ``True``) boolean; whether to display vertex labels + + - ``display_complex`` -- (default: ``False``) boolean; display vertex labels as + complex numbers + + OUTPUT: + + A ``GraphPlot`` object representing the ``n``-th pre-image tree + """ + if self.domain().dimension_relative() > 1: + raise NotImplementedError("only implemented for dimension 1") + base_ring = self.base_ring() + if not base_ring in NumberFields() or base_ring in FiniteFields(): + raise NotImplementedError("Only implemented for number fields and finite fields") + fbar = self.change_ring(self.field_of_definition_preimage(Q,n)) + V = __nth_preimage_tree_helper(fbar, Q, n, 1, numerical, display_complex) + G = DiGraph(V) + if display_complex: + Q = ProjectiveSpace(CC,1)(Q) + root = str(Q) + ", " + str(0) + options = {'layout':'tree', 'tree_orientation':'up', 'tree_root':root, 'vertex_labels':display_labels} + return GraphPlot(G, options) + + def __nth_preimage_tree_helper(self, Q, n, m, numerical, display_complex): + D = {} + if numerical: + CR = self.domain().ambient_space().coordinate_ring() + fn = self.dehomogenize(1) + poly = (fn[0].numerator()*CR(Q[1]) - fn[0].denominator()*CR(Q[0])).univariate_polynomial() + pre = [ProjectiveSpace(QQbar,1)(r) for r in poly.roots(ring=QQbar)] + else: + pre = self.rational_preimages(Q,1) + for pt in pre: + if display_complex: + pt = ProjectiveSpace(CC,1)(pt) + Q = ProjectiveSpace(CC,1)(Q) + key = str(pt) + ", " + str(m) + D[key] = [str(Q)+ ", " + str(m-1)] + if n==1: + return D + else: + for pt in pre: + D.update(__nth_preimage_tree_helper(self, pt, n-1, m+1, numerical, display_complex)) + return D + def possible_periods(self, **kwds): r""" Return the set of possible periods for rational periodic points of From 4937d0b9a9b469576eb36dc7a5ea721a6a169192 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Mon, 22 Jul 2019 01:54:31 +0200 Subject: [PATCH 061/340] trac #27408: fix small issue with graph_coloring.pyx --- src/sage/graphs/graph_coloring.pyx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/graphs/graph_coloring.pyx b/src/sage/graphs/graph_coloring.pyx index 229e1520b92..1a1704ba347 100644 --- a/src/sage/graphs/graph_coloring.pyx +++ b/src/sage/graphs/graph_coloring.pyx @@ -185,7 +185,6 @@ def all_graph_colorings(G, n, count_only=False, hex_colors=False, vertex_color_d raise ValueError("n must be non-negative") cdef list V = list(G) - cdef list E = G.edges(sort=False) cdef int nV = G.order() cdef int nE = G.size() @@ -203,7 +202,7 @@ def all_graph_colorings(G, n, count_only=False, hex_colors=False, vertex_color_d cdef int kk = nV cdef int v0, v1 - for e in E: + for e in G.edges(labels=False, sort=False): v0 = n * Vd[e[0]] v1 = n * Vd[e[1]] for c in range(n): From 7a07a2172d981856af960acdf330d352a98d6440 Mon Sep 17 00:00:00 2001 From: EnderWannabe Date: Thu, 25 Jul 2019 09:16:19 -0400 Subject: [PATCH 062/340] added ring parameter to all_preperiodic_points --- .../arithmetic_dynamics/projective_ds.py | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 0df0ab59905..ce55a579616 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -4799,6 +4799,9 @@ def all_preperiodic_points(self, **kwds): kwds: + - ``ring`` -- (default: domain of dynamical system) the base ring + over which the periodic points of the dynamical system are found + - ``prime_bound`` -- (default: ``[1, 20]``) a pair (list or tuple) of positive integers that represent the limits of primes to use in the reduction step or an integer that represents the upper bound @@ -4862,7 +4865,12 @@ def all_preperiodic_points(self, **kwds): (1/6*w + 1/4 : 1), (1/12*w + 1 : 1)] """ - PS = self.domain() + ring = kwds.pop("ring",None) + if not ring is None: + DS = self.change_ring(ring) + else: + DS = self + PS = DS.domain() K = PS.base_ring() if K not in NumberFields() or not K.is_absolute(): raise TypeError("base field must be an absolute field") @@ -4876,11 +4884,11 @@ def all_preperiodic_points(self, **kwds): #separately. We also check here that we are working with a polynomial. If the map #is not a polynomial, the Weil restriction will not be a morphism and we cannot #apply this algorithm. - g = self.dehomogenize(1) + g = DS.dehomogenize(1) inf = PS([1,0]) k = 1 if isinstance(g[0], FractionFieldElement): - g = self.dehomogenize(0) + g = DS.dehomogenize(0) inf = PS([0,1]) k = 0 if isinstance(g[0], FractionFieldElement): @@ -4902,7 +4910,7 @@ def all_preperiodic_points(self, **kwds): Q = PS(pt) #for each preperiodic point get the entire connected component if not Q in preper: - for t in self.connected_rational_component(Q): + for t in DS.connected_rational_component(Q): preper.add(t) preper = list(preper) else: @@ -4912,20 +4920,20 @@ def all_preperiodic_points(self, **kwds): primebound = kwds.pop("prime_bound", [1, 20]) num_cpus = kwds.pop("ncpus", ncpus()) if badprimes is None: - badprimes = self.primes_of_bad_reduction() + badprimes = DS.primes_of_bad_reduction() if periods is None: #determine the set of possible periods - periods = self.possible_periods(prime_bound=primebound, + periods = DS.possible_periods(prime_bound=primebound, bad_primes=badprimes, ncpus=num_cpus) if periods == []: return([]) #no rational preperiodic points else: p = kwds.pop("lifting_prime", 23) #find the rational preperiodic points - T = self.rational_periodic_points(prime_bound=primebound, lifting_prime=p, + T = DS.rational_periodic_points(prime_bound=primebound, lifting_prime=p, periods=periods, bad_primes=badprimes, ncpus=num_cpus) - preper = self.all_rational_preimages(T) #find the preperiodic points + preper = DS.all_rational_preimages(T) #find the preperiodic points preper = list(preper) return preper From ddb879f4056a04dc1456eebc8ab356f3f68042b6 Mon Sep 17 00:00:00 2001 From: joey Date: Thu, 25 Jul 2019 10:03:37 -0400 Subject: [PATCH 063/340] 28214: fix scope/import errors --- .../arithmetic_dynamics/projective_ds.py | 50 ++++++++++--------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index bdd6a03ca6f..605c538b5ef 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -2233,7 +2233,29 @@ def _multipliermod(self, P, n, p, k): Q = R return(l) - def nth_preimage_tree(self, Q, n, numerical=False, diplay_labels=True, display_complex=False): + def _nth_preimage_tree_helper(self, fbar, Q, n, m, numerical, display_complex): + D = {} + if numerical: + CR = fbar.domain().ambient_space().coordinate_ring() + fn = fbar.dehomogenize(1) + poly = (fn[0].numerator()*CR(Q[1]) - fn[0].denominator()*CR(Q[0])).univariate_polynomial() + pre = [ProjectiveSpace(QQbar,1)(r) for r in poly.roots(ring=QQbar)] + else: + pre = fbar.rational_preimages(Q,1) + for pt in pre: + if display_complex: + pt = ProjectiveSpace(CC,1)(pt) + Q = ProjectiveSpace(CC,1)(Q) + key = str(pt) + ", " + str(m) + D[key] = [str(Q)+ ", " + str(m-1)] + if n==1: + return D + else: + for pt in pre: + D.update(self._nth_preimage_tree_helper(fbar, pt, n-1, m+1, numerical, display_complex)) + return D + + def nth_preimage_tree(self, Q, n, numerical=False, display_labels=True, display_complex=False): r""" Return the ``n``-th pre-image tree rooted at ``Q`` @@ -2263,36 +2285,16 @@ def nth_preimage_tree(self, Q, n, numerical=False, diplay_labels=True, display_c if not base_ring in NumberFields() or base_ring in FiniteFields(): raise NotImplementedError("Only implemented for number fields and finite fields") fbar = self.change_ring(self.field_of_definition_preimage(Q,n)) - V = __nth_preimage_tree_helper(fbar, Q, n, 1, numerical, display_complex) + V = self._nth_preimage_tree_helper(fbar, Q, n, 1, numerical, display_complex) + from sage.graphs.digraph import DiGraph G = DiGraph(V) if display_complex: Q = ProjectiveSpace(CC,1)(Q) root = str(Q) + ", " + str(0) options = {'layout':'tree', 'tree_orientation':'up', 'tree_root':root, 'vertex_labels':display_labels} + from sage.graphs.graph_plot import GraphPlot return GraphPlot(G, options) - def __nth_preimage_tree_helper(self, Q, n, m, numerical, display_complex): - D = {} - if numerical: - CR = self.domain().ambient_space().coordinate_ring() - fn = self.dehomogenize(1) - poly = (fn[0].numerator()*CR(Q[1]) - fn[0].denominator()*CR(Q[0])).univariate_polynomial() - pre = [ProjectiveSpace(QQbar,1)(r) for r in poly.roots(ring=QQbar)] - else: - pre = self.rational_preimages(Q,1) - for pt in pre: - if display_complex: - pt = ProjectiveSpace(CC,1)(pt) - Q = ProjectiveSpace(CC,1)(Q) - key = str(pt) + ", " + str(m) - D[key] = [str(Q)+ ", " + str(m-1)] - if n==1: - return D - else: - for pt in pre: - D.update(__nth_preimage_tree_helper(self, pt, n-1, m+1, numerical, display_complex)) - return D - def possible_periods(self, **kwds): r""" Return the set of possible periods for rational periodic points of From 7c2f54ca99a3ea4b0d3db46b4cf2a7edb750b72d Mon Sep 17 00:00:00 2001 From: EnderWannabe Date: Thu, 25 Jul 2019 10:38:27 -0400 Subject: [PATCH 064/340] wrote perperiodic_points method --- .../arithmetic_dynamics/projective_ds.py | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index ce55a579616..afe4ef1c0cb 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -3172,6 +3172,113 @@ def critical_height(self, **kwds): ch += F.canonical_height(P, **kwds) return ch + def preperiodic_points(self, n, m, **kwds): + r""" + Computes the preperiodic points of period ``m``,``n`` of this dynamical system + defined over the ring ``R`` or the base ring of the map. + + This can be done either by finding the rational points on the variety + defining the points of period ``m``,``n``, or, for finite fields, + finding the cycle of appropriate length in the cyclegraph. For small + cardinality fields, the cyclegraph algorithm is effective for any + map and length cycle, but is slow when the cyclegraph is large. + The variety algorithm is good for small period, degree, and dimension, + but is slow as the defining equations of the variety get more + complicated. + + For rational map, where there are potentially infinitely many periodic + points of a given period, you must use the ``return_scheme`` option. + Note that this scheme will include the indeterminacy locus. + + INPUT: + + - ``n`` - a positive integer + + - ``m`` - a non negative integer + + kwds: + + - ``minimal`` -- (default: ``True``) boolean; ``True`` specifies to + find only the periodic points of minimal period ``n`` and ``False`` + specifies to find all periodic points of period ``n`` + + - ``R`` -- (default: the base ring of the dynamical system) a + commutative ring over which to find the preperiodic points + + - ``return_scheme`` -- (default: ``False``) boolean; return a + subscheme of the ambient space that defines the ``n`` th periodic points + + OUTPUT: + + A list of preperiodic points of this map or the subscheme defining + the preperiodic points. + + EXAMPLES:: + + + """ + if n <= 0: + raise ValueError("a positive integer period must be specified") + if m < 0: + raise ValueError("a non negative preperiod must be specified") + R = kwds.pop('R', None) + if R is None: + f = self + R = self.base_ring() + else: + f = self.change_ring(R) + R = f.base_ring() + CR = f.coordinate_ring() + dom = f.domain() + PS = f.codomain().ambient_space() + N = PS.dimension_relative() + 1 + F = f.nth_iterate_map(n+m) - f.nth_iterate_map(m) + L = [F[i]*CR.gen(j) - F[j]*CR.gen(i) for i in range(0,N) + for j in range(i+1, N)] + L = [t for t in L if t != 0] + X = PS.subscheme(L + list(dom.defining_polynomials())) + minimal = kwds.pop('minimal',True) + return_scheme = kwds.pop('return_scheme',False) + if return_scheme: # this includes the indeterminacy locus points! + if minimal and n != 1: + raise NotImplementedError("return_subscheme only implemented for minimal=False") + return X + if X.dimension() == 0: + if R in NumberFields() or R is QQbar or R in FiniteFields(): + Z = f.indeterminacy_locus() + points = [dom(Q) for Q in X.rational_points()] + good_points = [] + for Q in points: + try: + Z(list(Q)) + except TypeError: + good_points.append(Q) + points = good_points + + if not minimal: + return points + else: + #we want only the points with minimal period n + #so we go through the list and remove any that + #have smaller period by checking the iterates + minimal_points = [] + for P in points: + orbit = [dom(P)] + Q = f(dom(P)) + n_plus_m = 1 + while not Q in orbit: + Q = f(Q) + n_plus_m += 1 + preperiod = orbit.index(Q) + period = n_plus_m - preperiod + if period == n and preperiod == m: + minimal_points.append(P) + return minimal_points + else: + raise NotImplementedError("ring must a number field or finite field") + else: #a higher dimensional scheme + raise TypeError("use return_scheme=True") + def periodic_points(self, n, minimal=True, R=None, algorithm='variety', return_scheme=False): r""" From 0b6ead011672404f088ab46b04b0b7ea8c270065 Mon Sep 17 00:00:00 2001 From: julia Date: Thu, 25 Jul 2019 09:47:03 -0500 Subject: [PATCH 065/340] Edit 28170 to address doctest failure --- .../dynamics/arithmetic_dynamics/projective_ds.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 0fb7760422b..75c852842a6 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -70,6 +70,7 @@ class initialization directly. from sage.rings.all import Integer, CIF from sage.arith.all import gcd, lcm, next_prime, binomial, primes, moebius from sage.categories.finite_fields import FiniteFields +from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField_generic from sage.rings.complex_field import ComplexField from sage.rings.finite_rings.finite_field_constructor import (is_FiniteField, GF, is_PrimeFiniteField) @@ -83,7 +84,7 @@ class initialization directly. from sage.rings.polynomial.multi_polynomial_ring_base import is_MPolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.polynomial_ring import is_PolynomialRing -from sage.rings.qqbar import QQbar +from sage.rings.qqbar import QQbar, AlgebraicField_common from sage.rings.quotient_ring import QuotientRing_generic from sage.rings.rational_field import QQ from sage.rings.real_double import RDF @@ -3058,9 +3059,12 @@ def is_postcritically_finite(self, err=0.01, embedding=None): if not K in NumberFields() and not K is QQbar: raise NotImplementedError("must be over a number field or a number field order or QQbar") - if embedding is None: - embedding = self.field_of_definition_critical(return_embedding=True)[1] - F = self.change_ring(embedding) + if not isinstance(K,AlgebraicClosureFiniteField_generic) and not isinstance(K,AlgebraicField_common): + if embedding is None: + embedding = self.field_of_definition_critical(return_embedding=True)[1] + F = self.change_ring(embedding) + else: + F = self crit_points = F.critical_points() pcf = True i = 0 From a54b88b74d22b86692d0904dc289a3bc6ee1d05c Mon Sep 17 00:00:00 2001 From: EnderWannabe Date: Thu, 25 Jul 2019 10:47:26 -0400 Subject: [PATCH 066/340] builds, but does not run --- src/sage/dynamics/arithmetic_dynamics/projective_ds.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index afe4ef1c0cb..cbcd2a84253 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -3215,7 +3215,13 @@ def preperiodic_points(self, n, m, **kwds): EXAMPLES:: - + sage: set_verbose(None) + sage: P. = ProjectiveSpace(QQbar,1) + sage: f = DynamicalSystem_projective([x^2-x*y+y^2, x^2-y^2+x*y]) + sage: f.periodic_points(1) + [(-0.500000000000000? - 0.866025403784439?*I : 1), + (-0.500000000000000? + 0.866025403784439?*I : 1), + (1 : 1)] """ if n <= 0: raise ValueError("a positive integer period must be specified") From 2830a1dc1da7747e3ceb5c55a101e2e32a663135 Mon Sep 17 00:00:00 2001 From: EnderWannabe Date: Thu, 25 Jul 2019 11:22:20 -0400 Subject: [PATCH 067/340] working preperiodic_points --- .../arithmetic_dynamics/projective_ds.py | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index cbcd2a84253..28812129272 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -3172,7 +3172,7 @@ def critical_height(self, **kwds): ch += F.canonical_height(P, **kwds) return ch - def preperiodic_points(self, n, m, **kwds): + def preperiodic_points(self, m, n, **kwds): r""" Computes the preperiodic points of period ``m``,``n`` of this dynamical system defined over the ring ``R`` or the base ring of the map. @@ -3215,13 +3215,17 @@ def preperiodic_points(self, n, m, **kwds): EXAMPLES:: - sage: set_verbose(None) sage: P. = ProjectiveSpace(QQbar,1) - sage: f = DynamicalSystem_projective([x^2-x*y+y^2, x^2-y^2+x*y]) - sage: f.periodic_points(1) - [(-0.500000000000000? - 0.866025403784439?*I : 1), - (-0.500000000000000? + 0.866025403784439?*I : 1), - (1 : 1)] + sage: f = DynamicalSystem_projective([x^2-y^2, y^2]) + sage: f.preperiodic_points(1) + [(1 : 1)] + + :: + + sage: P. = ProjectiveSpace(QQ,1) + sage: f = DynamicalSystem_projective([x^2-29/16*y^2, y^2]) + sage: f.preperiodic_points(1,3) + [(-5/4 : 1), (1/4 : 1), (7/4 : 1)] """ if n <= 0: raise ValueError("a positive integer period must be specified") @@ -3238,8 +3242,9 @@ def preperiodic_points(self, n, m, **kwds): dom = f.domain() PS = f.codomain().ambient_space() N = PS.dimension_relative() + 1 - F = f.nth_iterate_map(n+m) - f.nth_iterate_map(m) - L = [F[i]*CR.gen(j) - F[j]*CR.gen(i) for i in range(0,N) + F_1 = f.nth_iterate_map(n+m) + F_2 = f.nth_iterate_map(m) + L = [F_1[i]*F_2[j] - F_1[j]*F_2[i] for i in range(0,N) for j in range(i+1, N)] L = [t for t in L if t != 0] X = PS.subscheme(L + list(dom.defining_polynomials())) @@ -3273,6 +3278,7 @@ def preperiodic_points(self, n, m, **kwds): Q = f(dom(P)) n_plus_m = 1 while not Q in orbit: + orbit.append(Q) Q = f(Q) n_plus_m += 1 preperiod = orbit.index(Q) From 2f569670ad3f818b5e460920be9625783177fcdc Mon Sep 17 00:00:00 2001 From: joey Date: Thu, 25 Jul 2019 15:53:04 -0400 Subject: [PATCH 068/340] 28214: fix display_complex --- .../arithmetic_dynamics/projective_ds.py | 48 ++++++++++++++----- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 605c538b5ef..aa5a927cf6a 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -2233,7 +2233,7 @@ def _multipliermod(self, P, n, p, k): Q = R return(l) - def _nth_preimage_tree_helper(self, fbar, Q, n, m, numerical, display_complex): + def _nth_preimage_tree_helper(self, fbar, Q, n, m, numerical, display_complex, embed, digits): D = {} if numerical: CR = fbar.domain().ambient_space().coordinate_ring() @@ -2244,18 +2244,21 @@ def _nth_preimage_tree_helper(self, fbar, Q, n, m, numerical, display_complex): pre = fbar.rational_preimages(Q,1) for pt in pre: if display_complex: - pt = ProjectiveSpace(CC,1)(pt) - Q = ProjectiveSpace(CC,1)(Q) - key = str(pt) + ", " + str(m) - D[key] = [str(Q)+ ", " + str(m-1)] + pt1 = "(" + str(embed(pt[0]).n(digits=digits)) + ": 1)" + Q1 = "(" + str(embed(Q[0]).n(digits=digits)) + ": 1)" + key = pt1 + ", " + str(m) + D[key] = [Q1 + ", " + str(m-1)] + else: + key = str(pt) + ", " + str(m) + D[key] = [str(Q) + ", " + str(m-1)] if n==1: return D else: for pt in pre: - D.update(self._nth_preimage_tree_helper(fbar, pt, n-1, m+1, numerical, display_complex)) + D.update(self._nth_preimage_tree_helper(fbar, pt, n-1, m+1, numerical, display_complex, embed, digits)) return D - def nth_preimage_tree(self, Q, n, numerical=False, display_labels=True, display_complex=False): + def nth_preimage_tree(self, Q, n, **kwds): r""" Return the ``n``-th pre-image tree rooted at ``Q`` @@ -2264,33 +2267,52 @@ def nth_preimage_tree(self, Q, n, numerical=False, display_labels=True, display_ INPUT: - - ``Q`` -- a point on domain of this map + - ``Q`` -- a point in the domain of this map - ``n`` -- a positive integer, the depth of the pre-image tree + kwds: + - ``numerical`` -- (default: ``False``) boolean; calculate pre-images numerically - ``display_labels`` -- (default: ``True``) boolean; whether to display vertex labels - ``display_complex`` -- (default: ``False``) boolean; display vertex labels as - complex numbers + complex numbers. Note if this option is chosen that we must choose an embedding + from the splitting field ``field_def`` of the nth-preimage equation into C. We make + the choice of the first embedding returned by ``field_def.embeddings(ComplexField())``. + + - ``digits`` -- a positive integer, the number of decimal digits to display for complex + numbers. This only applies if ``display_complex`` is set to ``True`` OUTPUT: A ``GraphPlot`` object representing the ``n``-th pre-image tree """ + numerical = kwds.pop("numerical", False) + display_labels = kwds.pop("display_labels", True) + display_complex = kwds.pop("display_complex", False) + digits = kwds.pop("digits", 5) + if self.domain().dimension_relative() > 1: raise NotImplementedError("only implemented for dimension 1") base_ring = self.base_ring() if not base_ring in NumberFields() or base_ring in FiniteFields(): raise NotImplementedError("Only implemented for number fields and finite fields") - fbar = self.change_ring(self.field_of_definition_preimage(Q,n)) - V = self._nth_preimage_tree_helper(fbar, Q, n, 1, numerical, display_complex) + field_def = self.field_of_definition_preimage(Q,n) + if display_complex: + embed = field_def.embeddings(ComplexField())[0] + else: + embed = None + fbar = self.change_ring(field_def) + V = self._nth_preimage_tree_helper(fbar, Q, n, 1, numerical, display_complex, embed, digits) from sage.graphs.digraph import DiGraph G = DiGraph(V) if display_complex: - Q = ProjectiveSpace(CC,1)(Q) - root = str(Q) + ", " + str(0) + Q = "(" + str(embed(Q[0]).n(digits=digits)) + ": 1)" + root = Q + ", " + str(0) + else: + root = str(Q) + ", " + str(0) options = {'layout':'tree', 'tree_orientation':'up', 'tree_root':root, 'vertex_labels':display_labels} from sage.graphs.graph_plot import GraphPlot return GraphPlot(G, options) From e649e4e2508c6a37cccb871fbd7b3b08cc41aa02 Mon Sep 17 00:00:00 2001 From: annanc2 Date: Fri, 26 Jul 2019 13:38:02 -0400 Subject: [PATCH 069/340] 28263 : Added a degree function for dynamical systems and affine morphisms. --- .../dynamics/arithmetic_dynamics/affine_ds.py | 27 +++++++++++++++++++ src/sage/schemes/affine/affine_morphism.py | 27 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/src/sage/dynamics/arithmetic_dynamics/affine_ds.py b/src/sage/dynamics/arithmetic_dynamics/affine_ds.py index 174a7c9a1ea..6836de30b69 100644 --- a/src/sage/dynamics/arithmetic_dynamics/affine_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/affine_ds.py @@ -794,6 +794,33 @@ def multiplier(self, P, n, check=True): Q = R return l + def degree(self): + r""" + Returns the degree of the affine dynamical system. + + EXAMPLES:: + + sage: R.=QuadraticField(7) + sage: A.=AffineSpace(R,3) + sage: f = DynamicalSystem_affine([x^2+y^5+c,x^11,z^19]) + sage: f.degree() + 19 + + :: + + sage: R.=QQ[] + sage: A.=AffineSpace(R,1) + sage: f = DynamicalSystem_affine([x^4]) + sage: f.degree() + 4 + """ + polys = self._polys + max_degree = 0 + for poly in polys: + if poly.degree() > max_degree: + max_degree = poly.degree() + return max_degree + class DynamicalSystem_affine_field(DynamicalSystem_affine, SchemeMorphism_polynomial_affine_space_field): @cached_method diff --git a/src/sage/schemes/affine/affine_morphism.py b/src/sage/schemes/affine/affine_morphism.py index 2a4b241c061..99db283b0af 100644 --- a/src/sage/schemes/affine/affine_morphism.py +++ b/src/sage/schemes/affine/affine_morphism.py @@ -807,6 +807,33 @@ def multiplier(self, P, n, check=True): deprecation(23479, "use sage.dynamics.arithmetic_dynamics.affine_ds.multiplier instead") return self.as_dynamical_system().multiplier(P, n, check) + def degree(self): + r""" + Returns the degree of the affine morphism. + + EXAMPLES:: + + sage: R. = AffineSpace(QQ, 1) + sage: H = Hom(R, R) + sage: f = H([x^7]) + sage: f.degree() + 7 + + :: + + sage: R. = AffineSpace(QQ, 3) + sage: H = Hom(R, R) + sage: f = H([x^3,y^2+5,z^4+y]) + sage: f.degree() + 4 + """ + polys = self._polys + max_degree = 0 + for poly in polys: + if poly.degree() > max_degree: + max_degree = poly.degree() + return max_degree + class SchemeMorphism_polynomial_affine_space_field(SchemeMorphism_polynomial_affine_space): @cached_method From c5d7ae04827b267085174946893a9bf4d121223a Mon Sep 17 00:00:00 2001 From: joey Date: Tue, 30 Jul 2019 00:28:41 -0400 Subject: [PATCH 070/340] 28214: fix over GF and QQbar --- .../arithmetic_dynamics/projective_ds.py | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index aa5a927cf6a..cdfd81580d8 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -2263,7 +2263,7 @@ def nth_preimage_tree(self, Q, n, **kwds): Return the ``n``-th pre-image tree rooted at ``Q`` This map must be an endomorphism of the projective line defined - over a number field or finite field. + over a number field, algebraic field, or finite field. INPUT: @@ -2293,19 +2293,27 @@ def nth_preimage_tree(self, Q, n, **kwds): display_labels = kwds.pop("display_labels", True) display_complex = kwds.pop("display_complex", False) digits = kwds.pop("digits", 5) - if self.domain().dimension_relative() > 1: raise NotImplementedError("only implemented for dimension 1") - base_ring = self.base_ring() - if not base_ring in NumberFields() or base_ring in FiniteFields(): - raise NotImplementedError("Only implemented for number fields and finite fields") - field_def = self.field_of_definition_preimage(Q,n) + if self.base_ring() is QQbar: + f = self._number_field_from_algebraics().as_dynamical_system() + else: + f = self + base_ring = f.base_ring() + if base_ring in NumberFields() or base_ring in FiniteFields(): + field_def = f.field_of_definition_preimage(Q,n) + else: + raise NotImplementedError("Only implemented for number fields, algebraic fields, and finite fields") + fbar = f.change_ring(field_def) + Q = f.codomain()(Q) + # No embedding from finite field into C + if base_ring in FiniteFields(): + display_complex = False if display_complex: embed = field_def.embeddings(ComplexField())[0] else: embed = None - fbar = self.change_ring(field_def) - V = self._nth_preimage_tree_helper(fbar, Q, n, 1, numerical, display_complex, embed, digits) + V = f._nth_preimage_tree_helper(fbar, Q, n, 1, numerical, display_complex, embed, digits) from sage.graphs.digraph import DiGraph G = DiGraph(V) if display_complex: From d451af42d93d612fc72d8b6d1653de7860ee9b41 Mon Sep 17 00:00:00 2001 From: EnderWannabe Date: Tue, 30 Jul 2019 09:43:58 -0400 Subject: [PATCH 071/340] added tests and fixed documentation --- .../arithmetic_dynamics/projective_ds.py | 89 ++++++++++++++----- 1 file changed, 66 insertions(+), 23 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 28812129272..610746397ad 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -3174,19 +3174,13 @@ def critical_height(self, **kwds): def preperiodic_points(self, m, n, **kwds): r""" - Computes the preperiodic points of period ``m``,``n`` of this dynamical system + Computes the preperiodic points of period ``m, n`` of this dynamical system defined over the ring ``R`` or the base ring of the map. - This can be done either by finding the rational points on the variety - defining the points of period ``m``,``n``, or, for finite fields, - finding the cycle of appropriate length in the cyclegraph. For small - cardinality fields, the cyclegraph algorithm is effective for any - map and length cycle, but is slow when the cyclegraph is large. - The variety algorithm is good for small period, degree, and dimension, - but is slow as the defining equations of the variety get more - complicated. + This is done by finding the rational points on the variety + defining the points of period ``m, n``. - For rational map, where there are potentially infinitely many periodic + For rational maps, where there are potentially infinitely many periodic points of a given period, you must use the ``return_scheme`` option. Note that this scheme will include the indeterminacy locus. @@ -3199,14 +3193,16 @@ def preperiodic_points(self, m, n, **kwds): kwds: - ``minimal`` -- (default: ``True``) boolean; ``True`` specifies to - find only the periodic points of minimal period ``n`` and ``False`` - specifies to find all periodic points of period ``n`` + find only the preperiodic points of minimal period ``m``,``n`` and + ``False`` specifies to find all preperiodic points of period + ``m``, ``n`` - ``R`` -- (default: the base ring of the dynamical system) a commutative ring over which to find the preperiodic points - ``return_scheme`` -- (default: ``False``) boolean; return a - subscheme of the ambient space that defines the ``n`` th periodic points + subscheme of the ambient space that defines the ``m``,``n`` th + preperiodic points OUTPUT: @@ -3217,8 +3213,8 @@ def preperiodic_points(self, m, n, **kwds): sage: P. = ProjectiveSpace(QQbar,1) sage: f = DynamicalSystem_projective([x^2-y^2, y^2]) - sage: f.preperiodic_points(1) - [(1 : 1)] + sage: f.preperiodic_points(0,1) + [(-0.618033988749895? : 1), (1 : 0), (1.618033988749895? : 1)] :: @@ -3226,6 +3222,55 @@ def preperiodic_points(self, m, n, **kwds): sage: f = DynamicalSystem_projective([x^2-29/16*y^2, y^2]) sage: f.preperiodic_points(1,3) [(-5/4 : 1), (1/4 : 1), (7/4 : 1)] + + :: + + sage: P. = ProjectiveSpace(QQbar,1) + sage: f = DynamicalSystem_projective([x^2-x*y+2*y^2, x^2-y^2]) + sage: f.preperiodic_points(1,2,minimal=False) + [(-3.133185666641252? : 1), + (-1 : 1), + (-0.3478103847799310? - 1.028852254136693?*I : 1), + (-0.3478103847799310? + 1.028852254136693?*I : 1), + (0.8165928333206258? - 0.6710067557437100?*I : 1), + (0.8165928333206258? + 0.6710067557437100?*I : 1), + (1 : 0), + (1 : 1), + (1.695620769559862? : 1), + (3 : 1)] + + :: + + sage: w = QQ['w'].0 + sage: K = NumberField(w^6 - 3*w^5 + 5*w^4 - 5*w^3 + 5*w^2 - 3*w + 1,'s') + sage: P. = ProjectiveSpace(K,2) + sage: f = DynamicalSystem_projective([x^2+z^2, y^2+x^2, z^2+y^2]) + sage: f.preperiodic_points(0,1) + [(-s^5 + 3*s^4 - 5*s^3 + 4*s^2 - 3*s + 1 : s^5 - 2*s^4 + 3*s^3 - 3*s^2 + 4*s - 1 : 1), + (-2*s^5 + 4*s^4 - 5*s^3 + 3*s^2 - 4*s : -2*s^5 + 5*s^4 - 7*s^3 + 6*s^2 - 7*s + 3 : 1), + (-s^5 + 3*s^4 - 4*s^3 + 4*s^2 - 4*s + 2 : -s^5 + 2*s^4 - 2*s^3 + s^2 - s : 1), + (s^5 - 2*s^4 + 3*s^3 - 3*s^2 + 3*s - 1 : -s^5 + 3*s^4 - 5*s^3 + 4*s^2 - 4*s + 2 : 1), + (2*s^5 - 6*s^4 + 9*s^3 - 8*s^2 + 7*s - 4 : 2*s^5 - 5*s^4 + 7*s^3 - 5*s^2 + 6*s - 2 : 1), + (1 : 1 : 1), + (s^5 - 2*s^4 + 2*s^3 + s : s^5 - 3*s^4 + 4*s^3 - 3*s^2 + 2*s - 1 : 1)] + + :: + + sage: P. = ProjectiveSpace(QQ, 2) + sage: f = DynamicalSystem_projective([x^2, x*y, z^2]) + sage: f.preperiodic_points(2,1) + Traceback (most recent call last): + ... + TypeError: use return_scheme=True + + :: + + sage: P. = ProjectiveSpace(QQ,1) + sage: K. = QuadraticField(5) + sage: phi = QQ.embeddings(K)[0] + sage: f = DynamicalSystem_projective([x^2-y^2,y^2]) + sage: f.preperiodic_points(1,1,R=phi) + [(-1/2*v - 1/2 : 1), (1/2*v - 1/2 : 1)] """ if n <= 0: raise ValueError("a positive integer period must be specified") @@ -3237,12 +3282,11 @@ def preperiodic_points(self, m, n, **kwds): R = self.base_ring() else: f = self.change_ring(R) - R = f.base_ring() - CR = f.coordinate_ring() + R = f.base_ring() #in the case when R is an embedding dom = f.domain() PS = f.codomain().ambient_space() N = PS.dimension_relative() + 1 - F_1 = f.nth_iterate_map(n+m) + F_1 = f.nth_iterate_map(n+m) F_2 = f.nth_iterate_map(m) L = [F_1[i]*F_2[j] - F_1[j]*F_2[i] for i in range(0,N) for j in range(i+1, N)] @@ -3265,13 +3309,12 @@ def preperiodic_points(self, m, n, **kwds): except TypeError: good_points.append(Q) points = good_points - if not minimal: return points else: - #we want only the points with minimal period n - #so we go through the list and remove any that - #have smaller period by checking the iterates + #we want only the points with minimal period m,n + #so we go through the list and create a new list + #that only includes the points with minimal period minimal_points = [] for P in points: orbit = [dom(P)] @@ -3306,7 +3349,7 @@ def periodic_points(self, n, minimal=True, R=None, algorithm='variety', but is slow as the defining equations of the variety get more complicated. - For rational map, where there are potentially infinitely many periodic + For rational maps, where there are potentially infinitely many periodic points of a given period, you must use the ``return_scheme`` option. Note that this scheme will include the indeterminacy locus. From 6490e4fcf3268c91d6ab112051e6ab95b8c12887 Mon Sep 17 00:00:00 2001 From: joey Date: Tue, 30 Jul 2019 11:17:17 -0400 Subject: [PATCH 072/340] 28214: rework QQbar, add return_points --- .../arithmetic_dynamics/projective_ds.py | 104 +++++++++++++----- 1 file changed, 74 insertions(+), 30 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index cdfd81580d8..89b090d1326 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -2233,15 +2233,21 @@ def _multipliermod(self, P, n, p, k): Q = R return(l) - def _nth_preimage_tree_helper(self, fbar, Q, n, m, numerical, display_complex, embed, digits): + def _nth_preimage_tree_helper(self, Q, n, m, **kwds): + return_points = kwds.get("return_points", False) + numerical = kwds.get("numerical", False) + display_labels = kwds.get("display_labels", True) + display_complex = kwds.get("display_complex", False) + digits = kwds.get("digits", 5) + embed = kwds.get("embed", None) D = {} if numerical: - CR = fbar.domain().ambient_space().coordinate_ring() - fn = fbar.dehomogenize(1) + CR = self.domain().ambient_space().coordinate_ring() + fn = self.dehomogenize(1) poly = (fn[0].numerator()*CR(Q[1]) - fn[0].denominator()*CR(Q[0])).univariate_polynomial() pre = [ProjectiveSpace(QQbar,1)(r) for r in poly.roots(ring=QQbar)] else: - pre = fbar.rational_preimages(Q,1) + pre = self.rational_preimages(Q,1) for pt in pre: if display_complex: pt1 = "(" + str(embed(pt[0]).n(digits=digits)) + ": 1)" @@ -2251,12 +2257,26 @@ def _nth_preimage_tree_helper(self, fbar, Q, n, m, numerical, display_complex, e else: key = str(pt) + ", " + str(m) D[key] = [str(Q) + ", " + str(m-1)] - if n==1: - return D + if return_points: + kwds["points"][m].append(pt) + + if return_points: + points = kwds["points"] + if n==1: + # base case of recursion + return D, points + else: + for pt in pre: + D.update(self._nth_preimage_tree_helper(pt, n-1, m+1, **kwds)[0]) + return D, points else: - for pt in pre: - D.update(self._nth_preimage_tree_helper(fbar, pt, n-1, m+1, numerical, display_complex, embed, digits)) - return D + if n==1: + # base case of recursion + return D + else: + for pt in pre: + D.update(self._nth_preimage_tree_helper(pt, n-1, m+1, **kwds)) + return D def nth_preimage_tree(self, Q, n, **kwds): r""" @@ -2273,6 +2293,11 @@ def nth_preimage_tree(self, Q, n, **kwds): kwds: + - ``return_points`` -- (default: ``False``) boolean; if ``True``, return a list of lists + where the index ``i`` is the level of the tree and the elements of the list at that + index are the ``i``-th preimage points. These points will be algebraic unless `numerical`` + is set to ``True`` + - ``numerical`` -- (default: ``False``) boolean; calculate pre-images numerically - ``display_labels`` -- (default: ``True``) boolean; whether to display vertex labels @@ -2287,34 +2312,50 @@ def nth_preimage_tree(self, Q, n, **kwds): OUTPUT: - A ``GraphPlot`` object representing the ``n``-th pre-image tree + If ``return_points`` is ``False``, a ``GraphPlot`` object representing the ``n``-th pre-image tree. + If ``return_points`` is ``True``, a tuple ``(GP, points)``, where ``GP`` is a ``GraphPlot`` object, + and ``points`` is a list of lists as described above under ``return_points`` """ - numerical = kwds.pop("numerical", False) - display_labels = kwds.pop("display_labels", True) - display_complex = kwds.pop("display_complex", False) - digits = kwds.pop("digits", 5) + return_points = kwds.get("return_points", False) + numerical = kwds.get("numerical", False) + display_labels = kwds.get("display_labels", True) + digits = kwds.get("digits", 5) + if self.domain().dimension_relative() > 1: raise NotImplementedError("only implemented for dimension 1") - if self.base_ring() is QQbar: - f = self._number_field_from_algebraics().as_dynamical_system() + base_ring = self.base_ring() + if base_ring is QQbar: + fbar = self + # No embedding from QQbar into C + kwds["display_complex"] = False + elif base_ring in NumberFields(): + field_def = self.field_of_definition_preimage(Q,n) + fbar = self.change_ring(field_def) + elif base_ring in FiniteFields(): + field_def = self.field_of_definition_preimage(Q,n) + fbar = self.change_ring(field_def) + # No embedding from finite field into C + kwds["display_complex"] = False else: - f = self - base_ring = f.base_ring() - if base_ring in NumberFields() or base_ring in FiniteFields(): - field_def = f.field_of_definition_preimage(Q,n) - else: - raise NotImplementedError("Only implemented for number fields, algebraic fields, and finite fields") - fbar = f.change_ring(field_def) - Q = f.codomain()(Q) - # No embedding from finite field into C - if base_ring in FiniteFields(): - display_complex = False + raise NotImplementedError("Only implemented for number fields, algebraic fields, and finite fields") + Q = fbar.codomain()(Q) + + display_complex = kwds.get("display_complex", False) if display_complex: embed = field_def.embeddings(ComplexField())[0] else: embed = None - V = f._nth_preimage_tree_helper(fbar, Q, n, 1, numerical, display_complex, embed, digits) + kwds["embed"] = embed + if return_points: + # n+1 since we have n levels with root as 0th level + points = [[] for i in range(n+1)] + points[0].append(Q) + kwds["points"] = points + V, points = fbar._nth_preimage_tree_helper(Q, n, 1, **kwds) + else: + V = fbar._nth_preimage_tree_helper(Q, n, 1, **kwds) from sage.graphs.digraph import DiGraph + from sage.graphs.graph_plot import GraphPlot G = DiGraph(V) if display_complex: Q = "(" + str(embed(Q[0]).n(digits=digits)) + ": 1)" @@ -2322,8 +2363,11 @@ def nth_preimage_tree(self, Q, n, **kwds): else: root = str(Q) + ", " + str(0) options = {'layout':'tree', 'tree_orientation':'up', 'tree_root':root, 'vertex_labels':display_labels} - from sage.graphs.graph_plot import GraphPlot - return GraphPlot(G, options) + + if return_points: + return GraphPlot(G, options), points + else: + return GraphPlot(G, options) def possible_periods(self, **kwds): r""" From 5c8e1f044be74a0b3d4f27c18421cfd81cd4d00e Mon Sep 17 00:00:00 2001 From: julia Date: Tue, 30 Jul 2019 10:47:09 -0500 Subject: [PATCH 073/340] 28170 - added embedding parameter to is_pcf over finite fields so that critical_point_portrait works over finite fields --- src/sage/dynamics/arithmetic_dynamics/projective_ds.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 952beaa44fd..024ed183685 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -5743,7 +5743,7 @@ def normal_form(self, return_conjugation=False): class DynamicalSystem_projective_finite_field(DynamicalSystem_projective_field, SchemeMorphism_polynomial_projective_space_finite_field): - def is_postcritically_finite(self): + def is_postcritically_finite(self, embedding=None): r""" Every point is postcritically finite in a finite field. From 35f829c92937d4c914ed0c756a8cd63f3d6389e4 Mon Sep 17 00:00:00 2001 From: joey Date: Tue, 30 Jul 2019 11:50:44 -0400 Subject: [PATCH 074/340] 28214: update docs --- .../arithmetic_dynamics/projective_ds.py | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 89b090d1326..486a7b3d306 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -2266,6 +2266,7 @@ def _nth_preimage_tree_helper(self, Q, n, m, **kwds): # base case of recursion return D, points else: + # recurse for each point in the tree for pt in pre: D.update(self._nth_preimage_tree_helper(pt, n-1, m+1, **kwds)[0]) return D, points @@ -2274,6 +2275,7 @@ def _nth_preimage_tree_helper(self, Q, n, m, **kwds): # base case of recursion return D else: + # recurse for each point in the tree for pt in pre: D.update(self._nth_preimage_tree_helper(pt, n-1, m+1, **kwds)) return D @@ -2295,8 +2297,8 @@ def nth_preimage_tree(self, Q, n, **kwds): - ``return_points`` -- (default: ``False``) boolean; if ``True``, return a list of lists where the index ``i`` is the level of the tree and the elements of the list at that - index are the ``i``-th preimage points. These points will be algebraic unless `numerical`` - is set to ``True`` + index are the ``i``-th preimage points as an algebraic element of the splitting field + of the polynomial ``f^n - Q = 0``. - ``numerical`` -- (default: ``False``) boolean; calculate pre-images numerically @@ -2315,6 +2317,23 @@ def nth_preimage_tree(self, Q, n, **kwds): If ``return_points`` is ``False``, a ``GraphPlot`` object representing the ``n``-th pre-image tree. If ``return_points`` is ``True``, a tuple ``(GP, points)``, where ``GP`` is a ``GraphPlot`` object, and ``points`` is a list of lists as described above under ``return_points`` + + EXAMPLES:: + + sage: P. = ProjectiveSpace(QQ,1) + sage: f = DynamicalSystem_projective([x^2 + y^2, y^2]) + sage: Q = P(0,1) + sage: f.nth_preimage_tree(Q, 2) + GraphPlot object for Digraph on 7 vertices + + :: + + sage: P. = ProjectiveSpace(GF(3),1) + sage: f = DynamicalSystem_projective([x^2 + x*y + y^2, y^2]) + sage: Q = P(0,1) + sage: f.nth_preimage_tree(Q, 2, return_points=True) + (GraphPlot object for Digraph on 4 vertices, + [[(0 : 1)], [(1 : 1)], [(0 : 1), (2 : 1)]]) """ return_points = kwds.get("return_points", False) numerical = kwds.get("numerical", False) @@ -2338,8 +2357,8 @@ def nth_preimage_tree(self, Q, n, **kwds): kwds["display_complex"] = False else: raise NotImplementedError("Only implemented for number fields, algebraic fields, and finite fields") - Q = fbar.codomain()(Q) + Q = fbar.codomain()(Q) display_complex = kwds.get("display_complex", False) if display_complex: embed = field_def.embeddings(ComplexField())[0] From 0d06e772a5fa4f30290bb7468bed0dc9ba5b46b8 Mon Sep 17 00:00:00 2001 From: EnderWannabe Date: Tue, 30 Jul 2019 14:08:18 -0400 Subject: [PATCH 075/340] added another example and cleaned up documentation --- .../dynamics/arithmetic_dynamics/projective_ds.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 610746397ad..ca35322970f 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -3186,9 +3186,9 @@ def preperiodic_points(self, m, n, **kwds): INPUT: - - ``n`` - a positive integer + - ``n`` - a positive integer, the period - - ``m`` - a non negative integer + - ``m`` - a non negative integer, the preperiod kwds: @@ -3271,6 +3271,14 @@ def preperiodic_points(self, m, n, **kwds): sage: f = DynamicalSystem_projective([x^2-y^2,y^2]) sage: f.preperiodic_points(1,1,R=phi) [(-1/2*v - 1/2 : 1), (1/2*v - 1/2 : 1)] + + :: + + sage: P. = ProjectiveSpace(QQ,2) + sage: X = P.subscheme(2*x-y) + sage: f = DynamicalSystem_projective([x^2-y^2, 2*(x^2-y^2), y^2-z^2], domain=X) + sage: f.preperiodic_points(1,1) + [(-1/4 : -1/2 : 1), (1 : 2 : 1)] """ if n <= 0: raise ValueError("a positive integer period must be specified") @@ -3290,7 +3298,6 @@ def preperiodic_points(self, m, n, **kwds): F_2 = f.nth_iterate_map(m) L = [F_1[i]*F_2[j] - F_1[j]*F_2[i] for i in range(0,N) for j in range(i+1, N)] - L = [t for t in L if t != 0] X = PS.subscheme(L + list(dom.defining_polynomials())) minimal = kwds.pop('minimal',True) return_scheme = kwds.pop('return_scheme',False) From 9dd414f3da14aa191054b4e20a8dc8350c7e3d8d Mon Sep 17 00:00:00 2001 From: joey Date: Tue, 30 Jul 2019 16:25:05 -0400 Subject: [PATCH 076/340] 28214: rework solving numerical --- .../arithmetic_dynamics/projective_ds.py | 46 ++++++++++++++----- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 486a7b3d306..becc74e862c 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -2236,6 +2236,7 @@ def _multipliermod(self, P, n, p, k): def _nth_preimage_tree_helper(self, Q, n, m, **kwds): return_points = kwds.get("return_points", False) numerical = kwds.get("numerical", False) + prec = kwds.get("prec", 100) display_labels = kwds.get("display_labels", True) display_complex = kwds.get("display_complex", False) digits = kwds.get("digits", 5) @@ -2245,7 +2246,8 @@ def _nth_preimage_tree_helper(self, Q, n, m, **kwds): CR = self.domain().ambient_space().coordinate_ring() fn = self.dehomogenize(1) poly = (fn[0].numerator()*CR(Q[1]) - fn[0].denominator()*CR(Q[0])).univariate_polynomial() - pre = [ProjectiveSpace(QQbar,1)(r) for r in poly.roots(ring=QQbar)] + K = ComplexField(prec=prec) + pre = [ProjectiveSpace(K,1)(r) for r in poly.roots(ring=K)] else: pre = self.rational_preimages(Q,1) for pt in pre: @@ -2300,9 +2302,15 @@ def nth_preimage_tree(self, Q, n, **kwds): index are the ``i``-th preimage points as an algebraic element of the splitting field of the polynomial ``f^n - Q = 0``. - - ``numerical`` -- (default: ``False``) boolean; calculate pre-images numerically + - ``numerical`` -- (default: ``False``) boolean; calculate pre-images numerically. Note if this + is set to ``True``, preimage points are displayed as complex numbers. + + - ``prec`` -- (default: 100) postive integer; the precision of the ``ComplexField`` if + we compute the preimage points numerically - - ``display_labels`` -- (default: ``True``) boolean; whether to display vertex labels + - ``display_labels`` -- (default: ``True``) boolean; whether to display vertex labels. Since labels + can be very cluttered, can set ``display_labels`` to ``False`` and use ``return_points`` to get a + hold of the points themselves, either as algebraic or complex numbers - ``display_complex`` -- (default: ``False``) boolean; display vertex labels as complex numbers. Note if this option is chosen that we must choose an embedding @@ -2337,34 +2345,48 @@ def nth_preimage_tree(self, Q, n, **kwds): """ return_points = kwds.get("return_points", False) numerical = kwds.get("numerical", False) + prec = kwds.get("prec", 100) display_labels = kwds.get("display_labels", True) + display_complex = kwds.get("display_complex", False) digits = kwds.get("digits", 5) if self.domain().dimension_relative() > 1: raise NotImplementedError("only implemented for dimension 1") base_ring = self.base_ring() if base_ring is QQbar: + if numerical: + raise ValueError("can't solve numerically over QQbar, no embedding into CC") fbar = self # No embedding from QQbar into C kwds["display_complex"] = False + display_complex = False elif base_ring in NumberFields(): - field_def = self.field_of_definition_preimage(Q,n) - fbar = self.change_ring(field_def) + if numerical: + field_def = ComplexField(prec=prec) + embed = base_ring.embeddings(field_def)[0] + fbar = self.change_ring(embed) + embed = End(field_def).identity() + kwds["display_complex"] = True + display_complex = True + kwds["embed"] = embed + else: + field_def = self.field_of_definition_preimage(Q,n) + fbar = self.change_ring(field_def) + if display_complex: + embed = field_def.embeddings(ComplexField())[0] + kwds["embed"] = embed elif base_ring in FiniteFields(): + if numerical: + raise ValueError("can't solve numerically over a finite field, no embedding into CC") field_def = self.field_of_definition_preimage(Q,n) fbar = self.change_ring(field_def) # No embedding from finite field into C kwds["display_complex"] = False + display_complex = False else: - raise NotImplementedError("Only implemented for number fields, algebraic fields, and finite fields") + raise NotImplementedError("only implemented for number fields, algebraic fields, and finite fields") Q = fbar.codomain()(Q) - display_complex = kwds.get("display_complex", False) - if display_complex: - embed = field_def.embeddings(ComplexField())[0] - else: - embed = None - kwds["embed"] = embed if return_points: # n+1 since we have n levels with root as 0th level points = [[] for i in range(n+1)] From 296b749a019a0365169fe82b5e0859502af909b3 Mon Sep 17 00:00:00 2001 From: joey Date: Tue, 30 Jul 2019 16:55:02 -0400 Subject: [PATCH 077/340] 28214: doc additions --- .../arithmetic_dynamics/projective_ds.py | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index becc74e862c..61c80766180 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -2234,6 +2234,15 @@ def _multipliermod(self, P, n, p, k): return(l) def _nth_preimage_tree_helper(self, Q, n, m, **kwds): + r""" + A recusive method to fill in ``n``-th preimage tree. + + This helper function is used by ``nth_preimage_tree`` below to actually compute the + points of the tree and populate the dictionary used to create a ``DiGraph`` + object. Note the addition of an ``m`` parameter, which counts upwards as n counts + downwards to keep track of what level we are at in the tree for the purposes of + returning points and displaying the point's level in the tree. + """ return_points = kwds.get("return_points", False) numerical = kwds.get("numerical", False) prec = kwds.get("prec", 100) @@ -2243,14 +2252,17 @@ def _nth_preimage_tree_helper(self, Q, n, m, **kwds): embed = kwds.get("embed", None) D = {} if numerical: + # Solve for preimages numerically CR = self.domain().ambient_space().coordinate_ring() fn = self.dehomogenize(1) poly = (fn[0].numerator()*CR(Q[1]) - fn[0].denominator()*CR(Q[0])).univariate_polynomial() K = ComplexField(prec=prec) pre = [ProjectiveSpace(K,1)(r) for r in poly.roots(ring=K)] else: + # Solve for preimages algebraically pre = self.rational_preimages(Q,1) for pt in pre: + # Fill in dictionary entries of preimage points to Q if display_complex: pt1 = "(" + str(embed(pt[0]).n(digits=digits)) + ": 1)" Q1 = "(" + str(embed(Q[0]).n(digits=digits)) + ": 1)" @@ -2260,31 +2272,34 @@ def _nth_preimage_tree_helper(self, Q, n, m, **kwds): key = str(pt) + ", " + str(m) D[key] = [str(Q) + ", " + str(m-1)] if return_points: + # Fill in m-th level preimage points in points list kwds["points"][m].append(pt) if return_points: points = kwds["points"] if n==1: - # base case of recursion + # Base case of recursion return D, points else: - # recurse for each point in the tree + # For each preimage point of Q, use recursion to find that point's preimages + # and update the dictionary for pt in pre: D.update(self._nth_preimage_tree_helper(pt, n-1, m+1, **kwds)[0]) return D, points else: if n==1: - # base case of recursion + # Base case of recursion return D else: - # recurse for each point in the tree + # For each preimage point of Q, use recursion to find that point's preimages + # and update the dictionary for pt in pre: D.update(self._nth_preimage_tree_helper(pt, n-1, m+1, **kwds)) return D def nth_preimage_tree(self, Q, n, **kwds): r""" - Return the ``n``-th pre-image tree rooted at ``Q`` + Return the ``n``-th pre-image tree rooted at ``Q``. This map must be an endomorphism of the projective line defined over a number field, algebraic field, or finite field. @@ -2300,10 +2315,10 @@ def nth_preimage_tree(self, Q, n, **kwds): - ``return_points`` -- (default: ``False``) boolean; if ``True``, return a list of lists where the index ``i`` is the level of the tree and the elements of the list at that index are the ``i``-th preimage points as an algebraic element of the splitting field - of the polynomial ``f^n - Q = 0``. + of the polynomial ``f^n - Q = 0`` - ``numerical`` -- (default: ``False``) boolean; calculate pre-images numerically. Note if this - is set to ``True``, preimage points are displayed as complex numbers. + is set to ``True``, preimage points are displayed as complex numbers - ``prec`` -- (default: 100) postive integer; the precision of the ``ComplexField`` if we compute the preimage points numerically @@ -2315,7 +2330,7 @@ def nth_preimage_tree(self, Q, n, **kwds): - ``display_complex`` -- (default: ``False``) boolean; display vertex labels as complex numbers. Note if this option is chosen that we must choose an embedding from the splitting field ``field_def`` of the nth-preimage equation into C. We make - the choice of the first embedding returned by ``field_def.embeddings(ComplexField())``. + the choice of the first embedding returned by ``field_def.embeddings(ComplexField())`` - ``digits`` -- a positive integer, the number of decimal digits to display for complex numbers. This only applies if ``display_complex`` is set to ``True`` @@ -2324,7 +2339,7 @@ def nth_preimage_tree(self, Q, n, **kwds): If ``return_points`` is ``False``, a ``GraphPlot`` object representing the ``n``-th pre-image tree. If ``return_points`` is ``True``, a tuple ``(GP, points)``, where ``GP`` is a ``GraphPlot`` object, - and ``points`` is a list of lists as described above under ``return_points`` + and ``points`` is a list of lists as described above under ``return_points``. EXAMPLES:: From 6878a904005c7969641fe2d7acd773b843d048a1 Mon Sep 17 00:00:00 2001 From: julia Date: Wed, 31 Jul 2019 10:06:51 -0500 Subject: [PATCH 078/340] 28170 - remove affine degree function from code for ticket --- src/sage/dynamics/arithmetic_dynamics/projective_ds.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 75c852842a6..2400ec99ce5 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -5700,7 +5700,7 @@ def normal_form(self, return_conjugation=False): class DynamicalSystem_projective_finite_field(DynamicalSystem_projective_field, SchemeMorphism_polynomial_projective_space_finite_field): - def is_postcritically_finite(self): + def is_postcritically_finite(self, embedding=None): r""" Every point is postcritically finite in a finite field. From b684a71832a24f5c34a06cd7b2e4781d35aa4db0 Mon Sep 17 00:00:00 2001 From: julia Date: Wed, 31 Jul 2019 10:19:33 -0500 Subject: [PATCH 079/340] 28170: removed affine degree function code --- .../dynamics/arithmetic_dynamics/affine_ds.py | 27 ------------------- src/sage/schemes/affine/affine_morphism.py | 27 ------------------- 2 files changed, 54 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/affine_ds.py b/src/sage/dynamics/arithmetic_dynamics/affine_ds.py index ac65ba69d6d..6c5b18702b5 100644 --- a/src/sage/dynamics/arithmetic_dynamics/affine_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/affine_ds.py @@ -803,33 +803,6 @@ def multiplier(self, P, n, check=True): Q = R return l - def degree(self): - r""" - Returns the degree of the affine dynamical system. - - EXAMPLES:: - - sage: R.=QuadraticField(7) - sage: A.=AffineSpace(R,3) - sage: f = DynamicalSystem_affine([x^2+y^5+c,x^11,z^19]) - sage: f.degree() - 19 - - :: - - sage: R.=QQ[] - sage: A.=AffineSpace(R,1) - sage: f = DynamicalSystem_affine([x^4]) - sage: f.degree() - 4 - """ - polys = self._polys - max_degree = 0 - for poly in polys: - if poly.degree() > max_degree: - max_degree = poly.degree() - return max_degree - class DynamicalSystem_affine_field(DynamicalSystem_affine, SchemeMorphism_polynomial_affine_space_field): @cached_method diff --git a/src/sage/schemes/affine/affine_morphism.py b/src/sage/schemes/affine/affine_morphism.py index 8fa4fdd9170..5090801fe0c 100644 --- a/src/sage/schemes/affine/affine_morphism.py +++ b/src/sage/schemes/affine/affine_morphism.py @@ -713,33 +713,6 @@ def jacobian(self): self.__jacobian = jacobian(list(self),self.domain().ambient_space().gens()) return self.__jacobian - def degree(self): - r""" - Returns the degree of the affine morphism. - - EXAMPLES:: - - sage: R. = AffineSpace(QQ, 1) - sage: H = Hom(R, R) - sage: f = H([x^7]) - sage: f.degree() - 7 - - :: - - sage: R. = AffineSpace(QQ, 3) - sage: H = Hom(R, R) - sage: f = H([x^3,y^2+5,z^4+y]) - sage: f.degree() - 4 - """ - polys = self._polys - max_degree = 0 - for poly in polys: - if poly.degree() > max_degree: - max_degree = poly.degree() - return max_degree - class SchemeMorphism_polynomial_affine_space_field(SchemeMorphism_polynomial_affine_space): @cached_method From 67ae944e6206cd766b1e565ebf5fb95126393725 Mon Sep 17 00:00:00 2001 From: EnderWannabe Date: Wed, 31 Jul 2019 11:29:27 -0400 Subject: [PATCH 080/340] fixed keyword mismatch --- src/sage/dynamics/arithmetic_dynamics/projective_ds.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index ca35322970f..830f5d0d864 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -4968,7 +4968,7 @@ def all_preperiodic_points(self, **kwds): kwds: - - ``ring`` -- (default: domain of dynamical system) the base ring + - ``R`` -- (default: domain of dynamical system) the base ring over which the periodic points of the dynamical system are found - ``prime_bound`` -- (default: ``[1, 20]``) a pair (list or tuple) @@ -5034,7 +5034,7 @@ def all_preperiodic_points(self, **kwds): (1/6*w + 1/4 : 1), (1/12*w + 1 : 1)] """ - ring = kwds.pop("ring",None) + ring = kwds.pop("R",None) if not ring is None: DS = self.change_ring(ring) else: From 0c9ad6c45d5b7d2abca7d19847bea6eda0a49690 Mon Sep 17 00:00:00 2001 From: ckelln Date: Thu, 1 Aug 2019 15:41:46 -0400 Subject: [PATCH 081/340] 23720: Wrote documentation to be more informative. Changed base() to base_ring() --- .../dynamics/complex_dynamics/mandel_julia.py | 69 +++++++++++-------- .../complex_dynamics/mandel_julia_helper.pyx | 68 ++++++++++-------- 2 files changed, 78 insertions(+), 59 deletions(-) diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia.py b/src/sage/dynamics/complex_dynamics/mandel_julia.py index 77f709c522e..c99cba08da3 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia.py +++ b/src/sage/dynamics/complex_dynamics/mandel_julia.py @@ -46,11 +46,13 @@ from sage.plot.colors import Color from sage.repl.image import Image from sage.functions.log import logb -from sage.rings.all import QQ, CC +from sage.rings.all import QQ, CC, CDF from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.schemes.projective.projective_space import ProjectiveSpace from sage.misc.prandom import randint from sage.calculus.var import var +from sage.rings.fraction_field import is_FractionField +from sage.categories.function_fields import FunctionFields EPS = 0.00001 @@ -58,6 +60,9 @@ def mandelbrot_plot(f=None, **kwds): r""" Plot of the Mandelbrot set for a general polynomial map `f_c(z)`. + + If a general polynomial map `f_c(z)` is passed, parent R must be of the + form `R. = CC[]`. REFERENCE: @@ -65,39 +70,38 @@ def mandelbrot_plot(f=None, **kwds): INPUT: - - ``f`` -- map (optional - default: ``z^2 + c``), polynomial map used to - plot the Mandelbrot set. + plot the Mandelbrot set. - ``parameter`` -- variable (optional - default: ``c``), parameter variable - used to plot the Mandelbrot set. + used to plot the Mandelbrot set. - ``x_center`` -- double (optional - default: ``-1.0``), Real part of center - point. + point. - ``y_center`` -- double (optional - default: ``0.0``), Imaginary part of - center point. + center point. - ``image_width`` -- double (optional - default: ``4.0``), width of image - in the complex plane. + in the complex plane. - ``max_iteration`` -- long (optional - default: ``500``), maximum number of - iterations the map ``f_c(z)``. + iterations the map ``f_c(z)``. - ``pixel_count`` -- long (optional - default: ``500``), side length of - image in number of pixels. + image in number of pixels. - ``base_color`` -- Hex color (optional - default: ``tomato``) color - used to determine the coloring of set. + used to determine the coloring of set. - ``level_sep`` -- long (optional - default: 1) number of iterations - between each color level. + between each color level. - ``number_of_colors`` -- long (optional - default: 30) number of colors - used to plot image. + used to plot image. - ``interact`` -- boolean (optional - default: ``False``), controls whether - plot will have interactive functionality. + plot will have interactive functionality. OUTPUT: @@ -143,8 +147,8 @@ def mandelbrot_plot(f=None, **kwds): :: - sage: B. = CC[] - sage: R. = B[] + sage: B. = CC[] + sage: R. = B[] sage: f = z^5 + c sage: mandelbrot_plot(f) # not tested 500x500px 24-bit RGB image @@ -220,16 +224,23 @@ def mandelbrot_plot(f=None, **kwds): P = f.parent() if P.base_ring() is CC or P.base_ring() is CDF: + if is_FractionField(P): + raise NotImplementedError("coefficients must be polynomials in the parameter") gen_list = list(P.gens()) parameter = gen_list.pop(gen_list.index(parameter)) variable = gen_list.pop() elif P.base_ring().base_ring() is CC or P.base_ring().base_ring() is CDF: - parameter = P.gen() - variable = P.base().gen() + if is_FractionField(P.base_ring()): + raise NotImplementedError("coefficients must be polynomials in the parameter") + variable = P.gen() + parameter = P.base_ring().gen() + + elif P.base_ring() in FunctionFields(): + raise NotImplementedError("coefficients must be polynomials in the parameter") else: - raise ValueError("Base ring must be a complex field") + raise ValueError("base ring must be a complex field") if f == variable**2 + parameter: # Quadratic map f = z^2 + c @@ -272,27 +283,27 @@ def external_ray(theta, **kwds): kwds: - ``image`` -- 24-bit RGB image (optional - default: None) user specified - image of Mandelbrot set. + image of Mandelbrot set. - ``D`` -- long (optional - default: ``25``) depth of the approximation. - As ``D`` increases, the external ray gets closer to the boundary of the - Mandelbrot set. If the ray doesn't reach the boundary of the Mandelbrot - set, increase ``D``. + As ``D`` increases, the external ray gets closer to the boundary of the + Mandelbrot set. If the ray doesn't reach the boundary of the Mandelbrot + set, increase ``D``. - ``S`` -- long (optional - default: ``10``) sharpness of the approximation. - Adjusts the number of points used to approximate the external ray (number - of points is equal to ``S*D``). If ray looks jagged, increase ``S``. + Adjusts the number of points used to approximate the external ray (number + of points is equal to ``S*D``). If ray looks jagged, increase ``S``. - ``R`` -- long (optional - default: ``100``) radial parameter. If ``R`` is - large, the external ray reaches sufficiently close to infinity. If ``R`` is - too small, Newton's method may not converge to the correct ray. + large, the external ray reaches sufficiently close to infinity. If ``R`` is + too small, Newton's method may not converge to the correct ray. - ``prec`` -- long (optional - default: ``300``) specifies the bits of - precision used by the Complex Field when using Newton's method to compute - points on the external ray. + precision used by the Complex Field when using Newton's method to compute + points on the external ray. - ``ray_color`` -- RGB color (optional - default: ``[255, 255, 255]``) color - of the external ray(s). + of the external ray(s). OUTPUT: diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx index c048b944883..bd87f8fa345 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +++ b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx @@ -37,6 +37,8 @@ from sage.functions.other import sqrt from sage.ext.fast_callable import fast_callable from sage.calculus.all import symbolic_expression from sage.calculus.var import var +from sage.rings.fraction_field import is_FractionField +from sage.categories.function_fields import FunctionFields def _color_to_RGB(color): """ @@ -426,31 +428,31 @@ cpdef fast_julia_plot(double c_real, double c_imag, - ``c_real`` -- double, Real part of `c` value that determines Julia set. - ``c_imag`` -- double, Imaginary part of `c` value that determines Julia - set. + set. - ``x_center`` -- double (optional - default: ``0.0``), Real part of center - point. + point. - ``y_center`` -- double (optional - default: ``0.0``), Imaginary part of - center point. + center point. - ``image_width`` -- double (optional - default: ``4.0``), width of image - in the complex plane. + in the complex plane. - ``max_iteration`` -- long (optional - default: ``500``), maximum number of - iterations the map ``Q_c(z)``. + iterations the map ``Q_c(z)``. - ``pixel_count`` -- long (optional - default: ``500``), side length of - image in number of pixels. + image in number of pixels. - ``level_sep`` -- long (optional - default: ``2``), number of iterations - between each color level. + between each color level. - ``color_num`` -- long (optional - default: ``40``), number of colors used - to plot image. + to plot image. - ``base_color`` -- RGB color (optional - default: ``[50, 50, 50]``), color - used to determine the coloring of set. + used to determine the coloring of set. OUTPUT: @@ -541,34 +543,34 @@ cpdef julia_helper(double c_real, double c_imag, double x_center=0, - ``c_real`` -- double, Real part of `c` value that determines Julia set. - ``c_imag`` -- double, Imaginary part of `c` value that determines Julia - set. + set. - ``x_center`` -- double (optional - default: ``0.0``), Real part of center - point. + point. - ``y_center`` -- double (optional - default: ``0.0``), Imaginary part of - center point. + center point. - ``image_width`` -- double (optional - default: ``4.0``), width of image in - the complex plane. + the complex plane. - ``max_iteration`` -- long (optional - default: ``500``), maximum number of - iterations the map ``Q_c(z)``. + iterations the map ``Q_c(z)``. - ``pixel_count`` -- long (optional - default: ``500``), side length of - image in number of pixels. + image in number of pixels. - ``level_sep`` -- long (optional - default: ``2``), number of iterations - between each color level. + between each color level. - ``color_num`` -- long (optional - default: ``40``), number of colors used - to plot image. + to plot image. - ``base_color`` -- RGB color (optional - default: ``[50, 50, 50]``), color - used to determine the coloring of set. + used to determine the coloring of set. - ``point_color`` -- RGB color (optional - default: ``[255, 0, 0]``), color - of the point `c` in the Mandelbrot set. + of the point `c` in the Mandelbrot set. OUTPUT: @@ -621,27 +623,27 @@ cpdef julia_helper(double c_real, double c_imag, double x_center=0, cpdef polynomial_mandelbrot(f, parameter=None, double x_center=0, double y_center=0, image_width=4, int max_iteration=50, int pixel_count=500, - int level_sep=1, int color_num=30, base_color='red'): + int level_sep=1, int color_num=30, base_color=Color('red')): r""" Plots the Mandelbrot set in the complex plane for a general polynomial map. INPUT: - ``f`` -- polynomial map defined over the multivariate polynomial ring in - z, c over the Complex field. + z, c over the Complex field. - ``parameter`` -- designates which variable is used as the parameter. - If no parameter is provided, ``c`` will be used as the parameter. + If no parameter is provided, ``c`` will be used as the parameter. - ``x_center`` -- double, real part of the center point in the complex plane. - ``y_center`` -- double, imaginary part of the center point in the complex - plane. + plane. - ``image_width`` -- double, width of the image in the complex plane. - ``max_iteration`` -- long, maximum number of iterations the map `f(z)` - considered. + considered. - ``pixel_count`` -- long, side length of image in number of pixels. @@ -690,18 +692,24 @@ cpdef polynomial_mandelbrot(f, parameter=None, double x_center=0, P = f.parent() - if P.base() is CC: + if P.base_ring() is CC: + if is_FractionField(P): + raise NotImplementedError("coefficients must be polynomials in the parameter") gen_list = list(P.gens()) parameter = gen_list.pop(gen_list.index(parameter)) variable = gen_list.pop() - elif P.base().base() is CC: - parameter = P.gen() - variable = P.base().gen() + elif P.base_ring().base_ring() is CC: + if is_FractionField(P.base_ring()): + raise NotImplementedError("coefficients must be polynomials in the parameter") + parameter = P.base_ring().gen() + variable = P.gen() - else: - return ValueError("Base ring must be a complex field.") + elif P.base_ring() in FunctionFields(): + raise NotImplementedError("coefficients must be polynomials in the parameter") + else: + return ValueError("base ring must be a complex field") # Make sure image_width is positive image_width = abs(image_width) From 671efa739944f9188f5187f14ce5e1656994c765 Mon Sep 17 00:00:00 2001 From: nheir Date: Tue, 6 Aug 2019 14:14:59 +0200 Subject: [PATCH 082/340] restore terminal default colors --- build/make/install | 1 + 1 file changed, 1 insertion(+) diff --git a/build/make/install b/build/make/install index d3e31fc06fd..46267c4278f 100755 --- a/build/make/install +++ b/build/make/install @@ -55,6 +55,7 @@ fi # Dump environment for debugging purposes: echo "*** ALL ENVIRONMENT VARIABLES BEFORE BUILD: ***" env | sort +printf '\E[m' echo "***********************************************" ############################################################################### From ab8cda9b0f36fd522865a3dc3bb7113faff3aec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20R=C3=BCth?= Date: Tue, 20 Aug 2019 20:16:05 +0200 Subject: [PATCH 083/340] Save HTML documentation as browseable GitLab artifacts --- .ci/build-docker.sh | 4 ++++ .gitlab-ci.yml | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/.ci/build-docker.sh b/.ci/build-docker.sh index 56c837b8322..16f877e343b 100755 --- a/.ci/build-docker.sh +++ b/.ci/build-docker.sh @@ -39,6 +39,10 @@ docker_build --target run-time-dependencies --tag run-time-dependencies:$DOCKER_ docker_build --target build-time-dependencies --tag build-time-dependencies:$DOCKER_TAG . docker_build --target make-all --tag make-all:$DOCKER_TAG . +# Copy docs out of the docker image to save them into browseable GitLab artifacts +container=$(docker create make-all:$DOCKER_TAG) +docker cp $container:/home/sage/sage/local/share/doc/sage/html html + # Build the release image without build artifacts. docker_build --target sagemath --tag "$DOCKER_IMAGE_CLI" . # Display the layers of this image diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e2f2427b02e..770fe3421e4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -88,6 +88,7 @@ build-from-latest: when: always paths: - gitlab-build-docker.log + - html expire_in: 1 month script: - apk --update add coreutils @@ -114,6 +115,12 @@ build-from-latest: build-from-clean: extends: - build-from-latest + artifacts: + when: always + paths: + - gitlab-build-docker.log + - html + expire_in: 99 years variables: ARTIFACT_BASE: "source-clean" only: @@ -132,18 +139,21 @@ build-from-clean: test-dev: stage: test + dependencies: [] script: - . .ci/pull-gitlab.sh sagemath-dev - sh .ci/test-dev.sh "$DOCKER_IMAGE" test-cli: stage: test + dependencies: [] script: - . .ci/pull-gitlab.sh sagemath - sh .ci/test-cli.sh "$DOCKER_IMAGE" test-jupyter: stage: test + dependencies: [] script: - . .ci/pull-gitlab.sh sagemath - sh .ci/test-jupyter.sh "$DOCKER_IMAGE" docker @@ -152,6 +162,7 @@ test-jupyter: # variables DOCKER_USER and SECRET_DOCKER_PASS have been set up. push-dockerhub: stage: release + dependencies: [] only: refs: - branches @@ -166,6 +177,7 @@ push-dockerhub: # variables DOCKER_USER and SECRET_DOCKER_PASS have been set up. push-dockerhub-dev: stage: release + dependencies: [] only: refs: - master From 819cf4ab887c8631f518321cbd29945ab7ac6ea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20R=C3=BCth?= Date: Tue, 20 Aug 2019 23:21:48 +0200 Subject: [PATCH 084/340] follow symlinks to fix CSS --- .ci/build-docker.sh | 4 +++- .gitlab-ci.yml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.ci/build-docker.sh b/.ci/build-docker.sh index 16f877e343b..9df4c932c68 100755 --- a/.ci/build-docker.sh +++ b/.ci/build-docker.sh @@ -41,7 +41,9 @@ docker_build --target make-all --tag make-all:$DOCKER_TAG . # Copy docs out of the docker image to save them into browseable GitLab artifacts container=$(docker create make-all:$DOCKER_TAG) -docker cp $container:/home/sage/sage/local/share/doc/sage/html html +docker cp $container:/home/sage/sage/local/share/doc/sage/html html_ +# GitLab's browser does not like symlinks, so we flatten them +rsync html_/ html/ -a --copy-links # Build the release image without build artifacts. docker_build --target sagemath --tag "$DOCKER_IMAGE_CLI" . diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 770fe3421e4..accca9971e5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -91,7 +91,7 @@ build-from-latest: - html expire_in: 1 month script: - - apk --update add coreutils + - apk --update add coreutils rsync # The output of the build can get larger than gitlab.com's limit; only # print the first 1MB (and the last 80 lines.) GitLab's limit is 4MB, # however, the list of all branches and tags that shows up in the initial From 4c5cce6dbecf6c3552c5552bf33a9797ca19a883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20R=C3=BCth?= Date: Sun, 15 Sep 2019 16:59:43 +0200 Subject: [PATCH 085/340] Honour docbuild limits when building documentation in Dockerfile since the docbuild requires more RAM we need to be a bit more careful about parallelizing it. This has not been an issue on GitLab but we should set the correct variables anyway. --- docker/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 4c8bc553959..a8b73e7c48b 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -178,9 +178,9 @@ FROM make-build as make-all # overcommit limit of the system (no RAM is actually used, but this limit is # very low because there is not even swap on most CI systems.) ARG MAKEOPTS_DOCBUILD=$MAKEOPTS -ENV MAKEOPTS_DOCBUILD $MAKEOPTS_DOCBUILD +ENV MAKEOPTS $MAKEOPTS_DOCBUILD ARG SAGE_NUM_THREADS_DOCBUILD=$SAGE_NUM_THREADS -ENV SAGE_NUM_THREADS_DOCBUILD $SAGE_NUM_THREADS_DOCBUILD +ENV SAGE_NUM_THREADS $SAGE_NUM_THREADS_DOCBUILD RUN make ################################################################################ From b26026fae9017174a6f7fe471cd371e231d8a75a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20R=C3=BCth?= Date: Mon, 16 Sep 2019 14:23:56 +0200 Subject: [PATCH 086/340] Update symlinks in the docker -dev image Otherwise, when a library gets updated, it's .so is stale. This currently the libpynac.so point to the wrong place in the non-official docker dev images. --- docker/Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 8187fd9d939..8255f9a189c 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -126,7 +126,7 @@ ARG SAGE_ROOT=/home/sage/sage WORKDIR $SAGE_ROOT # We create a list of all files present in the artifact-base (with a timestamp # of now) so we can find out later which files were added/changed/removed. -RUN find . -type f > $HOME/artifact-base.manifest +RUN find . \( -type f -or -type l \) > $HOME/artifact-base.manifest RUN git fetch "$HOME/sage-context" HEAD \ && if [ -e docker/.commit ]; then \ git reset `cat docker/.commit` \ @@ -232,9 +232,9 @@ ARG SAGE_ROOT=/home/sage/sage # and a list of all modified files (added/updated/removed). RUN if [ x"$ARTIFACT_BASE" != x"source-clean" ]; then \ mkdir -p $HOME/patch \ - && find . -type f > $HOME/make-fast-rebuild-clean.manifest \ + && find . \( -type f -or -type l \) > $HOME/make-fast-rebuild-clean.manifest \ && cat $HOME/make-fast-rebuild-clean.manifest $HOME/artifact-base.manifest | sort | uniq -u > $HOME/obsolete \ - && find . -type f -cnewer $HOME/artifact-base.manifest > $HOME/modified \ + && find . \( -type f -or -type l \) -cnewer $HOME/artifact-base.manifest > $HOME/modified \ && tar -cJf $HOME/patch/modified.tar.xz -T $HOME/modified \ && cat $HOME/obsolete $HOME/modified | xz > $HOME/patch/modified.xz \ && rm -rf $SAGE_ROOT \ From bc31936fb962b8078056e34aa91ab71c8f7e5692 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 25 Sep 2019 15:01:50 +0200 Subject: [PATCH 087/340] using int_fast64 for vector_modn_sparse --- src/sage/modules/vector_modn_sparse.pxd | 14 +++-- src/sage/modules/vector_modn_sparse.pyx | 74 ++++++++++++++----------- 2 files changed, 50 insertions(+), 38 deletions(-) diff --git a/src/sage/modules/vector_modn_sparse.pxd b/src/sage/modules/vector_modn_sparse.pxd index 43cfb95a9a9..2e4e9f6ab41 100644 --- a/src/sage/modules/vector_modn_sparse.pxd +++ b/src/sage/modules/vector_modn_sparse.pxd @@ -1,5 +1,7 @@ +from sage.rings.finite_rings.stdint cimport * + cdef struct c_vector_modint: - int *entries + int_fast64_t *entries int p Py_ssize_t *positions Py_ssize_t degree @@ -8,10 +10,10 @@ cdef struct c_vector_modint: cdef int allocate_c_vector_modint(c_vector_modint* v, Py_ssize_t num_nonzero) except -1 cdef int init_c_vector_modint(c_vector_modint* v, int p, Py_ssize_t degree, Py_ssize_t num_nonzero) except -1 cdef void clear_c_vector_modint(c_vector_modint* v) -cdef Py_ssize_t binary_search0_modn(Py_ssize_t* v, Py_ssize_t n, int x) -cdef Py_ssize_t binary_search_modn(Py_ssize_t* v, Py_ssize_t n, int x, Py_ssize_t* ins) -cdef int get_entry(c_vector_modint* v, Py_ssize_t n) except -1 +cdef Py_ssize_t binary_search0_modn(Py_ssize_t* v, Py_ssize_t n, int_fast64_t x) +cdef Py_ssize_t binary_search_modn(Py_ssize_t* v, Py_ssize_t n, int_fast64_t x, Py_ssize_t* ins) +cdef int_fast64_t get_entry(c_vector_modint* v, Py_ssize_t n) except -1 cdef object to_list(c_vector_modint* v) -cdef int set_entry(c_vector_modint* v, Py_ssize_t n, int x) except -1 +cdef int set_entry(c_vector_modint* v, Py_ssize_t n, int_fast64_t x) except -1 cdef int add_c_vector_modint_init(c_vector_modint* sum, c_vector_modint* v, c_vector_modint* w, int multiple) except -1 -cdef int scale_c_vector_modint(c_vector_modint* v, int scalar) except -1 \ No newline at end of file +cdef int scale_c_vector_modint(c_vector_modint* v, int_fast64_t scalar) except -1 \ No newline at end of file diff --git a/src/sage/modules/vector_modn_sparse.pyx b/src/sage/modules/vector_modn_sparse.pyx index a2b7510a1b9..3a166786bfe 100644 --- a/src/sage/modules/vector_modn_sparse.pyx +++ b/src/sage/modules/vector_modn_sparse.pyx @@ -2,49 +2,54 @@ # Copyright (C) 2004, 2007 William Stein # Distributed under the terms of the GNU General Public License (GPL) # The full text of the GPL is available at: -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ############################################################################# from cysignals.memory cimport sig_malloc, sig_free from sage.modules.vector_modn_sparse cimport c_vector_modint + cdef int allocate_c_vector_modint(c_vector_modint* v, Py_ssize_t num_nonzero) except -1: """ Allocate memory for a c_vector_modint -- most user code won't call this. """ - v.entries = sig_malloc(num_nonzero*sizeof(int)) + v.entries = sig_malloc(num_nonzero*sizeof(int_fast64_t)) if v.entries == NULL: - raise MemoryError("Error allocating memory") + raise MemoryError("error allocating memory") v.positions = sig_malloc(num_nonzero*sizeof(Py_ssize_t)) if v.positions == NULL: sig_free(v.entries) - raise MemoryError("Error allocating memory") + raise MemoryError("error allocating memory") return 0 + cdef int init_c_vector_modint(c_vector_modint* v, int p, Py_ssize_t degree, Py_ssize_t num_nonzero) except -1: """ Initialize a c_vector_modint. """ if (allocate_c_vector_modint(v, num_nonzero) == -1): - raise MemoryError("Error allocating memory for sparse vector.") + raise MemoryError("error allocating memory for sparse vector") if p > 46340: clear_c_vector_modint(v) - raise OverflowError("The prime must be <= 46340.") + raise OverflowError("the prime must be <= 46340") v.num_nonzero = num_nonzero v.degree = degree v.p = p return 0 + cdef void clear_c_vector_modint(c_vector_modint* v): sig_free(v.entries) sig_free(v.positions) -cdef Py_ssize_t binary_search0_modn(Py_ssize_t* v, Py_ssize_t n, int x): + +cdef Py_ssize_t binary_search0_modn(Py_ssize_t* v, Py_ssize_t n, int_fast64_t x): """ Find the position of the int x in the array v, which has length n. - Returns -1 if x is not in the array v. + + Return -1 if x is not in the array v. """ if n == 0: return -1 @@ -52,7 +57,7 @@ cdef Py_ssize_t binary_search0_modn(Py_ssize_t* v, Py_ssize_t n, int x): cdef Py_ssize_t i, j, k i = 0 j = n-1 - while i<=j: + while i <= j: if i == j: if v[i] == x: return i @@ -66,10 +71,12 @@ cdef Py_ssize_t binary_search0_modn(Py_ssize_t* v, Py_ssize_t n, int x): return k return -1 -cdef Py_ssize_t binary_search_modn(Py_ssize_t* v, Py_ssize_t n, int x, Py_ssize_t* ins): + +cdef Py_ssize_t binary_search_modn(Py_ssize_t* v, Py_ssize_t n, int_fast64_t x, Py_ssize_t* ins): """ Find the position of the integer x in the array v, which has length n. - Returns -1 if x is not in the array v, and in this case ins is + + Return -1 if x is not in the array v, and in this case ins is set equal to the position where x should be inserted in order to obtain an ordered array. """ @@ -80,7 +87,7 @@ cdef Py_ssize_t binary_search_modn(Py_ssize_t* v, Py_ssize_t n, int x, Py_ssize_ cdef Py_ssize_t i, j, k i = 0 j = n-1 - while i<=j: + while i <= j: if i == j: if v[i] == x: ins[0] = i @@ -98,49 +105,54 @@ cdef Py_ssize_t binary_search_modn(Py_ssize_t* v, Py_ssize_t n, int x, Py_ssize_ else: # only possibility is that v[k] == x ins[0] = k return k - # end while ins[0] = j+1 return -1 -cdef int get_entry(c_vector_modint* v, Py_ssize_t n) except -1: + +cdef int_fast64_t get_entry(c_vector_modint* v, Py_ssize_t n) except -1: """ - Returns the n-th entry of the sparse vector v. This - would be v[n] in Python syntax. + Return the n-th entry of the sparse vector v. + + This would be v[n] in Python syntax. """ if n >= v.degree or n < 0: - raise IndexError("Index must be between 0 and the degree minus 1.") + raise IndexError("index must be between 0 and the degree minus 1") cdef Py_ssize_t m m = binary_search0_modn(v.positions, v.num_nonzero, n) if m == -1: return 0 return v.entries[m] + cdef object to_list(c_vector_modint* v): """ - Returns a Python list of 2-tuples (i,x), where x=v[i] runs + Return a Python list of 2-tuples (i,x), where x=v[i] runs through the nonzero elements of x, in order. """ cdef object X cdef Py_ssize_t i X = [] - for i from 0 <= i < v.num_nonzero: - X.append( (v.positions[i], v.entries[i]) ) + for i in range(v.num_nonzero): + X.append((v.positions[i], v.entries[i])) return X -cdef int set_entry(c_vector_modint* v, Py_ssize_t n, int x) except -1: + +cdef int set_entry(c_vector_modint* v, Py_ssize_t n, int_fast64_t x) except -1: """ Set the n-th component of the sparse vector v equal to x. + This would be v[n] = x in Python syntax. """ if n < 0 or n >= v.degree: - raise IndexError("Index (=%s) must be between 0 and %s."%(n, v.degree-1)) + raise IndexError("index (=%s) must be between 0 and %s" % (n, v.degree-1)) cdef Py_ssize_t i, m, ins cdef Py_ssize_t m2, ins2 cdef Py_ssize_t *pos - cdef int *e + cdef int_fast64_t *e x = x % v.p - if x<0: x = x + v.p + if x < 0: + x = x + v.p m = binary_search_modn(v.positions, v.num_nonzero, n, &ins) if m != -1: @@ -191,15 +203,16 @@ cdef int set_entry(c_vector_modint* v, Py_ssize_t n, int x) except -1: sig_free(e) sig_free(pos) + cdef int add_c_vector_modint_init(c_vector_modint* sum, c_vector_modint* v, c_vector_modint* w, int multiple) except -1: """ Set sum = v + multiple*w. """ if v.p != w.p: - raise ArithmeticError("The vectors must be modulo the same prime.") + raise ArithmeticError("the vectors must be modulo the same prime") if v.degree != w.degree: - raise ArithmeticError("The vectors must have the same degree.") + raise ArithmeticError("the vectors must have the same degree") cdef int s cdef Py_ssize_t nz, i, j, k @@ -260,12 +273,11 @@ cdef int add_c_vector_modint_init(c_vector_modint* sum, c_vector_modint* v, k = k + 1 # only increment if sum is nonzero! i = i + 1 j = j + 1 - #end if - # end while z.num_nonzero = k return 0 -cdef int scale_c_vector_modint(c_vector_modint* v, int scalar) except -1: + +cdef int scale_c_vector_modint(c_vector_modint* v, int_fast64_t scalar) except -1: scalar = scalar % v.p if scalar == 0: clear_c_vector_modint(v) @@ -274,8 +286,6 @@ cdef int scale_c_vector_modint(c_vector_modint* v, int scalar) except -1: if scalar < 0: scalar = scalar + v.p cdef Py_ssize_t i - for i from 0 <= i < v.num_nonzero: + for i in range(v.num_nonzero): v.entries[i] = (v.entries[i] * scalar) % v.p return 0 - - From c615bb68304cf32fc813f64052670e9077a718ba Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Fri, 27 Sep 2019 11:47:14 +0200 Subject: [PATCH 088/340] fallback to map_coefficients --- src/sage/rings/polynomial/polynomial_element.pyx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index cbe40aeb1a1..3859aa9644c 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -3244,10 +3244,7 @@ cdef class Polynomial(CommutativeAlgebraElement): True """ if isinstance(R, Map): - # we're given a hom of the base ring extend to a poly hom - if R.domain() == self.base_ring(): - R = self._parent.hom(R, self._parent.change_ring(R.codomain())) - return R(self) + return self.map_coefficients(R) else: return self._parent.change_ring(R)(self.list(copy=False)) From fe1d9daf0bab295e5cb7933c1c5abe1fc7ab7a06 Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Sun, 29 Sep 2019 06:58:29 +0200 Subject: [PATCH 089/340] add doctest --- src/sage/rings/polynomial/polynomial_element.pyx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 3859aa9644c..b2e98012f01 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -3242,6 +3242,14 @@ cdef class Polynomial(CommutativeAlgebraElement): True sage: x.change_ring(ZZ['x']) == ZZ['x']['x'].gen() True + + Check that :trac:`28541` is fixed:: + + sage: F. = GF(7^2) + sage: S. = F[] + sage: P = x^2 + a*x + a^2 + sage: P.change_ring(F.frobenius_endomorphism()) + x^2 + (6*a + 1)*x + 6*a + 5 """ if isinstance(R, Map): return self.map_coefficients(R) From 99c392c7f0bec8145544a2048d00c05eb73b0e79 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Sun, 6 Oct 2019 16:49:05 +0200 Subject: [PATCH 090/340] Copy and multiplication names --- .../manifolds/differentiable/diff_form.py | 10 ++-- .../manifolds/differentiable/mixed_form.py | 2 +- .../differentiable/multivectorfield.py | 6 +- .../manifolds/differentiable/scalarfield.py | 6 +- .../manifolds/differentiable/tensorfield.py | 55 ++++++++++++------- .../differentiable/tensorfield_paral.py | 6 +- src/sage/manifolds/scalarfield.py | 6 +- src/sage/tensor/modules/free_module_tensor.py | 18 ++++-- 8 files changed, 65 insertions(+), 44 deletions(-) diff --git a/src/sage/manifolds/differentiable/diff_form.py b/src/sage/manifolds/differentiable/diff_form.py index 7fe101976a7..2d2ba386138 100644 --- a/src/sage/manifolds/differentiable/diff_form.py +++ b/src/sage/manifolds/differentiable/diff_form.py @@ -196,11 +196,11 @@ class DiffForm(TensorField): sage: f = M.scalar_field({c_xy: (x+y)^2, c_uv: u^2}, name='f') sage: s = f*a ; s - 1-form on the 2-dimensional differentiable manifold M + 1-form f*a on the 2-dimensional differentiable manifold M sage: s.display(eU) - (-x^2*y - 2*x*y^2 - y^3) dx + (x^3 + 2*x^2*y + x*y^2) dy + f*a = (-x^2*y - 2*x*y^2 - y^3) dx + (x^3 + 2*x^2*y + x*y^2) dy sage: s.display(eV) - 1/2*u^2*v du - 1/2*u^3 dv + f*a = 1/2*u^2*v du - 1/2*u^3 dv .. RUBRIC:: Examples with SymPy as the symbolic engine @@ -263,9 +263,9 @@ class DiffForm(TensorField): sage: f = M.scalar_field({c_xy: (x+y)^2, c_uv: u^2}, name='f') sage: s = f*a sage: s.display(eU) - -y*(x**2 + 2*x*y + y**2) dx + x*(x**2 + 2*x*y + y**2) dy + f*a = -y*(x**2 + 2*x*y + y**2) dx + x*(x**2 + 2*x*y + y**2) dy sage: s.display(eV) - u**2*v/2 du - u**3/2 dv + f*a = u**2*v/2 du - u**3/2 dv """ def __init__(self, vector_field_module, degree, name=None, latex_name=None): diff --git a/src/sage/manifolds/differentiable/mixed_form.py b/src/sage/manifolds/differentiable/mixed_form.py index 1044ee25bb4..d078509f233 100644 --- a/src/sage/manifolds/differentiable/mixed_form.py +++ b/src/sage/manifolds/differentiable/mixed_form.py @@ -981,7 +981,7 @@ def copy(self): different name, but has the very same values:: sage: B = A.copy(); B.disp() - f + (unnamed 1-form) + (unnamed 2-form) + f + omega + zero sage: B.disp(e_uv) [1/2*u + 1/2*v] + [(1/4*u + 1/4*v) du + (1/4*u + 1/4*v) dv] + [0] sage: A == B diff --git a/src/sage/manifolds/differentiable/multivectorfield.py b/src/sage/manifolds/differentiable/multivectorfield.py index 082636f7bd7..4ac136fb147 100644 --- a/src/sage/manifolds/differentiable/multivectorfield.py +++ b/src/sage/manifolds/differentiable/multivectorfield.py @@ -147,11 +147,11 @@ class MultivectorField(TensorField): sage: f = M.scalar_field({c_xy: (x+y)^2, c_uv: u^2}, name='f') sage: s = f*s ; s - 2-vector field on the 2-dimensional differentiable manifold M + 2-vector field f*(a/\b) on the 2-dimensional differentiable manifold M sage: s.display(eU) - (-2*x^2*y^3 - x^3 - (4*x^3 + x)*y^2 - 2*(x^4 + x^2)*y) d/dx/\d/dy + f*(a/\b) = (-2*x^2*y^3 - x^3 - (4*x^3 + x)*y^2 - 2*(x^4 + x^2)*y) d/dx/\d/dy sage: s.display(eV) - (1/2*u^5 - 1/2*u^3*v^2 - 1/2*u^2*v^3 + u^3 + 1/2*(u^4 + 2*u^2)*v) + f*(a/\b) = (1/2*u^5 - 1/2*u^3*v^2 - 1/2*u^2*v^3 + u^3 + 1/2*(u^4 + 2*u^2)*v) d/du/\d/dv """ diff --git a/src/sage/manifolds/differentiable/scalarfield.py b/src/sage/manifolds/differentiable/scalarfield.py index 9feb6db15ce..946d78ea544 100644 --- a/src/sage/manifolds/differentiable/scalarfield.py +++ b/src/sage/manifolds/differentiable/scalarfield.py @@ -1021,12 +1021,12 @@ def wedge(self, other): sage: a = M.diff_form(2, name='a') sage: a[0,1] = x*y sage: s = f.wedge(a); s - 2-form on the 2-dimensional differentiable manifold M + 2-form f*a on the 2-dimensional differentiable manifold M sage: s.display() - (x*y^3 + x^2*y) dx/\dy + f*a = (x*y^3 + x^2*y) dx/\dy """ - return self*other + return self * other def degree(self): r""" diff --git a/src/sage/manifolds/differentiable/tensorfield.py b/src/sage/manifolds/differentiable/tensorfield.py index 8ee0c4977df..774e9d465e0 100644 --- a/src/sage/manifolds/differentiable/tensorfield.py +++ b/src/sage/manifolds/differentiable/tensorfield.py @@ -1792,7 +1792,7 @@ def copy(self): .. NOTE:: - The name and the derived quantities are not copied. + The name and the derived quantities are copied, too. EXAMPLES: @@ -1811,10 +1811,10 @@ def copy(self): sage: t[e_xy,:] = [[x+y, 0], [2, 1-y]] sage: t.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) sage: s = t.copy(); s - Tensor field of type (1,1) on + Tensor field t of type (1,1) on the 2-dimensional differentiable manifold M sage: s.display(e_xy) - (x + y) d/dx*dx + 2 d/dy*dx + (-y + 1) d/dy*dy + t = (x + y) d/dx*dx + 2 d/dy*dx + (-y + 1) d/dy*dy sage: s == t True @@ -1824,7 +1824,7 @@ def copy(self): sage: t.display(e_xy) t = -d/dx*dx + 2 d/dy*dx + (-y + 1) d/dy*dy sage: s.display(e_xy) - (x + y) d/dx*dx + 2 d/dy*dx + (-y + 1) d/dy*dy + t = (x + y) d/dx*dx + 2 d/dy*dx + (-y + 1) d/dy*dy sage: s == t False @@ -1832,6 +1832,7 @@ def copy(self): resu = self._new_instance() for dom, rst in self._restrictions.items(): resu._restrictions[dom] = rst.copy() + resu.set_name(name=self._name, latex_name=self._latex_name) return resu def _common_subdomains(self, other): @@ -2032,10 +2033,12 @@ def __pos__(self): resu = self._new_instance() for dom, rst in self._restrictions.items(): resu._restrictions[dom] = + rst - if self._name is not None: - resu._name = '+' + self._name - if self._latex_name is not None: - resu._latex_name = '+' + self._latex_name + ### + # Compose names: + from sage.tensor.modules.format_utilities import (format_unop_txt, + format_unop_latex) + resu._name = format_unop_txt('+', self._name) + resu._latex_name = format_unop_latex(r'+', self._latex_name) return resu def __neg__(self): @@ -2078,10 +2081,12 @@ def __neg__(self): resu = self._new_instance() for dom, rst in self._restrictions.items(): resu._restrictions[dom] = - rst - if self._name is not None: - resu._name = '-' + self._name - if self._latex_name is not None: - resu._latex_name = '-' + self._latex_name + ### + # Compose names: + from sage.tensor.modules.format_utilities import (format_unop_txt, + format_unop_latex) + resu._name = format_unop_txt('-', self._name) + resu._latex = format_unop_latex(r'-', self._latex_name) return resu ######### ModuleElement arithmetic operators ######## @@ -2251,16 +2256,16 @@ def _rmul_(self, scalar): on U: (x, y) |--> 1/(x^2 + y^2 + 1) on V: (u, v) |--> 2/(u^2 + v^2 + 2) sage: s = a._rmul_(f); s - Tensor field of type (1,1) on the 2-dimensional differentiable + Tensor field f*a of type (1,1) on the 2-dimensional differentiable manifold M sage: a.display(e_xy) a = x d/dx*dx + d/dx*dy + y d/dy*dx sage: s.display(e_xy) - x/(x^2 + y^2 + 1) d/dx*dx + 1/(x^2 + y^2 + 1) d/dx*dy + y/(x^2 + y^2 + 1) d/dy*dx + f*a = x/(x^2 + y^2 + 1) d/dx*dx + 1/(x^2 + y^2 + 1) d/dx*dy + y/(x^2 + y^2 + 1) d/dy*dx sage: a.display(e_uv) a = (1/2*u + 1/2) d/du*du + (1/2*u - 1/2) d/du*dv + (1/2*v + 1/2) d/dv*du + (1/2*v - 1/2) d/dv*dv sage: s.display(e_uv) - (u + 1)/(u^2 + v^2 + 2) d/du*du + (u - 1)/(u^2 + v^2 + 2) d/du*dv + (v + 1)/(u^2 + v^2 + 2) d/dv*du + (v - 1)/(u^2 + v^2 + 2) d/dv*dv + f*a = (u + 1)/(u^2 + v^2 + 2) d/du*du + (u - 1)/(u^2 + v^2 + 2) d/du*dv + (v + 1)/(u^2 + v^2 + 2) d/dv*du + (v - 1)/(u^2 + v^2 + 2) d/dv*dv sage: s == f*a # indirect doctest True sage: z = a.parent().zero(); z @@ -2275,6 +2280,14 @@ def _rmul_(self, scalar): resu = self._new_instance() for dom, rst in self._restrictions.items(): resu._restrictions[dom] = scalar.restrict(dom) * rst + ### + # Compose names: + from sage.tensor.modules.format_utilities import (format_mul_txt, + format_mul_latex) + resu_name = format_mul_txt(scalar._name, '*', self._name) + resu_latex = format_mul_latex(scalar._latex_name, ' \cdot ', + self._latex_name) + resu.set_name(name=resu_name, latex_name=resu_latex) return resu ######### End of ModuleElement arithmetic operators ######## @@ -2333,12 +2346,12 @@ def __mul__(self, other): sage: f = M.scalar_field({c_xy: x*y}, name='f') sage: f.add_expr_by_continuation(c_uv, U.intersection(V)) sage: s = a.__mul__(f); s - Tensor field of type (1,1) on the 2-dimensional differentiable + Tensor field f*a of type (1,1) on the 2-dimensional differentiable manifold M sage: s.display(e_xy) - x^2*y d/dx*dx + x*y d/dx*dy + x*y^2 d/dy*dx + f*a = x^2*y d/dx*dx + x*y d/dx*dy + x*y^2 d/dy*dx sage: s.display(e_uv) - (1/8*u^3 - 1/8*(u + 1)*v^2 + 1/8*u^2) d/du*du + f*a = (1/8*u^3 - 1/8*(u + 1)*v^2 + 1/8*u^2) d/du*du + (1/8*u^3 - 1/8*(u - 1)*v^2 - 1/8*u^2) d/du*dv + (1/8*u^2*v - 1/8*v^3 + 1/8*u^2 - 1/8*v^2) d/dv*du + (1/8*u^2*v - 1/8*v^3 - 1/8*u^2 + 1/8*v^2) d/dv*dv @@ -2367,12 +2380,12 @@ def __mul__(self, other): sage: M.set_calculus_method('sympy') sage: f.add_expr_by_continuation(c_uv, U.intersection(V)) sage: s = a.__mul__(f); s - Tensor field of type (1,1) on the 2-dimensional differentiable + Tensor field f*a of type (1,1) on the 2-dimensional differentiable manifold M sage: s.display(e_xy) - x**2*y d/dx*dx + x*y d/dx*dy + x*y**2 d/dy*dx + f*a = x**2*y d/dx*dx + x*y d/dx*dy + x*y**2 d/dy*dx sage: s.display(e_uv) - (u**3/8 + u**2/8 - u*v**2/8 - v**2/8) d/du*du + (u**3/8 - + f*a = (u**3/8 + u**2/8 - u*v**2/8 - v**2/8) d/du*du + (u**3/8 - u**2/8 - u*v**2/8 + v**2/8) d/du*dv + (u**2*v/8 + u**2/8 - v**3/8 - v**2/8) d/dv*du + (u**2*v/8 - u**2/8 - v**3/8 + v**2/8) d/dv*dv diff --git a/src/sage/manifolds/differentiable/tensorfield_paral.py b/src/sage/manifolds/differentiable/tensorfield_paral.py index dc845990ebf..e63a7edc5c1 100644 --- a/src/sage/manifolds/differentiable/tensorfield_paral.py +++ b/src/sage/manifolds/differentiable/tensorfield_paral.py @@ -1632,11 +1632,11 @@ def __mul__(self, other): sage: f = M.scalar_field({X: x+y}, name='f') sage: s = a.__mul__(f); s - Tensor field of type (0,2) on the 2-dimensional differentiable + Tensor field f*a of type (0,2) on the 2-dimensional differentiable manifold M sage: s.display() - (x^2 + (x + 1)*y + x) dx*dx + (2*x + 2*y) dx*dy + (x*y + y^2) dy*dx - + (-x^3 - x^2*y) dy*dy + f*a = (x^2 + (x + 1)*y + x) dx*dx + (2*x + 2*y) dx*dy + + (x*y + y^2) dy*dx + (-x^3 - x^2*y) dy*dy sage: s == f*a True diff --git a/src/sage/manifolds/scalarfield.py b/src/sage/manifolds/scalarfield.py index 3379b844784..d81fd655b34 100644 --- a/src/sage/manifolds/scalarfield.py +++ b/src/sage/manifolds/scalarfield.py @@ -2398,8 +2398,8 @@ def _mul_(self, other): True """ - from sage.tensor.modules.format_utilities import format_mul_txt, \ - format_mul_latex + from sage.tensor.modules.format_utilities import (format_mul_txt, + format_mul_latex) # Special cases: if self._is_zero or other._is_zero: return self._domain.zero_scalar_field() @@ -2412,7 +2412,7 @@ def _mul_(self, other): # ChartFunction multiplication: result._express[chart] = self._express[chart] * other._express[chart] result._name = format_mul_txt(self._name, '*', other._name) - result._latex_name = format_mul_latex(self._latex_name, ' ', + result._latex_name = format_mul_latex(self._latex_name, ' \cdot ', other._latex_name) return result diff --git a/src/sage/tensor/modules/free_module_tensor.py b/src/sage/tensor/modules/free_module_tensor.py index 8f3a5c75a75..de55085a002 100644 --- a/src/sage/tensor/modules/free_module_tensor.py +++ b/src/sage/tensor/modules/free_module_tensor.py @@ -1482,7 +1482,7 @@ def copy(self): r""" Return an exact copy of ``self``. - The name and the derived quantities are not copied. + The name and the derived quantities are copied, too. EXAMPLES: @@ -1512,6 +1512,7 @@ def copy(self): """ resu = self._new_instance() + resu.set_name(name=self._name, latex_name=self._latex_name) for basis, comp in self._components.items(): resu._components[basis] = comp.copy() return resu @@ -1972,6 +1973,16 @@ def _rmul_(self, other): result = self._new_instance() for basis in self._components: result._components[basis] = other * self._components[basis] + ### + # If other has a name, set the name of the result: + try: + from .format_utilities import format_mul_txt, format_mul_latex + result_name = format_mul_txt(other._name, '*', self._name) + result_latex = format_mul_latex(other._latex_name, r' \cdot ', + self._latex_name) + result.set_name(name=result_name, latex_name=result_latex) + except AttributeError: + pass return result ######### End of ModuleElement arithmetic operators ######## @@ -2020,10 +2031,7 @@ def __mul__(self, other): return result # multiplication by a scalar: - result = self._new_instance() - for basis in self._components: - result._components[basis] = other * self._components[basis] - return result + return FreeModuleTensor._rmul_(self, other) def __truediv__(self, other): r""" From b3e04682ae022ce8417f99f7d9145fb8a2782676 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Mon, 7 Oct 2019 21:53:58 +0200 Subject: [PATCH 091/340] MixedForm copies apply names --- src/sage/manifolds/differentiable/mixed_form.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/sage/manifolds/differentiable/mixed_form.py b/src/sage/manifolds/differentiable/mixed_form.py index d078509f233..f50e7371ee0 100644 --- a/src/sage/manifolds/differentiable/mixed_form.py +++ b/src/sage/manifolds/differentiable/mixed_form.py @@ -981,9 +981,9 @@ def copy(self): different name, but has the very same values:: sage: B = A.copy(); B.disp() - f + omega + zero + A = f + omega + zero sage: B.disp(e_uv) - [1/2*u + 1/2*v] + [(1/4*u + 1/4*v) du + (1/4*u + 1/4*v) dv] + [0] + A = [1/2*u + 1/2*v] + [(1/4*u + 1/4*v) du + (1/4*u + 1/4*v) dv] + [0] sage: A == B True sage: A is B @@ -998,11 +998,13 @@ def copy(self): sage: A.disp(e_xy) A = [x] + [y dx] + [0] sage: B.disp(e_xy) - [x] + [x dx] + [0] + A = [x] + [x dx] + [0] """ resu_comp = [form.copy() for form in self._comp] - return type(self)(self.parent(), comp=resu_comp) + resu = type(self)(self.parent(), comp=resu_comp) + resu.set_name(name=self._name, latex_name=self._latex_name) + return resu def __setitem__(self, index, values): r""" From 13bc675cc70daea7c12054961295a05a77477ffc Mon Sep 17 00:00:00 2001 From: Thierry Monteil Date: Fri, 18 Oct 2019 16:57:11 +0200 Subject: [PATCH 092/340] #28627 : lazy creation of OEIS sequences based only on their A-number --- src/sage/databases/oeis.py | 172 ++++++++++++++++++++++++++----------- 1 file changed, 120 insertions(+), 52 deletions(-) diff --git a/src/sage/databases/oeis.py b/src/sage/databases/oeis.py index 285ba6328f6..a3808871fe1 100644 --- a/src/sage/databases/oeis.py +++ b/src/sage/databases/oeis.py @@ -17,6 +17,9 @@ - Moritz Firsching (2016): modifies handling of dead sequence, see :trac:`17330` +- Thierry Monteil (2019): refactorization (unique representation :trac:`28480`, + laziness :trac:`28627`) + EXAMPLES:: sage: oeis @@ -316,7 +319,7 @@ class OEIS: sage: fibo == oeis(45) # optional -- internet True - sage: sfibo = oeis('A039834') # optional -- internet + sage: sfibo = oeis('A039834') sage: sfibo.first_terms() # optional -- internet (1, 1, 0, 1, -1, 2, -3, 5, -8, 13, -21, 34, -55, 89, -144, 233, -377, 610, -987, 1597, -2584, 4181, -6765, 10946, -17711, 28657, @@ -398,7 +401,7 @@ def __repr__(self): """ return "The On-Line Encyclopedia of Integer Sequences (%s)" % oeis_url - def find_by_id(self, ident): + def find_by_id(self, ident, fetch=False): r""" INPUT: @@ -406,10 +409,12 @@ def find_by_id(self, ident): - ``ident`` - a string representing the A-number of the sequence or an integer representing its number. + - ``fetch`` - (bool, default: ``False``) whether to force fetching the + content of the sequence on the internet. + OUTPUT: - - The OEIS sequence whose A-number or number corresponds to - ``ident``. + - The OEIS sequence whose A-number or number corresponds to ``ident``. EXAMPLES:: @@ -419,13 +424,27 @@ def find_by_id(self, ident): sage: oeis.find_by_id(40) # optional -- internet A000040: The prime numbers. """ - if not isinstance(ident, str): - ident = str(ident) - ident = 'A000000'[:-len(ident)] + ident - options = {'q': ident, 'n': '1', 'fmt': 'text'} - url = oeis_url + "search?" + urlencode(options) - sequence = _fetch(url).split('\n\n')[2] - return OEISSequence(sequence) + sequence = OEISSequence(ident=ident) + if fetch: + sequence.online_update() + return sequence + + def find_by_entry(self, entry): + r""" + + INPUT: + + - ``entry`` - a string corresponding to an entry in the internal format + of the OEIS. + + OUTPUT: + + - The corresponding OEIS sequence. + """ + ident = entry[3:10] + sequence = OEISSequence(ident=ident) + sequence._raw = entry + return sequence def find_by_description(self, description, max_results=3, first_result=0): r""" @@ -479,7 +498,7 @@ def find_by_description(self, description, max_results=3, first_result=0): 'start': str(first_result)} url = oeis_url + "search?" + urlencode(options) sequence_list = _fetch(url).split('\n\n')[2:-1] - return FancyTuple([OEISSequence(_) for _ in sequence_list]) + return FancyTuple([self.find_by_entry(entry=_) for _ in sequence_list]) def find_by_subsequence(self, subsequence, max_results=3, first_result=0): r""" @@ -615,9 +634,8 @@ class OEISSequence(SageObject, UniqueRepresentation): r""" The class of OEIS sequences. - This class implements OEIS sequences. Such sequences are produced from a - string in the OEIS format. They are usually produced by calls to the - On-Line Encyclopedia of Integer Sequences, represented by the class + This class implements OEIS sequences. They are usually produced by calls to + the On-Line Encyclopedia of Integer Sequences, represented by the class :class:`OEIS`. .. NOTE:: @@ -626,7 +644,7 @@ class OEISSequence(SageObject, UniqueRepresentation): between calling and getting item, see :meth:`__call__` for more details :: - sage: sfibo = oeis('A039834') # optional -- internet + sage: sfibo = oeis('A039834') sage: sfibo.first_terms()[:10] # optional -- internet (1, 1, 0, 1, -1, 2, -3, 5, -8, 13) @@ -644,33 +662,77 @@ class OEISSequence(SageObject, UniqueRepresentation): .. automethod:: __call__ """ + @staticmethod + def __classcall__(cls, ident): + r""" + Canonicalize the ID of the sequence into a A-number. + """ + if not isinstance(ident, str): + ident = str(ident) + ident = 'A000000'[:-len(ident)] + ident + return super(OEISSequence, cls).__classcall__(cls, ident) - def __init__(self, entry): + def __init__(self, ident): r""" Initializes an OEIS sequence. + There is no fetching of additional information about the sequence at + this point, only the A-number is required to construct a sequence. + + INPUT: + + - ``ident`` - a string representing the A-number of the sequence or an + integer representing its number. + TESTS:: - sage: sfibo = oeis('A039834') # optional -- internet + sage: sfibo = oeis('A039834') - Handle dead sequences: see :trac:`17330` :: + sage: s = oeis._imaginary_sequence() + """ + self._id = ident - sage: oeis(17) # optional -- internet - doctest:warning - ... - RuntimeWarning: This sequence is dead: "A000017: Erroneous version of A032522." - A000017: Erroneous version of A032522. + def online_update(self): + r""" + Fetch the online OEIS to update the informations about this sequence. + + TESTS:: + + sage: s = oeis._imaginary_sequence(ident='A004238') + sage: s + A004238: The characteristic sequence of 42 plus one, starting from 38. + sage: s.online_update() # optional -- internet + sage: s # optional -- internet + A004238: a(n) = 100*log(n) rounded to nearest integer. + """ + options = {'q': self._id, 'n': '1', 'fmt': 'text'} + url = oeis_url + "search?" + urlencode(options) + self._raw = _fetch(url).split('\n\n')[2] + try: + del self._fields + except AttributeError: + pass + + def _field(self, key): + r""" + Return the ``key`` field of the entry of ``self``. + + This method allows to handle the ``_fields`` dictionary in a lazy way. + + TESTS:: sage: s = oeis._imaginary_sequence() + sage: s._field('C')[0] + '42 is the product of the first 4 prime numbers, except 5 and perhaps 1.' """ - self._raw = entry - self._id = entry[3:10] - self._fields = defaultdict(list) - for line in entry.splitlines(): - self._fields[line[1]].append(line[11:]) - if 'dead' in self.keywords(): - from warnings import warn - warn('This sequence is dead: "{}: {}"'.format(self.id(), self.name()), RuntimeWarning) + try: + return self._fields[key] + except AttributeError: + fields = defaultdict(list) + for line in self.raw_entry().splitlines(): + fields[line[1]].append(line[11:]) + self._fields = fields + return self._fields[key] def id(self, format='A'): r""" @@ -748,6 +810,8 @@ def raw_entry(self): r""" Return the raw entry of the sequence ``self``, in the OEIS format. + The raw entry is fetched online if needed. + OUTPUT: - string. @@ -769,7 +833,11 @@ def raw_entry(self): sage: s.raw_entry() == oeis._imaginary_entry('sign,easy') True """ - return self._raw + try: + return self._raw + except AttributeError: + self.online_update() + return self._raw def name(self): r""" @@ -793,7 +861,7 @@ def name(self): sage: s.name() 'The characteristic sequence of 42 plus one, starting from 38.' """ - return self._fields['N'][0] + return self._field('N')[0] def old_IDs(self): r""" @@ -820,7 +888,7 @@ def old_IDs(self): sage: s.old_IDs() ('M9999', 'N9999') """ - return tuple(self._fields['I'][0].split(' ')) + return tuple(self._field('I')[0].split(' ')) def offsets(self): r""" @@ -855,7 +923,7 @@ def offsets(self): sage: s.offsets() (38, 4) """ - return to_tuple(self._fields['O'][0]) + return to_tuple(self._field('O')[0]) def author(self): r""" @@ -879,7 +947,7 @@ def author(self): sage: s.author() 'Anonymous.' """ - return self._fields['A'][0] + return self._field('A')[0] def keywords(self): r""" @@ -907,7 +975,7 @@ def keywords(self): sage: s.keywords() ('nonn', 'hard') """ - return tuple(self._fields['K'][0].split(',')) + return tuple(self._field('K')[0].split(',')) def natural_object(self): r""" @@ -1150,7 +1218,7 @@ def first_terms(self, number=None): (1, 1, 1, 1, 2) """ fields = ['S', 'T', 'U'] - return to_tuple(" ".join(flatten([self._fields[a] for a in fields])))[:number] + return to_tuple(" ".join(flatten([self._field(a) for a in fields])))[:number] def _repr_(self): r""" @@ -1379,7 +1447,7 @@ def references(self): sage: s.references()[1] 'Lewis Carroll, The Hunting of the Snark.' """ - return FancyTuple(self._fields['D']) + return FancyTuple(self._field('D')) def links(self, browse=None, format='guess'): r""" @@ -1439,15 +1507,15 @@ def links(self, browse=None, format='guess'): else: return self.links(format='url') elif format == 'raw': - return FancyTuple(self._fields['H']) + return FancyTuple(self._field('H')) elif format == 'html': - return HtmlFragment(FancyTuple([url_absolute(_) for _ in self._fields['H']])) + return HtmlFragment(FancyTuple([url_absolute(_) for _ in self._field('H')])) elif format == 'url': - url_list = flatten([_urls(url_absolute(string)) for string in self._fields['H']]) + url_list = flatten([_urls(url_absolute(string)) for string in self._field('H')]) return FancyTuple(url_list) else: import webbrowser - url_list = flatten([_urls(url_absolute(string)) for string in self._fields['H']]) + url_list = flatten([_urls(url_absolute(string)) for string in self._field('H')]) if isinstance(browse, (int, Integer)): webbrowser.open(url_list[browse]) elif isinstance(browse, (list, tuple)): @@ -1480,7 +1548,7 @@ def formulas(self): 0: For n big enough, s(n+1) - s(n) = 0. """ - return FancyTuple(self._fields['F']) + return FancyTuple(self._field('F')) def cross_references(self, fetch=False): r""" @@ -1518,7 +1586,7 @@ def cross_references(self, fetch=False): sage: s.cross_references() ('A000042', 'A000024') """ - ref_list = re.findall('A[0-9]{6}', " ".join(self._fields['Y'])) + ref_list = re.findall('A[0-9]{6}', " ".join(self._field('Y'))) if fetch: return FancyTuple([oeis.find_by_id(_) for _ in ref_list]) else: @@ -1548,7 +1616,7 @@ def extensions_or_errors(self): 0: This sequence does not contain errors. """ - return FancyTuple(self._fields['E']) + return FancyTuple(self._field('E')) def examples(self): r""" @@ -1574,7 +1642,7 @@ def examples(self): sage: s.examples() 0: s(42) + s(43) = 0. """ - return FancyTuple(self._fields['e']) + return FancyTuple(self._field('e')) def comments(self): r""" @@ -1601,7 +1669,7 @@ def comments(self): 0: 42 is the product of the first 4 prime numbers, except 5 and perhaps 1. 1: Apart from that, i have no comment. """ - return FancyTuple(self._fields['C']) + return FancyTuple(self._field('C')) def url(self): r""" @@ -1753,11 +1821,11 @@ def programs(self, language='other'): 0: Mathematica neither. """ if language == "maple": - return FancyTuple(self._fields['p']) + return FancyTuple(self._field('p')) elif language == "mathematica": - return FancyTuple(self._fields['t']) + return FancyTuple(self._field('t')) else: - return FancyTuple(self._fields['o']) + return FancyTuple(self._field('o')) class FancyTuple(tuple): From 203f63ecc8ff52e2c0e45cd8fd76c27f8d2de19c Mon Sep 17 00:00:00 2001 From: Thierry Monteil Date: Fri, 18 Oct 2019 17:00:32 +0200 Subject: [PATCH 093/340] #28627 : different imaginary sequences must have different A-numbers --- src/sage/databases/oeis.py | 94 +++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 46 deletions(-) diff --git a/src/sage/databases/oeis.py b/src/sage/databases/oeis.py index a3808871fe1..1ee29ccf448 100644 --- a/src/sage/databases/oeis.py +++ b/src/sage/databases/oeis.py @@ -545,12 +545,14 @@ def browse(self): import webbrowser webbrowser.open(oeis_url) - def _imaginary_entry(self, keywords=''): + def _imaginary_entry(self, ident='A999999', keywords=''): r""" This is an imaginary entry of an OEIS sequence for offline tests. INPUT: + - ``ident`` - a string representing the A-number of the sequence. + - ``keywords`` - a string corresponding to the keyword field of the sequence. @@ -563,53 +565,54 @@ def _imaginary_entry(self, keywords=''): sage: oeis._imaginary_entry().split('\n')[0] '%I A999999 M9999 N9999' - sage: from sage.databases.oeis import OEISSequence sage: keywords = 'simon,cussonet' - sage: s = OEISSequence(oeis._imaginary_entry(keywords)) + sage: s = oeis.find_by_entry(entry=oeis._imaginary_entry(ident='A999998', keywords=keywords)) sage: ','.join(s.keywords()) == keywords True """ - return ('%I A999999 M9999 N9999\n' - '%S A999999 1,1,1,1,2,1,1,1,\n' - '%T A999999 1,1,1,1,1,1,1,1,1,\n' - '%U A999999 1,1,1,1,1,1,1,1,1\n' - '%N A999999 The characteristic sequence of 42 plus one, starting from 38.\n' - '%D A999999 Lewis Carroll, Alice\'s Adventures in Wonderland.\n' - '%D A999999 Lewis Carroll, The Hunting of the Snark.\n' - '%D A999999 Deep Thought, The Answer to the Ultimate Question of Life, The Universe, and Everything.\n' - '%H A999999 Wikipedia, 42 (number)\n' - '%H A999999 See. also trac ticket #42\n' - '%H A999999 Do not confuse with the sequence A000042 or the sequence A000024\n' - '%H A999999 The string http://42.com is not a link.\n' - '%F A999999 For n big enough, s(n+1) - s(n) = 0.\n' - '%Y A999999 Related sequences are A000042 and its friend A000024.\n' - '%A A999999 Anonymous.\n' - '%O A999999 38,4\n' - '%E A999999 This sequence does not contain errors.\n' - '%e A999999 s(42) + s(43) = 0.\n' - '%p A999999 Do not even try, Maple is not able to produce such a sequence.\n' - '%t A999999 Mathematica neither.\n' - '%o A999999 (Python)\n' - '%o A999999 def A999999(n):\n' - '%o A999999 assert(isinstance(n, (int, Integer))), "n must be an integer."\n' - '%o A999999 if n < 38:\n' - '%o A999999 raise ValueError("The value %s is not accepted." %str(n)))\n' - '%o A999999 elif n == 42:\n' - '%o A999999 return 2\n' - '%o A999999 else:\n' - '%o A999999 return 1\n' - '%K A999999 ' + keywords + '\n' - '%C A999999 42 is the product of the first 4 prime numbers, except 5 and perhaps 1.\n' - '%C A999999 Apart from that, i have no comment.') - - def _imaginary_sequence(self, keywords='sign,easy'): + return ('%I ' + ident + ' M9999 N9999\n' + '%S ' + ident + ' 1,1,1,1,2,1,1,1,\n' + '%T ' + ident + ' 1,1,1,1,1,1,1,1,1,\n' + '%U ' + ident + ' 1,1,1,1,1,1,1,1,1\n' + '%N ' + ident + ' The characteristic sequence of 42 plus one, starting from 38.\n' + '%D ' + ident + ' Lewis Carroll, Alice\'s Adventures in Wonderland.\n' + '%D ' + ident + ' Lewis Carroll, The Hunting of the Snark.\n' + '%D ' + ident + ' Deep Thought, The Answer to the Ultimate Question of Life, The Universe, and Everything.\n' + '%H ' + ident + ' Wikipedia, 42 (number)\n' + '%H ' + ident + ' See. also trac ticket #42\n' + '%H ' + ident + ' Do not confuse with the sequence A000042 or the sequence A000024\n' + '%H ' + ident + ' The string http://42.com is not a link.\n' + '%F ' + ident + ' For n big enough, s(n+1) - s(n) = 0.\n' + '%Y ' + ident + ' Related sequences are A000042 and its friend A000024.\n' + '%A ' + ident + ' Anonymous.\n' + '%O ' + ident + ' 38,4\n' + '%E ' + ident + ' This sequence does not contain errors.\n' + '%e ' + ident + ' s(42) + s(43) = 0.\n' + '%p ' + ident + ' Do not even try, Maple is not able to produce such a sequence.\n' + '%t ' + ident + ' Mathematica neither.\n' + '%o ' + ident + ' (Python)\n' + '%o ' + ident + ' def ' + ident + '(n):\n' + '%o ' + ident + ' assert(isinstance(n, (int, Integer))), "n must be an integer."\n' + '%o ' + ident + ' if n < 38:\n' + '%o ' + ident + ' raise ValueError("The value %s is not accepted." %str(n)))\n' + '%o ' + ident + ' elif n == 42:\n' + '%o ' + ident + ' return 2\n' + '%o ' + ident + ' else:\n' + '%o ' + ident + ' return 1\n' + '%K ' + ident + ' ' + keywords + '\n' + '%C ' + ident + ' 42 is the product of the first 4 prime numbers, except 5 and perhaps 1.\n' + '%C ' + ident + ' Apart from that, i have no comment.') + + def _imaginary_sequence(self, ident='A999999', keywords='sign,easy'): r""" This is the OEIS sequence corresponding to the imaginary entry. Its main purpose is to allow offline doctesting. INPUT: + - ``ident`` - a string representing the A-number of the sequence. + - ``keywords`` - string (default: 'sign,easy'), a list of words separated by commas. @@ -627,8 +630,7 @@ def _imaginary_sequence(self, keywords='sign,easy'): sage: s(42) 2 """ - return OEISSequence(self._imaginary_entry(keywords)) - + return self.find_by_entry(entry=self._imaginary_entry(ident=ident, keywords=keywords)) class OEISSequence(SageObject, UniqueRepresentation): r""" @@ -830,7 +832,7 @@ def raw_entry(self): TESTS:: sage: s = oeis._imaginary_sequence() - sage: s.raw_entry() == oeis._imaginary_entry('sign,easy') + sage: s.raw_entry() == oeis._imaginary_entry(keywords='sign,easy') True """ try: @@ -971,7 +973,7 @@ def keywords(self): sage: s.keywords() ('sign', 'easy') - sage: s = oeis._imaginary_sequence(keywords='nonn,hard') + sage: s = oeis._imaginary_sequence(ident='A999997', keywords='nonn,hard') sage: s.keywords() ('nonn', 'hard') """ @@ -1056,11 +1058,11 @@ def natural_object(self): TESTS:: - sage: s = oeis._imaginary_sequence('nonn,cofr') + sage: s = oeis._imaginary_sequence(ident='A999996', keywords='nonn,cofr') sage: type(s.natural_object()) - sage: s = oeis._imaginary_sequence('nonn') + sage: s = oeis._imaginary_sequence(ident='A999995', keywords='nonn') sage: s.natural_object().universe() Non negative integer semiring @@ -1124,7 +1126,7 @@ def is_finite(self): sage: s.is_finite() Unknown - sage: s = oeis._imaginary_sequence('nonn,finit') + sage: s = oeis._imaginary_sequence(ident='A999993', keywords='nonn,finit') sage: s.is_finite() True @@ -1170,7 +1172,7 @@ def is_full(self): sage: s.is_full() Unknown - sage: s = oeis._imaginary_sequence('nonn,full,finit') + sage: s = oeis._imaginary_sequence(ident='A999992', keywords='nonn,full,finit') sage: s.is_full() True """ @@ -1410,7 +1412,7 @@ def __iter__(self): ....: break 2 - sage: s = oeis._imaginary_sequence(keywords='sign,full') + sage: s = oeis._imaginary_sequence(ident='A999991', keywords='sign,full') sage: for i in s: pass """ for x in self.first_terms(): From 0ce1c0bdfa641e7e50c9689396f6eca7f4bb1d41 Mon Sep 17 00:00:00 2001 From: Thierry Monteil Date: Fri, 18 Oct 2019 17:01:27 +0200 Subject: [PATCH 094/340] #28627 : dedicated handling of dead sequences --- src/sage/databases/oeis.py | 50 +++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/src/sage/databases/oeis.py b/src/sage/databases/oeis.py index 1ee29ccf448..b174d084b18 100644 --- a/src/sage/databases/oeis.py +++ b/src/sage/databases/oeis.py @@ -734,6 +734,7 @@ def _field(self, key): for line in self.raw_entry().splitlines(): fields[line[1]].append(line[11:]) self._fields = fields + self.is_dead(warn_only=True) return self._fields[key] def id(self, format='A'): @@ -1087,6 +1088,53 @@ def natural_object(self): from sage.rings.integer_ring import ZZ return Sequence(self.first_terms(), ZZ) + def is_dead(self, warn_only=False): + r""" + Tells whether the sequence is dead (i.e. eroneous). + + INPUT: + + - warn_only - (bool, default: ``False``), whether to warn when the + sequence is dead instead of returning a boolean. + + EXAMPLES: + + A warn_only test is triggered as soon as some information on the + sequence is queried:: + + sage: s = oeis(17) + sage: s # optional -- internet + doctest:warning + ... + RuntimeWarning: This sequence is dead: "A000017: Erroneous version of A032522." + A000017: Erroneous version of A032522. + + TESTS:: + + sage: s.is_dead() # optional -- internet + True + + sage: t = oeis._imaginary_sequence() + sage: t.is_dead() + False + + sage: u = oeis._imaginary_sequence(ident='A999994', keywords='dead') + sage: u + doctest:warning + ... + RuntimeWarning: This sequence is dead: "A999994: The characteristic sequence of 42 plus one, starting from 38." + A999994: The characteristic sequence of 42 plus one, starting from 38. + + sage: u.is_dead() + True + """ + if warn_only: + if 'dead' in self.keywords(): + from warnings import warn + warn('This sequence is dead: "{}: {}"'.format(self.id(), self.name()), RuntimeWarning) + else: + return 'dead' in self.keywords() + def is_finite(self): r""" Tells whether the sequence is finite. @@ -1203,7 +1251,7 @@ def first_terms(self, number=None): sage: f.first_terms()[:10] # optional -- internet (0, 1, 1, 2, 3, 5, 8, 13, 21, 34) - Handle dead sequences: see :trac:`17330` :: + Handle dead sequences, see :trac:`17330` :: sage: oeis(5000).first_terms(12) # optional -- internet doctest:warning From afa283355917d1e09cc0d60663aa32d8f352928f Mon Sep 17 00:00:00 2001 From: Thierry Monteil Date: Fri, 18 Oct 2019 17:02:46 +0200 Subject: [PATCH 095/340] #28627 : replace obsolete warning with a note --- src/sage/databases/oeis.py | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/sage/databases/oeis.py b/src/sage/databases/oeis.py index b174d084b18..c77e06f298c 100644 --- a/src/sage/databases/oeis.py +++ b/src/sage/databases/oeis.py @@ -347,26 +347,20 @@ class OEIS: A073491: Numbers having no prime gaps in their factorization., A073492: Numbers having at least one prime gap in their factorization.] - .. WARNING:: + .. NOTE:: - The following will fetch the OEIS database twice (once for searching the - database, and once again for creating the sequence ``fibo``):: + The following will fetch the OEIS database only once:: sage: oeis([1,2,3,5,8,13]) # optional -- internet - ... - - sage: fibo = oeis('A000045') # optional -- internet - - Do not do this, it is slow, it costs bandwidth and server resources ! - Instead, do the following, to reuse the result of the search to create - the sequence:: + 0: A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1. + 1: A290689: Number of transitive rooted trees with n nodes. + 2: A027926: Triangular array T read by rows: T(n,0) = T(n,2n) = 1 for n >= 0; T(n,1) = 1 for n >= 1; T(n,k) = T(n-1,k-2) + T(n-1,k-1) for k = 2..2n-1, n >= 2. - sage: sorted(oeis([1,2,3,5,8,13]), key=lambda x: x.id()) # optional -- internet - [A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1., - A027926: Triangular array T read by rows: T(n,0) = T(n,2n) = 1 for n >= 0; T(n,1) = 1 for n >= 1; T(n,k) = T(n-1,k-2) + T(n-1,k-1) for k = 2..2n-1, n >= 2., - A290689: Number of transitive rooted trees with n nodes.] + sage: oeis('A000045') # optional -- internet + A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1. - sage: fibo = _[0] # optional -- internet + Indeed, due to some caching mechanism, the sequence is not re-created + when called from its ID. """ def __call__(self, query, max_results=3, first_result=0): From 446af9801c51e8b9d20cd5176bad6d9d494e57ce Mon Sep 17 00:00:00 2001 From: Thierry Monteil Date: Fri, 18 Oct 2019 17:03:22 +0200 Subject: [PATCH 096/340] #28627 : examples are intended for humans --- src/sage/databases/oeis.py | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/sage/databases/oeis.py b/src/sage/databases/oeis.py index c77e06f298c..53d3553d08f 100644 --- a/src/sage/databases/oeis.py +++ b/src/sage/databases/oeis.py @@ -296,13 +296,12 @@ class OEIS: The database can be searched by subsequence:: - sage: search = oeis([1,2,3,5,8,13]) # optional -- internet - sage: search = sorted(search, key=lambda x: x.id()); search # optional -- internet - [A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1., - A027926: Triangular array T read by rows: T(n,0) = T(n,2n) = 1 for n >= 0; T(n,1) = 1 for n >= 1; T(n,k) = T(n-1,k-2) + T(n-1,k-1) for k = 2..2n-1, n >= 2., - A290689: Number of transitive rooted trees with n nodes.] + sage: search = oeis([1,2,3,5,8,13]) ; search # optional -- internet + 0: A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1. + 1: A290689: Number of transitive rooted trees with n nodes. + 2: A027926: Triangular array T read by rows: T(n,0) = T(n,2n) = 1 for n >= 0; T(n,1) = 1 for n >= 1; T(n,k) = T(n-1,k-2) + T(n-1,k-1) for k = 2..2n-1, n >= 2. - sage: fibo = search[0] # optional -- internet + sage: fibo = search[0] # optional -- internet sage: fibo.name() # optional -- internet 'Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.' @@ -341,11 +340,11 @@ class OEIS: The database can be searched by description:: - sage: sorted(oeis('prime gap factorization', max_results=4), key=lambda x: x.id()) # optional --internet - [A073485: Product of any number of consecutive primes; squarefree numbers with no gaps in their prime factorization., - A073490: Number of prime gaps in factorization of n., - A073491: Numbers having no prime gaps in their factorization., - A073492: Numbers having at least one prime gap in their factorization.] + sage: oeis('prime gap factorization', max_results=4) # optional --internet + 0: A073491: Numbers having no prime gaps in their factorization. + 1: A073485: Product of any number of consecutive primes; squarefree numbers with no gaps in their prime factorization. + 2: A073490: Number of prime gaps in factorization of n. + 3: A073492: Numbers having at least one prime gap in their factorization. .. NOTE:: @@ -465,12 +464,12 @@ def find_by_description(self, description, max_results=3, first_result=0): EXAMPLES:: - sage: sorted(oeis.find_by_description('prime gap factorization'), key=lambda x: x.id()) # optional -- internet - [A073485: Product of any number of consecutive primes; squarefree numbers with no gaps in their prime factorization., - A073490: Number of prime gaps in factorization of n., - A073491: Numbers having no prime gaps in their factorization.] + sage: oeis.find_by_description('prime gap factorization') # optional -- internet + 0: A073491: Numbers having no prime gaps in their factorization. + 1: A073485: Product of any number of consecutive primes; squarefree numbers with no gaps in their prime factorization. + 2: A073490: Number of prime gaps in factorization of n. - sage: prime_gaps = _[1] ; prime_gaps # optional -- internet + sage: prime_gaps = _[2] ; prime_gaps # optional -- internet A073490: Number of prime gaps in factorization of n. :: From ecd06dd657ce0f97145af394fb2724565751f0fc Mon Sep 17 00:00:00 2001 From: Thierry Monteil Date: Fri, 18 Oct 2019 19:33:09 +0200 Subject: [PATCH 097/340] #28627 : fix coverage regression --- src/sage/databases/oeis.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/sage/databases/oeis.py b/src/sage/databases/oeis.py index 53d3553d08f..1f46e4d2e52 100644 --- a/src/sage/databases/oeis.py +++ b/src/sage/databases/oeis.py @@ -433,6 +433,13 @@ def find_by_entry(self, entry): OUTPUT: - The corresponding OEIS sequence. + + EXAMPLES:: + + sage: entry = '%I A262002\n%N A262002 L.g.f.: log( Sum_{n>=0} x^n/n! * Product_{k=1..n} (k^2 + 1) ).\n%K A262002 nonn' + sage: s = oeis.find_by_entry(entry) + sage: s + A262002: L.g.f.: log( Sum_{n>=0} x^n/n! * Product_{k=1..n} (k^2 + 1) ). """ ident = entry[3:10] sequence = OEISSequence(ident=ident) @@ -661,6 +668,11 @@ class OEISSequence(SageObject, UniqueRepresentation): def __classcall__(cls, ident): r""" Canonicalize the ID of the sequence into a A-number. + + TESTS:: + + sage: oeis(45) is oeis('A000045') + True """ if not isinstance(ident, str): ident = str(ident) @@ -693,12 +705,12 @@ def online_update(self): TESTS:: - sage: s = oeis._imaginary_sequence(ident='A004238') - sage: s - A004238: The characteristic sequence of 42 plus one, starting from 38. - sage: s.online_update() # optional -- internet - sage: s # optional -- internet - A004238: a(n) = 100*log(n) rounded to nearest integer. + sage: s = oeis._imaginary_sequence(ident='A004238') + sage: s + A004238: The characteristic sequence of 42 plus one, starting from 38. + sage: s.online_update() # optional -- internet + sage: s # optional -- internet + A004238: a(n) = 100*log(n) rounded to nearest integer. """ options = {'q': self._id, 'n': '1', 'fmt': 'text'} url = oeis_url + "search?" + urlencode(options) From c42c907f184264859fa6a5e37e523feb37568041 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Sat, 19 Oct 2019 22:33:26 +0200 Subject: [PATCH 098/340] method to obtain cone from Vrep and Hrep --- .../geometry/polyhedron/backend_normaliz.py | 154 +++++++++++++++++- 1 file changed, 152 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index 119e318e007..63bf4957d26 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -379,7 +379,10 @@ def _init_from_normaliz_data(self, data, normaliz_field=None, verbose=False): """ if normaliz_field is None: normaliz_field = QQ + cone = self._cone_from_normaliz_data(data, verbose) + self._init_from_normaliz_cone(cone, normaliz_field) + def _cone_from_normaliz_data(self, data, verbose=False): if verbose: import six if isinstance(verbose, six.string_types): @@ -401,8 +404,7 @@ def _init_from_normaliz_data(self, data, normaliz_field=None, verbose=False): import PyNormaliz cone = PyNormaliz.NmzCone(**data) assert cone, "{} did not return a cone".format(_format_function_call('PyNormaliz.NmzCone', **data)) - - self._init_from_normaliz_cone(cone, normaliz_field) + return cone def _is_zero(self, x): """ @@ -630,6 +632,154 @@ def nmz_ieqs_eqns_QQ(ieqs, eqns): data["number_field"] = number_field_data self._init_from_normaliz_data(data, normaliz_field=normaliz_field, verbose=verbose) + def _cone_from_Vrepresentation_and_Hrepresentation(self, vertices, rays, ieqs, eqns, verbose=False): + r""" + Construct cone from V-representation data and H-representation data. + + INPUT: + + - ``vertices`` -- list of point; each point can be specified + as any iterable container of + :meth:`~sage.geometry.polyhedron.base.base_ring` elements + + - ``rays`` -- list of rays; each ray can be specified as any + iterable container of + :meth:`~sage.geometry.polyhedron.base.base_ring` elements + + - ``ieqs`` -- list of inequalities; each line can be specified + as any iterable container of + :meth:`~sage.geometry.polyhedron.base.base_ring` elements + + - ``eqns`` -- list of equalities; each line can be specified + as any iterable container of + :meth:`~sage.geometry.polyhedron.base.base_ring` elements + + - ``verbose`` -- boolean (default: ``False``); whether to print + verbose output for debugging purposes + + EXAMPLES:: + + sage: P = polytopes.hypercube(4,backend='normaliz') * Polyhedron(rays=[[0,1]]) * Polyhedron(lines=[[1,0]]) # optional - pynormaliz + sage: P # optional - pynormaliz + A 6-dimensional polyhedron in ZZ^8 defined as the convex hull of 16 vertices, 1 ray, 1 line + + sage: cone = P._cone_from_Vrepresentation_and_Hrepresentation(P.vertices(),P.rays(),P.inequalities(),P.equations()) # optional - pynormaliz + sage: import PyNormaliz # optional - pynormaliz + sage: PyNormaliz.NmzIsComputed(cone, "VerticesOfPolyhedron") # optional - pynormaliz + True + sage: PyNormaliz.NmzIsComputed(cone, "ExtremeRays") # optional - pynormaliz + True + sage: PyNormaliz.NmzIsComputed(cone, "MaximalSubspace") # optional - pynormaliz + False + sage: PyNormaliz.NmzIsComputed(cone, "SupportHyperplanes") # optional - pynormaliz + True + sage: PyNormaliz.NmzIsComputed(cone, "Equations") # optional - pynormaliz + False + + + TESTS:: + + sage: def test_poly(P): + ....: cone = P._cone_from_Vrepresentation_and_Hrepresentation(P.vertices(),P.rays(),P.inequalities(),P.equations()) + ....: cone2 = P._normaliz_cone + ....: args = ['Equations','VerticesOfPolyhedron','ExtremeRays','SupportHyperplanes','MaximalSubspace'] + ....: return all(P._nmz_result(cone,arg) == P._nmz_result(cone2,arg) for arg in args) + sage: test_poly(polytopes.simplex(backend='normaliz')) # optional - pynormaliz + True + sage: test_poly(polytopes.dodecahedron(backend='normaliz')) # optional - pynormaliz + True + sage: test_poly(Polyhedron(vertices=[[1,0],[0,1]],rays=[[1,1]], backend='normaliz')) # optional - pynormaliz + True + sage: test_poly(Polyhedron(vertices=[[0,0,0],[0,1,1],[1,0,1],[-1,-1,1]],rays=[[0,0,1]], backend='normaliz')) # optional - pynormaliz + True + sage: test_poly(Polyhedron(vertices=[[-1,0],[1,0]],lines=[[0,1]], backend='normaliz')) # optional - pynormaliz + True + """ + def vert_ray_QQ(vertices, rays): + nmz_vertices = [] + for v in vertices: + d = LCM_list([denominator(v_i) for v_i in v]) + dv = [ d*v_i for v_i in v ] + nmz_vertices.append(dv + [d]) + nmz_rays = [] + for r in rays: + d = LCM_list([denominator(r_i) for r_i in r]) + dr = [ d*r_i for r_i in r ] + nmz_rays.append(dr + [0]) + return nmz_vertices, nmz_rays + + def nmz_ieqs_eqns_QQ(ieqs, eqns): + nmz_ieqs = [] + for ieq in ieqs: + d = LCM_list([denominator(ieq_i) for ieq_i in ieq]) + dieq = [ ZZ(d*ieq_i) for ieq_i in ieq ] + b = dieq[0] + A = dieq[1:] + nmz_ieqs.append(A + [b]) + nmz_eqns = [] + for eqn in eqns: + d = LCM_list([denominator(eqn_i) for eqn_i in eqn]) + deqn = [ ZZ(d*eqn_i) for eqn_i in eqn ] + b = deqn[0] + A = deqn[1:] + nmz_eqns.append(A + [b]) + return nmz_ieqs, nmz_eqns + + def vert_ray_NF(vertices, rays): + h_vertices = [ list(v) + [1] for v in vertices ] + h_rays = [ list(r) + [0] for r in rays ] + return h_vertices, h_rays + + def nmz_ieqs_eqns_NF(ieqs, eqns): + nmz_ieqs = [] + for ieq in ieqs: + b = ieq[0] + A = ieq[1:] + nmz_ieqs.append(list(A) + [b]) + nmz_eqns = [] + for eqn in eqns: + b = eqn[0] + A = eqn[1:] + nmz_eqns.append(list(A) + [b]) + return nmz_ieqs, nmz_eqns + + if vertices is None: + vertices = [] + if rays is None: + rays = [] + if ieqs is None: + ieqs = [] + if eqns is None: + eqns = [] + + (nmz_vertices, nmz_rays), normaliz_field \ + = self._compute_nmz_data_lists_and_field((vertices, rays), + vert_ray_QQ, + vert_ray_NF) + + (nmz_ieqs, nmz_eqns), normaliz_field \ + = self._compute_nmz_data_lists_and_field((ieqs, eqns), + nmz_ieqs_eqns_QQ, + nmz_ieqs_eqns_NF) + + if not nmz_vertices and not nmz_rays: + # Special case to avoid: + # error: Some error in the normaliz input data detected: + # All input matrices empty! + return None + else: + data = {"extreme_rays": nmz_vertices + nmz_rays, + "equations": nmz_eqns, + "support_hyperplanes": nmz_ieqs} + + ambient_dim = len(data["extreme_rays"][0]) + data["dehomogenization"] = [[0]*(ambient_dim-1) + [1]] + + number_field_data = self._number_field_triple(normaliz_field) + if number_field_data: + data["number_field"] = number_field_data + return self._cone_from_normaliz_data(data, verbose=verbose) + def _compute_nmz_data_lists_and_field(self, data_lists, convert_QQ, convert_NF): r""" Compute data lists in Normaliz format and the number field to use with Normaliz. From cc17f0741bb323f06c6a65c5e0f08f1ea73a5655 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Mon, 21 Oct 2019 11:11:43 +0200 Subject: [PATCH 099/340] added documentation to cone from normaliz data --- src/sage/geometry/polyhedron/backend_normaliz.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index 63bf4957d26..d3b7cec8bde 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -359,7 +359,7 @@ def _init_from_normaliz_data(self, data, normaliz_field=None, verbose=False): sage: p = Polyhedron(backend='normaliz', ambient_dim=2) # optional - pynormaliz sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_QQ_normaliz # optional - pynormaliz - sage: data = {'inhom_inequalities': [[-1, 2, 0], [0, 0, 1], [2, -1, 0]]} # optional - pynormaliz + sage: data = {'inhom_inequalities': [[-1, 2, 0], [0, 0, 1], [2, -1, 0]]} # optional - pynormaliz sage: Polyhedron_QQ_normaliz._init_from_normaliz_data(p, data) # optional - pynormaliz sage: p.inequalities_list() # optional - pynormaliz [[0, -1, 2], [0, 2, -1]] @@ -383,6 +383,18 @@ def _init_from_normaliz_data(self, data, normaliz_field=None, verbose=False): self._init_from_normaliz_cone(cone, normaliz_field) def _cone_from_normaliz_data(self, data, verbose=False): + """ + Construct a normaliz cone from ``data`` (a dictionary). + + EXAMPLES:: + + sage: p = Polyhedron(backend='normaliz', ambient_dim=2) # optional - pynormaliz + sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_QQ_normaliz # optional - pynormaliz + sage: data = {'inhom_inequalities': [[-1, 2, 0], [0, 0, 1], [2, -1, 0]]} # optional - pynormaliz + sage: cone = Polyhedron_QQ_normaliz._cone_from_normaliz_data(p, data) # optional - pynormaliz + sage: p._nmz_result(cone,'SupportHyperplanes') # optional - pynormaliz + [[-1L, 2L, 0L], [0L, 0L, 1L], [2L, -1L, 0L]] + """ if verbose: import six if isinstance(verbose, six.string_types): @@ -664,7 +676,7 @@ def _cone_from_Vrepresentation_and_Hrepresentation(self, vertices, rays, ieqs, e A 6-dimensional polyhedron in ZZ^8 defined as the convex hull of 16 vertices, 1 ray, 1 line sage: cone = P._cone_from_Vrepresentation_and_Hrepresentation(P.vertices(),P.rays(),P.inequalities(),P.equations()) # optional - pynormaliz - sage: import PyNormaliz # optional - pynormaliz + sage: import PyNormaliz # optional - pynormaliz sage: PyNormaliz.NmzIsComputed(cone, "VerticesOfPolyhedron") # optional - pynormaliz True sage: PyNormaliz.NmzIsComputed(cone, "ExtremeRays") # optional - pynormaliz From 47e2f5132cd19a730ab4668e965061e7f344a8ab Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Sun, 27 Oct 2019 14:56:54 +0100 Subject: [PATCH 100/340] copy method with naming --- src/sage/manifolds/differentiable/tensorfield.py | 15 +++++++++------ src/sage/manifolds/scalarfield.py | 11 ++++++++--- src/sage/tensor/modules/free_module_tensor.py | 13 +++++++++---- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/sage/manifolds/differentiable/tensorfield.py b/src/sage/manifolds/differentiable/tensorfield.py index 774e9d465e0..04b51461cac 100644 --- a/src/sage/manifolds/differentiable/tensorfield.py +++ b/src/sage/manifolds/differentiable/tensorfield.py @@ -1786,13 +1786,19 @@ def __setitem__(self, args, value): frame = self._domain._def_frame self.set_comp(frame)[args] = value - def copy(self): + def copy(self, name=None, latex_name=None): r""" Return an exact copy of ``self``. + INPUT: + + - ``name`` -- (default: ``None``) name given to the copy + - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the + copy; if none is provided, the LaTeX symbol is set to ``name`` + .. NOTE:: - The name and the derived quantities are copied, too. + The name and the derived quantities are not copied. EXAMPLES: @@ -1832,7 +1838,7 @@ def copy(self): resu = self._new_instance() for dom, rst in self._restrictions.items(): resu._restrictions[dom] = rst.copy() - resu.set_name(name=self._name, latex_name=self._latex_name) + resu.set_name(name=name, latex_name=latex_name) return resu def _common_subdomains(self, other): @@ -2033,7 +2039,6 @@ def __pos__(self): resu = self._new_instance() for dom, rst in self._restrictions.items(): resu._restrictions[dom] = + rst - ### # Compose names: from sage.tensor.modules.format_utilities import (format_unop_txt, format_unop_latex) @@ -2081,7 +2086,6 @@ def __neg__(self): resu = self._new_instance() for dom, rst in self._restrictions.items(): resu._restrictions[dom] = - rst - ### # Compose names: from sage.tensor.modules.format_utilities import (format_unop_txt, format_unop_latex) @@ -2280,7 +2284,6 @@ def _rmul_(self, scalar): resu = self._new_instance() for dom, rst in self._restrictions.items(): resu._restrictions[dom] = scalar.restrict(dom) * rst - ### # Compose names: from sage.tensor.modules.format_utilities import (format_mul_txt, format_mul_latex) diff --git a/src/sage/manifolds/scalarfield.py b/src/sage/manifolds/scalarfield.py index d81fd655b34..cab644f0484 100644 --- a/src/sage/manifolds/scalarfield.py +++ b/src/sage/manifolds/scalarfield.py @@ -1439,10 +1439,16 @@ def domain(self): """ return self._domain - def copy(self): + def copy(self, name=None, latex_name=None): r""" Return an exact copy of the scalar field. + INPUT: + + - ``name`` -- (default: ``None``) name given to the copy + - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the + copy; if none is provided, the LaTeX symbol is set to ``name`` + EXAMPLES: Copy on a 2-dimensional manifold:: @@ -1461,8 +1467,7 @@ def copy(self): False """ - result = type(self)(self.parent(), name=self._name, - latex_name=self._latex_name) + result = type(self)(self.parent(), name=name, latex_name=latex_name) for chart, funct in self._express.items(): result._express[chart] = funct.copy() return result diff --git a/src/sage/tensor/modules/free_module_tensor.py b/src/sage/tensor/modules/free_module_tensor.py index de55085a002..678ebd38648 100644 --- a/src/sage/tensor/modules/free_module_tensor.py +++ b/src/sage/tensor/modules/free_module_tensor.py @@ -1478,11 +1478,17 @@ def __setitem__(self, args, value): self.set_comp(basis)[args] = value - def copy(self): + def copy(self, name=None, latex_name=None): r""" Return an exact copy of ``self``. - The name and the derived quantities are copied, too. + The name and the derived quantities are not copied. + + INPUT: + + - ``name`` -- (default: ``None``) name given to the copy + - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the + copy; if none is provided, the LaTeX symbol is set to ``name`` EXAMPLES: @@ -1512,7 +1518,7 @@ def copy(self): """ resu = self._new_instance() - resu.set_name(name=self._name, latex_name=self._latex_name) + resu.set_name(name=name, latex_name=latex_name) for basis, comp in self._components.items(): resu._components[basis] = comp.copy() return resu @@ -1973,7 +1979,6 @@ def _rmul_(self, other): result = self._new_instance() for basis in self._components: result._components[basis] = other * self._components[basis] - ### # If other has a name, set the name of the result: try: from .format_utilities import format_mul_txt, format_mul_latex From f55b881b1126c44b11f5cb0b6b5157721cd75983 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Sun, 27 Oct 2019 15:28:23 +0100 Subject: [PATCH 101/340] Doctest adapted --- src/sage/manifolds/differentiable/diff_form.py | 4 ++-- src/sage/manifolds/differentiable/mixed_form.py | 16 +++++++++++----- src/sage/manifolds/differentiable/tensorfield.py | 8 ++++---- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/sage/manifolds/differentiable/diff_form.py b/src/sage/manifolds/differentiable/diff_form.py index 2416ba5108d..08113134241 100644 --- a/src/sage/manifolds/differentiable/diff_form.py +++ b/src/sage/manifolds/differentiable/diff_form.py @@ -511,7 +511,7 @@ def wedge(self, other): sage: f.add_expr_by_continuation(c_uv, W) sage: t = a.wedge(f) sage: t.display() - x*y dx + x^2 dy + f*a = x*y dx + x^2 dy """ if other._tensor_rank == 0: @@ -1430,7 +1430,7 @@ def wedge(self, other): sage: f = M.scalar_field(x, name='f') sage: t = a.wedge(f) sage: t.display() - 2*x dx + (x^2 + x) dy + x*y*z dz + f*a = 2*x dx + (x^2 + x) dy + x*y*z dz """ if other._tensor_rank == 0: diff --git a/src/sage/manifolds/differentiable/mixed_form.py b/src/sage/manifolds/differentiable/mixed_form.py index f50e7371ee0..9405c1888dc 100644 --- a/src/sage/manifolds/differentiable/mixed_form.py +++ b/src/sage/manifolds/differentiable/mixed_form.py @@ -943,7 +943,7 @@ def exterior_derivative(self): return resu - def copy(self): + def copy(self, name=None, latex_name=None): r""" Return an exact copy of ``self``. @@ -951,6 +951,12 @@ def copy(self): The name and names of the components are not copied. + INPUT: + + - ``name`` -- (default: ``None``) name given to the copy + - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the + copy; if none is provided, the LaTeX symbol is set to ``name`` + EXAMPLES: Initialize a 2-dimensional manifold and differential forms:: @@ -981,9 +987,9 @@ def copy(self): different name, but has the very same values:: sage: B = A.copy(); B.disp() - A = f + omega + zero + (unnamed scalar field) + (unnamed 1-form) + (unnamed 2-form) sage: B.disp(e_uv) - A = [1/2*u + 1/2*v] + [(1/4*u + 1/4*v) du + (1/4*u + 1/4*v) dv] + [0] + [1/2*u + 1/2*v] + [(1/4*u + 1/4*v) du + (1/4*u + 1/4*v) dv] + [0] sage: A == B True sage: A is B @@ -998,12 +1004,12 @@ def copy(self): sage: A.disp(e_xy) A = [x] + [y dx] + [0] sage: B.disp(e_xy) - A = [x] + [x dx] + [0] + [x] + [x dx] + [0] """ resu_comp = [form.copy() for form in self._comp] resu = type(self)(self.parent(), comp=resu_comp) - resu.set_name(name=self._name, latex_name=self._latex_name) + resu.set_name(name=name, latex_name=latex_name) return resu def __setitem__(self, index, values): diff --git a/src/sage/manifolds/differentiable/tensorfield.py b/src/sage/manifolds/differentiable/tensorfield.py index 04b51461cac..0d584e5d1f9 100644 --- a/src/sage/manifolds/differentiable/tensorfield.py +++ b/src/sage/manifolds/differentiable/tensorfield.py @@ -1817,10 +1817,10 @@ def copy(self, name=None, latex_name=None): sage: t[e_xy,:] = [[x+y, 0], [2, 1-y]] sage: t.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) sage: s = t.copy(); s - Tensor field t of type (1,1) on - the 2-dimensional differentiable manifold M + Tensor field of type (1,1) on the 2-dimensional differentiable + manifold M sage: s.display(e_xy) - t = (x + y) d/dx*dx + 2 d/dy*dx + (-y + 1) d/dy*dy + (x + y) d/dx*dx + 2 d/dy*dx + (-y + 1) d/dy*dy sage: s == t True @@ -1830,7 +1830,7 @@ def copy(self, name=None, latex_name=None): sage: t.display(e_xy) t = -d/dx*dx + 2 d/dy*dx + (-y + 1) d/dy*dy sage: s.display(e_xy) - t = (x + y) d/dx*dx + 2 d/dy*dx + (-y + 1) d/dy*dy + (x + y) d/dx*dx + 2 d/dy*dx + (-y + 1) d/dy*dy sage: s == t False From eb92e6aa9a646360ea7a33c2bc27055c7386dc08 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Tue, 29 Oct 2019 14:35:51 +0100 Subject: [PATCH 102/340] Doctest fixed --- src/sage/manifolds/differentiable/tensorfield.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/manifolds/differentiable/tensorfield.py b/src/sage/manifolds/differentiable/tensorfield.py index 9dbb9fb1acb..8787c9360d3 100644 --- a/src/sage/manifolds/differentiable/tensorfield.py +++ b/src/sage/manifolds/differentiable/tensorfield.py @@ -258,7 +258,7 @@ class TensorField(ModuleElement): sage: t.parent().base_ring() is f.parent() True sage: s = f*t; s # long time - Tensor field of type (0,2) on the 2-dimensional differentiable + Tensor field f*t of type (0,2) on the 2-dimensional differentiable manifold S^2 sage: s[[0,0]] == f*t[[0,0]] # long time True From e16951ee794cb76aefa181103ae7d3a07d5e7bcb Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Thu, 31 Oct 2019 08:45:53 +0100 Subject: [PATCH 103/340] Deprecation notice for GraphicsArray import from sage.plot.graphics --- src/sage/plot/graphics.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/sage/plot/graphics.py b/src/sage/plot/graphics.py index 032ae17c6f6..a967f741167 100644 --- a/src/sage/plot/graphics.py +++ b/src/sage/plot/graphics.py @@ -3316,3 +3316,27 @@ def description(self): data.append([g_zorder, g_str, g]) data.sort() return '\n'.join(g[1] for g in data) + +# Deprecation notice for GraphicsArray import +def GraphicsArray(*args, **kwargs): + r""" + This is deprecated (see :trac:`28675`). + Use :class:`sage.plot.multigraphics.GraphicsArray` instead. + + TESTS:: + + sage: from sage.plot.graphics import GraphicsArray + sage: c = circle((0,0), 1) + sage: G = GraphicsArray([c, c]) + doctest:...: DeprecationWarning: GraphicsArray must be imported from sage.plot.multigraphics and no longer from sage.plot.graphics. + See https://trac.sagemath.org/28675 for details. + sage: G + Graphics Array of size 1 x 2 + + """ + from .multigraphics import GraphicsArray as NewGraphicsArray + from sage.misc.superseded import deprecation + deprecation(28675, "GraphicsArray must be imported from " + "sage.plot.multigraphics and no longer from " + "sage.plot.graphics.") + return NewGraphicsArray(*args, **kwargs) From 5b2eee2c3ef6f6d7613255b746e08beca7e99e23 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Fri, 1 Nov 2019 11:48:53 +0100 Subject: [PATCH 104/340] 'copy' with individual naming --- src/sage/manifolds/section.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/sage/manifolds/section.py b/src/sage/manifolds/section.py index adec2ab180c..67602e0e452 100644 --- a/src/sage/manifolds/section.py +++ b/src/sage/manifolds/section.py @@ -1411,13 +1411,19 @@ def __setitem__(self, args, value): frame = self._smodule.default_frame() self.set_comp(frame)[args] = value - def copy(self): + def copy(self, name=None, latex_name=None): r""" Return an exact copy of ``self``. + INPUT: + + - ``name`` -- (default: ``None``) name given to the copy + - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the + copy; if none is provided, the LaTeX symbol is set to ``name`` + .. NOTE:: - The name and the derived quantities are copied, too. + The name and the derived quantities are not copied. EXAMPLES: @@ -1442,10 +1448,10 @@ def copy(self): sage: s[fU,:] = [2, 1-y] sage: s.add_comp_by_continuation(fV, U.intersection(V), c_uv) sage: t = s.copy(); t - Section s on the 2-dimensional topological manifold M with values in + Section on the 2-dimensional topological manifold M with values in the real vector bundle E of rank 2 sage: t.display(fU) - s = 2 (phi_U^*e_1) + (-y + 1) (phi_U^*e_2) + 2 (phi_U^*e_1) + (-y + 1) (phi_U^*e_2) sage: t == s True @@ -1455,7 +1461,7 @@ def copy(self): sage: s.display(fU) s = -(phi_U^*e_1) + (-y + 1) (phi_U^*e_2) sage: t.display(fU) - s = 2 (phi_U^*e_1) + (-y + 1) (phi_U^*e_2) + 2 (phi_U^*e_1) + (-y + 1) (phi_U^*e_2) sage: t == s False @@ -1463,11 +1469,8 @@ def copy(self): resu = self._new_instance() for dom, rst in self._restrictions.items(): resu._restrictions[dom] = rst.copy() - ### # Propagate names to all restrictions - resu_name = self._name - resu_latex = self._latex_name - resu.set_name(name=resu_name, latex_name=resu_latex) + resu.set_name(name=name, latex_name=latex_name) return resu def _common_subdomains(self, other): From be4619e3efd1dfe119ace84f54a86c1222c888f8 Mon Sep 17 00:00:00 2001 From: Edgar Costa Date: Fri, 1 Nov 2019 11:55:37 -0400 Subject: [PATCH 105/340] fixing precision stuff --- .../schemes/elliptic_curves/ell_tate_curve.py | 41 ++++++++----------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_tate_curve.py b/src/sage/schemes/elliptic_curves/ell_tate_curve.py index caa02f23722..95d95471e3b 100644 --- a/src/sage/schemes/elliptic_curves/ell_tate_curve.py +++ b/src/sage/schemes/elliptic_curves/ell_tate_curve.py @@ -174,12 +174,9 @@ def parameter(self, prec=20): sage: eq.parameter(prec=5) 3*5^3 + 3*5^4 + 2*5^5 + 2*5^6 + 3*5^7 + O(5^8) """ - try: - qE = self._q - if qE.absolute_precision() >= prec: - return qE - except AttributeError: - pass + qE = getattr(self, "_q", None) + if qE and qE.precision_relative() >= prec: + return Qp(self._p, prec=prec)(qE) E4 = EisensteinForms(weight=4).basis()[0] Delta = CuspForms(weight=12).basis()[0] @@ -222,19 +219,16 @@ def curve(self, prec=20): (2*5^3+5^4+2*5^5+5^7+O(5^8)) over 5-adic Field with capped relative precision 5 """ - try: - Eq = self.__curve - if Eq.a6().absolute_precision() >= prec: - return Eq - except AttributeError: - pass + + Eq = getattr(self, "__curve", None) + if Eq and Eq.a6().precision_relative() >= prec: + return Eq.change_ring(Qp(self._p, prec)) qE = self.parameter(prec=prec) precp = prec + 2 - R = qE.parent() - tate_a4 = -5 * self.__sk(3, precp) tate_a6 = (tate_a4 - 7 * self.__sk(5, precp)) / 12 + R = qE.parent() Eq = EllipticCurve([R.one(), R.zero(), R.zero(), R(tate_a4), R(tate_a6)]) self.__curve = Eq return Eq @@ -259,12 +253,10 @@ def _Csquare(self, prec=20): sage: eq._Csquare(prec=5) 4 + 2*5^2 + 2*5^4 + O(5^5) """ - try: - Csq = self.__Csquare - if Csq.absolute_precision() >= prec: - return Csq - except AttributeError: - pass + + Csq = getattr(self, "__Csquare", None) + if Csq and Csq.precision_relative() >= prec: + return Csq Eq = self.curve(prec=prec) tateCsquare = Eq.c6() * self._E.c4() / Eq.c4() / self._E.c6() @@ -316,7 +308,7 @@ def is_split(self): """ return self._Csquare().is_square() - def parametrisation_onto_tate_curve(self, u, prec=20): + def parametrisation_onto_tate_curve(self, u, prec=None): r""" Given an element `u` in `\QQ_p^{\times}`, this computes its image on the Tate curve under the `p`-adic uniformisation of `E`. @@ -332,9 +324,12 @@ def parametrisation_onto_tate_curve(self, u, prec=20): sage: eq = EllipticCurve('130a1').tate_curve(5) sage: eq.parametrisation_onto_tate_curve(1+5+5^2+O(5^10)) - (5^-2 + 4*5^-1 + 1 + 2*5 + 3*5^2 + 2*5^5 + 3*5^6 + O(5^7) : - 4*5^-3 + 2*5^-1 + 4 + 2*5 + 3*5^4 + 2*5^5 + O(5^6) : 1 + O(5^20)) + (5^-2 + 4*5^-1 + 1 + 2*5 + 3*5^2 + 2*5^5 + 3*5^6 + O(5^7) : 4*5^-3 + 2*5^-1 + 4 + 2*5 + 3*5^4 + 2*5^5 + O(5^6) : 1 + O(5^10)) """ + if prec is None: + prec = u.precision_relative() + if prec > u.precision_relative(): + raise ValueError("Requested more precision than the precision of u") if u == 1: return self.curve(prec=prec)(0) From 2862adf3d228e21843826c504ac85397ddcc1dd7 Mon Sep 17 00:00:00 2001 From: Edgar Costa Date: Fri, 1 Nov 2019 16:22:34 -0400 Subject: [PATCH 106/340] making u a p-adic element --- src/sage/schemes/elliptic_curves/ell_tate_curve.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_tate_curve.py b/src/sage/schemes/elliptic_curves/ell_tate_curve.py index 95d95471e3b..19da9a6f060 100644 --- a/src/sage/schemes/elliptic_curves/ell_tate_curve.py +++ b/src/sage/schemes/elliptic_curves/ell_tate_curve.py @@ -308,7 +308,7 @@ def is_split(self): """ return self._Csquare().is_square() - def parametrisation_onto_tate_curve(self, u, prec=None): + def parametrisation_onto_tate_curve(self, u, prec=20): r""" Given an element `u` in `\QQ_p^{\times}`, this computes its image on the Tate curve under the `p`-adic uniformisation of `E`. @@ -326,12 +326,11 @@ def parametrisation_onto_tate_curve(self, u, prec=None): sage: eq.parametrisation_onto_tate_curve(1+5+5^2+O(5^10)) (5^-2 + 4*5^-1 + 1 + 2*5 + 3*5^2 + 2*5^5 + 3*5^6 + O(5^7) : 4*5^-3 + 2*5^-1 + 4 + 2*5 + 3*5^4 + 2*5^5 + O(5^6) : 1 + O(5^10)) """ - if prec is None: - prec = u.precision_relative() - if prec > u.precision_relative(): - raise ValueError("Requested more precision than the precision of u") if u == 1: return self.curve(prec=prec)(0) + u = Qp(self._p, prec)(u) + if prec > u.precision_relative(): + raise ValueError("Requested more precision than the precision of u") q = self.parameter(prec=prec) un = u * q ** (-(u.valuation() / q.valuation()).floor()) From cefc6cce9ac6baed4e7c160c06dc6e73066db9e8 Mon Sep 17 00:00:00 2001 From: Edgar Costa Date: Fri, 1 Nov 2019 16:22:55 -0400 Subject: [PATCH 107/340] reordering things --- src/sage/schemes/elliptic_curves/ell_tate_curve.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_tate_curve.py b/src/sage/schemes/elliptic_curves/ell_tate_curve.py index 19da9a6f060..4044f3da932 100644 --- a/src/sage/schemes/elliptic_curves/ell_tate_curve.py +++ b/src/sage/schemes/elliptic_curves/ell_tate_curve.py @@ -326,11 +326,11 @@ def parametrisation_onto_tate_curve(self, u, prec=20): sage: eq.parametrisation_onto_tate_curve(1+5+5^2+O(5^10)) (5^-2 + 4*5^-1 + 1 + 2*5 + 3*5^2 + 2*5^5 + 3*5^6 + O(5^7) : 4*5^-3 + 2*5^-1 + 4 + 2*5 + 3*5^4 + 2*5^5 + O(5^6) : 1 + O(5^10)) """ - if u == 1: - return self.curve(prec=prec)(0) u = Qp(self._p, prec)(u) if prec > u.precision_relative(): raise ValueError("Requested more precision than the precision of u") + if u == 1: + return self.curve(prec=prec)(0) q = self.parameter(prec=prec) un = u * q ** (-(u.valuation() / q.valuation()).floor()) From 95f35c530c3e4d4ec6677f3fcd8b5cf6cdece3f2 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Fri, 1 Nov 2019 13:26:11 -0700 Subject: [PATCH 108/340] trac 28685: upgrade beautifulsoup -> beautifulsoup4 --- build/pkgs/{beautifulsoup => beautifulsoup4}/type | 0 src/doc/en/thematic_tutorials/sws2rst.rst | 15 ++++++++++++++- src/sage/misc/package.py | 12 ++++++------ 3 files changed, 20 insertions(+), 7 deletions(-) rename build/pkgs/{beautifulsoup => beautifulsoup4}/type (100%) diff --git a/build/pkgs/beautifulsoup/type b/build/pkgs/beautifulsoup4/type similarity index 100% rename from build/pkgs/beautifulsoup/type rename to build/pkgs/beautifulsoup4/type diff --git a/src/doc/en/thematic_tutorials/sws2rst.rst b/src/doc/en/thematic_tutorials/sws2rst.rst index 6228a455b8f..1a6552b2518 100644 --- a/src/doc/en/thematic_tutorials/sws2rst.rst +++ b/src/doc/en/thematic_tutorials/sws2rst.rst @@ -8,6 +8,19 @@ Sage has a number of `thematic tutorials `_ and contains everything needed to turn a worksheet created in the `Sage notebook `_ (sagenb) into a tutorial. +.. WARNING:: + + The following will only work if Sage is built using Python 2 rather + than Python 3. As of version 9.0, the default is to build Sage with + Python 3. So either use an older version of Sage, or build a new + version of Sage with Python 2 by obtaining a Sage tarball and doing + + .. CODE-BLOCK:: shell-session + + $ make configure + $ ./configure --with-python=2 + $ make + * Once you have created a worksheet and are satisfied with the text and computations, download it to a directory. @@ -40,7 +53,7 @@ using the Mac app and have placed it in your Applications directory. files (which may be empty if there are no images). You can find help for ``sws2rst`` with the command - ``sage --sws2rst -h`` once you have installed beautifulsoup. + ``sage --sws2rst -h`` once you have installed beautifulsoup4. * In principle, such a file could be added directly to Sage's documentation (see the `developer's manual <../developer/index.html>`_). However, you probably diff --git a/src/sage/misc/package.py b/src/sage/misc/package.py index f65dcace062..5aabfc814ff 100644 --- a/src/sage/misc/package.py +++ b/src/sage/misc/package.py @@ -93,7 +93,7 @@ def pip_remote_version(pkg, pypi_url=DEFAULT_PYPI, ignore_URLError=False): :trac:`19213`):: sage: from sage.misc.package import pip_remote_version - sage: pip_remote_version('beautifulsoup') # optional - internet # not tested + sage: pip_remote_version('beautifulsoup4') # optional - internet # not tested u'...' These tests are reliable since the tested package does not exist:: @@ -140,7 +140,7 @@ def pip_installed_packages(): True sage: d['scipy'] # optional - build u'...' - sage: d['beautifulsoup'] # optional - build beautifulsoup + sage: d['beautifulsoup4'] # optional - build beautifulsoup4 u'...' """ with open(os.devnull, 'w') as devnull: @@ -199,14 +199,14 @@ def list_packages(*pkg_types, **opts): 'type': 'standard'} sage: L = list_packages('pip', local=True) # optional - build - sage: L['beautifulsoup'] # optional - build + sage: L['beautifulsoup4'] # optional - build {'installed': ..., 'installed_version': ..., 'remote_version': None, 'type': 'pip'} sage: L = list_packages('pip') # optional - build internet - sage: L['beautifulsoup'] # optional - build internet + sage: L['beautifulsoup4'] # optional - build internet {'installed': ..., 'installed_version': ..., 'remote_version': u'...', @@ -424,10 +424,10 @@ def optional_packages(): sage: installed, not_installed = optional_packages() # optional - build sage: 'ore_algebra' in installed+not_installed # optional - build True - sage: 'beautifulsoup' in installed+not_installed # optional - build + sage: 'beautifulsoup4' in installed+not_installed # optional - build True - sage: 'beautifulsoup' in installed # optional - build beautifulsoup + sage: 'beautifulsoup4' in installed # optional - build beautifulsoup4 True sage: 'ore_algebra' in installed # optional - build ore_algebra True From 58f126f2b8978c5da3c77c732753ca049a11ba14 Mon Sep 17 00:00:00 2001 From: Edgar Costa Date: Fri, 1 Nov 2019 17:02:11 -0400 Subject: [PATCH 109/340] making None the default prec, when another parameter is passed --- .../schemes/elliptic_curves/ell_tate_curve.py | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_tate_curve.py b/src/sage/schemes/elliptic_curves/ell_tate_curve.py index 4044f3da932..141480536f9 100644 --- a/src/sage/schemes/elliptic_curves/ell_tate_curve.py +++ b/src/sage/schemes/elliptic_curves/ell_tate_curve.py @@ -254,7 +254,7 @@ def _Csquare(self, prec=20): 4 + 2*5^2 + 2*5^4 + O(5^5) """ - Csq = getattr(self, "__Csquare", None) + Csq = getattr(self, "__csquare", None) if Csq and Csq.precision_relative() >= prec: return Csq @@ -308,7 +308,7 @@ def is_split(self): """ return self._Csquare().is_square() - def parametrisation_onto_tate_curve(self, u, prec=20): + def parametrisation_onto_tate_curve(self, u, prec=None): r""" Given an element `u` in `\QQ_p^{\times}`, this computes its image on the Tate curve under the `p`-adic uniformisation of `E`. @@ -323,9 +323,19 @@ def parametrisation_onto_tate_curve(self, u, prec=20): EXAMPLES:: sage: eq = EllipticCurve('130a1').tate_curve(5) + sage: eq.parametrisation_onto_tate_curve(1+5+5^2+O(5^10), prec=10) + (5^-2 + 4*5^-1 + 1 + 2*5 + 3*5^2 + 2*5^5 + 3*5^6 + O(5^7) : 4*5^-3 + 2*5^-1 + 4 + 2*5 + 3*5^4 + 2*5^5 + O(5^6) : 1 + O(5^10)) sage: eq.parametrisation_onto_tate_curve(1+5+5^2+O(5^10)) (5^-2 + 4*5^-1 + 1 + 2*5 + 3*5^2 + 2*5^5 + 3*5^6 + O(5^7) : 4*5^-3 + 2*5^-1 + 4 + 2*5 + 3*5^4 + 2*5^5 + O(5^6) : 1 + O(5^10)) + sage: eq.parametrisation_onto_tate_curve(1+5+5^2+O(5^10), prec=20) + Traceback (most recent call last): + ... + ValueError: Requested more precision than the precision of u + """ + + if prec is None: + prec = getattr(u, "precision_relative", lambda : 20)() u = Qp(self._p, prec)(u) if prec > u.precision_relative(): raise ValueError("Requested more precision than the precision of u") @@ -471,7 +481,7 @@ def lift(self, P, prec=20): Now we map the lift l back and check that it is indeed right.:: sage: eq.parametrisation_onto_original_curve(l) - (4*5^-2 + 2*5^-1 + 4*5 + 3*5^3 + 5^4 + 2*5^5 + 4*5^6 + O(5^7) : 2*5^-3 + 5^-1 + 4 + 4*5 + 5^2 + 3*5^3 + 4*5^4 + O(5^6) : 1 + O(5^20)) + (4*5^-2 + 2*5^-1 + 4*5 + 3*5^3 + 5^4 + 2*5^5 + 4*5^6 + O(5^7) : 2*5^-3 + 5^-1 + 4 + 4*5 + 5^2 + 3*5^3 + 4*5^4 + O(5^6) : 1 + O(5^10)) sage: e5 = e.change_ring(Qp(5,9)) sage: e5(12*P) (4*5^-2 + 2*5^-1 + 4*5 + 3*5^3 + 5^4 + 2*5^5 + 4*5^6 + O(5^7) : 2*5^-3 + 5^-1 + 4 + 4*5 + 5^2 + 3*5^3 + 4*5^4 + O(5^6) : 1 + O(5^9)) @@ -508,7 +518,7 @@ def lift(self, P, prec=20): u += z ** i / fac return u - def parametrisation_onto_original_curve(self, u, prec=20): + def parametrisation_onto_original_curve(self, u, prec=None): r""" Given an element `u` in `\QQ_p^{\times}`, this computes its image on the original curve under the `p`-adic uniformisation of `E`. @@ -525,7 +535,11 @@ def parametrisation_onto_original_curve(self, u, prec=20): sage: eq.parametrisation_onto_original_curve(1+5+5^2+O(5^10)) (4*5^-2 + 4*5^-1 + 4 + 2*5^3 + 3*5^4 + 2*5^6 + O(5^7) : 3*5^-3 + 5^-2 + 4*5^-1 + 1 + 4*5 + 5^2 + 3*5^5 + O(5^6) : - 1 + O(5^20)) + 1 + O(5^10)) + sage: eq.parametrisation_onto_original_curve(1+5+5^2+O(5^10), prec=20) + Traceback (most recent call last): + ... + ValueError: Requested more precision than the precision of u Here is how one gets a 4-torsion point on `E` over `\QQ_5`:: @@ -539,6 +553,9 @@ def parametrisation_onto_original_curve(self, u, prec=20): if not self.is_split(): raise ValueError("The curve must have split multiplicative " "reduction.") + if prec is None: + prec = getattr(u, "precision_relative", lambda : 20)() + P = self.parametrisation_onto_tate_curve(u, prec=prec) C, r, s, t = self._inverse_isomorphism(prec=prec) xx = r + C ** 2 * P[0] From d72dcf79b3b992d87dfe5a953d13c64e018c2d6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 3 Nov 2019 15:53:37 +0100 Subject: [PATCH 110/340] rich comparison for matrices --- src/sage/matrix/docs.py | 2 +- src/sage/matrix/matrix0.pyx | 2 +- src/sage/matrix/matrix_cyclo_dense.pyx | 2 +- src/sage/matrix/matrix_generic_dense.pyx | 2 +- src/sage/matrix/matrix_generic_sparse.pyx | 2 +- src/sage/matrix/matrix_gf2e_dense.pyx | 10 +++--- src/sage/matrix/matrix_gfpn_dense.pyx | 31 ++++++++++--------- src/sage/matrix/matrix_integer_dense.pyx | 21 ++++++------- src/sage/matrix/matrix_integer_sparse.pyx | 4 +-- src/sage/matrix/matrix_mod2_dense.pyx | 15 +++++---- .../matrix/matrix_modn_dense_template.pxi | 15 +++++---- src/sage/matrix/matrix_rational_dense.pyx | 12 ++++--- src/sage/matrix/matrix_rational_sparse.pyx | 4 +-- 13 files changed, 65 insertions(+), 57 deletions(-) diff --git a/src/sage/matrix/docs.py b/src/sage/matrix/docs.py index 97091b05d6d..6a76d6fb331 100644 --- a/src/sage/matrix/docs.py +++ b/src/sage/matrix/docs.py @@ -394,7 +394,7 @@ class derived from Matrix). They can be either sparse or dense, and * cdef _add_ -- add two matrices with identical parents * _matrix_times_matrix_c_impl -- multiply two matrices with compatible dimensions and identical base rings (both sparse or both dense) - * cpdef _cmp_ -- compare two matrices with identical parents + * cpdef _richcmp_ -- compare two matrices with identical parents * cdef _lmul_c_impl -- multiply this matrix on the right by a scalar, i.e., self * scalar * cdef _rmul_c_impl -- multiply this matrix on the left by a scalar, i.e., scalar * self * __copy__ diff --git a/src/sage/matrix/matrix0.pyx b/src/sage/matrix/matrix0.pyx index e062ac7e639..dc45925524b 100644 --- a/src/sage/matrix/matrix0.pyx +++ b/src/sage/matrix/matrix0.pyx @@ -5735,7 +5735,7 @@ cdef class Matrix(sage.structure.element.Matrix): # C[0] = (1 - m * (m - 1)/2) * C[2] - (m - 1) * C[1] C[0] = (1 - mm) * C[2] - (m - 1) * C[1] - cpdef int _cmp_(left, right) except -2: + cpdef _richcmp_(left, right, int op): """ Compare two matrices. diff --git a/src/sage/matrix/matrix_cyclo_dense.pyx b/src/sage/matrix/matrix_cyclo_dense.pyx index e472d676d5c..ae26af36122 100644 --- a/src/sage/matrix/matrix_cyclo_dense.pyx +++ b/src/sage/matrix/matrix_cyclo_dense.pyx @@ -454,7 +454,7 @@ cdef class Matrix_cyclo_dense(Matrix_dense): # x * cdef _sub_ # * cdef _mul_ # x * cdef _lmul_ -- scalar multiplication - # x * cpdef _cmp_ + # x * cpdef _richcmp_ # x * __neg__ # * __invert__ # x * __copy__ diff --git a/src/sage/matrix/matrix_generic_dense.pyx b/src/sage/matrix/matrix_generic_dense.pyx index 49322d88ff2..ad75514bc58 100644 --- a/src/sage/matrix/matrix_generic_dense.pyx +++ b/src/sage/matrix/matrix_generic_dense.pyx @@ -143,7 +143,7 @@ cdef class Matrix_generic_dense(matrix_dense.Matrix_dense): # LEVEL 2 functionality # X * cdef _add_ # * cdef _mul_ - # * cpdef _cmp_ + # * cpdef _richcmp_ # * __neg__ # * __invert__ # x * __copy__ diff --git a/src/sage/matrix/matrix_generic_sparse.pyx b/src/sage/matrix/matrix_generic_sparse.pyx index fba0f8292be..caac6abe66d 100644 --- a/src/sage/matrix/matrix_generic_sparse.pyx +++ b/src/sage/matrix/matrix_generic_sparse.pyx @@ -226,7 +226,7 @@ cdef class Matrix_generic_sparse(matrix_sparse.Matrix_sparse): # LEVEL 2 functionality # x * cdef _add_ # * cdef _mul_ - # * cpdef _cmp_ + # * cpdef _richcmp_ # * __neg__ # * __invert__ # x * __copy__ diff --git a/src/sage/matrix/matrix_gf2e_dense.pyx b/src/sage/matrix/matrix_gf2e_dense.pyx index da4a98f32c7..2ae9a82b66f 100644 --- a/src/sage/matrix/matrix_gf2e_dense.pyx +++ b/src/sage/matrix/matrix_gf2e_dense.pyx @@ -79,7 +79,7 @@ REFERENCES: # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** from cysignals.signals cimport sig_check, sig_on, sig_off @@ -87,6 +87,7 @@ from cysignals.signals cimport sig_check, sig_on, sig_off cimport sage.matrix.matrix_dense as matrix_dense from sage.structure.element cimport Matrix, Vector from sage.structure.element cimport ModuleElement, Element, RingElement +from sage.structure.richcmp cimport rich_to_bool from sage.rings.all import FiniteField as GF from sage.misc.randstate cimport randstate, current_randstate @@ -660,7 +661,7 @@ cdef class Matrix_gf2e_dense(matrix_dense.Matrix_dense): """ return self.__copy__() - cpdef int _cmp_(self, right) except -2: + cpdef _richcmp_(self, right, int op): """ EXAMPLES:: @@ -674,8 +675,9 @@ cdef class Matrix_gf2e_dense(matrix_dense.Matrix_dense): False """ if self._nrows == 0 or self._ncols == 0: - return 0 - return mzed_cmp(self._entries, (right)._entries) + return rich_to_bool(op, 0) + return rich_to_bool(op, mzed_cmp(self._entries, + (right)._entries)) def __copy__(self): """ diff --git a/src/sage/matrix/matrix_gfpn_dense.pyx b/src/sage/matrix/matrix_gfpn_dense.pyx index da6a8a87c95..ed9c0aaf09f 100644 --- a/src/sage/matrix/matrix_gfpn_dense.pyx +++ b/src/sage/matrix/matrix_gfpn_dense.pyx @@ -52,6 +52,7 @@ from sage.misc.randstate import current_randstate from sage.misc.randstate cimport randstate from sage.misc.cachefunc import cached_method, cached_function from sage.structure.element cimport Element, ModuleElement, RingElement, Matrix +from sage.structure.richcmp import rich_to_bool from .args cimport MatrixArgs_init from libc.string cimport memset, memcpy @@ -799,11 +800,11 @@ cdef class Matrix_gfpn_dense(Matrix_dense): ################## ## comparison - cpdef int _cmp_(left, right) except -2: + cpdef _richcmp_(left, right, int op): """ Compare two :class:`Matrix_gfpn_dense` matrices. - Of course, '<' and '>' doesn't make much sense for matrices. + Of course, '<' and '>' do not make much sense for matrices. EXAMPLES:: @@ -824,26 +825,26 @@ cdef class Matrix_gfpn_dense(Matrix_dense): cdef Matrix_gfpn_dense self = left cdef Matrix_gfpn_dense N = right if self is None or N is None: - return -1 + return rich_to_bool(op, -1) if self.Data == NULL: if N.Data == NULL: - return 0 + return rich_to_bool(op, 0) else: - return 1 + return rich_to_bool(op, 1) elif N.Data == NULL: - return -1 + return rich_to_bool(op, -1) if self.Data.Field != N.Data.Field: if self.Data.Field > N.Data.Field: - return 1 - return -1 + return rich_to_bool(op, 1) + return rich_to_bool(op, -1) if self.Data.Noc != N.Data.Noc: if self.Data.Noc > N.Data.Noc: - return 1 - return -1 + return rich_to_bool(op, 1) + return rich_to_bool(op, -1) if self.Data.Nor != N.Data.Nor: if self.Data.Nor > N.Data.Nor: - return 1 - return -1 + return rich_to_bool(op, 1) + return rich_to_bool(op, -1) cdef char* d1 = self.Data.Data cdef char* d2 = N.Data.Data @@ -854,9 +855,9 @@ cdef class Matrix_gfpn_dense(Matrix_dense): s2 = PyBytes_FromStringAndSize(d2, total_size) if s1 != s2: if s1 > s2: - return 1 - return -1 - return 0 + return rich_to_bool(op, 1) + return rich_to_bool(op, -1) + return rich_to_bool(op, 0) cpdef list _rowlist_(self, i, j=-1): """ diff --git a/src/sage/matrix/matrix_integer_dense.pyx b/src/sage/matrix/matrix_integer_dense.pyx index 1b001f337c5..3d5a70d24a7 100644 --- a/src/sage/matrix/matrix_integer_dense.pyx +++ b/src/sage/matrix/matrix_integer_dense.pyx @@ -77,6 +77,7 @@ from sage.arith.long cimport integer_check_long_py from sage.arith.power cimport generic_power from sage.structure.element cimport Element from sage.structure.proof.proof import get_flag as get_proof_flag +from sage.structure.richcmp cimport rich_to_bool from sage.misc.randstate cimport randstate, current_randstate from sage.matrix.matrix_rational_dense cimport Matrix_rational_dense @@ -586,7 +587,7 @@ cdef class Matrix_integer_dense(Matrix_dense): # x * cdef _add_ # x * cdef _sub_ # x * cdef _mul_ - # x * cpdef _cmp_ + # x * cpdef _richcmp_ # x * __neg__ # x * __invert__ -> SEE LEVEL 3 FUNCTIONALITIES # x * __copy__ @@ -975,8 +976,7 @@ cdef class Matrix_integer_dense(Matrix_dense): sig_off() return M - - cpdef int _cmp_(self, right) except -2: + cpdef _richcmp_(self, right, int op): r""" Compare ``self`` with ``right``, examining entries in lexicographic (row major) ordering. @@ -996,17 +996,18 @@ cdef class Matrix_integer_dense(Matrix_dense): cdef int k sig_on() - for i from 0 <= i < self._nrows: - for j from 0 <= j < self._ncols: - k = fmpz_cmp(fmpz_mat_entry(self._matrix,i,j),fmpz_mat_entry((right)._matrix,i,j)) + for i in range(self._nrows): + for j in range(self._ncols): + k = fmpz_cmp(fmpz_mat_entry(self._matrix,i,j), + fmpz_mat_entry((right)._matrix,i,j)) if k: sig_off() if k < 0: - return -1 + return rich_to_bool(op, -1) else: - return 1 + return rich_to_bool(op, 1) sig_off() - return 0 + return rich_to_bool(op, 0) # TODO: Implement better cdef _vector_times_matrix_(self, Vector v): @@ -1015,10 +1016,8 @@ cdef class Matrix_integer_dense(Matrix_dense): INPUT: - - ``v`` - a free module element. - OUTPUT: The vector times matrix product v\*A. EXAMPLES:: diff --git a/src/sage/matrix/matrix_integer_sparse.pyx b/src/sage/matrix/matrix_integer_sparse.pyx index 735e0bf2f1d..ea5e9b831ef 100644 --- a/src/sage/matrix/matrix_integer_sparse.pyx +++ b/src/sage/matrix/matrix_integer_sparse.pyx @@ -126,7 +126,7 @@ cdef class Matrix_integer_sparse(Matrix_sparse): # * cdef _add_ # * cdef _sub_ # * cdef _mul_ - # * cpdef _cmp_ + # * cpdef _richcmp_ # * __neg__ # * __invert__ # * __copy__ @@ -139,7 +139,7 @@ cdef class Matrix_integer_sparse(Matrix_sparse): # def _unpickle(self, data, int version): # use version >= 0 # cpdef _add_(self, right): # cdef _mul_(self, Matrix right): - # cpdef int _cmp_(self, Matrix right) except -2: + # cpdef _richcmp_(self, Matrix right, int op): # def __neg__(self): # def __invert__(self): # def __copy__(self): diff --git a/src/sage/matrix/matrix_mod2_dense.pyx b/src/sage/matrix/matrix_mod2_dense.pyx index 6212e664576..f21691211b3 100644 --- a/src/sage/matrix/matrix_mod2_dense.pyx +++ b/src/sage/matrix/matrix_mod2_dense.pyx @@ -114,6 +114,7 @@ from sage.misc.randstate cimport randstate, current_randstate from sage.misc.misc import verbose, get_verbose, cputime from sage.modules.free_module import VectorSpace from sage.modules.vector_mod2_dense cimport Vector_mod2_dense +from sage.structure.richcmp cimport rich_to_bool from sage.cpython.string cimport bytes_to_str, char_to_str, str_to_bytes from sage.cpython.string import FS_ENCODING @@ -477,7 +478,7 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse # * def _pickle # * def _unpickle # * cdef _mul_ - # * cpdef _cmp_ + # * cpdef _richcmp_ # * _list -- list of underlying elements (need not be a copy) # * _dict -- sparse dictionary of underlying elements (need not be a copy) ######################################################################## @@ -1373,9 +1374,11 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse A.subdivide(*self.subdivisions()) return A - cpdef int _cmp_(self, right) except -2: + cpdef _richcmp_(self, right, int op): """ - Compares ``self`` with ``right``. While equality and + Compare ``self`` with ``right``. + + While equality and inequality are clearly defined, ``<`` and ``>`` are not. For those first the matrix dimensions of ``self`` and ``right`` are compared. If these match then ``<`` means that there is a @@ -1400,9 +1403,9 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse False """ if self._nrows == 0 or self._ncols == 0: - return 0 - return mzd_cmp(self._entries, (right)._entries) - + return rich_to_bool(op, 0) + return rich_to_bool(op, mzd_cmp(self._entries, + (right)._entries)) def augment(self, right, subdivide=False): r""" diff --git a/src/sage/matrix/matrix_modn_dense_template.pxi b/src/sage/matrix/matrix_modn_dense_template.pxi index 108b642aed2..d948618f0dd 100644 --- a/src/sage/matrix/matrix_modn_dense_template.pxi +++ b/src/sage/matrix/matrix_modn_dense_template.pxi @@ -119,6 +119,7 @@ from sage.misc.misc import verbose, get_verbose, cputime from sage.rings.integer cimport Integer from sage.rings.integer_ring import ZZ from sage.structure.proof.proof import get_flag as get_proof_flag +from sage.structure.richcmp cimport rich_to_bool from sage.misc.randstate cimport randstate, current_randstate import sage.matrix.matrix_space as matrix_space from .args cimport MatrixArgs_init @@ -939,10 +940,9 @@ cdef class Matrix_modn_dense_template(Matrix_dense): sig_off() return M - - cpdef int _cmp_(self, right) except -2: + cpdef _richcmp_(self, right, int op): r""" - Compare two dense matrices over `\Z/n\Z` + Compare two dense matrices over `\Z/n\Z`. EXAMPLES:: @@ -982,16 +982,15 @@ cdef class Matrix_modn_dense_template(Matrix_dense): cdef Py_ssize_t i cdef celement* other_ent = (right)._entries sig_on() - for i in range(self._nrows*self._ncols): + for i in range(self._nrows * self._ncols): if self._entries[i] < other_ent[i]: sig_off() - return -1 + return rich_to_bool(op, -1) elif self._entries[i] > other_ent[i]: sig_off() - return 1 + return rich_to_bool(op, 1) sig_off() - return 0 - + return rich_to_bool(op, 0) cdef _matrix_times_matrix_(self, Matrix right): """ diff --git a/src/sage/matrix/matrix_rational_dense.pyx b/src/sage/matrix/matrix_rational_dense.pyx index ee63c26917c..77648949336 100644 --- a/src/sage/matrix/matrix_rational_dense.pyx +++ b/src/sage/matrix/matrix_rational_dense.pyx @@ -93,6 +93,7 @@ from sage.libs.flint.fmpq_mat cimport * cimport sage.structure.element from sage.structure.sequence import Sequence +from sage.structure.richcmp cimport rich_to_bool from sage.rings.rational cimport Rational from .matrix cimport Matrix from .args cimport SparseEntry, MatrixArgs_init @@ -374,7 +375,7 @@ cdef class Matrix_rational_dense(Matrix_dense): # x * cdef _add_ # x * cdef _mul_ # x * cdef _vector_times_matrix_ - # x * cpdef _cmp_ + # x * cpdef _richcmp_ # x * __neg__ # * __invert__ # x * __copy__ @@ -446,7 +447,7 @@ cdef class Matrix_rational_dense(Matrix_dense): sig_off() return ans - cpdef int _cmp_(self, right) except -2: + cpdef _richcmp_(self, right, int op): r""" TESTS:: @@ -481,8 +482,11 @@ cdef class Matrix_rational_dense(Matrix_dense): k = fmpq_cmp(fmpq_mat_entry(self._matrix, i, j), fmpq_mat_entry(( right)._matrix, i, j)) if k: - return (k > 0) - (k < 0) - return 0 + if k > 0: + return rich_to_bool(op, 1) + else: + return rich_to_bool(op, -1) + return rich_to_bool(op, 0) cdef _vector_times_matrix_(self, Vector v): """ diff --git a/src/sage/matrix/matrix_rational_sparse.pyx b/src/sage/matrix/matrix_rational_sparse.pyx index da9c73db7d9..95cfda136d4 100644 --- a/src/sage/matrix/matrix_rational_sparse.pyx +++ b/src/sage/matrix/matrix_rational_sparse.pyx @@ -147,7 +147,7 @@ cdef class Matrix_rational_sparse(Matrix_sparse): # * cdef _add_ # * cdef _sub_ # * cdef _mul_ - # * cpdef _cmp_ + # * cpdef _richcmp_ # * __neg__ # * __invert__ # * __copy__ @@ -255,7 +255,7 @@ cdef class Matrix_rational_sparse(Matrix_sparse): # def _unpickle(self, data, int version): # use version >= 0 # cpdef _add_(self, right): # cdef _mul_(self, Matrix right): - # cpdef int _cmp_(self, Matrix right) except -2: + # cpdef _richcmp_(self, Matrix right, int op): # def __neg__(self): # def __invert__(self): # def __copy__(self): From ee33771d262b76a9f1b4d25dda59fa86606d0a76 Mon Sep 17 00:00:00 2001 From: Edgar Costa Date: Sun, 3 Nov 2019 10:35:13 -0500 Subject: [PATCH 111/340] fixing two docstrings --- src/sage/schemes/elliptic_curves/ell_tate_curve.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_tate_curve.py b/src/sage/schemes/elliptic_curves/ell_tate_curve.py index 141480536f9..65abddbfd37 100644 --- a/src/sage/schemes/elliptic_curves/ell_tate_curve.py +++ b/src/sage/schemes/elliptic_curves/ell_tate_curve.py @@ -10,7 +10,8 @@ `\bar{\QQ}_p^{\times}\,/\, q^{\ZZ}`. More precisely there exists the series `s_4(q)` and `s_6(q)` such that the `y^2+x y = x^3 + s_4(q) x+s_6(q)` curve is isomorphic to `E` over -`\bar{\QQ}_p` (or over `\QQ_p` if the reduction is *split* multiplicative). There is `p`-adic analytic map from +`\bar{\QQ}_p` (or over `\QQ_p` if the reduction is *split* multiplicative). +There is `p`-adic analytic map from `\bar{\QQ}^{\times}_p` to this curve with kernel `q^{\ZZ}`. Points of good reduction correspond to points of valuation `0` in `\bar{\QQ}^{\times}_p`. @@ -317,7 +318,8 @@ def parametrisation_onto_tate_curve(self, u, prec=None): - ``u`` - a non-zero `p`-adic number. - - ``prec`` - the `p`-adic precision, default is 20. + - ``prec`` - the `p`-adic precision, default is the relative precision of ``u`` + otherwise 20. EXAMPLES:: @@ -527,7 +529,8 @@ def parametrisation_onto_original_curve(self, u, prec=None): - ``u`` - a non-zero `p`-adic number. - - ``prec`` - the `p`-adic precision, default is 20. + - ``prec`` - the `p`-adic precision, default is the relative precision of ``u`` + otherwise 20. EXAMPLES:: From e25e16b131c3da54af905f4f18aa847f80057ab9 Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Fri, 11 Oct 2019 13:18:01 -0500 Subject: [PATCH 112/340] 28304: add after_print_text() for Macaulay2 elements --- src/sage/interfaces/macaulay2.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/sage/interfaces/macaulay2.py b/src/sage/interfaces/macaulay2.py index 7bae83a78b4..8e6e3ba4998 100644 --- a/src/sage/interfaces/macaulay2.py +++ b/src/sage/interfaces/macaulay2.py @@ -1224,6 +1224,23 @@ def cls(self): """ return self.parent()("class %s"%self.name()) + def after_print_text(self): + r""" + Obtain the type information about this Macaulay2 element that is + displayed using ``AfterPrint`` in the Macaulay2 interpreter. + + EXAMPLES:: + + sage: B = macaulay2(matrix([[1, 2], [3, 6]])).kernel(); B # optional - macaulay2 + image | 2 | + | -1 | + sage: B.after_print_text() # optional - macaulay2 + 2 + ZZ-module, submodule of ZZ + """ + return self.parent().eval('(lookup({topLevelMode,AfterPrint},' + + 'class {0}))({0})'.format(self._name)) + ########################## #Aliases for M2 operators# ########################## From bcbf9aafa6e6977be1866f6973ef8ecba8bb37e7 Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Fri, 11 Oct 2019 13:59:10 -0500 Subject: [PATCH 113/340] 28304: add global options to Macaulay2 to enable AfterPrint --- src/sage/interfaces/macaulay2.py | 57 +++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/src/sage/interfaces/macaulay2.py b/src/sage/interfaces/macaulay2.py index 8e6e3ba4998..8e8cedac32f 100644 --- a/src/sage/interfaces/macaulay2.py +++ b/src/sage/interfaces/macaulay2.py @@ -128,6 +128,7 @@ from sage.misc.multireplace import multiple_replace from sage.interfaces.tab_completion import ExtraTabCompletion from sage.docs.instancedoc import instancedoc +from sage.structure.global_options import GlobalOptions def remove_output_labels(s): @@ -333,6 +334,17 @@ def set_seed(self, seed=None): self._seed = seed return seed + class options(GlobalOptions): + NAME = 'Macaulay2' + module = 'sage.interfaces.macaulay2' + # GlobalOptions currently only supports strings, so we use yes/no + # rather than True/False to avoid confusion with booleans + after_print = dict(default='no', + values=dict( + yes='append AfterPrint type information to ' + 'textual representations', + no='do not append AfterPrint text')) + def get(self, var): """ Get the value of the variable ``var``. @@ -892,9 +904,32 @@ def _repr_(self): 23, 24, 25) sage: str(macaulay2('1..25')) # optional - macaulay2 (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) + + If ``AfterPrint`` is enabled, the ``repr`` contains type information, + but the string representation does not:: + + sage: macaulay2.options.after_print = 'yes' # optional - macaulay2 + sage: repr(macaulay2('1..25')) # optional - macaulay2 + (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) + + Sequence + sage: str(macaulay2('1..25')) # optional - macaulay2 + (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) + sage: macaulay2.options.after_print = 'no' # optional - macaulay2 """ from sage.typeset.ascii_art import empty_ascii_art P = self.parent() + if P.options.after_print == 'yes': + # In M2, the wrapped output is indented by the width of the prompt, + # which we strip in Sage. We hardcode the width of the prompt to + # 14=len('o1000000001 = '), which is tested in the doctests by the + # output getting wrapped at 80 characters. + width = 14 + empty_ascii_art._terminal_width() + return P.eval('printWidth=%d;%s' % (width, self._name)) + # Otherwise manually wrap the net representation which does not display + # AfterPrint text return P.eval('print(wrap(%d,"-",net %s))' % (empty_ascii_art._terminal_width(), self._name), strip=False) @@ -985,7 +1020,8 @@ def __len__(self): <... 'int'> """ self._check_valid() - return int(self.parent()("#%s"%self.name())) + # we use str instead of repr to avoid wrapping + return int(str(self.parent()("#%s"%self.name()))) def __getitem__(self, n): """ @@ -1237,6 +1273,25 @@ def after_print_text(self): sage: B.after_print_text() # optional - macaulay2 2 ZZ-module, submodule of ZZ + + Note that Macaulay2 by default includes this information in the output. + In Sage, this behaviour can optionally be enabled by setting + :attr:`Macaulay2.options.after_print`. :: + + sage: macaulay2.options.after_print = 'yes' # optional - macaulay2 + sage: A = macaulay2(matrix([[1, 2], [3, 6]])); A # optional - macaulay2 + | 1 2 | + | 3 6 | + + 2 2 + Matrix ZZ <--- ZZ + sage: A.kernel() # optional - macaulay2 + image | 2 | + | -1 | + + 2 + ZZ-module, submodule of ZZ + sage: macaulay2.options.after_print = 'no' # optional - macaulay2 """ return self.parent().eval('(lookup({topLevelMode,AfterPrint},' + 'class {0}))({0})'.format(self._name)) From 3fc7b990ececd87325e0d56ada938ec2f886fe97 Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Thu, 7 Nov 2019 19:28:48 +0100 Subject: [PATCH 114/340] 28304: improve Macaulay2 documentation This also fixes an issue where `deprecated_function_alias` was added to the class `Macaulay2Element` and its documentation. --- src/sage/interfaces/macaulay2.py | 53 +++++++++++++++++++------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/src/sage/interfaces/macaulay2.py b/src/sage/interfaces/macaulay2.py index 8e8cedac32f..c93d729e5f7 100644 --- a/src/sage/interfaces/macaulay2.py +++ b/src/sage/interfaces/macaulay2.py @@ -126,6 +126,7 @@ FunctionElement) from sage.interfaces.interface import AsciiArtString from sage.misc.multireplace import multiple_replace +from sage.misc.superseded import deprecated_function_alias from sage.interfaces.tab_completion import ExtraTabCompletion from sage.docs.instancedoc import instancedoc from sage.structure.global_options import GlobalOptions @@ -335,6 +336,28 @@ def set_seed(self, seed=None): return seed class options(GlobalOptions): + r""" + Global options for Macaulay2 elements. + + @OPTIONS@ + + EXAMPLES:: + + sage: macaulay2.options.after_print = 'yes' # optional - macaulay2 + sage: A = macaulay2(matrix([[1, 2], [3, 6]])); A # optional - macaulay2 + | 1 2 | + | 3 6 | + + 2 2 + Matrix ZZ <--- ZZ + sage: A.kernel() # optional - macaulay2 + image | 2 | + | -1 | + + 2 + ZZ-module, submodule of ZZ + sage: macaulay2.options.after_print = 'no' # optional - macaulay2 + """ NAME = 'Macaulay2' module = 'sage.interfaces.macaulay2' # GlobalOptions currently only supports strings, so we use yes/no @@ -1262,8 +1285,14 @@ def cls(self): def after_print_text(self): r""" - Obtain the type information about this Macaulay2 element that is - displayed using ``AfterPrint`` in the Macaulay2 interpreter. + Obtain type information for this Macaulay2 element. + + This is the text that is displayed using ``AfterPrint`` in a Macaulay2 + interpreter. + + Macaulay2 by default includes this information in the output. + In Sage, this behavior can optionally be enabled by setting the option + ``after_print`` in :class:`Macaulay2.options`. EXAMPLES:: @@ -1273,25 +1302,6 @@ def after_print_text(self): sage: B.after_print_text() # optional - macaulay2 2 ZZ-module, submodule of ZZ - - Note that Macaulay2 by default includes this information in the output. - In Sage, this behaviour can optionally be enabled by setting - :attr:`Macaulay2.options.after_print`. :: - - sage: macaulay2.options.after_print = 'yes' # optional - macaulay2 - sage: A = macaulay2(matrix([[1, 2], [3, 6]])); A # optional - macaulay2 - | 1 2 | - | 3 6 | - - 2 2 - Matrix ZZ <--- ZZ - sage: A.kernel() # optional - macaulay2 - image | 2 | - | -1 | - - 2 - ZZ-module, submodule of ZZ - sage: macaulay2.options.after_print = 'no' # optional - macaulay2 """ return self.parent().eval('(lookup({topLevelMode,AfterPrint},' + 'class {0}))({0})'.format(self._name)) @@ -1648,7 +1658,6 @@ def _sage_(self): except Exception: raise NotImplementedError("cannot convert %s to a Sage object"%repr_str) - from sage.misc.superseded import deprecated_function_alias to_sage = deprecated_function_alias(27848, ExpectElement.sage) def _matrix_(self, R): From 195438cbe74f5140b8deb0a96167454ea9b5d03f Mon Sep 17 00:00:00 2001 From: "E. Madison Bray" Date: Fri, 8 Nov 2019 12:23:09 +0100 Subject: [PATCH 115/340] Trac #28289: Set default configs for TerminalInteractiveShell This should prevent some test failures when users override configuration for TerminalInteractiveShell in ipython_config.py --- src/sage/repl/configuration.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/sage/repl/configuration.py b/src/sage/repl/configuration.py index 67d7d2accf8..1c2c6d144c9 100644 --- a/src/sage/repl/configuration.py +++ b/src/sage/repl/configuration.py @@ -126,6 +126,21 @@ def default(self): True """ from sage.repl.interpreter import SageTerminalInteractiveShell + + # Use the same config for both InteractiveShell, and its subclass + # TerminalInteractiveShell (note: in fact some configs like term_title + # only apply to the latter, but we can still use the same config for + # both for simplicity's sake; see Trac #28289) + InteractiveShell=Config( + prompts_class=SagePrompts, + ast_node_interactivity='all', + colors=self.colors(), + simple_prompt=self.simple_prompt(), + term_title=self.term_title(), + confirm_exit=False, + separate_in='' + ) + cfg = Config( TerminalIPythonApp=Config( display_banner=False, @@ -133,15 +148,8 @@ def default(self): test_shell=False, shell_class=SageTerminalInteractiveShell, ), - InteractiveShell=Config( - prompts_class=SagePrompts, - ast_node_interactivity='all', - colors=self.colors(), - simple_prompt=self.simple_prompt(), - term_title=self.term_title(), - confirm_exit=False, - separate_in='' - ), + InteractiveShell=InteractiveShell, + TerminalInteractiveShell=InteractiveShell, InteractiveShellApp=Config(extensions=[SAGE_EXTENSION]), ) if self._doctest_mode(): From abd00fe155472589cfb34c20047a853fc57a5d5b Mon Sep 17 00:00:00 2001 From: dcoudert Date: Fri, 8 Nov 2019 18:55:13 +0100 Subject: [PATCH 116/340] trac #27790: use CPXsetlogfilename instead of CPXsetlogfile --- src/sage/numerical/backends/cplex_backend.pxd | 4 ++-- src/sage/numerical/backends/cplex_backend.pyx | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/sage/numerical/backends/cplex_backend.pxd b/src/sage/numerical/backends/cplex_backend.pxd index 8f59a8435ca..8216ad422b4 100644 --- a/src/sage/numerical/backends/cplex_backend.pxd +++ b/src/sage/numerical/backends/cplex_backend.pxd @@ -213,8 +213,8 @@ cdef extern from "cplex.h": # sets the value of a string parameter int CPXsetstrparam(c_cpxenv * env, int paramid, char * value) - # sets the log stream file - int CPXsetlogfile(c_cpxenv * env, FILE * f) + # Set the log file + int CPXsetlogfilename(c_cpxenv * env, char * filename, char * mode) # CONSTANTS int CPX_ON = 1 diff --git a/src/sage/numerical/backends/cplex_backend.pyx b/src/sage/numerical/backends/cplex_backend.pyx index c47333fd1be..239ccb3c5b5 100644 --- a/src/sage/numerical/backends/cplex_backend.pyx +++ b/src/sage/numerical/backends/cplex_backend.pyx @@ -1597,18 +1597,14 @@ cdef class CPLEXBackend(GenericBackend): cdef char * strv # Specific action for log file - cdef FILE *ff if name.lower() == "logfile": if value is None: # Return logfile name return self._logfilename elif not value: # Close current logfile and disable logs - check( CPXsetlogfile(self.env, NULL) ) + check( CPXsetlogfilename(self.env, NULL, NULL) ) self._logfilename = '' else: # Set log file to logfilename - ff = fopen(str_to_bytes(value), "a") - if not ff: - raise ValueError("Unable to append file {}.".format(value)) - check( CPXsetlogfile(self.env, ff) ) + check( CPXsetlogfilename(self.env, str_to_bytes(value), "a") ) self._logfilename = value return From 2324c95431269e4d7ab5f0c4653a70442c36d652 Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Fri, 8 Nov 2019 19:30:29 +0100 Subject: [PATCH 117/340] 28304: use booleans for after_print option --- src/sage/interfaces/macaulay2.py | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/sage/interfaces/macaulay2.py b/src/sage/interfaces/macaulay2.py index c93d729e5f7..7e77343682a 100644 --- a/src/sage/interfaces/macaulay2.py +++ b/src/sage/interfaces/macaulay2.py @@ -343,7 +343,7 @@ class options(GlobalOptions): EXAMPLES:: - sage: macaulay2.options.after_print = 'yes' # optional - macaulay2 + sage: macaulay2.options.after_print = True # optional - macaulay2 sage: A = macaulay2(matrix([[1, 2], [3, 6]])); A # optional - macaulay2 | 1 2 | | 3 6 | @@ -356,17 +356,14 @@ class options(GlobalOptions): 2 ZZ-module, submodule of ZZ - sage: macaulay2.options.after_print = 'no' # optional - macaulay2 + sage: macaulay2.options.after_print = False # optional - macaulay2 """ NAME = 'Macaulay2' module = 'sage.interfaces.macaulay2' - # GlobalOptions currently only supports strings, so we use yes/no - # rather than True/False to avoid confusion with booleans - after_print = dict(default='no', - values=dict( - yes='append AfterPrint type information to ' - 'textual representations', - no='do not append AfterPrint text')) + after_print = dict(default=False, + description='append AfterPrint type information to ' + 'textual representations', + checker=lambda val: isinstance(val, bool)) def get(self, var): """ @@ -931,7 +928,7 @@ def _repr_(self): If ``AfterPrint`` is enabled, the ``repr`` contains type information, but the string representation does not:: - sage: macaulay2.options.after_print = 'yes' # optional - macaulay2 + sage: macaulay2.options.after_print = True # optional - macaulay2 sage: repr(macaulay2('1..25')) # optional - macaulay2 (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, -------------------------------------------------------------------------------- @@ -940,11 +937,11 @@ def _repr_(self): Sequence sage: str(macaulay2('1..25')) # optional - macaulay2 (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) - sage: macaulay2.options.after_print = 'no' # optional - macaulay2 + sage: macaulay2.options.after_print = False # optional - macaulay2 """ from sage.typeset.ascii_art import empty_ascii_art P = self.parent() - if P.options.after_print == 'yes': + if P.options.after_print: # In M2, the wrapped output is indented by the width of the prompt, # which we strip in Sage. We hardcode the width of the prompt to # 14=len('o1000000001 = '), which is tested in the doctests by the From 95eacb01b65918cc27a2d75ae87fc8140010cbbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 8 Nov 2019 20:53:59 +0100 Subject: [PATCH 118/340] trac 28694 fix doctest in Cayley table for SL(2,2) --- src/sage/categories/groups.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index 3b278ca1aef..920ea94126a 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -269,12 +269,12 @@ def cayley_table(self, names='letters', elements=None): sage: M.cayley_table() * a b c d e f +------------ - a| c e a f b d - b| d f b e a c - c| a b c d e f - d| b a d c f e - e| f d e b c a - f| e c f a d b + a| a b c d e f + b| b a d c f e + c| c e a f b d + d| d f b e a c + e| e c f a d b + f| f d e b c a :: From 4b9bc7cfb9a3ae22290bedbaa4ab717c9722a987 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Fri, 8 Nov 2019 21:56:14 +0000 Subject: [PATCH 119/340] version 1.1.3 & don't try to install if Sage doesn't start see https://trac.sagemath.org/ticket/28513 for details --- build/pkgs/sagenb/checksums.ini | 6 +++--- build/pkgs/sagenb/dependencies | 2 +- build/pkgs/sagenb/package-version.txt | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/pkgs/sagenb/checksums.ini b/build/pkgs/sagenb/checksums.ini index 4b75c7b57c7..5b0930947d3 100644 --- a/build/pkgs/sagenb/checksums.ini +++ b/build/pkgs/sagenb/checksums.ini @@ -1,4 +1,4 @@ tarball=sagenb-VERSION.tar.bz2 -sha1=773e0c60ff4f3ec8245ab811fa4e42577e0933cb -md5=5cf62ebf347aea6750fc1b2d4bc9ebe1 -cksum=540029477 +sha1=722b7a15f2e1f911224ab6f397457f69d65027d7 +md5=0bdc2b44f3ce961c6b74bfc736ac2e09 +cksum=2540078270 diff --git a/build/pkgs/sagenb/dependencies b/build/pkgs/sagenb/dependencies index d62f93ad891..c5727e022e8 100644 --- a/build/pkgs/sagenb/dependencies +++ b/build/pkgs/sagenb/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(SAGERUNTIME) pip babel flask flask_autoindex flask_babel flask_oldsessions flask_openid mathjax twisted sphinx +$(STARTED) | pip babel flask flask_autoindex flask_babel flask_oldsessions flask_openid mathjax twisted sphinx ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sagenb/package-version.txt b/build/pkgs/sagenb/package-version.txt index 45a1b3f4452..781dcb07cd8 100644 --- a/build/pkgs/sagenb/package-version.txt +++ b/build/pkgs/sagenb/package-version.txt @@ -1 +1 @@ -1.1.2 +1.1.3 From 37dcc4d6f490d4e12c25470f1d3a53ae80876403 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 9 Nov 2019 11:00:45 +0100 Subject: [PATCH 120/340] trac #27790: update thematic tutorial on linear programming --- .../thematic_tutorials/linear_programming.rst | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/doc/en/thematic_tutorials/linear_programming.rst b/src/doc/en/thematic_tutorials/linear_programming.rst index 5641815625a..98cd54a0406 100644 --- a/src/doc/en/thematic_tutorials/linear_programming.rst +++ b/src/doc/en/thematic_tutorials/linear_programming.rst @@ -253,13 +253,13 @@ We can now define the MILP itself :: - sage: p.add_constraint(sum(weight[o] * taken[o] for o in L) <= C) + sage: p.add_constraint(p.sum(weight[o] * taken[o] for o in L) <= C) .. link :: - sage: p.set_objective(sum(usefulness[o] * taken[o] for o in L)) + sage: p.set_objective(p.sum(usefulness[o] * taken[o] for o in L)) .. link @@ -275,7 +275,7 @@ The solution found is (of course) admissible :: - sage: sum(weight[o] * taken[o] for o in L) # abs tol 1e-6 + sage: sum(weight[o] * taken[o] for o in L) # abs tol 1e-6 0.6964959796619171 Should we take a flashlight? @@ -331,14 +331,14 @@ Let us write the Sage code of this MILP:: :: - sage: p.set_objective(sum(matching[e] for e in g.edges(labels=False))) + sage: p.set_objective(p.sum(matching[e] for e in g.edges(labels=False))) .. link :: sage: for v in g: - ....: p.add_constraint(sum(matching[e] + ....: p.add_constraint(p.sum(matching[e] ....: for e in g.edges_incident(v, labels=False)) <= 1) .. link @@ -409,8 +409,8 @@ graph, in which all the edges have a capacity of 1:: sage: for v in g: ....: if v != s and v != t: ....: p.add_constraint( - ....: sum(f[(v,u)] for u in g.neighbors_out(v)) - ....: - sum(f[(u,v)] for u in g.neighbors_in(v)) == 0) + ....: p.sum(f[v,u] for u in g.neighbors_out(v)) + ....: - p.sum(f[u,v] for u in g.neighbors_in(v)) == 0) .. link @@ -423,7 +423,7 @@ graph, in which all the edges have a capacity of 1:: :: - sage: p.set_objective(sum(f[(s,u)] for u in g.neighbors_out(s))) + sage: p.set_objective(p.sum(f[s,u] for u in g.neighbors_out(s))) .. link @@ -455,6 +455,8 @@ following libraries are currently supported: Proprietary, but free for researchers and students. + Since :trac:`27790`, only versions 12.8 and above are supported. + * `CVXOPT `_: an LP solver from Python Software for Convex Optimization, uses an interior-point method, always installed in Sage. @@ -483,7 +485,6 @@ of several files to use it through Sage. In each case, the **expected** (it may change !) filename is joined. * A valid license file - * CPLEX : a ``.ilm`` file * GUROBI : a ``.lic`` file * A compiled version of the library @@ -497,12 +498,6 @@ change !) filename is joined. The environment variable defining the licence's path must also be set when running Sage. You can append to your ``.bashrc`` file one of the following : -* For CPLEX - - .. CODE-BLOCK:: bash - - export ILOG_LICENSE_FILE=/path/to/the/license/ilog/ilm/access_1.ilm - * For GUROBI .. CODE-BLOCK:: bash From b313f562826599d5361067df91606c32803a145a Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Mon, 11 Nov 2019 04:00:31 +0100 Subject: [PATCH 121/340] Characteristic Classes --- .../manifolds/diff_vector_bundle.rst | 4 + src/doc/en/reference/references/index.rst | 6 + .../differentiable/affine_connection.py | 23 + .../differentiable/bundle_connection.py | 755 +++++++++++++++ .../manifolds/differentiable/char_class.py | 874 ++++++++++++++++++ .../manifolds/differentiable/diff_form.py | 14 +- .../manifolds/differentiable/mixed_form.py | 21 +- .../differentiable/multivectorfield.py | 6 +- .../manifolds/differentiable/scalarfield.py | 6 +- .../manifolds/differentiable/tensorfield.py | 58 +- .../differentiable/tensorfield_paral.py | 6 +- .../manifolds/differentiable/vector_bundle.py | 133 +++ src/sage/manifolds/scalarfield.py | 17 +- src/sage/manifolds/vector_bundle.py | 63 +- src/sage/tensor/modules/free_module_tensor.py | 18 +- 15 files changed, 1948 insertions(+), 56 deletions(-) create mode 100644 src/sage/manifolds/differentiable/bundle_connection.py create mode 100644 src/sage/manifolds/differentiable/char_class.py diff --git a/src/doc/en/reference/manifolds/diff_vector_bundle.rst b/src/doc/en/reference/manifolds/diff_vector_bundle.rst index 4431426e27a..d3cb17c9e66 100644 --- a/src/doc/en/reference/manifolds/diff_vector_bundle.rst +++ b/src/doc/en/reference/manifolds/diff_vector_bundle.rst @@ -5,3 +5,7 @@ Differentiable Vector Bundles :maxdepth: 2 sage/manifolds/differentiable/vector_bundle + + sage/manifolds/differentiable/bundle_connection + + sage/manifolds/differentiable/char_class diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 468a4e559cc..ae850e4d6b6 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -3750,6 +3750,9 @@ REFERENCES: .. [Mil1958] \J. W. Milnor, *The Steenrod algebra and its dual*, Ann. of Math. (2) 67 (1958), 150-171. +.. [Mil1974] \J. W. Milnor and J. D. Stasheff, *Characteristic Classes*, + University Press, Princeton and Tokyo, 1974. + .. [Mil1978] \S. Milne, *A q-analog of restricted growth functions, Dobinsky’s equality and Charlier polynomials*. Trans. Amer. Math. Soc., 245 (1978), @@ -4394,6 +4397,9 @@ REFERENCES: .. [Roc1970] \R.T. Rockafellar, *Convex Analysis*. Princeton University Press, Princeton, 1970. +.. [Roe1988] John Roe, *Elliptic operators, topology and asymptotic methods*. + 2nd edition. CRC Press, 1988. + .. [Rog2018] Baptiste Rognerud, *Exceptional and modern intervals of the Tamari lattice*. :arxiv:`1801.04097` diff --git a/src/sage/manifolds/differentiable/affine_connection.py b/src/sage/manifolds/differentiable/affine_connection.py index 12aa8e554cc..44cd16efc0f 100644 --- a/src/sage/manifolds/differentiable/affine_connection.py +++ b/src/sage/manifolds/differentiable/affine_connection.py @@ -428,6 +428,7 @@ def _init_derived(self): # (key: vector frame) self._curvature_forms = {} # dict. of dict. of curvature 2-forms # (key: vector frame) + self._hash_value = -1 def _del_derived(self): r""" @@ -2321,3 +2322,25 @@ def set_calc_order(self, symbol, order, truncate=False): if truncate: coef[ind].simplify() self._del_derived() + + def __hash__(self): + r""" + Hash function. + + TESTS:: + + sage: M = Manifold(2, 'M') + sage: X. = M.chart() + sage: nab = M.affine_connection('nabla', latex_name=r'\nabla') + sage: hash(nab) == nab.__hash__() + True + + Let us check that ``nab`` can be used as a dictionary key:: + + sage: {nab: 1}[nab] + 1 + + """ + if self._hash_value == -1: + self._hash_value = hash(repr(self)) + return self._hash_value diff --git a/src/sage/manifolds/differentiable/bundle_connection.py b/src/sage/manifolds/differentiable/bundle_connection.py new file mode 100644 index 00000000000..565fd579d22 --- /dev/null +++ b/src/sage/manifolds/differentiable/bundle_connection.py @@ -0,0 +1,755 @@ +r""" +Bundle Connections + +Let `E \to M` be a smooth vector bundle of rank `n` over a smooth manifold `M` +and over a non-discrete topological field `K` (typically `K=\RR` or `K=\CC`). A +*bundle connection* on this vector bundle is a `K`-linear map + +.. MATH:: + + \nabla : C^\infty(M;E) \to C^\infty(M;E \otimes T^*M) + +such that the Leibniz rule applies for each scalar field `f \in C^\infty(M)` and +section `s \in C^\infty(M;E)`: + +.. MATH:: + + \nabla(f \, s) = f \cdot \nabla s + s \otimes \mathrm{d}f . + +If `e` is a local frame on `E`, we have + +.. MATH:: + + \nabla e_i = \sum^n_{j=1} e_j \otimes \omega^j_i , + +and the corresponding `n \times n`-matrix `(\omega^j_i)_{i,j}` consisting of +one forms is called *connection matrix of* `\nabla` *with respect to* `e`. + +AUTHORS: + +- Michael Jung (2019) : initial version + +""" +#****************************************************************************** +# Copyright (C) 2019 Michael Jung +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.structure.unique_representation import UniqueRepresentation +from sage.rings.integer import Integer +from sage.structure.sage_object import SageObject +from sage.manifolds.differentiable.vector_bundle\ + import DifferentiableVectorBundle + +class BundleConnection(SageObject): + r""" + An instance of this class represents a bundle connection `\nabla` on a + smooth vector bundle `E \to M`. + + .. NOTE:: + + Notice that this is a *very* rudimentary form of bundle connections. + A more detailed implementation is devoted to :trac:`28640`. + + INPUT: + + - ``vbundle`` -- the vector bundle on which the connection is defined + (must be an instance of class + :class:`~sage.manifolds.differentiable.vector_bundle.DifferentiableVectorBundle`) + - ``name`` -- name given to the bundle connection + - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the bundle + connection; if ``None``, it is set to ``name``. + + EXAMPLES: + + Define a bundle connection on a rank 2 vector bundle over some 3-dimensional + smooth manifold:: + + sage: M = Manifold(3, 'M', start_index=1) + sage: X. = M.chart() + sage: E = M.vector_bundle(2, 'E') + sage: e = E.local_frame('e') # standard frame for E + sage: nab = E.bundle_connection('nabla', latex_name=r'\nabla'); nab + Bundle connection nabla on the Differentiable real vector bundle E -> M + of rank 2 over the base space 3-dimensional differentiable manifold M + + The bundle connection is specified by the connection 1-forms:: + + sage: a = M.one_form([x*z, y*z, z^2], name='a') + sage: b = M.one_form([x, x^2, x^3], name='b') + sage: nab.set_connection_form(1, 2, a) + sage: nab.set_connection_form(1, 1, b) + + From this, the connection 2-forms can be derived:: + + sage: for i in E.irange(): + ....: for j in E.irange(): + ....: print(nab.curvature_form(i ,j).display()) + curvature (1,1) of bundle connection nabla w.r.t. Local frame + (E|_M, (e_1,e_2)) = 2*x dx/\dy + 3*x^2 dx/\dz + curvature (1,2) of bundle connection nabla w.r.t. Local frame + (E|_M, (e_1,e_2)) = (x^3 - x*y)*z dx/\dy + (x^4*z - x*z^2 - x) dx/\dz + + (x^3*y*z - x^2*z^2 - y) dy/\dz + curvature (2,1) of bundle connection nabla w.r.t. Local frame + (E|_M, (e_1,e_2)) = 0 + curvature (2,2) of bundle connection nabla w.r.t. Local frame + (E|_M, (e_1,e_2)) = 0 + + They certainly obey Cartan's second structure equation:: + + sage: omega = nab.connection_form + sage: check = [] + sage: for i in E.irange(): # long time + ....: for j in E.irange(): + ....: check.append(nab.curvature_form(i,j,e) == \ + ....: omega(i,j,e).exterior_derivative() + \ + ....: sum(omega(k,j,e).wedge(omega(i,k,e)) for k in E.irange())) + sage: check # long time + [True, True, True, True] + + """ + def __init__(self, vbundle, name, latex_name=None): + r""" + Construct a bundle connection. + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: E = M.vector_bundle(2, 'E') + sage: from sage.manifolds.differentiable.bundle_connection import \ + BundleConnection + sage: nab = BundleConnection(E, 'nabla', latex_name=r'\nabla') + sage: nab + Bundle connection nabla on the Differentiable real vector bundle + E -> M of rank 2 over the base space 3-dimensional differentiable + manifold M + sage: X. = M.chart() + sage: e = E.local_frame('e') + sage: a = M.one_form([x*z, y*z, z^2], name='a') + sage: nab.set_connection_form(1, 0, a) + sage: TestSuite(nab).run() + + """ + if not isinstance(vbundle, DifferentiableVectorBundle): + raise TypeError("the first argument must be a differentiable " + + "vector bundle") + self._vbundle = vbundle + self._base_space = vbundle.base_space() + self._name = name + if latex_name is None: + self._latex_name = self._name + else: + self._latex_name = latex_name + self._connection_forms = {} # dict. of connection coefficients, with + # the local frames as keys + self._coefficients = self._connection_forms + # Initialization of derived quantities: + self._init_derived() + + def _repr_(self): + r""" + String representation of the object. + + TESTS:: + + sage: M = Manifold(5, 'M') + sage: E = M.vector_bundle(3, 'E') + sage: nab = E.bundle_connection('nabla', latex_name=r'\nabla') + sage: nab._repr_() + 'Bundle connection nabla on the Differentiable real vector bundle + E -> M of rank 3 over the base space 5-dimensional differentiable + manifold M' + sage: repr(nab) # indirect doctest + 'Bundle connection nabla on the Differentiable real vector bundle + E -> M of rank 3 over the base space 5-dimensional differentiable + manifold M' + + """ + description = "Bundle connection" + if self._name is not None: + description += " " + self._name + description += " on the {}".format(self._vbundle) + return description + + def _latex_(self): + r""" + LaTeX representation of the object. + + TESTS:: + + sage: M = Manifold(5, 'M') + sage: E = M.vector_bundle(3, 'E') + sage: nab = E.bundle_connection('nabla', latex_name=r'\nabla') + sage: nab._latex_() + '\\nabla' + sage: latex(nab) # indirect doctest + \nabla + sage: nab = E.bundle_connection('D') + sage: nab._latex_() + 'D' + sage: latex(nab) # indirect doctest + D + + """ + return self._latex_name + + def _init_derived(self): + r""" + Initialize the derived quantities. + + TESTS:: + + sage: M = Manifold(4, 'M') + sage: E = M.vector_bundle(2, 'E') + sage: nab = E.bundle_connection('nabla', latex_name=r'\nabla') + sage: nab._init_derived() + + """ + self._curvature_forms = {} # dict. of dict. of curvature forms + # (key: local frame) + self._hash_value = -1 + + def _del_derived(self): + r""" + Delete the derived quantities. + + TESTS:: + + sage: M = Manifold(4, 'M') + sage: E = M.vector_bundle(2, 'E') + sage: nab = E.bundle_connection('nabla', latex_name=r'\nabla') + sage: nab._del_derived() + + """ + self._curvature_forms.clear() + + def __eq__(self, other): + r""" + Comparison (equality) operator. + + INPUT: + + - ``other`` -- a bundle connection + + OUTPUT: + + - ``True`` if ``self`` is equal to ``other`` and ``False`` otherwise + + TESTS:: + + sage: M = Manifold(2, 'M') + sage: X. = M.chart() + sage: E = M.vector_bundle(2, 'E') + sage: e = E.local_frame('e') # standard frame for E + sage: nab = E.bundle_connection('nabla', latex_name=r'\nabla') + sage: a = M.one_form([x^2, x]) + sage: b = M.one_form([y^2, y]) + sage: nab.set_connection_form(0, 1, a) + sage: nab.set_connection_form(1, 0, b) + sage: nab1 = E.bundle_connection('nabla', latex_name=r'\nabla') + sage: (nab1 == nab) or (nab == nab1) + False + sage: nab1.set_connection_form(1, 0, a) + sage: nab1.set_connection_form(0, 1, b) + sage: (nab1 == nab) or (nab == nab1) + False + sage: nab1.set_connection_form(0, 1, a) + sage: nab1.set_connection_form(1, 0, b) + sage: (nab1 == nab) and (nab == nab1) + True + + """ + if other is self: + return True + if not isinstance(other, BundleConnection): + return False + if other._base_space != self._base_space: + return False + if self._connection_forms == {}: + return False + for frame in self._connection_forms: + if frame not in other._connection_forms: + return False + for ind in self._connection_forms[frame]: + if (other._connection_forms[frame][ind] != + self._connection_forms[frame][ind]): + return False + return True + + def __ne__(self, other): + r""" + Inequality operator. + + INPUT: + + - ``other`` -- an affine connection + + OUTPUT: + + - ``True`` if ``self`` is different from ``other`` and ``False`` + otherwise + + TESTS:: + + sage: M = Manifold(2, 'M') + sage: X. = M.chart() + sage: E = M.vector_bundle(2, 'E') + sage: e = E.local_frame('e') + sage: nab = E.bundle_connection('nabla', latex_name=r'\nabla') + sage: a = M.one_form([x^2, x]) + sage: b = M.one_form([y^2, y]) + sage: nab.set_connection_form(0, 1, a) + sage: nab.set_connection_form(1, 0, b) + sage: nab1 = E.bundle_connection('nabla', latex_name=r'\nabla') + sage: (nab1 != nab) and (nab != nab1) + True + sage: nab1.set_connection_form(1, 0, a) + sage: nab1.set_connection_form(0, 1, b) + sage: (nab1 != nab) and (nab != nab1) + True + sage: nab1.set_connection_form(0, 1, a) + sage: nab1.set_connection_form(1, 0, b) + sage: (nab1 != nab) or (nab != nab1) + False + + """ + return not (self == other) + + def vector_bundle(self): + r""" + Return the vector bundle on which the bundle connection is defined. + + OUTPUT: + + - instance of class + :class:`~sage.manifolds.differentiable.vector_bundle.DifferentiableVectorBundle` + representing the vector bundle on which ``self`` is defined. + + EXAMPLES:: + + sage: M = Manifold(3, 'M', start_index=1) + sage: c_xyz. = M.chart() + sage: E = M.vector_bundle(2, 'E') + sage: nab = E.bundle_connection('nabla', r'\nabla') + sage: nab.vector_bundle() + Differentiable real vector bundle E -> M of rank 2 over the base + space 3-dimensional differentiable manifold M + + """ + return self._vbundle + + def _new_forms(self, frame): + r""" + Create the connection forms w.r.t. the given frame. + + TESTS:: + + sage: M = Manifold(2, 'M', start_index=1) + sage: X. = M.chart() + sage: E = M.vector_bundle(2, 'E') + sage: e = E.local_frame('e') + sage: nab = E.bundle_connection('nabla', latex_name=r'\nabla') + sage: nab._new_forms(e) # random + {(1, 1): 1-form zero on the 2-dimensional differentiable manifold M, + (1, 2): 1-form zero on the 2-dimensional differentiable manifold M, + (2, 1): 1-form zero on the 2-dimensional differentiable manifold M, + (2, 2): 1-form zero on the 2-dimensional differentiable manifold M} + + """ + dom = frame._domain + forms_dict = {} + for i in self._vbundle.irange(): + for j in self._vbundle.irange(): + forms_dict[(i,j)] = dom.diff_form_module(1).zero() + return forms_dict + + def connection_forms(self, frame=None): + r""" + Return the connection forms relative to the given frame. + + If `e` is a local frame on `E`, we have + + .. MATH:: + + \nabla e_i = \sum^n_{j=1} e_j \otimes \omega^j_i , + + and the corresponding `n \times n`-matrix `(\omega^j_i)_{i,j}` + consisting of one forms is called *connection matrix of* `\nabla` *with + respect to* `e`. + + INPUT: + + - ``frame`` -- (default: ``None``) local frame relative to which the + connection forms are required; if none is provided, the + vector bundle's default frame is assumed + + OUTPUT: + + - connection forms relative to the frame ``frame``, as a dictionary with + tuples `(i, j)` as key and one forms as instances of + :class:`~sage.manifolds.differentiable.diff_form` as value + representing the matrix entries. + + EXAMPLES: + + Connection forms of a bundle connection on a rank 2 vector bundle over a + 3-dimensional manifold:: + + sage: M = Manifold(3, 'M', start_index=1) + sage: c_xyz. = M.chart() + sage: E = M.vector_bundle(2, 'E') + sage: e = E.local_frame('e') + sage: nab = E.bundle_connection('nabla', r'\nabla') + sage: a = M.one_form([x^2, z, x], name='a') + sage: b = M.one_form([y^2, z, y], name='b') + sage: nab.set_connection_form(1, 1, a) + sage: nab.set_connection_form(2, 2, b) + sage: nab.connection_forms() # random + {(1, 1): 1-form a on the 3-dimensional differentiable manifold M, + (1, 2): 1-form zero on the 3-dimensional differentiable manifold M, + (2, 1): 1-form zero on the 3-dimensional differentiable manifold M, + (2, 2): 1-form b on the 3-dimensional differentiable manifold M} + + """ + if frame is None: + smodule = self._vbundle.section_module(domain=self._base_space) + frame = smodule.default_frame() + if frame is None: + raise ValueError("A frame must be provided!") + if frame not in self._connection_forms: + # the connection forms must be computed + # + # Check whether frame is a subframe of a frame in which the + # forms are already known: + for oframe in self._connection_forms: + if frame in oframe._subframes: + self._connection_forms[frame] = self._new_forms(frame) + comp_store = self._connection_forms[frame] + ocomp_store = self._connection_forms[oframe] + for ind, value in ocomp_store.items(): + comp_store[ind] = value.restrict(frame._domain) + break + # TODO: Compute transformations + else: + self._connection_forms[frame] = self._new_forms(frame) + + return self._connection_forms[frame] + + def connection_form(self, i, j, frame=None): + r""" + Return the connection 1-form corresponding to the given index and + local frame. + + INPUT: + + - ``i``, ``j`` -- indices identifying the 1-form `\omega^i_j` + - ``frame`` -- (default: ``None``) local frame relative to which the + connection 1-forms are defined; if ``None``, the default frame of the + vector bundle's corresponding section module is assumed. + + OUTPUT: + + - the 1-form `\omega^i_{\ \, j}`, as an instance of + :class:`~sage.manifolds.differentiable.diff_form.DiffForm` + + EXAMPLES:: + + sage: M = Manifold(2, 'M') + sage: X. = M.chart() + sage: E = M.vector_bundle(2, 'E') + sage: e = E.local_frame('e') # standard frame for E + sage: nab = E.bundle_connection('nabla', latex_name=r'\nabla') + sage: a = M.one_form([x^2, x], name='a') + sage: b = M.one_form([y^2, y], name='b') + sage: nab.set_connection_form(0, 1, a) + sage: nab.set_connection_form(1, 0, b) + sage: nab.connection_form(0, 1) + 1-form a on the 2-dimensional differentiable manifold M + sage: nab.connection_form(0, 0) + 1-form zero on the 2-dimensional differentiable manifold M + + """ + return self.connection_forms(frame)[(i,j)] + + def add_connection_form(self, i, j, form, frame=None): + r""" + Assign the connection 1-form corresponding to the given index and + local frame. + + See method :meth:`connection_forms` for details about the definition of + the connection forms. + + To delete the connection forms in other frames, use the method + :meth:`set_connection_form` instead. + + INPUT: + + - ``i``, ``j`` -- indices identifying the 1-form `\omega^i_j` + - ``frame`` -- (default: ``None``) local frame in which the connection + 1-form is defined; if ``None``, the default frame of the vector bundle + is assumed. + + .. WARNING:: + + If the connection has already forms in other frames, it is the + user's responsibility to make sure that the 1-forms to be added + are consistent with them. + + OUTPUT: + + - connection 1-form `\omega^i_j in the given frame, as an instance of + the class :class:`~sage.manifolds.differentiable.diff_form.DiffForm`; + if such connection 1-form did not exist previously, it is created. See + method :meth:`connection_forms` for the storage convention of the + connection 1-forms. + + EXAMPLES:: + + sage: M = Manifold(2, 'M') + sage: X. = M.chart() + sage: E = M.vector_bundle(2, 'E') + sage: e = E.local_frame('e') # standard frame for E + sage: nab = E.bundle_connection('nabla', latex_name=r'\nabla') + sage: a = M.one_form([x^2, x], name='a') + sage: b = M.one_form([y^2, y], name='b') + sage: nab.add_connection_form(0, 1, a, frame=e) + sage: nab.connection_form(0, 1) + 1-form a on the 2-dimensional differentiable manifold M + + Since ``e`` is the vector bundle's default local frame, its mention may + be omitted:: + + sage: nab.add_connection_form(1, 0, b) + sage: nab.connection_form(1, 0) + 1-form b on the 2-dimensional differentiable manifold M + + Adding connection 1-forms w.r.t. to another local frame:: + + sage: f = E.local_frame('f') + sage: nab.add_connection_form(1, 1, a+b, frame=f) + sage: nab.connection_form(1, 1, frame=f) + 1-form a+b on the 2-dimensional differentiable manifold M + + The forms w.r.t. the frame ``e`` have been kept:: + + sage: nab.connection_form(0, 1, frame=e) + 1-form a on the 2-dimensional differentiable manifold M + + To delete them, use the method :meth:`set_connection_form` instead. + + """ + if frame is None: + smodule = self._vbundle.section_module(domain=self._base_space) + frame = smodule.default_frame() + if frame is None: + raise ValueError("A frame must be provided!") + ### + # Certainly, the form must be a differential form, otherwise try to + # convert: + dom = frame._domain + dmodule = dom.diff_form_module(1) + form = dmodule(form) + ### + # Are the components already known? + if frame not in self._connection_forms: + if frame not in self._vbundle._frames: + raise ValueError("the {} is not".format(frame) + + " a frame on the {}".format(self._base_space)) + self._connection_forms[frame] = self._new_forms(frame) + self._del_derived() # deletes the derived quantities + self._connection_forms[frame][(i,j)] = form + + def set_connection_form(self, i, j, form, frame=None): + r""" + Return the connection coefficients in a given frame for assignment. + + See method :meth:`connection_forms` for details about the definition of + the connection forms. + + The connection forms with respect to other frames are deleted, + in order to avoid any inconsistency. To keep them, use the method + :meth:`add_connection_form` instead. + + INPUT: + + - ``i``, ``j`` -- indices identifying the 1-form `\omega^i_j` + - ``frame`` -- (default: ``None``) local frame in which the connection + 1-form is defined; if ``None``, the default frame of the vector bundle + is assumed. + + EXAMPLES: + + Setting the connection forms of a bundle connection w.r.t. some local + frame:: + + sage: M = Manifold(2, 'M') + sage: X. = M.chart() + sage: E = M.vector_bundle(2, 'E') + sage: e = E.local_frame('e') # standard frame for E + sage: nab = E.bundle_connection('nabla', latex_name=r'\nabla') + sage: a = M.one_form([x^2, x], name='a') + sage: b = M.one_form([y^2, y], name='b') + sage: nab.set_connection_form(0, 1, a, frame=e) + sage: nab.connection_form(0, 1) + 1-form a on the 2-dimensional differentiable manifold M + + Since ``e`` is the vector bundle's default local frame, its mention may + be omitted:: + + sage: nab.set_connection_form(1, 0, b) + sage: nab.connection_form(1, 0) + 1-form b on the 2-dimensional differentiable manifold M + + Setting connection 1-forms w.r.t. to another local frame:: + + sage: f = E.local_frame('f') + sage: nab.set_connection_form(1, 1, a+b, frame=f) + sage: nab.connection_form(1, 1, frame=f) + 1-form a+b on the 2-dimensional differentiable manifold M + + The forms w.r.t. the frame ``e`` have been resetted:: + + sage: nab.connection_form(0, 1, frame=f) + 1-form zero on the 2-dimensional differentiable manifold M + + To keep them, use the method :meth:`add_connection_form` instead. + + """ + self.add_connection_form(i, j, form, frame=frame) + self.del_other_forms(frame) + + def del_other_forms(self, frame=None): + r""" + Delete all the connection forms but those corresponding to ``frame``. + + INPUT: + + - ``frame`` -- (default: ``None``) local frame, the connection forms + w.r.t. which are to be kept; if ``None``, the default frame of the + vector bundle is assumed. + + EXAMPLES: + + We first create two sets of connection coefficients:: + + sage: M = Manifold(2, 'M', start_index=1) + sage: X. = M.chart() + sage: E = M.vector_bundle(2, 'E') + sage: nab = E.bundle_connection('nabla', latex_name=r'\nabla') + sage: e = E.local_frame('e') + sage: a = M.one_form([x^2, x], name='a') + sage: b = M.one_form([y^2, y], name='b') + sage: nab.set_connection_form(1, 1, a, frame=e) + sage: f = M.vector_frame('f') + sage: nab.add_connection_form(1, 1, b, frame=e) + + Let us reset the connection coefficients w.r.t. all frames except for + frame ``e``:: + + sage: nab.del_other_forms(e) + sage: nab.connection_form(1, 1, frame=f) + 1-form zero on the 2-dimensional differentiable manifold M + + """ + if frame is None: + smodule = self._vbundle.section_module(domain=self._base_space) + frame = smodule.default_frame() + if frame is None: + raise ValueError("A frame must be provided!") + if frame not in self._connection_forms: + raise ValueError("the coefficients w.r.t. {}".format(frame) + + " have not been defined") + to_be_deleted = [] + for other_frame in self._connection_forms: + if other_frame != frame: + to_be_deleted.append(other_frame) + for other_frame in to_be_deleted: + del self._connection_forms[other_frame] + + def curvature_form(self, i, j, frame=None): + r""" + Return the curvature 2-form corresponding to the given index and local + frame. + + The *curvature 2-forms* with respect to the frame `e` are the 2-forms + `\Omega^i_j` given by the formula + + .. MATH:: + + \Omega^j_i = \mathrm{d} \omega^j_i + \sum^n_{k=1} \omega^j_k \wedge \omega^k_i + + INPUT: + + - ``i``, ``j`` -- indices identifying the 2-form `\Omega^i_j` + - ``frame`` -- (default: ``None``) local frame relative to which the + curvature 2-forms are defined; if ``None``, the default frame + of the vector bundle is assumed. + + OUTPUT: + + - the 2-form `\Omega^i_j`, as an instance of + :class:`~sage.manifolds.differentiable.diff_form.DiffForm` + + EXAMPLES:: + + sage: M = Manifold(2, 'M', start_index=1) + sage: X. = M.chart() + sage: E = M.vector_bundle(1, 'E') + sage: nab = E.bundle_connection('nabla', latex_name=r'\nabla') + sage: e = E.local_frame('e') + sage: a = M.one_form([x^2, x], name='a') + sage: nab.set_connection_form(1, 1, a) + sage: curv = nab.curvature_form(1, 1); curv + 2-form curvature (1,1) of bundle connection nabla w.r.t. Local + frame (E|_M, (e_1)) on the 2-dimensional differentiable manifold M + sage: curv.display() + curvature (1,1) of bundle connection nabla w.r.t. Local frame + (E|_M, (e_1)) = dx/\dy + + """ + if frame is None: + smodule = self._vbundle.section_module(domain=self._base_space) + frame = smodule.default_frame() + if frame is None: + raise ValueError("A frame must be provided!") + if frame not in self._curvature_forms: + self._curvature_forms[frame] = {} + if (i, j) not in self._curvature_forms[frame]: + name = "curvature ({},{}) of bundle connection ".format(i,j) + \ + self._name + " w.r.t. {}".format(frame) + latex_name = r"\Omega^" + str(i) + r"_{\ \, " + \ + str(j) + "}" + omega = self.connection_form + curv_form = omega(i, j, frame).exterior_derivative() + \ + sum(omega(k, j, frame).wedge(omega(i, k, frame)) + for k in self._vbundle.irange()) + curv_form.set_name(name=name, latex_name=latex_name) + self._curvature_forms[frame][(i, j)] = curv_form + return self._curvature_forms[frame][(i, j)] + + def __hash__(self): + r""" + Hash function. + + TESTS:: + + sage: M = Manifold(2, 'M') + sage: X. = M.chart() + sage: E = M.vector_bundle(2, 'E') + sage: nab = E.bundle_connection('nabla', latex_name=r'\nabla') + sage: hash(nab) == nab.__hash__() + True + + Let us check that ``nab`` can be used as a dictionary key:: + + sage: {nab: 1}[nab] + 1 + + """ + if self._hash_value == -1: + self._hash_value = hash(repr(self)) + return self._hash_value diff --git a/src/sage/manifolds/differentiable/char_class.py b/src/sage/manifolds/differentiable/char_class.py new file mode 100644 index 00000000000..ebd0f6dea28 --- /dev/null +++ b/src/sage/manifolds/differentiable/char_class.py @@ -0,0 +1,874 @@ +r""" +Characteristic Classes + +Let `E \to M` be some complex vector bundle over a differentiable manifold `M`. +A *characteristic class* `c(E)` is an element of the the cohomology ring +`H^{*}_{\mathrm{dR}}(M, \CC)` such that for any differentiable map `f: M \to N` +we have the *naturality condition*: + +.. MATH:: + + c(f^*E) = f^*c(E) . + +Roughly speaking, characteristic classes measure the non-triviality of the +vector bundle `E`. Notice, that this definition can be generalized to more +general cohomologies. + +One way to obtain and compute characteristic classes is via the so-called +*Chern-Weil theory* using the curvature of the vector bundle. This approach is +used for computation in SAGE. + +In the following, let `\nabla` be a connection on `E`, `e` a local frame on +`E` and `\Omega` be the corresponding curvature matrix +(see: :meth:`~sage.manifolds.differentiable.bundle_connection.BundleConnection.curvature_form`). + +Namely, if `P: \mathfrak{g} \to \CC` is an invariant polynomial, the object + +.. MATH:: + + \left[ P \left( \Omega \right) \right] \in H^{2*}_{\mathrm{dR}}(M, \CC) + +is well-defined and independent of the choice of `\nabla` (the proof can be +found in [Roe1988]_ pp. 31). This is the foundation of Chern-Weil theory and +therefore the following definitions. + +.. NOTE:: + + This documentation is rich of examples, but sparse in explanations. Please + consult the references for more details. + +AUTHORS: + +- Michael Jung (2019) : initial version + +REFERENCES: + +- [Mil1974]_ +- [Roe1988]_ + +Contents +-------- + +We consider the following three types of classes: + +- :ref:`additive` +- :ref:`multiplicative` +- :ref:`Pfaffian` + +.. _additive: + +Additive Classes +---------------- + +In the **complex** case, let `f` be a holomorphic function around zero. Then, +we call + +.. MATH:: + + \left[\mathrm{tr}\left( f\left( \frac{\Omega}{2 \pi i} \right) + \right)\right] \in H^{2*}_{\mathrm{dR}}(M, \CC) + +the *additive Chern f-genus*. + +Important and predefined additive Chern genera are: + +- *Chern Character* with `f(x) = \exp(x)` + +In the **real** case, let `g` be a holomorphic function around zero. Then, we +call + +.. MATH:: + + \left[\mathrm{tr}\left( \frac{1}{2} g\left( -\frac{\Omega^2}{4 \pi^2} + \right) \right)\right] \in H^{4*}_{\mathrm{dR}}(M, \CC) + +the *additive Pontryagin g-genus*. + +EXAMPLES: + +Consider the **Chern character** on some 2-dimensional spacetime:: + + sage: M = Manifold(2, 'M', structure='Lorentzian') + sage: X. = M.chart() + sage: E = M.vector_bundle(1, 'E', field='complex'); E + Differentiable complex vector bundle E -> M of rank 1 over the base space + 2-dimensional Lorentzian manifold M + sage: e = E.local_frame('e') + +Let us define the connection `\nabla^E` in terms of an electro-magnetic +potential `A(t)`:: + + sage: nab = E.bundle_connection('nabla^E', latex_name=r'\nabla^E') + sage: omega = M.one_form(name='omega') + sage: A = function('A') + sage: omega[1] = I*A(t) + sage: omega.display() + omega = I*A(t) dx + sage: nab.set_connection_form(0, 0, omega) + +The Chern character is then given by:: + + sage: ch = E.char_class('ChernChar'); ch + Characteristic class ch of additive type associated to e^x on the + Differentiable complex vector bundle E -> M of rank 1 over the base space + 2-dimensional Lorentzian manifold M + sage: ch_form = ch.get_form(nab); ch_form.display_expansion() + ch(E, nabla^E) = [1] + [0] + [1/2*d(A)/dt/pi dt/\dx] + +.. _multiplicative: + +Multiplicative Classes +---------------------- + +In the **complex** case, let `f` be a holomorphic function around zero. +Then, we call + +.. MATH:: + + \left[\det\left( f\left( \frac{\Omega}{2 \pi i} \right) + \right)\right] \in H^{2*}_{\mathrm{dR}}(M, \CC) + +the *multiplicative Chern f-genus*. + +Important and predefined multiplicative Chern genera are: + +- *Chern class* with `f(x) = 1+x` +- *Todd class* with `f(x) = \frac{x}{1-\exp(-x)}` + +In the **real** case, let `g` be a holomorphic function around zero with +`g(0)=1`. Then, we call + +.. MATH:: + + \left[\det\left( \sqrt{ g \left( -\frac{\Omega^2}{4 \pi^2} \right) } \right) \right] \in H^{4*}_{\mathrm{dR}}(M, \CC) + +the *multiplicative Pontryagin g-genus* + +Important and predefined multiplicative Pontryagin genera are: + +- *Pontryagin class* with `g(x) = 1+x` +- `\hat{A}` *class* with `g(x) = \frac{\sqrt{x}/2}{\sinh(\sqrt{x}/2)}` +- *Hirzebruch class* with `g(x) = \frac{\sqrt{x}}{\tanh(\sqrt{x})}` + +EXAMPLES: + +We consider the **Chern class** of the tautological line bundle `\gamma^1` over +`\CC\mathbf{P}^1`:: + + sage: M = Manifold(2, 'CP^1', start_index=1) + sage: U = M.open_subset('U') + sage: c_cart. = U.chart() # homogeneous coordinates in real terms + sage: c_comp. = U.chart(r'z:z zbar:\bar{z}') # complexification + sage: cart_to_comp = c_cart.transition_map(c_comp, (x+I*y, x-I*y)) + sage: comp_to_cart = cart_to_comp.inverse() + sage: E = M.vector_bundle(1, 'gamma^1', field='complex') + sage: e = E.local_frame('e', domain=U) + +To apply the Chern-Weil approach, we need a bundle connection in terms of a +connection one form. For this, we take the connection induced from the +hermitian metric on the trivial bundle +`\CC^2 \times \CC\mathbf{P}^1 \supset \gamma^1` in which the frame `e` above +corresponds to the section `[z:1] \mapsto (z,1)` and its magnitude-squared +is given by `1+|z|^2`:: + + sage: nab = E.bundle_connection('nabla') + sage: omega = U.one_form(name='omega') + sage: omega[c_comp.frame(),1,c_comp] = zbar/(1+z*zbar) + sage: nab.set_connection_form(1, 1, omega, frame=e) + +Now, the Chern class can be constructed:: + + sage: c = E.char_class('Chern'); c + Characteristic class c of multiplicative type associated to x + 1 on the + Differentiable complex vector bundle gamma^1 -> CP^1 of rank 1 over the + base space 2-dimensional differentiable manifold CP^1 + sage: c_form = c.get_form(nab) + sage: c_form.display_expansion(c_comp.frame(), chart=c_comp) + c(gamma^1, nabla) = [1] + [0] + [1/2*I/(pi + pi*z^2*zbar^2 + 2*pi*z*zbar) dz/\dzbar] + +Since `U` and `\CC\mathbf{P}^1` differ only by a point and therefore a null +set, the integral over the top form is independent of that choice:: + + sage: integrate(integrate(c_form[2][[1,2]].expr(c_cart), x, -infinity, infinity).full_simplify(), + ....: y, -infinity, infinity) + 1 + +The result shows that `c_1(\gamma^1)` generates the second integer +cohomology of `\CC\mathbf{P}^1`. + +.. _Pfaffian: + +Pfaffian Classes +---------------- + +Usually, in the literature, there are no such things defined as "Pfaffian +classes". However, using the Pfaffian of a matrix and inspired by the +aforementioned definitions, such classes can be defined as follows. + +Let `E` be a real vector bundle of rank `2n` and `f` be an odd real function +being analytic at zero. Furthermore, let `\Omega` be skew-symmetric, which is +certainly true when `\nabla` is metric and `e` is orthonormal. Then, we call + +.. MATH:: + + \left[\mathrm{Pf}\left( f\left( \frac{\Omega}{2 \pi} \right) \right)\right] + \in H^{2n*}(M,\RR) + +the *Pfaffian class associated to f*. + +The most important Pfaffian class is the *Euler class* which is simply given by +`f(x)=x`. + +EXAMPLES: + +We consider the **Euler class** of `S^2`:: + + sage: M = Manifold(2, name='S2', latex_name=r'S^2', start_index=1) + sage: U = M.open_subset('U') ; V = M.open_subset('V') + sage: M.declare_union(U,V) # M is the union of U and V + sage: c_xy. = U.chart() ; c_uv. = V.chart() + sage: xy_to_uv = c_xy.transition_map(c_uv, + ....: (x/(x^2+y^2), y/(x^2+y^2)), + ....: intersection_name='W', + ....: restrictions1= x^2+y^2!=0, + ....: restrictions2= u^2+v^2!=0) + sage: uv_to_xy = xy_to_uv.inverse() + sage: eU = c_xy.frame() ; eV = c_uv.frame() + sage: TM = M.tangent_bundle() + sage: e_class = TM.char_class('Euler'); e_class + Characteristic class e of Pfaffian type associated to x on the Tangent + bundle TS2 over the 2-dimensional differentiable manifold S2 + +To compute a particular representative of the Euler class, we need a +connection first:: + + sage: g = M.metric('g') # standard metric on S2 + sage: g[eU,1,1], g[eU,2,2] = 4/(1+x^2+y^2)^2, 4/(1+x^2+y^2)^2 + sage: g[eV,1,1], g[eV,2,2] = 4/(1+u^2+v^2)^2, 4/(1+u^2+v^2)^2 + sage: nab = g.connection() + +In case of the the Euler class, skew-symmetric curvature matrices are needed +for the Pfaffian. For this, we need to define the curvature matrices by +hand:: + + sage: cmatrix_U = [[nab.curvature_form(i,j,eU) for j in TM.irange()] + ....: for i in TM.irange()] + sage: cmatrix_V = [[nab.curvature_form(i,j,eV) for j in TM.irange()] + ....: for i in TM.irange()] + +Fortunately, both curvature matrices are skew-symmetric already:: + + sage: for i in range(TM.rank()): + ....: for j in range(TM.rank()): + ....: print(cmatrix_U[i][j].display()) + curvature (1,1) of connection nabla_g w.r.t. Coordinate frame + (U, (d/dx,d/dy)) = 0 + curvature (1,2) of connection nabla_g w.r.t. Coordinate frame + (U, (d/dx,d/dy)) = 4/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) dx/\dy + curvature (2,1) of connection nabla_g w.r.t. Coordinate frame + (U, (d/dx,d/dy)) = -4/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) dx/\dy + curvature (2,2) of connection nabla_g w.r.t. Coordinate frame + (U, (d/dx,d/dy)) = 0 + sage: for i in range(TM.rank()): + ....: for j in range(TM.rank()): + ....: print(cmatrix_V[i][j].display()) + curvature (1,1) of connection nabla_g w.r.t. Coordinate frame + (V, (d/du,d/dv)) = 0 + curvature (1,2) of connection nabla_g w.r.t. Coordinate frame + (V, (d/du,d/dv)) = 4/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1) du/\dv + curvature (2,1) of connection nabla_g w.r.t. Coordinate frame + (V, (d/du,d/dv)) = -4/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1) du/\dv + curvature (2,2) of connection nabla_g w.r.t. Coordinate frame + (V, (d/du,d/dv)) = 0 + +Now, the representative of the Euler class with respect to the connection +`\nabla` induced by the standard metric can be computed:: + + sage: cmatrices = {eU: cmatrix_U, eV: cmatrix_V} + sage: e_class_form = e_class.get_form(nab, cmatrices) + sage: e_class_form.display_expansion() + e(TS2, nabla_g) = [0] + [0] + [2/(pi + pi*x^4 + pi*y^4 + 2*pi*x^2 + + 2*(pi + pi*x^2)*y^2) dx/\dy] + +Indeed, this form represents the Euler class since integrating yields the +Euler characteristic of `S^2`:: + + sage: integrate(integrate(e_class_form[2][[1,2]].expr(), x, -infinity, infinity).simplify_full(), + ....: y, -infinity, infinity) + 2 + +.. _documentation: + +Class Documentation +------------------- +""" + +#****************************************************************************** +# Copyright (C) 2019 Michael Jung +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +#****************************************************************************** + +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.sage_object import SageObject + +################################################################################ +## Static methods + +def _get_predefined_class(arg): + r""" + Return the signature of the predefined class given by the string `arg`. + + The signature is given by a tuple following the syntax + (base field, class type, name, LaTeX name, function). + + Modify this method to add new predefined characteristic classes. + + TESTS:: + + sage: from sage.manifolds.differentiable.char_class import _get_predefined_class + sage: _get_predefined_class('Chern') + ('complex', 'multiplicative', 'c', 'c', x + 1) + sage: _get_predefined_class('Pontryagin') + ('real', 'multiplicative', 'p', 'p', x + 1) + sage: _get_predefined_class('Euler') + ('real', 'Pfaffian', 'e', 'e', x) + + """ + if not isinstance(arg, str): + raise TypeError("argument 'arg' must be string") + + from sage.symbolic.ring import SR + from sage.libs.pynac.pynac import I + # Define variable: + x = SR.symbol('x') + # Define dictionary. The syntax is as follows: + # (field_type, class_type, name, latex_name, func) + c_dict = {} + c_dict['ChernChar'] = ('complex', 'additive', 'ch', r'\mathrm{ch}', x.exp()) + c_dict['Todd'] = ('complex', 'additive', 'Td', r'\mathrm{Td}', + x / (1 - (-x).exp())) + c_dict['Chern'] = ('complex', 'multiplicative', 'c', 'c', 1 + x) + c_dict['Pontryagin'] = ('real', 'multiplicative', 'p', 'p', 1 + x) + c_dict['AHat'] = ('real', 'multiplicative', 'A^', r'\hat{A}', + x.sqrt() / (2 * (x.sqrt() / 2).sinh())) + c_dict['Hirzebruch'] = ('real', 'multiplicative', 'L', 'L', + (x.sqrt() / x.sqrt().tanh())) + c_dict['Euler'] = ('real', 'Pfaffian', 'e', 'e', x) + # Get class from arg + try: + res = c_dict[arg] + except KeyError: + raise ValueError("the characteristic class '{}' is ".format(arg) + + "not predefined yet.") + return res + +################################################################################ +## Classes + +class CharClass(SageObject, UniqueRepresentation): + r""" + An instance of this class represents a characteristic class on some + differentiable vector bundle over the field `\RR` or `\CC`. + + INPUT: + + - vbundle -- vector bundle on which the characteristic class should be + defined + - func -- symbolic expression representing the function to which ``self`` + should be associated to + - class_type -- (default: ``'multiplicative'``) class type of the + characteristic class; at this stage, the following options are possible: + + - ``'multiplicative'`` -- returns a class of multiplicative type, + using the determinant + - ``'additive'`` -- returns a class of additive type, using the trace + - ``'Pfaffian'`` -- returns a class of Pfaffian type, using the + Pfaffian + + - ``name`` -- string representation given to the characteristic class + - ``latex_name`` -- (default: ``None``) LaTeX name given to the + characteristic class + + EXAMPLES: + + Get characteristic classes using predefined ones:: + + sage: M = Manifold(4, 'M') + sage: TM = M.tangent_bundle() + sage: TM.char_class('Pontryagin') + Characteristic class p of multiplicative type associated to x + 1 on the + Tangent bundle TM over the 4-dimensional differentiable manifold M + sage: TM.char_class('Hirzebruch') + Characteristic class L of multiplicative type associated to + sqrt(x)/tanh(sqrt(x)) on the Tangent bundle TM over the 4-dimensional + differentiable manifold M + sage: TM.char_class('AHat') + Characteristic class A^ of multiplicative type associated to + 1/2*sqrt(x)/sinh(1/2*sqrt(x)) on the Tangent bundle TM over the + 4-dimensional differentiable manifold M + + The vector bundle's base field and definition domain of the characteristic + class must fit together, otherwise an error message occurs:: + + sage: TM.char_class('Chern') + Traceback (most recent call last): + ... + ValueError: base field must be complex for class 'Chern' + + If your favourite class is not predefined yet, the associated function can + be put manually:: + + sage: cl = TM.char_class(1+x^2, name='cl'); cl + Characteristic class cl of multiplicative type associated to x^2 + 1 on + the Tangent bundle TM over the 4-dimensional differentiable manifold M + + """ + def __init__(self, vbundle, func, class_type='multiplicative', name=None, + latex_name=None): + r""" + Construct a characteristic class. + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: TM = M.tangent_bundle() + sage: from sage.manifolds.differentiable.char_class import CharClass + sage: c = CharClass(TM, 1+x, name='c'); c + Characteristic class c of multiplicative type associated to x + 1 on + the Tangent bundle TM over the 3-dimensional differentiable + manifold M + sage: TestSuite(c).run() + + """ + if vbundle._field_type == 'neither_real_nor_complex': + raise ValueEror("the vector bundle must either be real or complex") + if class_type not in ['additive', 'multiplicative', 'Pfaffian']: + raise ValueError("the argument 'class_type' must either be " + "'additive', 'multiplicative' or 'Pfaffian'") + if class_type == 'Pfaffian': + if vbundle._field_type != 'real' or vbundle._rank % 2 != 0: + raise ValueError("Pfaffian classes can only be defined for real" + " vector bundles of even rank") + self._name = name + if latex_name is None: + self._latex_name = name + else: + self._latex_name = latex_name + self._func = func + self._class_type = class_type + self._vbundle = vbundle + self._base_space = vbundle._base_space + self._rank = vbundle._rank + self._coeff_list = self._get_coeff_list() + self._init_derived() + + def _get_coeff_list(self): + r""" + Return the list of coefficients of the Taylor expansion at zero of the + function. + + TESTS:: + + sage: M = Manifold(2, 'M') + sage: E = M.vector_bundle(1, 'E', field='complex') + sage: c = E.char_class(1+x) + sage: c._get_coeff_list() + [1, 1] + + """ + pow_range = (self._base_space._dim / 2).floor() + from sage.symbolic.ring import SR + def_var = self._func.default_variable() + # Use a complex variable without affecting the old one: + new_var = SR.symbol('x_char_class_', domain='complex') + if self._vbundle._field_type == 'real': + if self._class_type == 'additive': + func = self._func.subs({def_var: new_var ** 2}) / 2 + elif self._class_type == 'multiplicative': + # This could case problems in the real domain, where sqrt(x^2) + # is simplified to |x|. However, the variable must be complex + # anyway. + func = self._func.subs({def_var : new_var**2}).sqrt() + elif self._class_type == 'Pfaffian': + # There are no canonical Pfaffian classes, however, consider the + # projection onto the odd part of the function to keep the + # matrices skew: + func = (self._func.subs({def_var: new_var}) - + self._func.subs({def_var: -new_var})) / 2 + else: + func = self._func.subs({def_var: new_var}) + coef = func.taylor(new_var, 0, pow_range).coefficients(sparse=False) + + return coef + + def _init_derived(self): + r""" + Initialize the derived quantities. + + TESTS:: + + sage: M = Manifold(2, 'M') + sage: TM = M.tangent_bundle() + sage: c = TM.char_class(1+x) + sage: c._init_derived() + + """ + self._mixed_forms = {} # dict. of mixed forms corresponding this + # characteristic class + # (key: bundle connection) + + def _del_derived(self): + r""" + Delete the derived quantities. + + TESTS:: + + sage: M = Manifold(2, 'M') + sage: TM = M.tangent_bundle() + sage: c = TM.char_class(1+x) + sage: c._del_derived() + + """ + self._mixed_forms.clear() + + def _repr_(self): + r""" + String representation of the object. + + TESTS:: + + sage: M = Manifold(2, 'M') + sage: TM = M.tangent_bundle() + sage: c = TM.char_class(1+x, name='c') + sage: c # indirect doctest + Characteristic class c of multiplicative type associated to x + 1 on + the Tangent bundle TM over the 2-dimensional differentiable + manifold M + sage: repr(c) # indirect doctest + 'Characteristic class c of multiplicative type associated to x + 1 + on the Tangent bundle TM over the 2-dimensional differentiable + manifold M' + sage: c._repr_() + 'Characteristic class c of multiplicative type associated to x + 1 + on the Tangent bundle TM over the 2-dimensional differentiable + manifold M' + + """ + desc = "Characteristic class " + if self._name is not None: + desc += self._name + " " + desc += "of {} type ".format(self._class_type) + desc += "associated to {} on the {}".format(self._func, self._vbundle) + return desc + + def _latex_(self): + r""" + LaTeX representation of the object. + + TESTS:: + + sage: M = Manifold(2, 'M') + sage: TM = M.tangent_bundle() + sage: ch = TM.char_class(exp(x), class_type='additive', name='ch', + ....: latex_name=r'\mathrm{ch}') + sage: ch._latex_() + '\\mathrm{ch}(TM)' + + """ + return self._latex_name + "(" + self._vbundle._latex_name + ")" + + def class_type(self): + r""" + Return the class type of ``self``. + + EXAMPLES:: + + sage: M = Manifold(2, 'M') + sage: TM = M.tangent_bundle() + sage: ch = TM.char_class(exp(x), class_type='additive', name='ch', + ....: latex_name=r'\mathrm{ch}') + sage: ch.class_type() + 'additive' + + """ + return self._class_type + + def function(self): + r""" + Return the function corresponding to this characteristic class. + + EXAMPLES:: + + sage: M = Manifold(2, 'M') + sage: TM = M.tangent_bundle() + sage: e_class = TM.char_class('Euler') + sage: e_class.function() + x + sage: AHat = TM.char_class('AHat') + sage: AHat.function() + 1/2*sqrt(x)/sinh(1/2*sqrt(x)) + sage: c = TM.char_class(1+x, name='c') + sage: c.function() + x + 1 + + """ + return self._func + + def get_form(self, con, cmatrices=None): + r""" + Return the form representing ``self`` with respect to the given + connection ``con``. + + INPUT: + + - ``con`` -- connection to which the form should be associated to; this + can be either a bundle connection as an instance of + :class:`~sage.manifolds.differentiable.bundle_connection.BundleConnection` + or, in case of the tensor bundle, an affine connection as an instance + of :class:`~sage.manifolds.differentiable.affine_connection.AffineConnection` + - ``cmatrices`` -- (default: ``None``) a dictionary of curvature + matrices with local frames as keys and curvature matrices as items; if + ``None``, SAGE tries to get the curvature matrices from the connection + + OUTPUT: + + - mixed form as an instance of + :class:`~sage.manifolds.differentiable.mixed_form.MixedForm` + representing the total characteristic class + + .. NOTE:: + + Be aware that depending on the characteristic class and complexity + of the manifold, computation times may vary a lot. In addition, if + not done before, the curvature form is computed from the connection, + here. If this behaviour is not wanted and the curvature form is + already known, please use the argument ``cmatrices``. + + EXAMPLES: + + Again, consider the Chern character on some 2-dimensional spacetime:: + + sage: M = Manifold(2, 'M', structure='Lorentzian') + sage: X. = M.chart() + sage: E = M.vector_bundle(1, 'E', field='complex'); E + Differentiable complex vector bundle E -> M of rank 1 over the base space + 2-dimensional Lorentzian manifold M + sage: e = E.local_frame('e') + + And again, we define the connection `\nabla^E` in terms of an + electro-magnetic potential `A(t)`:: + + sage: nab = E.bundle_connection('nabla^E', latex_name=r'\nabla^E') + sage: omega = M.one_form(name='omega') + sage: A = function('A') + sage: omega[1] = I*A(t) + sage: omega.display() + omega = I*A(t) dx + sage: nab.set_connection_form(0, 0, omega) + + The Chern character is then given by:: + + sage: ch = E.char_class('ChernChar'); ch + Characteristic class ch of additive type associated to e^x on the + Differentiable complex vector bundle E -> M of rank 1 over the base space + 2-dimensional Lorentzian manifold M + + Inserting the connection, the result is a mixed differential form with + a priori non-zero components in even degrees:: + + sage: ch_form = ch.get_form(nab); ch_form + Mixed differential form ch(E, nabla^E) on the 2-dimensional + Lorentzian manifold M + sage: ch_form.display() + ch(E, nabla^E) = ch_0(E, nabla^E) + zero + ch_1(E, nabla^E) + sage: ch_form.display_expansion() + ch(E, nabla^E) = [1] + [0] + [1/2*d(A)/dt/pi dt/\dx] + + Due to long computation times, the form is saved:: + + sage: ch_form is ch.get_form(nab) + True + + """ + from .bundle_connection import BundleConnection + from .affine_connection import AffineConnection + if not isinstance(con, (AffineConnection, BundleConnection)): + raise TypeError("argument must be an affine connection on the " + "manifold or bundle connection on the vector " + "bundle") + if con not in self._mixed_forms: + if cmatrices is None: + if self._class_type == 'Pfaffian': + raise NotImplementedError( + "At this stage, Pfaffian forms cannot be derived from " + "(metric) connections. Please use the argument " + "'cmatrices' to insert a dictionary of skew-symmetric " + "curvature matrices by hand, instead.") + cmatrices = {} + for frame in self._get_min_frames(con._coefficients.keys()): + cmatrix = [[con.curvature_form(i, j, frame) + for j in self._vbundle.irange()] + for i in self._vbundle.irange()] + cmatrices[frame] = cmatrix + # Prepare mixed form: + name, latex_name = self._name, self._latex_name + if name is not None and con._name is not None: + name += "(" + self._vbundle._name + ", " + con._name + ")" + if latex_name is not None and con._latex_name is not None: + latex_name += "(" + self._vbundle._latex_name + ", " + \ + con._latex_name + ")" + res = self._base_space.mixed_form(name=name, latex_name=latex_name) + # Set name of homogeneous components: + # + # Only even (or in the real case, by four divisible) degrees are + # non-zero: + if self._class_type == 'Pfaffian': + deg_dist = self._rank + elif self._vbundle._field_type == 'real': + deg_dist = 4 + elif self._vbundle._field_type == 'complex': + deg_dist = 2 + else: + # You never know... + deg_dist = 1 + # Now, define the name for each form: + for k in res.irange(): + if k % deg_dist != 0: + res[k].set_name(name="zero", latex_name="0") + res[k]._is_zero = True + else: + if self._name is not None: + name = self._name + "_" + str(k / deg_dist) + \ + "(" + self._vbundle._name + if con._name is not None: + name += ", " + con._name + name += ")" + # LaTeX name: + if self._latex_name is not None: + latex_name = self._latex_name + \ + r"_{" + str(k / deg_dist) + r"}" + \ + r"(" + self._vbundle._latex_name + if con._latex_name is not None: + latex_name += r", " + con._latex_name + latex_name += r")" + # Set name: + res[k].set_name(name=name, latex_name=latex_name) + res[k]._is_zero = False # a priori + # Begin computation: + from sage.matrix.matrix_space import MatrixSpace + for frame, cmatrix in cmatrices.items(): + # Define matrix space: + dom = frame._domain + alg = dom.mixed_form_algebra() + mspace = MatrixSpace(alg, self._rank) + # Insert "normalized" curvature matrix into polynomial: + cmatrix = mspace(cmatrix) # convert curvature matrix + ncmatrix = self._normalize_matrix(cmatrix) + rmatrix = self._insert_in_polynomial(ncmatrix) + # Compute classes: + if self._class_type == 'additive': + rst = rmatrix.trace() # mixed form + elif self._class_type == 'multiplicative': + rst = rmatrix.det() # mixed form + elif self._class_type == 'Pfaffian': + rst = rmatrix.pfaffian() # mixed form + # Set restriction: + res.set_restriction(rst) + + self._mixed_forms[con] = res + + return self._mixed_forms[con] + + def _insert_in_polynomial(self, cmatrix): + r""" + Return the matrix after inserting `cmatrix` into the polynomial given by + the taylor expansion of `self._func`. + + TESTS:: + + sage: M = Manifold(4, 'M') + sage: c = M.tangent_bundle().char_class('Pontryagin') + sage: c._insert_in_polynomial(x) + 1/2*x^2 + 1 + + """ + mspace = cmatrix.parent() + # Compute matrix powers: + power_list = [mspace.one()] + for pow in range(len(self._coeff_list) - 1): + power_list.append(cmatrix * power_list[pow]) + # Put things together: + rmatrix = sum(self._coeff_list[k] * power_list[k] + for k in range(len(self._coeff_list))) + + return rmatrix + + def _normalize_matrix(self, cmatrix): + r""" + Return the curvature matrix "normalized" with `i/(2 \pi)` or `1/(2 \pi)` + respectively. + + INPUT: + + - ``cmatrix`` curvature matrix + + OUTPUT: + + - ``I/(2*pi)*cmatrix`` + + TESTS:: + + sage: M = Manifold(2, 'M') + sage: TM = M.tangent_bundle() + sage: c = TM.char_class(1+x) + sage: c._normalize_matrix(x) + -1/2*I*x/pi + + """ + from sage.symbolic.constants import pi + fac = 1 / (2 * pi) + if self._class_type != 'Pfaffian': + from sage.libs.pynac.pynac import I + fac = fac / I + return fac * cmatrix + + def _get_min_frames(self, frame_list): + r""" + Return the minimal amount of frames necessary to cover the union of all + frame's domains. + + INPUT: + + - list of frames + + OUTPUT: + + - set of frames + + TESTS:: + + sage: M = Manifold(2, 'M') + sage: U = M.open_subset('U'); V = M.open_subset('V') + sage: e = U.vector_frame('e'); f = V.vector_frame('f') + sage: g = M.vector_frame('g') + sage: c = M.tangent_bundle().char_class('Pontryagin') + sage: c._get_min_frames([e, f, g]) + {Vector frame (M, (g_0,g_1))} + + """ + min_frame_set = set() + for frame in frame_list: + redund_frame_set = set() + for oframe in min_frame_set: + if frame._domain.is_subset(oframe._domain): + break + elif oframe._domain.is_subset(frame._domain): + redund_frame_set.add(oframe) + else: + min_frame_set.add(frame) + min_frame_set.difference_update(redund_frame_set) + return min_frame_set diff --git a/src/sage/manifolds/differentiable/diff_form.py b/src/sage/manifolds/differentiable/diff_form.py index 14d2812222d..49c44503b2e 100644 --- a/src/sage/manifolds/differentiable/diff_form.py +++ b/src/sage/manifolds/differentiable/diff_form.py @@ -196,11 +196,11 @@ class DiffForm(TensorField): sage: f = M.scalar_field({c_xy: (x+y)^2, c_uv: u^2}, name='f') sage: s = f*a ; s - 1-form on the 2-dimensional differentiable manifold M + 1-form f*a on the 2-dimensional differentiable manifold M sage: s.display(eU) - (-x^2*y - 2*x*y^2 - y^3) dx + (x^3 + 2*x^2*y + x*y^2) dy + f*a = (-x^2*y - 2*x*y^2 - y^3) dx + (x^3 + 2*x^2*y + x*y^2) dy sage: s.display(eV) - 1/2*u^2*v du - 1/2*u^3 dv + f*a = 1/2*u^2*v du - 1/2*u^3 dv .. RUBRIC:: Examples with SymPy as the symbolic engine @@ -263,9 +263,9 @@ class DiffForm(TensorField): sage: f = M.scalar_field({c_xy: (x+y)^2, c_uv: u^2}, name='f') sage: s = f*a sage: s.display(eU) - -y*(x**2 + 2*x*y + y**2) dx + x*(x**2 + 2*x*y + y**2) dy + f*a = -y*(x**2 + 2*x*y + y**2) dx + x*(x**2 + 2*x*y + y**2) dy sage: s.display(eV) - u**2*v/2 du - u**3/2 dv + f*a = u**2*v/2 du - u**3/2 dv """ def __init__(self, vector_field_module, degree, name=None, latex_name=None): @@ -511,7 +511,7 @@ def wedge(self, other): sage: f.add_expr_by_continuation(c_uv, W) sage: t = a.wedge(f) sage: t.display() - x*y dx + x^2 dy + f*a = x*y dx + x^2 dy """ if other._tensor_rank == 0: @@ -1441,7 +1441,7 @@ def wedge(self, other): sage: f = M.scalar_field(x, name='f') sage: t = a.wedge(f) sage: t.display() - 2*x dx + (x^2 + x) dy + x*y*z dz + f*a = 2*x dx + (x^2 + x) dy + x*y*z dz """ if other._tensor_rank == 0: diff --git a/src/sage/manifolds/differentiable/mixed_form.py b/src/sage/manifolds/differentiable/mixed_form.py index 94d916dde71..92dd1003693 100644 --- a/src/sage/manifolds/differentiable/mixed_form.py +++ b/src/sage/manifolds/differentiable/mixed_form.py @@ -974,7 +974,7 @@ def exterior_derivative(self): resu._latex_name = format_unop_latex(r'\mathrm{d}', self._latex_name) return resu - def copy(self): + def copy(self, name=None, latex_name=None): r""" Return an exact copy of ``self``. @@ -982,6 +982,12 @@ def copy(self): The name and names of the components are not copied. + INPUT: + + - ``name`` -- (default: ``None``) name given to the copy + - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the + copy; if none is provided, the LaTeX symbol is set to ``name`` + EXAMPLES: Initialize a 2-dimensional manifold and differential forms:: @@ -1015,8 +1021,8 @@ def copy(self): An exact copy is made. The copy is an entirely new instance and has a different name, but has the very same values:: - sage: B = A.copy(); B.display() - f + (unnamed 1-form) + (unnamed 2-form) + sage: B = A.copy(); B.disp() + (unnamed scalar field) + (unnamed 1-form) + (unnamed 2-form) sage: B.display_expansion(e_uv) [1/2*u + 1/2*v] + [(1/4*u + 1/4*v) du + (1/4*u + 1/4*v) dv] + [0] sage: A == B @@ -1038,7 +1044,9 @@ def copy(self): """ resu = self._new_instance() resu[:] = [form.copy() for form in self] - resu._is_zero = self._is_zero + resu.set_name(name=name, latex_name=latex_name) + resu._is_zero = self._is_zero # a priori + return resu def __setitem__(self, index, values): @@ -1174,11 +1182,10 @@ def set_restriction(self, rst): """ if not isinstance(rst, MixedForm): raise TypeError("the argument must be a mixed form") - subdomain = rst._domain - if not subdomain.is_subset(self._domain): + if not rst._domain.is_subset(self._domain): raise ValueError("the specified domain is not a subset of " + "the domain of definition of the mixed form") - for j in range(0, self._max_deg + 1): + for j in self.irange(): self[j].set_restriction(rst[j]) self._is_zero = False # a priori diff --git a/src/sage/manifolds/differentiable/multivectorfield.py b/src/sage/manifolds/differentiable/multivectorfield.py index 082636f7bd7..4ac136fb147 100644 --- a/src/sage/manifolds/differentiable/multivectorfield.py +++ b/src/sage/manifolds/differentiable/multivectorfield.py @@ -147,11 +147,11 @@ class MultivectorField(TensorField): sage: f = M.scalar_field({c_xy: (x+y)^2, c_uv: u^2}, name='f') sage: s = f*s ; s - 2-vector field on the 2-dimensional differentiable manifold M + 2-vector field f*(a/\b) on the 2-dimensional differentiable manifold M sage: s.display(eU) - (-2*x^2*y^3 - x^3 - (4*x^3 + x)*y^2 - 2*(x^4 + x^2)*y) d/dx/\d/dy + f*(a/\b) = (-2*x^2*y^3 - x^3 - (4*x^3 + x)*y^2 - 2*(x^4 + x^2)*y) d/dx/\d/dy sage: s.display(eV) - (1/2*u^5 - 1/2*u^3*v^2 - 1/2*u^2*v^3 + u^3 + 1/2*(u^4 + 2*u^2)*v) + f*(a/\b) = (1/2*u^5 - 1/2*u^3*v^2 - 1/2*u^2*v^3 + u^3 + 1/2*(u^4 + 2*u^2)*v) d/du/\d/dv """ diff --git a/src/sage/manifolds/differentiable/scalarfield.py b/src/sage/manifolds/differentiable/scalarfield.py index 8c7934d061e..3116731150e 100644 --- a/src/sage/manifolds/differentiable/scalarfield.py +++ b/src/sage/manifolds/differentiable/scalarfield.py @@ -1026,12 +1026,12 @@ def wedge(self, other): sage: a = M.diff_form(2, name='a') sage: a[0,1] = x*y sage: s = f.wedge(a); s - 2-form on the 2-dimensional differentiable manifold M + 2-form f*a on the 2-dimensional differentiable manifold M sage: s.display() - (x*y^3 + x^2*y) dx/\dy + f*a = (x*y^3 + x^2*y) dx/\dy """ - return self*other + return self * other def degree(self): r""" diff --git a/src/sage/manifolds/differentiable/tensorfield.py b/src/sage/manifolds/differentiable/tensorfield.py index ec11c25d234..c2d66ffdb4b 100644 --- a/src/sage/manifolds/differentiable/tensorfield.py +++ b/src/sage/manifolds/differentiable/tensorfield.py @@ -267,7 +267,7 @@ class TensorField(ModuleElement): sage: s.restrict(U) == f.restrict(U) * t.restrict(U) # long time True sage: s = f*t.restrict(U); s - Tensor field of type (0,2) on the Open subset U of the 2-dimensional + Tensor field f*t of type (0,2) on the Open subset U of the 2-dimensional differentiable manifold S^2 sage: s.restrict(U) == f.restrict(U) * t.restrict(U) True @@ -2041,10 +2041,16 @@ def copy_from(self, other): self.set_name(name=name, latex_name=latex_name) self._is_zero = other._is_zero - def copy(self): + def copy(self, name=None, latex_name=None): r""" Return an exact copy of ``self``. + INPUT: + + - ``name`` -- (default: ``None``) name given to the copy + - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the + copy; if none is provided, the LaTeX symbol is set to ``name`` + .. NOTE:: The name and the derived quantities are not copied. @@ -2066,8 +2072,8 @@ def copy(self): sage: t[e_xy,:] = [[x+y, 0], [2, 1-y]] sage: t.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) sage: s = t.copy(); s - Tensor field of type (1,1) on - the 2-dimensional differentiable manifold M + Tensor field of type (1,1) on the 2-dimensional differentiable + manifold M sage: s.display(e_xy) (x + y) d/dx*dx + 2 d/dy*dx + (-y + 1) d/dy*dy sage: s == t @@ -2087,6 +2093,7 @@ def copy(self): resu = self._new_instance() for dom, rst in self._restrictions.items(): resu._restrictions[dom] = rst.copy() + resu.set_name(name=name, latex_name=latex_name) resu._is_zero = self._is_zero return resu @@ -2288,10 +2295,11 @@ def __pos__(self): resu = self._new_instance() for dom, rst in self._restrictions.items(): resu._restrictions[dom] = + rst - if self._name is not None: - resu._name = '+' + self._name - if self._latex_name is not None: - resu._latex_name = '+' + self._latex_name + # Compose names: + from sage.tensor.modules.format_utilities import (format_unop_txt, + format_unop_latex) + resu._name = format_unop_txt('+', self._name) + resu._latex_name = format_unop_latex(r'+', self._latex_name) return resu def __neg__(self): @@ -2334,10 +2342,11 @@ def __neg__(self): resu = self._new_instance() for dom, rst in self._restrictions.items(): resu._restrictions[dom] = - rst - if self._name is not None: - resu._name = '-' + self._name - if self._latex_name is not None: - resu._latex_name = '-' + self._latex_name + # Compose names: + from sage.tensor.modules.format_utilities import (format_unop_txt, + format_unop_latex) + resu._name = format_unop_txt('-', self._name) + resu._latex = format_unop_latex(r'-', self._latex_name) return resu ######### ModuleElement arithmetic operators ######## @@ -2519,16 +2528,16 @@ def _rmul_(self, scalar): on U: (x, y) |--> 1/(x^2 + y^2 + 1) on V: (u, v) |--> 2/(u^2 + v^2 + 2) sage: s = a._rmul_(f); s - Tensor field of type (1,1) on the 2-dimensional differentiable + Tensor field f*a of type (1,1) on the 2-dimensional differentiable manifold M sage: a.display(e_xy) a = x d/dx*dx + d/dx*dy + y d/dy*dx sage: s.display(e_xy) - x/(x^2 + y^2 + 1) d/dx*dx + 1/(x^2 + y^2 + 1) d/dx*dy + y/(x^2 + y^2 + 1) d/dy*dx + f*a = x/(x^2 + y^2 + 1) d/dx*dx + 1/(x^2 + y^2 + 1) d/dx*dy + y/(x^2 + y^2 + 1) d/dy*dx sage: a.display(e_uv) a = (1/2*u + 1/2) d/du*du + (1/2*u - 1/2) d/du*dv + (1/2*v + 1/2) d/dv*du + (1/2*v - 1/2) d/dv*dv sage: s.display(e_uv) - (u + 1)/(u^2 + v^2 + 2) d/du*du + (u - 1)/(u^2 + v^2 + 2) d/du*dv + (v + 1)/(u^2 + v^2 + 2) d/dv*du + (v - 1)/(u^2 + v^2 + 2) d/dv*dv + f*a = (u + 1)/(u^2 + v^2 + 2) d/du*du + (u - 1)/(u^2 + v^2 + 2) d/du*dv + (v + 1)/(u^2 + v^2 + 2) d/dv*du + (v - 1)/(u^2 + v^2 + 2) d/dv*dv sage: s == f*a # indirect doctest True sage: z = a.parent().zero(); z @@ -2550,6 +2559,13 @@ def _rmul_(self, scalar): resu = self._new_instance() for dom, rst in self._restrictions.items(): resu._restrictions[dom] = scalar.restrict(dom) * rst + # Compose names: + from sage.tensor.modules.format_utilities import (format_mul_txt, + format_mul_latex) + resu_name = format_mul_txt(scalar._name, '*', self._name) + resu_latex = format_mul_latex(scalar._latex_name, ' \cdot ', + self._latex_name) + resu.set_name(name=resu_name, latex_name=resu_latex) return resu ######### End of ModuleElement arithmetic operators ######## @@ -2608,12 +2624,12 @@ def __mul__(self, other): sage: f = M.scalar_field({c_xy: x*y}, name='f') sage: f.add_expr_by_continuation(c_uv, U.intersection(V)) sage: s = a.__mul__(f); s - Tensor field of type (1,1) on the 2-dimensional differentiable + Tensor field f*a of type (1,1) on the 2-dimensional differentiable manifold M sage: s.display(e_xy) - x^2*y d/dx*dx + x*y d/dx*dy + x*y^2 d/dy*dx + f*a = x^2*y d/dx*dx + x*y d/dx*dy + x*y^2 d/dy*dx sage: s.display(e_uv) - (1/8*u^3 - 1/8*(u + 1)*v^2 + 1/8*u^2) d/du*du + f*a = (1/8*u^3 - 1/8*(u + 1)*v^2 + 1/8*u^2) d/du*du + (1/8*u^3 - 1/8*(u - 1)*v^2 - 1/8*u^2) d/du*dv + (1/8*u^2*v - 1/8*v^3 + 1/8*u^2 - 1/8*v^2) d/dv*du + (1/8*u^2*v - 1/8*v^3 - 1/8*u^2 + 1/8*v^2) d/dv*dv @@ -2642,12 +2658,12 @@ def __mul__(self, other): sage: M.set_calculus_method('sympy') sage: f.add_expr_by_continuation(c_uv, U.intersection(V)) sage: s = a.__mul__(f); s - Tensor field of type (1,1) on the 2-dimensional differentiable + Tensor field f*a of type (1,1) on the 2-dimensional differentiable manifold M sage: s.display(e_xy) - x**2*y d/dx*dx + x*y d/dx*dy + x*y**2 d/dy*dx + f*a = x**2*y d/dx*dx + x*y d/dx*dy + x*y**2 d/dy*dx sage: s.display(e_uv) - (u**3/8 + u**2/8 - u*v**2/8 - v**2/8) d/du*du + (u**3/8 - + f*a = (u**3/8 + u**2/8 - u*v**2/8 - v**2/8) d/du*du + (u**3/8 - u**2/8 - u*v**2/8 + v**2/8) d/du*dv + (u**2*v/8 + u**2/8 - v**3/8 - v**2/8) d/dv*du + (u**2*v/8 - u**2/8 - v**3/8 + v**2/8) d/dv*dv diff --git a/src/sage/manifolds/differentiable/tensorfield_paral.py b/src/sage/manifolds/differentiable/tensorfield_paral.py index c7597fdfef3..d1a791b6fc0 100644 --- a/src/sage/manifolds/differentiable/tensorfield_paral.py +++ b/src/sage/manifolds/differentiable/tensorfield_paral.py @@ -1811,11 +1811,11 @@ def __mul__(self, other): sage: f = M.scalar_field({X: x+y}, name='f') sage: s = a.__mul__(f); s - Tensor field of type (0,2) on the 2-dimensional differentiable + Tensor field f*a of type (0,2) on the 2-dimensional differentiable manifold M sage: s.display() - (x^2 + (x + 1)*y + x) dx*dx + (2*x + 2*y) dx*dy + (x*y + y^2) dy*dx - + (-x^3 - x^2*y) dy*dy + f*a = (x^2 + (x + 1)*y + x) dx*dx + (2*x + 2*y) dx*dy + + (x*y + y^2) dy*dx + (-x^3 - x^2*y) dy*dy sage: s == f*a True diff --git a/src/sage/manifolds/differentiable/vector_bundle.py b/src/sage/manifolds/differentiable/vector_bundle.py index 180e61af1e1..439406e65e5 100644 --- a/src/sage/manifolds/differentiable/vector_bundle.py +++ b/src/sage/manifolds/differentiable/vector_bundle.py @@ -134,6 +134,139 @@ def _repr_(self): desc = "Differentiable " return desc + TopologicalVectorBundle._repr_object_name(self) + def bundle_connection(self, name, latex_name=None): + r""" + Return a bundle connection on ``self``. + + OUTPUT: + + - a bundle connection on ``self`` as an instance of + :class:`~sage.manifolds.differentiable.bundle_connection.BundleConnection` + + EXAMPLES:: + + sage: M = Manifold(3, 'M', start_index=1) + sage: X. = M.chart() + sage: E = M.vector_bundle(2, 'E') + sage: e = E.local_frame('e') # standard frame for E + sage: nab = E.bundle_connection('nabla', latex_name=r'\nabla'); nab + Bundle connection nabla on the Differentiable real vector bundle + E -> M of rank 2 over the base space 3-dimensional differentiable + manifold M + + .. SEEALSO:: + + Further examples can be found in + :class:`~sage.manifolds.differentiable.bundle_connection.BundleConnection`. + + """ + from .bundle_connection import BundleConnection + return BundleConnection(self, name, latex_name) + + def char_class(self, func, **kwargs): + r""" + Return a characteristic class of the given type with respect to the + given function. + + INPUT: + + - ``func`` -- the function corresponding to the characteristic class + using the Chern-Weil homomorphism; this argument can be either one of + the predefined classes, in the following specified by + (field type, class type, name, LaTeX name, function): + + - ``'Chern'`` -- (complex, multiplicative, ``c``, `c`, `1+x`), + - ``'ChernChar'`` -- (complex, additive, ``ch``, `\mathrm{ch}`, + `\exp(x)`), + - ``'Todd'`` -- (complex, additive, ``Td``, `\mathrm{Td}`, + `\frac{x}{1-\exp(-x)}`), + - ``'Pontryagin'`` -- (real, multiplicative, ``p``, `p`, `1+x`), + - ``'Hirzebruch'`` -- (real, multiplicative, ``L``, `L`, + `\frac{\sqrt{x}}{\tanh(\sqrt{x})}`), + - ``'AHat'`` -- (real, multiplicative, ``A^``, `\hat{A}`, + `\frac{\sqrt{x}/2}{\sinh(\sqrt{x}/2)}`), + - ``'Euler'`` -- (real, Pfaffian, ``e``, `e`, `x`), + + or a symbolic expression. If ``func`` is one of the predefined classes, + the following arguments are obsolete. + + - ``class_type`` -- (default: ``'multiplicative'``) the type of the + characteristic class; possible values are: + + - ``'multiplicative'`` -- returns a class of multiplicative type, + using the determinant + - ``'additive'`` -- returns a class of additive type, using the trace + - ``'Pfaffian'`` -- returns a class of Pfaffian type, using the + Pfaffian + + - ``name`` -- string representation given to the characteristic class + - ``latex_name`` -- (default: ``None``) LaTeX name given to the + characteristic class + + EXAMPLES: + + Pontryagin class on the Minkowski space:: + + sage: M = Manifold(4, 'M', structure='Lorentzian', start_index=1) + sage: X. = M.chart() + sage: g = M.metric('g') + sage: g[1,1] = -1 + sage: g[2,2] = 1 + sage: g[3,3] = 1 + sage: g[4,4] = 1 + sage: g.display() + g = -dt*dt + dx*dx + dy*dy + dz*dz + + Let us introduce the corresponding Levi-Civita connection:: + + sage: nab = g.connection(); nab + Levi-Civita connection nab associated with the Lorentzian metric g + on the 4-dimensional Lorentzian manifold M + + Of course, `\nabla_g` is flat:: + + sage: nab.display() + + Let us check the total Pontryagin class which must be the one + element in the corresponding cohomology ring in this case:: + + sage: TM = M.tangent_bundle(); TM + sage: p = TM.char_class('Pontryagin'); p + Characteristic class p of multiplicative type associated to x + 1 on + the Tangent bundle TM over the 4-dimensional Lorentzian manifold M + sage: p.function() + x + 1 + sage: p_form = p.get_form(nab); p_form.display_expansion() + p(TM, nab) = [1] + [0] + [0] + [0] + [0] + + .. SEEALSO:: + + More examples can be found in + :class:`~sage.manifolds.differentiable.char_class.CharClass`. + + """ + if self._field_type == 'neither_real_nor_complex': + raise ValueEror("the vector bundle must be real or complex") + from .char_class import CharClass, _get_predefined_class + # Is func a predefined class? + if isinstance(func, str): + func_str = func + # Get predefined class: + (field_type, class_type, name, + latex_name, func) = _get_predefined_class(func_str) + # The fields must be equal: + if field_type != self._field_type: + raise ValueError("base field must be {} ".format(field_type) + + "for class '{}'".format(func_str)) + else: + # Get arguments: + class_type = kwargs.pop('class_type', 'multiplicative') + name = kwargs.pop('name', None) + latex_name = kwargs.pop('latex_name', None) + + return CharClass(self, func, class_type=class_type, name=name, + latex_name=latex_name) + def diff_degree(self): r""" Return the vector bundle's degree of differentiability. diff --git a/src/sage/manifolds/scalarfield.py b/src/sage/manifolds/scalarfield.py index 87141cd0b14..4eb4043ac5b 100644 --- a/src/sage/manifolds/scalarfield.py +++ b/src/sage/manifolds/scalarfield.py @@ -1474,10 +1474,16 @@ def domain(self): """ return self._domain - def copy(self): + def copy(self, name=None, latex_name=None): r""" Return an exact copy of the scalar field. + INPUT: + + - ``name`` -- (default: ``None``) name given to the copy + - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the + copy; if none is provided, the LaTeX symbol is set to ``name`` + EXAMPLES: Copy on a 2-dimensional manifold:: @@ -1496,8 +1502,7 @@ def copy(self): False """ - result = type(self)(self.parent(), name=self._name, - latex_name=self._latex_name) + result = type(self)(self.parent(), name=name, latex_name=latex_name) for chart, funct in self._express.items(): result._express[chart] = funct.copy() result._is_zero = self._is_zero @@ -2543,8 +2548,8 @@ def _mul_(self, other): True """ - from sage.tensor.modules.format_utilities import format_mul_txt, \ - format_mul_latex + from sage.tensor.modules.format_utilities import (format_mul_txt, + format_mul_latex) # Special cases: if self._is_zero or other._is_zero: return self._domain.zero_scalar_field() @@ -2557,7 +2562,7 @@ def _mul_(self, other): # ChartFunction multiplication: result._express[chart] = self._express[chart] * other._express[chart] result._name = format_mul_txt(self._name, '*', other._name) - result._latex_name = format_mul_latex(self._latex_name, ' ', + result._latex_name = format_mul_latex(self._latex_name, ' \cdot ', other._latex_name) return result diff --git a/src/sage/manifolds/vector_bundle.py b/src/sage/manifolds/vector_bundle.py index 9289f566732..582bb8fc1a2 100644 --- a/src/sage/manifolds/vector_bundle.py +++ b/src/sage/manifolds/vector_bundle.py @@ -249,10 +249,10 @@ def __init__(self, rank, name, base_space, field='real', else: self._latex_name = latex_name ### - # Initialize derived quantities like frames and trivializations: - self._init_derived() + # Initialize quantities like frames and trivializations: + self._init_attributes() - def _init_derived(self): + def _init_attributes(self): r""" Initialize the derived quantities. @@ -260,7 +260,7 @@ def _init_derived(self): sage: M = Manifold(2, 'M', structure='topological') sage: E = M.vector_bundle(2, 'E') - sage: E._init_derived() + sage: E._init_attributes() """ self._section_modules = {} # dict of section modules with domains as @@ -1083,4 +1083,57 @@ def set_default_frame(self, frame): raise ValueError("the frame must be defined on " + "the {}".format(self)) frame._fmodule.set_default_basis(frame) - self._def_frame = frame \ No newline at end of file + self._def_frame = frame + + def irange(self, start=None): + r""" + Single index generator. + + INPUT: + + - ``start`` -- (default: ``None``) initial value `i_0` of the index; + if none are provided, the value returned by + :meth:`sage.manifolds.manifold.Manifold.start_index()` is assumed + + OUTPUT: + + - an iterable index, starting from `i_0` and ending at + `i_0 + n - 1`, where `n` is the vector bundle's dimension + + EXAMPLES: + + Index range on a 4-dimensional vector bundle over a 5-dimensional + manifold:: + + sage: M = Manifold(5, 'M', structure='topological') + sage: E = M.vector_bundle(4, 'E') + sage: list(E.irange()) + [0, 1, 2, 3] + sage: list(E.irange(2)) + [2, 3] + + Index range on a 4-dimensional vector bundle over a 5-dimensional + manifold with starting index=1:: + + sage: M = Manifold(5, 'M', structure='topological', start_index=1) + sage: E = M.vector_bundle(4, 'E') + sage: list(E.irange()) + [1, 2, 3, 4] + sage: list(E.irange(2)) + [2, 3, 4] + + In general, one has always:: + + sage: next(E.irange()) == M.start_index() + True + + """ + si = self._base_space._sindex + imax = self._rank + si + if start is None: + i = si + else: + i = start + while i < imax: + yield i + i += 1 diff --git a/src/sage/tensor/modules/free_module_tensor.py b/src/sage/tensor/modules/free_module_tensor.py index bada148ed78..3974df78154 100644 --- a/src/sage/tensor/modules/free_module_tensor.py +++ b/src/sage/tensor/modules/free_module_tensor.py @@ -1678,12 +1678,18 @@ def copy_from(self, other): self._components[basis] = comp.copy() self._is_zero = other._is_zero - def copy(self): + def copy(self, name=None, latex_name=None): r""" Return an exact copy of ``self``. The name and the derived quantities are not copied. + INPUT: + + - ``name`` -- (default: ``None``) name given to the copy + - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the + copy; if none is provided, the LaTeX symbol is set to ``name`` + EXAMPLES: Copy of a tensor of type `(1,1)`:: @@ -1712,6 +1718,7 @@ def copy(self): """ resu = self._new_instance() + resu.set_name(name=name, latex_name=latex_name) for basis, comp in self._components.items(): resu._components[basis] = comp.copy() resu._is_zero = self._is_zero @@ -2187,6 +2194,15 @@ def _rmul_(self, other): result = self._new_instance() for basis in self._components: result._components[basis] = other * self._components[basis] + # If other has a name, set the name of the result: + try: + from .format_utilities import format_mul_txt, format_mul_latex + result_name = format_mul_txt(other._name, '*', self._name) + result_latex = format_mul_latex(other._latex_name, r' \cdot ', + self._latex_name) + result.set_name(name=result_name, latex_name=result_latex) + except AttributeError: + pass return result ######### End of ModuleElement arithmetic operators ######## From 013fb8b665adaf1339372c457fca851246d30a3c Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Mon, 11 Nov 2019 10:10:59 +0100 Subject: [PATCH 122/340] Add construction of a vector frame from a family of vector fields --- src/sage/manifolds/differentiable/manifold.py | 71 ++++++++++++++++--- .../tensor/modules/finite_rank_free_module.py | 27 ++----- src/sage/tensor/modules/free_module_basis.py | 58 +++++++++++++++ 3 files changed, 124 insertions(+), 32 deletions(-) diff --git a/src/sage/manifolds/differentiable/manifold.py b/src/sage/manifolds/differentiable/manifold.py index c1bd8c0ab87..42a602df9f7 100644 --- a/src/sage/manifolds/differentiable/manifold.py +++ b/src/sage/manifolds/differentiable/manifold.py @@ -2786,9 +2786,10 @@ def set_change_of_frame(self, frame1, frame2, change_of_frame, for sdom in self._supersets: sdom._frame_changes[(frame2, frame1)] = change_of_frame.inverse() - def vector_frame(self, symbol=None, latex_symbol=None, dest_map=None, - from_frame=None, indices=None, latex_indices=None, - symbol_dual=None, latex_symbol_dual=None): + def vector_frame(self, symbol=None, latex_symbol=None, from_family=None, + dest_map=None, from_frame=None, indices=None, + latex_indices=None, symbol_dual=None, + latex_symbol_dual=None): r""" Define a vector frame on ``self``. @@ -2796,6 +2797,10 @@ def vector_frame(self, symbol=None, latex_symbol=None, dest_map=None, point `p` of the manifold, a vector basis of the tangent space at `p` (or at `\Phi(p)` when ``dest_map`` is not ``None``, see below). + The vector frame can be defined from a set of `n` linearly independent + vector fields by means of the argument ``from_family``, `n` being the + dimension of ``self``. + .. SEEALSO:: :class:`~sage.manifolds.differentiable.vectorframe.VectorFrame` @@ -2813,6 +2818,9 @@ def vector_frame(self, symbol=None, latex_symbol=None, dest_map=None, constituting the vector frame, or a list/tuple of strings, representing the individual LaTeX symbols of the vector fields; if ``None``, ``symbol`` is used in place of ``latex_symbol`` + - ``from_family`` -- (default: ``None``) tuple or list of `n` linearly + independent vector fields on the manifold ``self`` (`n` being the + dimension of ``self``) - ``dest_map`` -- (default: ``None``) :class:`~sage.manifolds.differentiable.diff_map.DiffMap`; destination map `\Phi:\ U \rightarrow M`, where `U` is ``self`` and @@ -2845,14 +2853,45 @@ def vector_frame(self, symbol=None, latex_symbol=None, dest_map=None, EXAMPLES: - Setting a vector frame on a 3-dimensional manifold:: + Introducing a vector frame on a 2-dimensional manifold:: - sage: M = Manifold(3, 'M') - sage: X. = M.chart() + sage: M = Manifold(2, 'M') + sage: X. = M.chart() sage: e = M.vector_frame('e'); e - Vector frame (M, (e_0,e_1,e_2)) + Vector frame (M, (e_0,e_1)) sage: e[0] - Vector field e_0 on the 3-dimensional differentiable manifold M + Vector field e_0 on the 2-dimensional differentiable manifold M + + Defining a vector frame from a family of vector fields:: + + sage: f0 = (1+y^2)*e[0] + (1+x^2)*e[1] + sage: f1 = 2*e[0] - e[1] + sage: f = M.vector_frame('f', from_family=[f0, f1]); f + Vector frame (M, (f_0,f_1)) + sage: f[0].display(e) + f_0 = (y^2 + 1) e_0 + (x^2 + 1) e_1 + sage: f[1].display(e) + f_1 = 2 e_0 - e_1 + sage: (f[0], f[1]) == (f0, f1) + True + + Another example, with a family of vector fields along a curve:: + + sage: R. = RealLine() + sage: c = M.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c') + sage: I = c.domain(); I + Real interval (0, 2*pi) + sage: v = c.tangent_vector_field() + sage: v.display() + c' = cos(t) d/dx + (2*cos(t)^2 - 1) d/dy + sage: w = I.vector_field(1-2*cos(t)^2, cos(t), dest_map=c) + sage: u = I.vector_frame('u', from_family=(v, w)) + sage: u[0].display() + u_0 = cos(t) d/dx + (2*cos(t)^2 - 1) d/dy + sage: u[1].display() + u_1 = (-2*cos(t)^2 + 1) d/dx + cos(t) d/dy + sage: (u[0], u[1]) == (v, w) + True .. SEEALSO:: @@ -2862,12 +2901,26 @@ def vector_frame(self, symbol=None, latex_symbol=None, dest_map=None, """ from sage.manifolds.differentiable.vectorframe import VectorFrame - return VectorFrame(self.vector_field_module(dest_map=dest_map, + if from_family: + dest_map0 = from_family[0].parent().destination_map() + if dest_map and dest_map is not dest_map0: + raise ValueError("incompatible values of destination maps") + dest_map = dest_map0 + resu = VectorFrame(self.vector_field_module(dest_map=dest_map, force_free=True), symbol=symbol, latex_symbol=latex_symbol, from_frame=from_frame, indices=indices, latex_indices=latex_indices, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) + if from_family: + resu._init_from_family(from_family) + # Adding the newly generated changes of frame to the + # dictionary _frame_changes of self and its supersets: + for frame_pair, chge in resu._fmodule._basis_changes.items(): + if resu in frame_pair: + for sdom in self._supersets: + sdom._frame_changes[frame_pair] = chge + return resu def _set_covering_frame(self, frame): r""" diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 4d06ac1e455..35df087b546 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1188,7 +1188,7 @@ def basis(self, symbol, latex_symbol=None, from_family=None, or a list/tuple of strings, representing the individual LaTeX symbols of the elements of the basis; if ``None``, ``symbol`` is used in place of ``latex_symbol`` - - ``from_family`` -- (default: ``None``) tuple of `n` linearly + - ``from_family`` -- (default: ``None``) tuple or list of `n` linearly independent elements of the free module ``self`` (`n` being the rank of ``self``) - ``indices`` -- (default: ``None``; used only if ``symbol`` is a @@ -1268,8 +1268,8 @@ def basis(self, symbol, latex_symbol=None, from_family=None, sage: e[1] Element e_1 of the Rank-3 free module M over the Integer Ring - Construction of a basis from a family of linearly independent module - elements:: + Construction of a basis from a spanning family of linearly independent + module elements:: sage: f1 = -e[2] sage: f2 = 4*e[1] + 3*e[3] @@ -1315,26 +1315,7 @@ def basis(self, symbol, latex_symbol=None, from_family=None, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) if from_family: - n = self._rank - if len(from_family) != n: - raise ValueError("the size of the family is not {}".format(n)) - for ff in from_family: - if ff not in self: - raise TypeError("{} is not an element of {}".format(ff, - self)) - # The automorphisms relating the family to previously defined - # bases are registered: - ff0 = from_family[0] - for basis in ff0._components: - try: - comp = [ff.components(basis) for ff in from_family] - except ValueError: - continue - mat = [[comp_ff[[i]] for comp_ff in comp] - for i in self.irange()] - aut = self.automorphism() - aut.set_comp(basis)[:] = mat - self.set_change_of_basis(basis, resu, aut) + resu._init_from_family(from_family) return resu def tensor(self, tensor_type, name=None, latex_name=None, sym=None, diff --git a/src/sage/tensor/modules/free_module_basis.py b/src/sage/tensor/modules/free_module_basis.py index 32b436ac289..8ea3c37e6ba 100644 --- a/src/sage/tensor/modules/free_module_basis.py +++ b/src/sage/tensor/modules/free_module_basis.py @@ -712,6 +712,64 @@ def _new_instance(self, symbol, latex_symbol=None, indices=None, ###### End of methods to be redefined by derived classes ###### + def _init_from_family(self, family): + r""" + Identify ``self`` to a linearly independent spanning family of + module elements. + + INPUT: + + - ``family``: a family of elements of ``self.free_module()`` that are + linearly independent and spanning ``self.free_module()`` + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(QQ, 2, name='M', start_index=1) + sage: e = M.basis('e') + sage: f1 = e[1] + e[2] + sage: f2 = e[1] - e[2] + sage: f = M.basis('f') + sage: f._init_from_family([f1, f2]) + sage: (f[1], f[2]) == (f1, f2) + True + sage: f[1].display() + f_1 = e_1 + e_2 + sage: f[2].display() + f_2 = e_1 - e_2 + sage: e[1].display(f) + e_1 = 1/2 f_1 + 1/2 f_2 + sage: e[2].display(f) + e_2 = 1/2 f_1 - 1/2 f_2 + + """ + fmodule = self._fmodule + n = fmodule.rank() + if len(family) != n: + raise ValueError("the size of the family must be {}".format(n)) + # Copy of the components of each element of the family: + for i, ff in enumerate(family): + if ff not in fmodule: + raise TypeError("{} is not an element of {}".format(ff, + fmodule)) + vs = self._vec[i] + for basis, comp in ff._components.items(): + vs._components[basis] = comp.copy() + # Automorphisms relating the family to previously defined bases are + # constructed from the components of the family elements and are + # registered as changes of basis to ``self``: + ff0 = family[0] + for basis in ff0._components: + try: + comps = [ff.components(basis) for ff in family] + except ValueError: + continue + aut = fmodule.automorphism() + mat = [[c[[i]] for c in comps] for i in fmodule.irange()] + aut.add_comp(basis)[:] = mat + aut.add_comp(self)[:] = mat + fmodule.set_change_of_basis(basis, self, aut) + + def module(self): r""" Return the free module on which the basis is defined. From 0a2190fc1c0f7cf9e74a60f8ea3d590fdded30da Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Mon, 11 Nov 2019 15:10:03 +0100 Subject: [PATCH 123/340] Ticket #27784: Wrong naming in Doctest --- src/sage/manifolds/differentiable/vector_bundle.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/manifolds/differentiable/vector_bundle.py b/src/sage/manifolds/differentiable/vector_bundle.py index 439406e65e5..63cf2903353 100644 --- a/src/sage/manifolds/differentiable/vector_bundle.py +++ b/src/sage/manifolds/differentiable/vector_bundle.py @@ -220,8 +220,8 @@ def char_class(self, func, **kwargs): Let us introduce the corresponding Levi-Civita connection:: sage: nab = g.connection(); nab - Levi-Civita connection nab associated with the Lorentzian metric g - on the 4-dimensional Lorentzian manifold M + Levi-Civita connection nabla_g associated with the Lorentzian metric + g on the 4-dimensional Lorentzian manifold M Of course, `\nabla_g` is flat:: @@ -231,13 +231,14 @@ def char_class(self, func, **kwargs): element in the corresponding cohomology ring in this case:: sage: TM = M.tangent_bundle(); TM + Tangent bundle TM over the 4-dimensional Lorentzian manifold M sage: p = TM.char_class('Pontryagin'); p Characteristic class p of multiplicative type associated to x + 1 on the Tangent bundle TM over the 4-dimensional Lorentzian manifold M sage: p.function() x + 1 sage: p_form = p.get_form(nab); p_form.display_expansion() - p(TM, nab) = [1] + [0] + [0] + [0] + [0] + p(TM, nabla_g) = [1] + [0] + [0] + [0] + [0] .. SEEALSO:: From 1bae0ab620ca652edcf75979583626c4bf82f438 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Mon, 11 Nov 2019 19:37:48 +0100 Subject: [PATCH 124/340] Trac #27784: Documentation grammar checkup --- .../manifolds/differentiable/char_class.py | 49 ++++++++++--------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/src/sage/manifolds/differentiable/char_class.py b/src/sage/manifolds/differentiable/char_class.py index ebd0f6dea28..05feaeaa518 100644 --- a/src/sage/manifolds/differentiable/char_class.py +++ b/src/sage/manifolds/differentiable/char_class.py @@ -2,7 +2,7 @@ Characteristic Classes Let `E \to M` be some complex vector bundle over a differentiable manifold `M`. -A *characteristic class* `c(E)` is an element of the the cohomology ring +A *characteristic class* `c(E)` is an element of the cohomology ring `H^{*}_{\mathrm{dR}}(M, \CC)` such that for any differentiable map `f: M \to N` we have the *naturality condition*: @@ -29,7 +29,7 @@ \left[ P \left( \Omega \right) \right] \in H^{2*}_{\mathrm{dR}}(M, \CC) is well-defined and independent of the choice of `\nabla` (the proof can be -found in [Roe1988]_ pp. 31). This is the foundation of Chern-Weil theory and +found in [Roe1988]_ pp. 31). This is the foundation of the Chern-Weil theory and therefore the following definitions. .. NOTE:: @@ -60,7 +60,7 @@ Additive Classes ---------------- -In the **complex** case, let `f` be a holomorphic function around zero. Then, +In the **complex** case, let `f` be a holomorphic function around zero. Then we call .. MATH:: @@ -74,7 +74,7 @@ - *Chern Character* with `f(x) = \exp(x)` -In the **real** case, let `g` be a holomorphic function around zero. Then, we +In the **real** case, let `g` be a holomorphic function around zero. Then we call .. MATH:: @@ -121,7 +121,7 @@ ---------------------- In the **complex** case, let `f` be a holomorphic function around zero. -Then, we call +Then we call .. MATH:: @@ -136,13 +136,13 @@ - *Todd class* with `f(x) = \frac{x}{1-\exp(-x)}` In the **real** case, let `g` be a holomorphic function around zero with -`g(0)=1`. Then, we call +`g(0)=1`. Then we call .. MATH:: \left[\det\left( \sqrt{ g \left( -\frac{\Omega^2}{4 \pi^2} \right) } \right) \right] \in H^{4*}_{\mathrm{dR}}(M, \CC) -the *multiplicative Pontryagin g-genus* +the *multiplicative Pontryagin g-genus*. Important and predefined multiplicative Pontryagin genera are: @@ -165,9 +165,9 @@ sage: e = E.local_frame('e', domain=U) To apply the Chern-Weil approach, we need a bundle connection in terms of a -connection one form. For this, we take the connection induced from the +connection one form. To achieve this, we take the connection induced from the hermitian metric on the trivial bundle -`\CC^2 \times \CC\mathbf{P}^1 \supset \gamma^1` in which the frame `e` above +`\CC^2 \times \CC\mathbf{P}^1 \supset \gamma^1`. In this the frame `e` corresponds to the section `[z:1] \mapsto (z,1)` and its magnitude-squared is given by `1+|z|^2`:: @@ -187,7 +187,7 @@ c(gamma^1, nabla) = [1] + [0] + [1/2*I/(pi + pi*z^2*zbar^2 + 2*pi*z*zbar) dz/\dzbar] Since `U` and `\CC\mathbf{P}^1` differ only by a point and therefore a null -set, the integral over the top form is independent of that choice:: +set, it is enough to integrate the top form over the domain `U`:: sage: integrate(integrate(c_form[2][[1,2]].expr(c_cart), x, -infinity, infinity).full_simplify(), ....: y, -infinity, infinity) @@ -201,13 +201,14 @@ Pfaffian Classes ---------------- -Usually, in the literature, there are no such things defined as "Pfaffian -classes". However, using the Pfaffian of a matrix and inspired by the -aforementioned definitions, such classes can be defined as follows. +Usually, there is no such thing as "Pfaffian classes" in literature. However, +using the matrix' Pfaffian and inspired by the aforementioned definitions, +such classes can be defined as follows. -Let `E` be a real vector bundle of rank `2n` and `f` be an odd real function -being analytic at zero. Furthermore, let `\Omega` be skew-symmetric, which is -certainly true when `\nabla` is metric and `e` is orthonormal. Then, we call +Let `E` be a real vector bundle of rank `2n` and `f` an odd real function +being analytic at zero. Furthermore, let `\Omega` be skew-symmetric, which +certainly will be true if `\nabla` is metric and `e` is orthonormal. Then +we call .. MATH:: @@ -239,8 +240,8 @@ Characteristic class e of Pfaffian type associated to x on the Tangent bundle TS2 over the 2-dimensional differentiable manifold S2 -To compute a particular representative of the Euler class, we need a -connection first:: +To compute a particular representative of the Euler class, we need to determine +a connection :: sage: g = M.metric('g') # standard metric on S2 sage: g[eU,1,1], g[eU,2,2] = 4/(1+x^2+y^2)^2, 4/(1+x^2+y^2)^2 @@ -256,7 +257,7 @@ sage: cmatrix_V = [[nab.curvature_form(i,j,eV) for j in TM.irange()] ....: for i in TM.irange()] -Fortunately, both curvature matrices are skew-symmetric already:: +Fortunately, both curvature matrices are already skew-symmetric:: sage: for i in range(TM.rank()): ....: for j in range(TM.rank()): @@ -281,8 +282,8 @@ curvature (2,2) of connection nabla_g w.r.t. Coordinate frame (V, (d/du,d/dv)) = 0 -Now, the representative of the Euler class with respect to the connection -`\nabla` induced by the standard metric can be computed:: +Now the representative of the Euler class with respect to the connection +`\nabla_g` induced by the standard metric can be computed:: sage: cmatrices = {eU: cmatrix_U, eV: cmatrix_V} sage: e_class_form = e_class.get_form(nab, cmatrices) @@ -290,13 +291,15 @@ e(TS2, nabla_g) = [0] + [0] + [2/(pi + pi*x^4 + pi*y^4 + 2*pi*x^2 + 2*(pi + pi*x^2)*y^2) dx/\dy] -Indeed, this form represents the Euler class since integrating yields the -Euler characteristic of `S^2`:: +Let us check whether this form represents the Euler class correctly:: sage: integrate(integrate(e_class_form[2][[1,2]].expr(), x, -infinity, infinity).simplify_full(), ....: y, -infinity, infinity) 2 +As we can see, the integral coincides with the Euler characteristic of `S^2` so +that our form actually represents the Euler class appropriately. + .. _documentation: Class Documentation From 71b5f0f28d69d556ddd3ff5fd9e177ac56c03500 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Mon, 11 Nov 2019 20:22:39 +0100 Subject: [PATCH 125/340] Replace keyword argument 'from_family' by positional argument in vector_frame() --- src/sage/manifolds/differentiable/manifold.py | 115 ++++++++++++------ .../manifolds/differentiable/vectorframe.py | 52 ++++++-- .../tensor/modules/finite_rank_free_module.py | 15 ++- 3 files changed, 135 insertions(+), 47 deletions(-) diff --git a/src/sage/manifolds/differentiable/manifold.py b/src/sage/manifolds/differentiable/manifold.py index 42a602df9f7..2d3c38d9abc 100644 --- a/src/sage/manifolds/differentiable/manifold.py +++ b/src/sage/manifolds/differentiable/manifold.py @@ -2786,10 +2786,7 @@ def set_change_of_frame(self, frame1, frame2, change_of_frame, for sdom in self._supersets: sdom._frame_changes[(frame2, frame1)] = change_of_frame.inverse() - def vector_frame(self, symbol=None, latex_symbol=None, from_family=None, - dest_map=None, from_frame=None, indices=None, - latex_indices=None, symbol_dual=None, - latex_symbol_dual=None): + def vector_frame(self, *args, **kwargs): r""" Define a vector frame on ``self``. @@ -2798,8 +2795,7 @@ def vector_frame(self, symbol=None, latex_symbol=None, from_family=None, (or at `\Phi(p)` when ``dest_map`` is not ``None``, see below). The vector frame can be defined from a set of `n` linearly independent - vector fields by means of the argument ``from_family``, `n` being the - dimension of ``self``. + vector fields, `n` being the dimension of ``self``. .. SEEALSO:: @@ -2808,26 +2804,27 @@ def vector_frame(self, symbol=None, latex_symbol=None, from_family=None, INPUT: - - ``symbol`` -- (default: ``None``) either a string, to be used as a + - ``symbol`` -- either a string, to be used as a common base for the symbols of the vector fields constituting the vector frame, or a list/tuple of strings, representing the individual - symbols of the vector fields; can be ``None`` only if ``from_frame`` + symbols of the vector fields; can be omitted only if ``from_frame`` is not ``None`` (see below) + - ``vector_fields`` -- tuple or list of `n` linearly independent vector + fields on the manifold ``self`` (`n` being the dimension of ``self``) + defining the vector frame; can be omitted if the vector frame is + created from scratch or if ``from_frame`` is not ``None`` - ``latex_symbol`` -- (default: ``None``) either a string, to be used as a common base for the LaTeX symbols of the vector fields constituting the vector frame, or a list/tuple of strings, representing the individual LaTeX symbols of the vector fields; if ``None``, ``symbol`` is used in place of ``latex_symbol`` - - ``from_family`` -- (default: ``None``) tuple or list of `n` linearly - independent vector fields on the manifold ``self`` (`n` being the - dimension of ``self``) - ``dest_map`` -- (default: ``None``) :class:`~sage.manifolds.differentiable.diff_map.DiffMap`; destination map `\Phi:\ U \rightarrow M`, where `U` is ``self`` and `M` is a differentiable manifold; for each `p\in U`, the vector frame evaluated at `p` is a basis of the tangent space - `T_{\Phi(p)}M`; if ``dest_map`` is ``None``, the identity is assumed - (case of a vector frame *on* `U`) + `T_{\Phi(p)}M`; if ``dest_map`` is ``None``, the identity map is + assumed (case of a vector frame *on* `U`) - ``from_frame`` -- (default: ``None``) vector frame `\tilde{e}` on the codomain `M` of the destination map `\Phi`; the returned frame `e` is then such that for all `p \in U`, @@ -2853,29 +2850,32 @@ def vector_frame(self, symbol=None, latex_symbol=None, from_family=None, EXAMPLES: - Introducing a vector frame on a 2-dimensional manifold:: + Defining a vector frame from two linearly independent vector + fields on a 2-dimensional manifold:: sage: M = Manifold(2, 'M') sage: X. = M.chart() - sage: e = M.vector_frame('e'); e + sage: e0 = M.vector_field(1+x^2, 1+y^2) + sage: e1 = M.vector_field(2, -x*y) + sage: e = M.vector_frame('e', (e0, e1)); e Vector frame (M, (e_0,e_1)) - sage: e[0] - Vector field e_0 on the 2-dimensional differentiable manifold M + sage: e[0].display() + e_0 = (x^2 + 1) d/dx + (y^2 + 1) d/dy + sage: e[1].display() + e_1 = 2 d/dx - x*y d/dy + sage: (e[0], e[1]) == (e0, e1) + True - Defining a vector frame from a family of vector fields:: + If the vector fields are not linearly independent, an error is + raised:: - sage: f0 = (1+y^2)*e[0] + (1+x^2)*e[1] - sage: f1 = 2*e[0] - e[1] - sage: f = M.vector_frame('f', from_family=[f0, f1]); f - Vector frame (M, (f_0,f_1)) - sage: f[0].display(e) - f_0 = (y^2 + 1) e_0 + (x^2 + 1) e_1 - sage: f[1].display(e) - f_1 = 2 e_0 - e_1 - sage: (f[0], f[1]) == (f0, f1) - True + sage: z = M.vector_frame('z', (e0, -e0)) + Traceback (most recent call last): + ... + ValueError: the provided vector fields are not linearly + independent - Another example, with a family of vector fields along a curve:: + Another example, involving a pair vector fields along a curve:: sage: R. = RealLine() sage: c = M.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c') @@ -2885,7 +2885,7 @@ def vector_frame(self, symbol=None, latex_symbol=None, from_family=None, sage: v.display() c' = cos(t) d/dx + (2*cos(t)^2 - 1) d/dy sage: w = I.vector_field(1-2*cos(t)^2, cos(t), dest_map=c) - sage: u = I.vector_frame('u', from_family=(v, w)) + sage: u = I.vector_frame('u', (v, w)) sage: u[0].display() u_0 = cos(t) d/dx + (2*cos(t)^2 - 1) d/dy sage: u[1].display() @@ -2893,6 +2893,30 @@ def vector_frame(self, symbol=None, latex_symbol=None, from_family=None, sage: (u[0], u[1]) == (v, w) True + It is also possible to create a vector frame from scratch, without + any connection with previously defined vector frames or vector fields + (the connection can be performed later via the method + :meth:`~sage.manifolds.differentiable.manifold.DifferentiableManifold.set_change_of_frame`):: + + sage: f = M.vector_frame('f'); f + Vector frame (M, (f_0,f_1)) + sage: f[0] + Vector field f_0 on the 2-dimensional differentiable manifold M + + Thanks to the keywords ``dest_map`` and ``from_frame``, one can also + define a vector frame from one prexisting on another manifold, via a + differentiable map (here provided by the curve ``c``):: + + sage: fc = I.vector_frame(dest_map=c, from_frame=f); fc + Vector frame ((0, 2*pi), (f_0,f_1)) with values on the + 2-dimensional differentiable manifold M + sage: fc[0] + Vector field f_0 along the Real interval (0, 2*pi) with values on + the 2-dimensional differentiable manifold M + + Note that the symbol for ``fc``, namely `f`, is inherited from ``f``, + the original vector frame. + .. SEEALSO:: For more options, in particular for the choice of symbols and @@ -2901,8 +2925,27 @@ def vector_frame(self, symbol=None, latex_symbol=None, from_family=None, """ from sage.manifolds.differentiable.vectorframe import VectorFrame - if from_family: - dest_map0 = from_family[0].parent().destination_map() + # Input processing + symbol = None + vector_fields = None + n_args = len(args) + if n_args >= 1: + symbol = args[0] + if n_args == 2: + vector_fields = args[1] + elif n_args > 2: + raise TypeError("vector_frame() takes at most two positional " + "arguments") + latex_symbol = kwargs.pop('latex_symbol', None) + dest_map = kwargs.pop('dest_map', None) + from_frame = kwargs.pop('from_frame', None) + indices = kwargs.pop('indices', None) + latex_indices = kwargs.pop('latex_indices', None) + symbol_dual = kwargs.pop('symbol_dual', None) + latex_symbol_dual = kwargs.pop('latex_symbol_dual', None) + # + if vector_fields: + dest_map0 = vector_fields[0].parent().destination_map() if dest_map and dest_map is not dest_map0: raise ValueError("incompatible values of destination maps") dest_map = dest_map0 @@ -2912,8 +2955,12 @@ def vector_frame(self, symbol=None, latex_symbol=None, from_family=None, from_frame=from_frame, indices=indices, latex_indices=latex_indices, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) - if from_family: - resu._init_from_family(from_family) + if vector_fields: + try: + resu._init_from_family(vector_fields) + except ZeroDivisionError: + raise ValueError("the provided vector fields are not " + "linearly independent") # Adding the newly generated changes of frame to the # dictionary _frame_changes of self and its supersets: for frame_pair, chge in resu._fmodule._basis_changes.items(): diff --git a/src/sage/manifolds/differentiable/vectorframe.py b/src/sage/manifolds/differentiable/vectorframe.py index a577d11658e..b8f8ff8eba8 100644 --- a/src/sage/manifolds/differentiable/vectorframe.py +++ b/src/sage/manifolds/differentiable/vectorframe.py @@ -34,18 +34,29 @@ EXAMPLES: -Defining a vector frame on a 3-dimensional manifold:: +Introducing a chart on a manifold automatically endows it with a vector frame: +the coordinate frame associated to the chart:: sage: M = Manifold(3, 'M') sage: X. = M.chart() - sage: e = M.vector_frame('e') ; e + sage: M.frames() + [Coordinate frame (M, (d/dx,d/dy,d/dz))] + sage: M.frames()[0] is X.frame() + True + +A new vector frame can be defined from a family of 3 linearly independent +vector fields:: + + sage: e1 = M.vector_field(1, x, y) + sage: e2 = M.vector_field(z, -2, x*y) + sage: e3 = M.vector_field(1, 1, 0) + sage: e = M.vector_frame('e', (e1, e2, e3)); e Vector frame (M, (e_0,e_1,e_2)) sage: latex(e) \left(M, \left(e_{0},e_{1},e_{2}\right)\right) -The first frame defined on a manifold is its default frame; in the present -case it is the coordinate frame defined when introducing the chart -``X``:: +The first frame defined on a manifold is its *default frame*; in the present +case it is the coordinate frame associated to the chart ``X``:: sage: M.default_frame() Coordinate frame (M, (d/dx,d/dy,d/dz)) @@ -70,6 +81,13 @@ sage: e[0] Vector field e_0 on the 3-dimensional differentiable manifold M + sage: e[0].display(X.frame()) + e_0 = d/dx + x d/dy + y d/dz + sage: X.frame()[1] + Vector field d/dy on the 3-dimensional differentiable manifold M + sage: X.frame()[1].display(e) + d/dy = x/(x^2 - x + z + 2) e_0 - 1/(x^2 - x + z + 2) e_1 + - (x - z)/(x^2 - x + z + 2) e_2 The slice operator ``:`` can be used to access to more than one element:: @@ -81,6 +99,18 @@ Vector field e_1 on the 3-dimensional differentiable manifold M, Vector field e_2 on the 3-dimensional differentiable manifold M) +Vector frames can be constructed from scratch, without any connection to +previously defined frames or vector fields (the connection can be performed +later via the method +:meth:`~sage.manifolds.differentiable.manifold.DifferentiableManifold.set_change_of_frame`):: + + sage: f = M.vector_frame('f'); f + Vector frame (M, (f_0,f_1,f_2)) + sage: M.frames() + [Coordinate frame (M, (d/dx,d/dy,d/dz)), + Vector frame (M, (e_0,e_1,e_2)), + Vector frame (M, (f_0,f_1,f_2))] + The index range depends on the starting index defined on the manifold:: sage: M = Manifold(3, 'M', start_index=1) @@ -152,14 +182,12 @@ The orthonormal frame constructed from the coordinate frame:: - sage: change_frame = M.automorphism_field() - sage: change_frame[:] = [[1,0], [0, 1/sin(th)]] - sage: e = b.new_frame(change_frame, 'e') ; e + sage: e = M.vector_frame('e', (b[1], b[2]/sin(th))); e Vector frame (S^2, (e_1,e_2)) - sage: e[1][:] - [1, 0] - sage: e[2][:] - [0, 1/sin(th)] + sage: e[1].display() + e_1 = d/dth + sage: e[2].display() + e_2 = 1/sin(th) d/dph The change-of-frame automorphisms and their matrices:: diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 35df087b546..715c0e24462 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1302,6 +1302,15 @@ def basis(self, symbol, latex_symbol=None, from_family=None, sage: all( f[i] == a(e[i]) for i in M.irange() ) True + Providing a family of module elements that are not linearly independent + raise an error:: + + sage: g = M.basis('g', from_family=(f1, f2, f1+f2)) + Traceback (most recent call last): + ... + ValueError: the provided module elements are not linearly + independent + For more documentation on bases see :class:`~sage.tensor.modules.free_module_basis.FreeModuleBasis`. @@ -1315,7 +1324,11 @@ def basis(self, symbol, latex_symbol=None, from_family=None, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) if from_family: - resu._init_from_family(from_family) + try: + resu._init_from_family(from_family) + except ZeroDivisionError: + raise ValueError("the provided module elements are not " + "linearly independent") return resu def tensor(self, tensor_type, name=None, latex_name=None, sym=None, From d0ef4d77e44422e25fbdfbc90e9c852387a15033 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Mon, 11 Nov 2019 22:47:56 +0100 Subject: [PATCH 126/340] Add construction of a local frame from a set of vector fields in TensorBundle.local_frame() --- .../manifolds/differentiable/vector_bundle.py | 27 ++++++++++--------- src/sage/manifolds/vector_bundle.py | 8 +++++- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/sage/manifolds/differentiable/vector_bundle.py b/src/sage/manifolds/differentiable/vector_bundle.py index 180e61af1e1..bdb41800862 100644 --- a/src/sage/manifolds/differentiable/vector_bundle.py +++ b/src/sage/manifolds/differentiable/vector_bundle.py @@ -1175,9 +1175,7 @@ def is_manifestly_trivial(self): return True return False - def local_frame(self, symbol=None, latex_symbol=None, from_frame=None, - indices=None, latex_indices=None, symbol_dual=None, - latex_symbol_dual=None, domain=None): + def local_frame(self, *args, **kwargs): r""" Define a vector frame on ``domain``, possibly with values in the tangent bundle of the ambient domain. @@ -1220,6 +1218,10 @@ def local_frame(self, symbol=None, latex_symbol=None, from_frame=None, vector frame, or a list/tuple of strings, representing the individual symbols of the vector fields; can be ``None`` only if ``from_frame`` is not ``None`` (see below) + - ``vector_fields`` -- tuple or list of `n` linearly independent vector + fields on ``domain`` (`n` being the dimension of ``domain``) + defining the vector frame; can be omitted if the vector frame is + created from scratch or if ``from_frame`` is not ``None`` - ``latex_symbol`` -- (default: ``None``) either a string, to be used as a common base for the LaTeX symbols of the vector fields constituting the vector frame, or a list/tuple of strings, @@ -1280,16 +1282,17 @@ def local_frame(self, symbol=None, latex_symbol=None, from_frame=None, :class:`~sage.manifolds.differentiable.vectorframe.VectorFrame`. """ + domain = kwargs.pop('domain', None) if domain is None: domain = self._base_space - vmodule = domain.vector_field_module( - dest_map=self._dest_map.restrict(domain), - force_free=True) - return vmodule.basis(symbol=symbol, latex_symbol=latex_symbol, - from_frame=from_frame, - indices=indices, latex_indices=latex_indices, - symbol_dual=symbol_dual, - latex_symbol_dual=latex_symbol_dual) + dest_map = self._dest_map.restrict(domain) + if not args and not kwargs: + # if no argument is provided, the default basis of the + # base vector field module is returned: + return domain.vector_field_module(dest_map=dest_map, + force_free=True).basis() + kwargs['dest_map'] = dest_map + return domain.vector_frame(*args, **kwargs) vector_frame = local_frame @@ -1434,4 +1437,4 @@ def set_default_frame(self, frame): self._base_space.set_default_frame(frame) else: frame._fmodule.set_default_basis(frame) - self._def_frame = frame \ No newline at end of file + self._def_frame = frame diff --git a/src/sage/manifolds/vector_bundle.py b/src/sage/manifolds/vector_bundle.py index 9289f566732..c2822494eea 100644 --- a/src/sage/manifolds/vector_bundle.py +++ b/src/sage/manifolds/vector_bundle.py @@ -760,6 +760,12 @@ def local_frame(self, symbol, latex_symbol=None, indices=None, For more options, in particular for the choice of symbols and indices, see :class:`~sage.manifolds.local_frame.LocalFrame`. + .. TODO:: + + Allow construction of a local frame from a family of local + sections, in a way similar to + :meth:`~sage.manifolds.differentiable.manifold.DifferentiableManifold.vector_frame` + """ from sage.manifolds.local_frame import LocalFrame sec_module = self.section_module(domain=domain, force_free=True) @@ -1083,4 +1089,4 @@ def set_default_frame(self, frame): raise ValueError("the frame must be defined on " + "the {}".format(self)) frame._fmodule.set_default_basis(frame) - self._def_frame = frame \ No newline at end of file + self._def_frame = frame From 277fdbdb7b8e0d9e904bd035008c65305503ec7f Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Tue, 12 Nov 2019 14:59:37 +0900 Subject: [PATCH 127/340] Fixed is_diagonalizable() and added diagonalization() --- src/sage/matrix/matrix2.pyx | 380 +++++++++++++++++++----------------- 1 file changed, 200 insertions(+), 180 deletions(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index 2b3658f7bb8..9317ab4edc3 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -7,6 +7,26 @@ AUTHORS: - William Stein: initial version +- Jaap Spies (2006-02-18): added ``prod_of_row_sums`` method + +- Jaap Spies (2006-02-16): added ``permanent`` method + +- Jaap Spies (2006-02-19): added ``permanental_minor`` method + +- Jaap Spies (2006-02-24): added ``rook_vector`` method + +- Robert Bradshaw (2007-06-14): added ``subdivide`` method + +- Jaap Spies (2007-10-26): implemented ``_binomial`` auxiliary function + +- Jaap Spies (2007-11-14): implemented ``_choose`` auxiliary function + +- William Stein (2007-11-18): added ``_gram_schmidt_noscale`` method + +- David Loeffler (2008-12-05): added ``smith_form`` method + +- David Loeffler (2009-06-01): added ``_echelon_form_PID`` method + - Sebastian Pancratz (2009-06-12): implemented ``adjoint`` and ``charpoly`` methods - Sebastian Pancratz (2009-06-25): fixed ``adjoint`` reflecting the change that @@ -14,6 +34,8 @@ AUTHORS: - Sebastian Pancratz (2009-06-25): use the division-free algorithm for ``charpoly`` +- Rob Beezer (2009-07-13) added ``elementwise_product`` method + - Miguel Marco (2010-06-19): modified eigenvalues and eigenvectors functions to allow the option ``extend=False`` @@ -21,8 +43,45 @@ AUTHORS: determinant is computed even for rings for which the ``is_field`` method is not implemented. +- Rob Beezer (2010-12-13): added ``conjugate_transpose`` method + +- Rob Beezer (2011-02-02): added ``extended_echelon_form`` method + - Rob Beezer (2011-02-05): refactored all of the matrix kernel routines +- Rob Beezer (2011-02-05): added ``right_kernel_matrix`` method + +- Rob Beezer (2011-02-17): added ``QR`` method + +- Rob Beezer (2011-02-25): modified ``_gram_schmidt_noscale`` method + +- Rob Beezer (2011-03-15): added ``is_similar`` method + +- Moritz Minzlaff (2011-03-17): corrected ``_echelon_form_PID`` method for + matrices of one row, fixed in :trac:`9053` + +- Rob Beezer (2011-03-31): added ``is_normal`` method + +- Rob Beezer (2011-04-01): added ``is_diagonalizable`` method + +- Rob Beezer (2011-04-26): added ``LU`` method + +- Rob Beezer (2011-05-20): added ``cyclic_subspace`` method + +- Rob Beezer (2011-06-09): added ``zigzag_form`` method + +- Rob Beezer (2011-06-09): added ``rational_form`` method + +- Rob Beezer (2012-05-24): added ``indefinite_factorization`` and + ``is_positive_definite`` methods + +- Rob Beezer (2012-05-27): added ``cholesky`` method + +- Darij Grinberg (2013-10-01): added first (slow) pfaffian implementation + +- Mario Pernici (2014-07-01): modified ``rook_vector`` method + +- Rob Beezer (2015-05-25): modified ``is_similar`` method """ # **************************************************************************** @@ -604,10 +663,6 @@ cdef class Matrix(Matrix1): [2 5 6] sage: a.prod_of_row_sums([1,2]) 55 - - AUTHORS: - - - Jaap Spies (2006-02-18) """ cdef Py_ssize_t c, row pr = 1 @@ -776,10 +831,6 @@ cdef class Matrix(Matrix1): sage: C = A.elementwise_product(B) sage: len(C.nonzero_positions()) == 0 True - - AUTHOR: - - - Rob Beezer (2009-07-13) """ # Optimized routines for specialized classes would likely be faster # See the "pairwise_product" of vectors for some guidance on doing this @@ -895,10 +946,6 @@ cdef class Matrix(Matrix1): sage: A = matrix(R,2,2,[x, y, x^2, y^2]) sage: A.permanent() x^2*y + x*y^2 - - AUTHORS: - - - Jaap Spies (2006-02-16 and 2006-02-21) """ if algorithm == "Ryser": return self._permanent_ryser() @@ -1012,10 +1059,6 @@ cdef class Matrix(Matrix1): sage: A.permanental_minor(5) 0 - - AUTHORS: - - - Jaap Spies (2006-02-19) """ if algorithm == "Ryser": return self._permanental_minor_ryser(k) @@ -1356,11 +1399,6 @@ cdef class Matrix(Matrix1): ....: v = m.rook_vector(complement=True, use_complement=False) ....: if v != [1, 16, 78, 128, 53]: ....: print("ERROR with algorithm={} use_complement=False".format(algorithm)) - - AUTHORS: - - - Jaap Spies (2006-02-24) - - Mario Pernici (2014-07-01) """ cdef Py_ssize_t i,j cdef unsigned int num_ones @@ -1862,11 +1900,6 @@ cdef class Matrix(Matrix1): sage: AA = Matrix(ZZ, A) sage: AA.pfaffian() ** 2 == AA.det() True - - AUTHORS: - - - Darij Grinberg (1 Oct 2013): first (slow) - implementation. """ k = self._nrows @@ -3748,10 +3781,6 @@ cdef class Matrix(Matrix1): Traceback (most recent call last): ... ValueError: 'proof' flag only valid for matrices over the integers - - AUTHOR: - - - Rob Beezer (2011-02-05) """ R = self.base_ring() @@ -4776,10 +4805,6 @@ cdef class Matrix(Matrix1): - ``self`` - a matrix with field entries OUTPUT: a list of reduced row echelon form basis - - AUTHORS: - - - William Stein """ if not self.is_square(): raise ValueError("self must be a square matrix") @@ -7291,10 +7316,6 @@ cdef class Matrix(Matrix1): Traceback (most recent call last): ... TypeError: subdivide must be True or False, not junk - - AUTHOR: - - - Rob Beezer (2011-02-02) """ if not subdivide in [True, False]: raise TypeError("subdivide must be True or False, not %s" % subdivide) @@ -7929,11 +7950,6 @@ cdef class Matrix(Matrix1): [53|59 61|67 71] [--+-----+-----] [73|79 83|89 97] - - - AUTHORS: - - - Robert Bradshaw (2007-06-14) """ self.check_mutability() @@ -8662,10 +8678,6 @@ cdef class Matrix(Matrix1): sage: A = matrix(QQ, 0, 0) sage: A.is_normal() True - - AUTHOR: - - - Rob Beezer (2011-03-31) """ key = 'normal' n = self.fetch(key) @@ -9322,10 +9334,6 @@ cdef class Matrix(Matrix1): sage: R [2 3] [0 1] - - AUTHOR: - - - Rob Beezer (2011-02-17) """ from sage.modules.free_module_element import zero_vector from sage.matrix.constructor import zero_matrix, matrix @@ -9501,11 +9509,6 @@ cdef class Matrix(Matrix1): Traceback (most recent call last): ... TypeError: Gram-Schmidt orthogonalization requires a base ring with a fraction field, not Ring of integers modulo 6 - - AUTHORS: - - - William Stein (2007-11-18) - - Rob Beezer (2011-02-25) """ from sage.matrix.constructor import matrix, zero_matrix R = self.base_ring() @@ -10356,33 +10359,109 @@ cdef class Matrix(Matrix1): else: return J + def diagonalization(self, base_field=None): + """ + Return a diagonal matrix similar to ``self`` along with the + transformation matrix. + + INPUT: + + - ``base_field`` -- if given, ``self`` is regarded as a matrix over it + + OUTPUT: a diagonal matrix `D` and an invertible matrix `P` such + that `P^{-1}AP=D`, if ``self`` is a diagonalizable matrix `A`. + + EXAMPLES:: + + sage: A = matrix(QQ, 4, [-4, 6, 3, 3, -3, 5, 3, 3, 3, -6, -4, -3, -3, 6, 3, 2]) + sage: A + [-4 6 3 3] + [-3 5 3 3] + [ 3 -6 -4 -3] + [-3 6 3 2] + sage: A.is_diagonalizable() + True + sage: A.diagonalization() + ( + [ 2 0 0 0] [ 1 1 0 0] + [ 0 -1 0 0] [ 1 0 1 0] + [ 0 0 -1 0] [-1 0 0 1] + [ 0 0 0 -1], [ 1 1 -2 -1] + ) + sage: D, P = A.diagonalization() + sage: P^-1*A*P == D + True + + sage: A = matrix(QQ, 2, [0, 2, 1, 0]) + sage: A.is_diagonalizable() + False + sage: A.is_diagonalizable(QQbar) + True + sage: D, P = A.diagonalization(QQbar) + sage: P^-1*A*P == D + True + """ + if not self.is_square(): + raise TypeError('not a square matrix') + + if base_field is not None: + A = self.change_ring(base_field) + else: + A = self + + if not A.base_ring() in _Fields: + raise ValueError('matrix entries must be from a field') + if not A.base_ring().is_exact(): + raise ValueError('base field must be exact, but {} is not'.format(A.base_ring())) + + from sage.matrix.constructor import diagonal_matrix, matrix + + # check if the sum of algebraic multiplicities equals the number of rows + evals = A.charpoly().roots() + if sum(mult for (_, mult) in evals) < self._nrows: + raise ValueError('not diagonalizable over {}'.format(A.base_ring())) + + # compute diagonalization from the eigenspaces + dia = [] + bas = [] + for e, am in evals: + b = (A - e).right_kernel().basis() + if len(b) != am: + raise ValueError('not diagonalizable') + dia += [e]*am + bas += b + + return diagonal_matrix(dia), matrix(bas).transpose() + def is_diagonalizable(self, base_field=None): r""" - Determines if the matrix is similar to a diagonal matrix. + Determine if the matrix is similar to a diagonal matrix. INPUT: - - ``base_field`` - a new field to use for entries - of the matrix. + - ``base_field`` - a new field to use for entries of the matrix. OUTPUT: If ``self`` is the matrix `A`, then it is diagonalizable - if there is an invertible matrix `S` and a diagonal matrix + if there is an invertible matrix `P` and a diagonal matrix `D` such that .. MATH:: - S^{-1}AS = D + P^{-1}AP = D This routine returns ``True`` if ``self`` is diagonalizable. The diagonal entries of the matrix `D` are the eigenvalues - of `A`. It may be necessary to "increase" the base field to - contain all of the eigenvalues. Over the rationals, the field - of algebraic numbers, :mod:`sage.rings.qqbar` is a good choice. + of `A`. + + A matrix not diagonalizable over the base field may become + diagonalizable by extending the base field to contain all of the + eigenvalues. Over the rationals, the field of algebraic numbers, + :mod:`sage.rings.qqbar` is a good choice. - To obtain the matrices `S` and `D` use the :meth:`jordan_form` - method with the ``transformation=True`` keyword. + To obtain the matrices `D` and `P`, use the :meth:`diagonalization` + method. ALGORITHM: @@ -10390,47 +10469,48 @@ cdef class Matrix(Matrix1): multiplicity (number of occurrences as a root of the characteristic polynomial) is equal to the geometric multiplicity (dimension of the eigenspace), which is sufficient to ensure a basis of - eigenvectors for the columns of `S`. + eigenvectors for the columns of `P`. EXAMPLES: - A matrix that is diagonalizable over the rationals, as evidenced - by its Jordan form. :: + A matrix that is diagonalizable over the rationals:: sage: A = matrix(QQ, [[-7, 16, 12, 0, 6], ....: [-9, 15, 0, 12, -27], ....: [ 9, -8, 11, -12, 51], ....: [ 3, -4, 0, -1, 9], ....: [-1, 0, -4, 4, -12]]) - sage: A.jordan_form(subdivide=False) - [ 2 0 0 0 0] - [ 0 3 0 0 0] - [ 0 0 3 0 0] - [ 0 0 0 -1 0] - [ 0 0 0 0 -1] sage: A.is_diagonalizable() True + sage: A.diagonalization() + ( + [ 2 0 0 0 0] [ 1 1 0 1 0] + [ 0 3 0 0 0] [ 1/2 0 1 0 1] + [ 0 0 3 0 0] [ 1/6 1 -3/2 2/3 -14/9] + [ 0 0 0 -1 0] [ -1/6 0 -1/4 0 -1/3] + [ 0 0 0 0 -1], [ -1/6 -1/3 1/3 -1/3 4/9] + ) - A matrix that is not diagonalizable over the rationals, as evidenced - by its Jordan form. :: + This is a matrix not diagonalizable over the rationals, but you + can still get its Jordan form. :: sage: A = matrix(QQ, [[-3, -14, 2, -1, 15], ....: [4, 6, -2, 3, -8], ....: [-2, -14, 0, 0, 10], ....: [3, 13, -2, 0, -11], ....: [-1, 6, 1, -3, 1]]) + sage: A.is_diagonalizable() + False sage: A.jordan_form(subdivide=False) [-1 1 0 0 0] [ 0 -1 0 0 0] [ 0 0 2 1 0] [ 0 0 0 2 1] [ 0 0 0 0 2] - sage: A.is_diagonalizable() - False - If any eigenvalue of a matrix is outside the base ring, then - this routine raises an error. However, the ring can be - "expanded" to contain the eigenvalues. :: + If any eigenvalue of a matrix is outside the base ring, then this + routine raises an error. However, the ring can be extended to contain + the eigenvalues. :: sage: A = matrix(QQ, [[1, 0, 1, 1, -1], ....: [0, 1, 0, 4, 8], @@ -10441,9 +10521,11 @@ cdef class Matrix(Matrix1): sage: [e in QQ for e in A.eigenvalues()] [False, False, False, False, False] sage: A.is_diagonalizable() + False + sage: A.diagonalization() Traceback (most recent call last): ... - RuntimeError: an eigenvalue of the matrix is not contained in Rational Field + ValueError: not diagonalizable over Rational Field sage: [e in QQbar for e in A.eigenvalues()] [True, True, True, True, True] @@ -10451,37 +10533,39 @@ cdef class Matrix(Matrix1): True Other exact fields may be employed, though it will not always - be possible to expand their base fields to contain all - the eigenvalues. :: + be possible to extend their base fields to contain all + the eigenvalues. :: sage: F. = FiniteField(5^2) sage: A = matrix(F, [[ 4, 3*b + 2, 3*b + 1, 3*b + 4], ....: [2*b + 1, 4*b, 0, 2], ....: [ 4*b, b + 2, 2*b + 3, 3], ....: [ 2*b, 3*b, 4*b + 4, 3*b + 3]]) + sage: A.is_diagonalizable() + False sage: A.jordan_form() [ 4 1| 0 0] [ 0 4| 0 0] [---------------+---------------] [ 0 0|2*b + 1 1] [ 0 0| 0 2*b + 1] - sage: A.is_diagonalizable() - False sage: F. = QuadraticField(-7) sage: A = matrix(F, [[ c + 3, 2*c - 2, -2*c + 2, c - 1], ....: [2*c + 10, 13*c + 15, -13*c - 17, 11*c + 31], ....: [2*c + 10, 14*c + 10, -14*c - 12, 12*c + 30], ....: [ 0, 2*c - 2, -2*c + 2, 2*c + 2]]) - sage: A.jordan_form(subdivide=False) - [ 4 0 0 0] - [ 0 -2 0 0] - [ 0 0 c + 3 0] - [ 0 0 0 c + 3] sage: A.is_diagonalizable() True + sage: A.diagonalization() + ( + [ 4 0 0 0] [ 1 0 1 0] + [ 0 -2 0 0] [ 4 1 0 1] + [ 0 0 c + 3 0] [ 5 1 -2/9 10/9] + [ 0 0 0 c + 3], [ 1 0 -4/9 2/9] + ) - A trivial matrix is diagonalizable, trivially. :: + A trivial matrix is diagonalizable, trivially. :: sage: A = matrix(QQ, 0, 0) sage: A.is_diagonalizable() @@ -10491,39 +10575,42 @@ cdef class Matrix(Matrix1): sage: A = matrix(QQ, 3, 4) sage: A.is_diagonalizable() - False + Traceback (most recent call last): + ... + TypeError: not a square matrix - The matrix must have entries from a field, - and it must be an exact field. :: + The matrix must have entries from a field, and it must be an exact + field. :: sage: A = matrix(ZZ, 4, range(16)) sage: A.is_diagonalizable() Traceback (most recent call last): ... - ValueError: matrix entries must be from a field, not Integer Ring + ValueError: matrix entries must be from a field sage: A = matrix(RDF, 4, range(16)) sage: A.is_diagonalizable() Traceback (most recent call last): ... - ValueError: base field must be exact, not Real Double Field - - AUTHOR: - - - Rob Beezer (2011-04-01) + ValueError: base field must be exact, but Real Double Field is not """ if not self.is_square(): - return False - if not base_field is None: - self = self.change_ring(base_field) - if not self.base_ring().is_exact(): - raise ValueError('base field must be exact, not {0}'.format(self.base_ring())) - if self.base_ring() not in _Fields: - raise ValueError('matrix entries must be from a field, not {0}'.format(self.base_ring())) + raise TypeError('not a square matrix') - evals = self.charpoly().roots() + if base_field is not None: + A = self.change_ring(base_field) + else: + A = self + + if not A.base_ring() in _Fields: + raise ValueError('matrix entries must be from a field') + if not A.base_ring().is_exact(): + raise ValueError('base field must be exact, but {} is not'.format(A.base_ring())) + + # check if the sum of algebraic multiplicities equals to the number of rows + evals = A.charpoly().roots() if sum(mult for (_, mult) in evals) < self._nrows: - raise RuntimeError('an eigenvalue of the matrix is not contained in {0}'.format(self.base_ring())) + return False # Obtaining a generic minimal polynomial requires much more # computation with kernels and their dimensions than the following. @@ -10532,9 +10619,10 @@ cdef class Matrix(Matrix1): # check equality of algebraic multiplicity and geometric multiplicity for e, am in evals: - gm = (self - e).right_kernel().dimension() + gm = (A - e).right_kernel().dimension() if am != gm: return False + return True def is_similar(self, other, transformation=False): @@ -10831,10 +10919,6 @@ cdef class Matrix(Matrix1): Traceback (most recent call last): ... ValueError: similarity only makes sense for square matrices - - AUTHOR: - - - Rob Beezer (2011-03-15, 2015-05-25) """ from sage.structure.element import is_Matrix @@ -11041,10 +11125,6 @@ cdef class Matrix(Matrix1): True sage: (QQ^4).span(iterates) == (QQ^4).span(augmented[:, 0:4].rows()) True - - AUTHOR: - - - Rob Beezer (2011-05-20) """ cdef Py_ssize_t n, i, j, k, pivcol cdef Matrix aug @@ -11260,10 +11340,6 @@ cdef class Matrix(Matrix1): Traceback (most recent call last): ... TypeError: unable to make vector entries compatible with matrix entries - - AUTHOR: - - - Rob Beezer (2011-05-20) """ import sage.rings.polynomial.polynomial_ring n = self.ncols() @@ -11594,10 +11670,6 @@ cdef class Matrix(Matrix1): sage: E = matrix(QQ, [[2, 1], [1, 1]]) sage: E.cholesky().base_ring() Algebraic Real Field - - AUTHOR: - - - Rob Beezer (2012-05-27) """ from copy import copy C = self.fetch('cholesky') @@ -12021,10 +12093,6 @@ cdef class Matrix(Matrix1): sage: P, L, U = C.LU(pivot='partial') sage: C == P*L*U True - - AUTHOR: - - - Rob Beezer (2011-04-26) """ if not pivot in [None, 'partial', 'nonzero']: msg = "pivot strategy must be None, 'partial' or 'nonzero', not {0}" @@ -12305,10 +12373,6 @@ cdef class Matrix(Matrix1): [-2 10 -2 -7] [ 4 -2 8 4] [ 2 -7 4 7] - - AUTHOR: - - - Rob Beezer (2012-05-24) """ # Implementation note: L begins as a copy of self. # Entries below the diagonal are replaced as the loops proceed. @@ -12543,10 +12607,6 @@ cdef class Matrix(Matrix1): sage: Matrix(0).indefinite_factorization() ([], ()) - - AUTHOR: - - - Rob Beezer (2012-05-24) """ from sage.modules.free_module_element import vector L, d = self._indefinite_factorization(algorithm, check=check) @@ -12722,10 +12782,6 @@ cdef class Matrix(Matrix1): sage: Matrix(0).is_positive_definite() True - - AUTHOR: - - - Rob Beezer (2012-05-24) """ from sage.rings.real_lazy import RLF,CLF @@ -13058,10 +13114,6 @@ cdef class Matrix(Matrix1): Traceback (most recent call last): ... AttributeError: 'sage.rings.finite_rings.integer_mod.IntegerMod_int' object has no attribute 'conjugate' - - AUTHOR: - - Rob Beezer (2010-12-13) """ # limited testing on a 1000 x 1000 matrix over CC: # transpose is fast, conjugate is slow @@ -13452,10 +13504,6 @@ cdef class Matrix(Matrix1): See ``_matrix_smith_form`` on the base ring for more detail. - AUTHORS: - - - David Loeffler (2008-12-05) - EXAMPLES: An example over the ring of integers of a number field (of class @@ -13812,14 +13860,6 @@ cdef class Matrix(Matrix1): When ideals of the base ring have a "small_residue" method (as is the case for number field ideals), we use this to reduce entries above each column pivot. - - AUTHOR: - - - David Loeffler (2009-06-01) - - - Moritz Minzlaff (2011-03-17): corrected code for matrices of one row; - this fixed :trac:`9053` - EXAMPLES:: sage: L. = NumberField(x^3 - 2) @@ -14023,10 +14063,6 @@ cdef class Matrix(Matrix1): True sage: U.inverse()*A*U == X True - - AUTHOR: - - - Rob Beezer (2011-06-09) """ cdef Py_ssize_t n, s, c, i, j, k @@ -14428,10 +14464,6 @@ cdef class Matrix(Matrix1): Traceback (most recent call last): ... ValueError: 'subdivide' keyword must be True or False, not garbage - - AUTHOR: - - - Rob Beezer (2011-06-09) """ R = self.base_ring() if not self.is_square(): @@ -14813,10 +14845,6 @@ cdef class Matrix(Matrix1): Traceback (most recent call last): ... ValueError: 'subdivide' keyword must be True or False, not garbage - - AUTHOR: - - - Rob Beezer (2011-06-09) """ from sage.arith.all import gcd import sage.rings.polynomial.polynomial_ring_constructor @@ -15787,10 +15815,6 @@ def _choose(Py_ssize_t n, Py_ssize_t t): [[0], [1], [2], [3]] sage: _choose(4,4) [[0, 1, 2, 3]] - - AUTHORS: - - - Jaap Spies (2007-11-14) """ cdef Py_ssize_t j, temp @@ -15846,10 +15870,6 @@ def _binomial(Py_ssize_t n, Py_ssize_t k): 45 sage: _binomial(10,5) 252 - - AUTHORS: - - - Jaap Spies (2007-10-26) """ cdef Py_ssize_t i From 32ecd26f6f0172c3a3ab0ec0f2928a37a9d72862 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Tue, 12 Nov 2019 11:39:28 +0100 Subject: [PATCH 128/340] Trac #27784: 0-th element of Pfaffian class is always zero --- src/sage/manifolds/differentiable/char_class.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/manifolds/differentiable/char_class.py b/src/sage/manifolds/differentiable/char_class.py index 05feaeaa518..7f693d7118b 100644 --- a/src/sage/manifolds/differentiable/char_class.py +++ b/src/sage/manifolds/differentiable/char_class.py @@ -740,7 +740,8 @@ def get_form(self, con, cmatrices=None): deg_dist = 1 # Now, define the name for each form: for k in res.irange(): - if k % deg_dist != 0: + if k % deg_dist != 0 or (self._class_type == 'Pfaffian' and + k == 0): res[k].set_name(name="zero", latex_name="0") res[k]._is_zero = True else: From cacd4131916ff872077ef17f516a58a99f63474e Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Tue, 12 Nov 2019 11:52:43 +0100 Subject: [PATCH 129/340] Trac #27784: Pyflake errors --- src/sage/manifolds/differentiable/bundle_connection.py | 2 -- src/sage/manifolds/differentiable/char_class.py | 3 +-- src/sage/manifolds/differentiable/vector_bundle.py | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/sage/manifolds/differentiable/bundle_connection.py b/src/sage/manifolds/differentiable/bundle_connection.py index 565fd579d22..2b3bc88500b 100644 --- a/src/sage/manifolds/differentiable/bundle_connection.py +++ b/src/sage/manifolds/differentiable/bundle_connection.py @@ -39,8 +39,6 @@ # https://www.gnu.org/licenses/ #****************************************************************************** -from sage.structure.unique_representation import UniqueRepresentation -from sage.rings.integer import Integer from sage.structure.sage_object import SageObject from sage.manifolds.differentiable.vector_bundle\ import DifferentiableVectorBundle diff --git a/src/sage/manifolds/differentiable/char_class.py b/src/sage/manifolds/differentiable/char_class.py index 7f693d7118b..13f386cd2b5 100644 --- a/src/sage/manifolds/differentiable/char_class.py +++ b/src/sage/manifolds/differentiable/char_class.py @@ -345,7 +345,6 @@ def _get_predefined_class(arg): raise TypeError("argument 'arg' must be string") from sage.symbolic.ring import SR - from sage.libs.pynac.pynac import I # Define variable: x = SR.symbol('x') # Define dictionary. The syntax is as follows: @@ -448,7 +447,7 @@ def __init__(self, vbundle, func, class_type='multiplicative', name=None, """ if vbundle._field_type == 'neither_real_nor_complex': - raise ValueEror("the vector bundle must either be real or complex") + raise ValueError("the vector bundle must either be real or complex") if class_type not in ['additive', 'multiplicative', 'Pfaffian']: raise ValueError("the argument 'class_type' must either be " "'additive', 'multiplicative' or 'Pfaffian'") diff --git a/src/sage/manifolds/differentiable/vector_bundle.py b/src/sage/manifolds/differentiable/vector_bundle.py index 63cf2903353..fdeaa481d8c 100644 --- a/src/sage/manifolds/differentiable/vector_bundle.py +++ b/src/sage/manifolds/differentiable/vector_bundle.py @@ -247,7 +247,7 @@ def char_class(self, func, **kwargs): """ if self._field_type == 'neither_real_nor_complex': - raise ValueEror("the vector bundle must be real or complex") + raise ValueError("the vector bundle must be real or complex") from .char_class import CharClass, _get_predefined_class # Is func a predefined class? if isinstance(func, str): From 2ec3a435fc3742a583f01a897ab393a4f514cf9c Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Tue, 12 Nov 2019 12:03:54 +0100 Subject: [PATCH 130/340] Trac #27784: Whitspace removed --- src/sage/manifolds/differentiable/bundle_connection.py | 2 +- src/sage/manifolds/differentiable/char_class.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/manifolds/differentiable/bundle_connection.py b/src/sage/manifolds/differentiable/bundle_connection.py index 2b3bc88500b..9b8fb852f1a 100644 --- a/src/sage/manifolds/differentiable/bundle_connection.py +++ b/src/sage/manifolds/differentiable/bundle_connection.py @@ -97,7 +97,7 @@ class BundleConnection(SageObject): curvature (2,2) of bundle connection nabla w.r.t. Local frame (E|_M, (e_1,e_2)) = 0 - They certainly obey Cartan's second structure equation:: + They certainly obey the structure equation:: sage: omega = nab.connection_form sage: check = [] diff --git a/src/sage/manifolds/differentiable/char_class.py b/src/sage/manifolds/differentiable/char_class.py index 13f386cd2b5..22a5eaa55fa 100644 --- a/src/sage/manifolds/differentiable/char_class.py +++ b/src/sage/manifolds/differentiable/char_class.py @@ -241,7 +241,7 @@ bundle TS2 over the 2-dimensional differentiable manifold S2 To compute a particular representative of the Euler class, we need to determine -a connection :: +a connection:: sage: g = M.metric('g') # standard metric on S2 sage: g[eU,1,1], g[eU,2,2] = 4/(1+x^2+y^2)^2, 4/(1+x^2+y^2)^2 From a78e1eca7caa78caf5d592ff9ed93843496294e1 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Tue, 12 Nov 2019 13:54:56 +0100 Subject: [PATCH 131/340] Trac #27784: Documentation improved --- .../manifolds/differentiable/char_class.py | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/sage/manifolds/differentiable/char_class.py b/src/sage/manifolds/differentiable/char_class.py index 22a5eaa55fa..9bf3d90094c 100644 --- a/src/sage/manifolds/differentiable/char_class.py +++ b/src/sage/manifolds/differentiable/char_class.py @@ -1,24 +1,25 @@ r""" Characteristic Classes -Let `E \to M` be some complex vector bundle over a differentiable manifold `M`. +Let `E \to M` be some topological vector bundle over a topological manifold `M` +and `R` be some ring. A *characteristic class* `c(E)` is an element of the cohomology ring -`H^{*}_{\mathrm{dR}}(M, \CC)` such that for any differentiable map `f: M \to N` -we have the *naturality condition*: +`H^{*}(M, R)` such that for any continuous map `f: M \to N` the *naturality +condition* is satisfied: .. MATH:: c(f^*E) = f^*c(E) . Roughly speaking, characteristic classes measure the non-triviality of the -vector bundle `E`. Notice, that this definition can be generalized to more -general cohomologies. +vector bundle `E`. -One way to obtain and compute characteristic classes is via the so-called -*Chern-Weil theory* using the curvature of the vector bundle. This approach is -used for computation in SAGE. +One way to obtain and compute characteristic classes in the de Rham cohomology +with coefficients in the ring `\CC` is via the so-called *Chern-Weil theory* +using the curvature of a differentiable vector bundle. This approach is used for +computation in SAGE. -In the following, let `\nabla` be a connection on `E`, `e` a local frame on +For that let `\nabla` be a connection on `E`, `e` a local frame on `E` and `\Omega` be the corresponding curvature matrix (see: :meth:`~sage.manifolds.differentiable.bundle_connection.BundleConnection.curvature_form`). @@ -28,9 +29,10 @@ \left[ P \left( \Omega \right) \right] \in H^{2*}_{\mathrm{dR}}(M, \CC) -is well-defined and independent of the choice of `\nabla` (the proof can be -found in [Roe1988]_ pp. 31). This is the foundation of the Chern-Weil theory and -therefore the following definitions. +is well-defined, independent of the choice of `\nabla` (the proof can be +found in [Roe1988]_ pp. 31) and fulfills the naturality condition. +This is the foundation of the Chern-Weil theory and therefore the following +definitions. .. NOTE:: From c306963aa5e03b5c7bfef24217374066dd3a0232 Mon Sep 17 00:00:00 2001 From: "E. Madison Bray" Date: Wed, 13 Nov 2019 18:28:00 +0100 Subject: [PATCH 132/340] Trac #28258: Reduce the likelihood of DLL base address collisions in temp modules created by cython() For technical reasons specific to Cygwin, specifically for fork() to work, it's important to give generated DLLs an "ImageBase" (the virtual memory address at which a DLL is loaded into a process) that does not overlap with any other DLL. Normally Windows can relocate them if there is an overlap, but that breaks Cygwin's fork(). This is a common issue with Cygwin and there is more discussion at https://trac.sagemath.org/wiki/Cygwin64Port#Rebasing When building Sage for Cygwin we normally take care to ensure that none of the DLLs in Sage overlap each other, but with these generated cython() modules we can't do that. Fortunately, GNU binutils/ld has a ready-made solution for that which originates from the Cygwin community: A linker flag --enable-auto-image-base, which tries to set ImageBase based on a hash of the DLL name, such that there is low (but non-zero) probability of collisions. Unfortunately, there are *so* many DLLs in Sage that some of their base addresses are already in the range assigned via --enable-auto-image-base, so there is still a high likelihood of a generated DLL conflicting with an existing DLL. Fortunately, the Cygwin community added an optional argument to --enable-auto-image-base which allows us to set the minimum base address to one in a range that will not conflict with Cygwin. Unfortunately, when this was implemented, 64-bit Cygwin was still in development, and because it is a little-used feature it was only ever supported for 32-bit binaries, and never got carried over to 64-bit binaries (presumably not intentionally, as the documentation suggests it should still work). Therefore we are forced to use the simpler --image-base linker flag which just sets a hard-coded ImageBase for the binary, but we re-implement the "auto image base" algorithm and pass its result to --image-base. This requires some unnecessary code hacks, but it is in fact quite effective, and drastically lowers the incidence of problems caused by DLL conflicts when running tests that happen to use cython(). --- src/sage/misc/cython.py | 124 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 122 insertions(+), 2 deletions(-) diff --git a/src/sage/misc/cython.py b/src/sage/misc/cython.py index 4914a80bb0f..0bb586e5fc9 100644 --- a/src/sage/misc/cython.py +++ b/src/sage/misc/cython.py @@ -19,7 +19,7 @@ # **************************************************************************** from __future__ import print_function, absolute_import from six.moves import builtins -from six import iteritems +from six import iteritems, PY2 import os import sys @@ -32,6 +32,7 @@ from .temporary_file import tmp_filename from sage.repl.user_globals import get_globals from sage.misc.sage_ostools import restore_cwd, redirection +from sage.cpython.string import str_to_bytes # CBLAS can be one of multiple implementations @@ -65,6 +66,10 @@ sequence_number = {} +# Only used on Cygwin; see note below about --enable-auto-image-base +CYTHON_IMAGE_BASE = 0x580000000 + + def cython(filename, verbose=0, compile_message=False, use_cache=False, create_local_c_file=False, annotate=True, sage_namespace=True, create_local_so_file=False): @@ -274,9 +279,39 @@ def cython(filename, verbose=0, compile_message=False, Cython.Compiler.Options.embed_pos_in_docstring = True Cython.Compiler.Options.pre_import = "sage.all" if sage_namespace else None + extra_compile_args = ['-w'] # no warnings + extra_link_args = [] + if sys.platform == 'cygwin': + # Link using --enable-auto-image-base, reducing the likelihood of the + # new DLL colliding with existing DLLs in memory. + # Note: Cygwin locates --enable-auto-image-base DLLs in the range + # 0x4:00000000 up to 0x6:00000000; this is documented in heap.cc in the + # Cygwin sources, while 0x6:00000000 and up is reserved for the Cygwin + # heap. + # In practice, Sage has enough DLLs that when rebasing everything we + # use up through, approximately, 0x4:80000000 though there is nothing + # precise here. When running 'rebase' it just start from 0x2:00000000 + # (below that is reserved for Cygwin's DLL and some internal + # structures). + # Therefore, to minimize the likelihood of collision with one of Sage's + # standard DLLs, while giving ~2GB (should be more than enough) for + # Sage to grow, we base these DLLs from 0x5:8000000, leaving again ~2GB + # for temp DLLs which in normal use should be more than enough. + # See https://trac.sagemath.org/ticket/28258 + # It should be noted, this is not a bulletproof solution; there is + # still a potential for DLL overlaps with this. But this reduces the + # probability thereof, especially in normal practice. + dll_filename = os.path.splitext(pyxfile)[0] + '.dll' + image_base = _compute_dll_image_base(dll_filename) + extra_link_args.extend([ + '-Wl,--disable-auto-image-base', + '-Wl,--image-base=0x{:x}'.format(image_base) + ]) + ext = Extension(name, sources=[pyxfile], - extra_compile_args=["-w"], # no warnings + extra_compile_args=extra_compile_args, + extra_link_args=extra_link_args, libraries=standard_libs, library_dirs=standard_libdirs) @@ -597,3 +632,88 @@ def cython_compile(code, **kwds): with open(tmpfile, 'w') as f: f.write(code) return cython_import_all(tmpfile, get_globals(), **kwds) + + +# THe following utility functions are used on Cygwin only to work around a +# shortcoming in ld/binutils; see https://trac.sagemath.org/ticket/28258 +def _strhash(s): + """ + Implementation of the strhash function from binutils + + See + https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=binutils/dllwrap.c;hb=d0e6d77b3fb64561ca66535f8ed6ca523eac923e#l449 + + This is used to re-implement support for --enable-auto-image-base with a + custom base address, which is currently broken in ld/binutils for PE32+ + binaries. + + TESTS:: + + sage: from sage.misc.cython import _strhash + sage: hex(_strhash('test.pyx')) + '0x3d99a20' + """ + + s = str_to_bytes(s) + h = 0 + l = len(s) + + for c in s: + if PY2: + c = ord(c) + + h += c + (c << 17) + h ^= h >> 2 + + h += l + (l << 17) + h ^= h >> 2 + return h + + +def _compute_dll_image_base(filename, auto_image_base=None): + """ + Compute a DLL image base address from a hash of its filename, using the + same implementation as --enable-auto-image-base from binutils, but with + support for a custom minimum base address. + + See + https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=ld/emultempl/pe.em;h=c18cb266beb23d14108044571382e0c7f4dbedb3;hb=d0e6d77b3fb64561ca66535f8ed6ca523eac923e#l919 + which implements this for PE32 images (for PE32+ images the support for + custom base addresses is broken). + + See also :trac:`28258`. + + TESTS:: + + sage: from sage.misc.cython import _compute_dll_image_base + sage: hex(_compute_dll_image_base('test.pyx')) + '0x59a200000' + + Test that given a random filename it is always below 0x6:00000000; in + principle this could fail randomly, but if it never fails then no problem. + We do not test for collisions since there is always a random chance of + collisions with two arbitrary filenames:: + + sage: from sage.misc.temporary_file import tmp_filename + sage: image_base = _compute_dll_image_base(tmp_filename(ext='.pyx')) + sage: hex(image_base) # random + '0x59a200000' + sage: image_base <= (0x600000000 - 0x10000) + True + """ + + if auto_image_base is None: + # The default, which can in principle be modified at runtime if needed + auto_image_base = CYTHON_IMAGE_BASE + + # See https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=ld/emultempl/pep.em;h=dca36cc341aabfa2ec9db139b8ec94690165201a;hb=d0e6d77b3fb64561ca66535f8ed6ca523eac923e#l113 + # where move_default_addr_high=1 on Cygwin targets. + # This is actually derived from taking the upper limit 0x6:00000000 minus + # the lower limit 0x4:00000000 minus a gap of at least 0x10000. I don't + # know why but this is supposed to work: https://narkive.com/HCyWCS6h.23 + # Currently in binutils auto_image_base of 0x4:00000000 is hard-coded, so + # this comes out to 0x1:ffff0000, but here we must compute it. + NT_DLL_AUTO_IMAGE_MASK = 0x600000000 - auto_image_base - 0x10000 + + h = _strhash(filename) + return auto_image_base + ((h << 16) & NT_DLL_AUTO_IMAGE_MASK) From 16b5e119b4db974e0f180c0fcd3f87d04022a446 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Thu, 14 Nov 2019 13:54:34 +0900 Subject: [PATCH 133/340] Fix sage_auto_doc for GlobalOptions to appear correctly. --- src/sage_setup/docbuild/ext/sage_autodoc.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/sage_setup/docbuild/ext/sage_autodoc.py b/src/sage_setup/docbuild/ext/sage_autodoc.py index 667f0500241..d73a0dc96ca 100644 --- a/src/sage_setup/docbuild/ext/sage_autodoc.py +++ b/src/sage_setup/docbuild/ext/sage_autodoc.py @@ -1041,12 +1041,12 @@ def can_document_member(cls, member, membername, isattr, parent): # However, there is an exception: CachedFunction(f) returns a class instance, # whose doc string coincides with that of f and is thus different from # that of the class CachedFunction. In that situation, we want that f is documented. - # This is part of SAGE TRAC 9976 + # This is part of trac #9976. return (inspect.isfunction(member) or inspect.isbuiltin(member) or (isclassinstance(member) and sage_getdoc_original(member) != sage_getdoc_original(member.__class__))) - # Sage Trac #9976: This function has been rewritten to support the + # Trac #9976: This function has been rewritten to support the # _sage_argspec_ attribute which makes it possible to get argument # specification of decorated callables in documentation correct. # See e.g. sage.misc.decorators.sage_wraps @@ -1409,10 +1409,10 @@ def import_object(self): self.directivetype = 'method' return ret - # Sage Trac #9976: This function has been rewritten to support the + # Trac #9976: This function has been rewritten to support the # _sage_argspec_ attribute which makes it possible to get argument # specification of decorated callables in documentation correct. - # See e.g. sage.misc.decorators.sage_wraps + # See e.g. sage.misc.decorators.sage_wraps. # # Note, however, that sage.misc.sageinspect.sage_getargspec already # uses a method _sage_argspec_, that only works on objects, not on classes, though. @@ -1482,8 +1482,13 @@ def can_document_member(cls, member, membername, isattr, parent): # descriptors. isattribute = isattribute or isinstance(type(member), ClasscallMetaclass) - if PY2: - return isattribute + return isattribute + + # We ignore the obscure case supported in the following return + # statement. The additional check opens a door for attributes without + # docstrings to appear in the Sage documentation, and more seriously + # effectively prevents certain attributes to get properly documented. + # See trac #28698. # That last condition addresses an obscure case of C-defined # methods using a deprecated type in Python 3, that is not otherwise From e5b1ca33870046f4ed9bc5a3a4561fec54b54b3b Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Thu, 14 Nov 2019 18:36:53 +0900 Subject: [PATCH 134/340] Refactored authors section; added more doctests --- src/sage/matrix/matrix2.pyx | 226 +++++++++++++++++++----------------- 1 file changed, 120 insertions(+), 106 deletions(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index 9317ab4edc3..a7f5463fcbc 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -7,19 +7,12 @@ AUTHORS: - William Stein: initial version -- Jaap Spies (2006-02-18): added ``prod_of_row_sums`` method - -- Jaap Spies (2006-02-16): added ``permanent`` method - -- Jaap Spies (2006-02-19): added ``permanental_minor`` method - -- Jaap Spies (2006-02-24): added ``rook_vector`` method +- Jaap Spies (2006-02-24): added ``prod_of_row_sums``, ``permanent``, + ``permanental_minor``, ``rook_vector`` methods - Robert Bradshaw (2007-06-14): added ``subdivide`` method -- Jaap Spies (2007-10-26): implemented ``_binomial`` auxiliary function - -- Jaap Spies (2007-11-14): implemented ``_choose`` auxiliary function +- Jaap Spies (2007-11-14): implemented ``_binomial``, ``_choose`` auxiliary functions - William Stein (2007-11-18): added ``_gram_schmidt_noscale`` method @@ -27,55 +20,34 @@ AUTHORS: - David Loeffler (2009-06-01): added ``_echelon_form_PID`` method -- Sebastian Pancratz (2009-06-12): implemented ``adjoint`` and ``charpoly`` methods - -- Sebastian Pancratz (2009-06-25): fixed ``adjoint`` reflecting the change that - ``_adjoint`` is now implemented in :class:`Matrix` - -- Sebastian Pancratz (2009-06-25): use the division-free algorithm for ``charpoly`` +- Sebastian Pancratz (2009-06-25): implemented ``adjoint`` and ``charpoly`` + methods; fixed ``adjoint`` reflecting the change that ``_adjoint`` is now + implemented in :class:`Matrix`; used the division-free algorithm for + ``charpoly`` -- Rob Beezer (2009-07-13) added ``elementwise_product`` method +- Rob Beezer (2009-07-13): added ``elementwise_product`` method - Miguel Marco (2010-06-19): modified eigenvalues and eigenvectors functions to allow the option ``extend=False`` -- Thierry Monteil (2010-10-05): Bugfix for :trac:`10063`, so that the +- Thierry Monteil (2010-10-05): bugfix for :trac:`10063`, so that the determinant is computed even for rings for which the ``is_field`` method is not implemented. - Rob Beezer (2010-12-13): added ``conjugate_transpose`` method -- Rob Beezer (2011-02-02): added ``extended_echelon_form`` method - -- Rob Beezer (2011-02-05): refactored all of the matrix kernel routines - -- Rob Beezer (2011-02-05): added ``right_kernel_matrix`` method - -- Rob Beezer (2011-02-17): added ``QR`` method - -- Rob Beezer (2011-02-25): modified ``_gram_schmidt_noscale`` method - -- Rob Beezer (2011-03-15): added ``is_similar`` method +- Rob Beezer (2011-02-05): refactored all of the matrix kernel routines; added + ``extended_echelon_form``, ``right_kernel_matrix``, ``QR``, + ``_gram_schmidt_noscale``, ``is_similar`` methods - Moritz Minzlaff (2011-03-17): corrected ``_echelon_form_PID`` method for matrices of one row, fixed in :trac:`9053` -- Rob Beezer (2011-03-31): added ``is_normal`` method - -- Rob Beezer (2011-04-01): added ``is_diagonalizable`` method +- Rob Beezer (2011-06-09): added ``is_normal``, ``is_diagonalizable``, ``LU``, + ``cyclic_subspace``, ``zigzag_form``, ``rational_form`` methods -- Rob Beezer (2011-04-26): added ``LU`` method - -- Rob Beezer (2011-05-20): added ``cyclic_subspace`` method - -- Rob Beezer (2011-06-09): added ``zigzag_form`` method - -- Rob Beezer (2011-06-09): added ``rational_form`` method - -- Rob Beezer (2012-05-24): added ``indefinite_factorization`` and - ``is_positive_definite`` methods - -- Rob Beezer (2012-05-27): added ``cholesky`` method +- Rob Beezer (2012-05-27): added ``indefinite_factorization``, + ``is_positive_definite``, ``cholesky`` methods - Darij Grinberg (2013-10-01): added first (slow) pfaffian implementation @@ -1536,6 +1508,18 @@ cdef class Matrix(Matrix1): m.append(self.matrix_from_rows_and_columns(rows,cols).determinant()) return m + def det(self, *args, **kwds): + """ + Synonym for self.determinant(...). + + EXAMPLES:: + + sage: A = MatrixSpace(Integers(8),3)([1,7,3, 1,1,1, 3,4,5]) + sage: A.det() + 6 + """ + return self.determinant(*args, **kwds) + def determinant(self, algorithm=None): r""" Returns the determinant of self. @@ -1938,19 +1922,6 @@ cdef class Matrix(Matrix1): return res - # shortcuts - def det(self, *args, **kwds): - """ - Synonym for self.determinant(...). - - EXAMPLES:: - - sage: A = MatrixSpace(Integers(8),3)([1,7,3, 1,1,1, 3,4,5]) - sage: A.det() - 6 - """ - return self.determinant(*args, **kwds) - def apply_morphism(self, phi): """ Apply the morphism phi to the coefficients of this dense matrix. @@ -2692,48 +2663,48 @@ cdef class Matrix(Matrix1): return d def diagonal(self): - r""" - Return the diagonal entries of ``self``. + r""" + Return the diagonal entries of ``self``. - OUTPUT: + OUTPUT: - A list containing the entries of the matrix that - have equal row and column indices, in order of the - indices. Behavior is not limited to square matrices. + A list containing the entries of the matrix that + have equal row and column indices, in order of the + indices. Behavior is not limited to square matrices. - EXAMPLES:: + EXAMPLES:: - sage: A = matrix([[2,5],[3,7]]); A - [2 5] - [3 7] - sage: A.diagonal() - [2, 7] + sage: A = matrix([[2,5],[3,7]]); A + [2 5] + [3 7] + sage: A.diagonal() + [2, 7] - Two rectangular matrices. :: + Two rectangular matrices. :: - sage: B = matrix(3, 7, range(21)); B - [ 0 1 2 3 4 5 6] - [ 7 8 9 10 11 12 13] - [14 15 16 17 18 19 20] - sage: B.diagonal() - [0, 8, 16] + sage: B = matrix(3, 7, range(21)); B + [ 0 1 2 3 4 5 6] + [ 7 8 9 10 11 12 13] + [14 15 16 17 18 19 20] + sage: B.diagonal() + [0, 8, 16] - sage: C = matrix(3, 2, range(6)); C - [0 1] - [2 3] - [4 5] - sage: C.diagonal() - [0, 3] + sage: C = matrix(3, 2, range(6)); C + [0 1] + [2 3] + [4 5] + sage: C.diagonal() + [0, 3] - Empty matrices behave properly. :: + Empty matrices behave properly. :: - sage: E = matrix(0, 5, []); E - [] - sage: E.diagonal() - [] - """ - n = min(self.nrows(), self.ncols()) - return [self[i,i] for i in range(n)] + sage: E = matrix(0, 5, []); E + [] + sage: E.diagonal() + [] + """ + n = min(self.nrows(), self.ncols()) + return [self[i,i] for i in range(n)] def trace(self): """ @@ -3062,9 +3033,9 @@ cdef class Matrix(Matrix1): """ return self.ncols() - self.rank() - ###################################### + ##################################################################################### # Kernel Helper Functions - ###################################### + ##################################################################################### def _right_kernel_matrix_over_number_field(self): r""" @@ -4406,7 +4377,6 @@ cdef class Matrix(Matrix1): verbose("done computing left kernel for %sx%s matrix" % (self.nrows(), self.ncols()),level=1,t=tm) return K - # .kernel() is a an alias for .left_kernel() kernel = left_kernel def kernel_on(self, V, poly=None, check=True): @@ -6423,7 +6393,7 @@ cdef class Matrix(Matrix1): ##################################################################################### # Generic Echelon Form - ################################################################################### + ##################################################################################### def rref(self, *args, **kwds): """ @@ -6943,7 +6913,7 @@ cdef class Matrix(Matrix1): self.cache('echelon_' + algorithm, E) return E - # This is for backward compatibility + # for backward compatibility def _echelon_classical(self): """ @@ -7332,9 +7302,9 @@ cdef class Matrix(Matrix1): extended.set_immutable() return extended - ########################################################################## - # Functions for symmetries of a matrix under row and column permutations # - ########################################################################## + ##################################################################################### + # Functions for symmetries of a matrix under row and column permutations + ##################################################################################### def as_bipartite_graph(self): r""" Construct a bipartite graph ``B`` representing @@ -8196,7 +8166,7 @@ cdef class Matrix(Matrix1): else: return (self._subdivisions[0][1:-1], self._subdivisions[1][1:-1]) - # 'get_subdivisions' is kept for backwards compatibility: see #4983. + # for backwards compatibility: see #4983. get_subdivisions = subdivisions def tensor_product(self, A, subdivide=True): @@ -10400,6 +10370,56 @@ cdef class Matrix(Matrix1): sage: D, P = A.diagonalization(QQbar) sage: P^-1*A*P == D True + + Matrices may fail to be diagonalizable for various reasons:: + + sage: A = matrix(QQ, 2, [1,2,3,4,5,6]) + sage: A + [1 2 3] + [4 5 6] + sage: A.diagonalization() + Traceback (most recent call last): + ... + TypeError: not a square matrix + + sage: B = matrix(ZZ, 2, [1, 2, 3, 4]) + sage: B + [1 2] + [3 4] + sage: B.diagonalization() + Traceback (most recent call last): + ... + ValueError: matrix entries must be from a field + + sage: C = matrix(RR, 2, [1., 2., 3., 4.]) + sage: C + [1.00000000000000 2.00000000000000] + [3.00000000000000 4.00000000000000] + sage: C.diagonalization() + Traceback (most recent call last): + ... + ValueError: base field must be exact, but Real Field with 53 bits of precision is not + + sage: D = matrix(QQ, 2, [0, 2, 1, 0]) + sage: D + [0 2] + [1 0] + sage: D.diagonalization() + Traceback (most recent call last): + ... + ValueError: not diagonalizable over Rational Field + + sage: E = matrix(QQ, 2, [3, 1, 0, 3]) + sage: E + [3 1] + [0 3] + sage: E.diagonalization() + Traceback (most recent call last): + ... + ValueError: not diagonalizable + sage: E.jordan_form() + [3 1] + [0 3] """ if not self.is_square(): raise TypeError('not a square matrix') @@ -15478,7 +15498,7 @@ cdef class Matrix(Matrix1): return all(s * (self * x) == 0 for (x, s) in K.discrete_complementarity_set()) - # A limited number of access-only properties are provided for matrices + # a limited number of access-only properties are provided for matrices @property def T(self): r""" @@ -15720,7 +15740,6 @@ def _generic_clear_column(m): return left_mat, a - def _smith_onestep(m): r""" Carry out one step of Smith normal form for matrix m. Returns three matrices a,b,c over @@ -15777,7 +15796,6 @@ def _smith_onestep(m): return left_mat, a, right_mat - def decomp_seq(v): """ This function is used internally be the decomposition matrix @@ -15797,7 +15815,6 @@ def decomp_seq(v): list.sort(v, key=lambda x: x[0].dimension()) return Sequence(v, universe=tuple, check=False, cr=True) - def _choose(Py_ssize_t n, Py_ssize_t t): """ Returns all possible sublists of length t from range(n) @@ -15857,7 +15874,6 @@ def _choose(Py_ssize_t n, Py_ssize_t t): return x - def _binomial(Py_ssize_t n, Py_ssize_t k): """ Fast and unchecked implementation of binomial(n,k) This is only for @@ -15886,7 +15902,6 @@ def _binomial(Py_ssize_t n, Py_ssize_t k): i, n, k = i + 1, n - 1, k - 1 return result - def _jordan_form_vector_in_difference(V, W): r""" Given two lists of vectors ``V`` and ``W`` over the same base field, @@ -15916,7 +15931,6 @@ def _jordan_form_vector_in_difference(V, W): return v return None - def _matrix_power_symbolic(A, n): r""" Return the symbolic `n`-th power `A^n` of the matrix `A` From 98ffcd0f304e09537044470df856d6a3fc9a630d Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Thu, 14 Nov 2019 11:05:19 +0000 Subject: [PATCH 135/340] update sagetex to version 3.4 --- build/pkgs/sagetex/checksums.ini | 6 +++--- build/pkgs/sagetex/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/sagetex/checksums.ini b/build/pkgs/sagetex/checksums.ini index 0ce8a7ffaf4..076dc70bfd4 100644 --- a/build/pkgs/sagetex/checksums.ini +++ b/build/pkgs/sagetex/checksums.ini @@ -1,4 +1,4 @@ tarball=sagetex-VERSION.tar.gz -sha1=fcbc8c3d449eadf1907803b81333fcc643ff944d -md5=6ab022edc969166359fdb94946fbd87d -cksum=1913907590 +sha1=03eb79a60fe6d63affc19f4b1ad65f63484caa51 +md5=e8cf419a03e60899d11741f78c994aaa +cksum=3862613381 diff --git a/build/pkgs/sagetex/package-version.txt b/build/pkgs/sagetex/package-version.txt index eb39e5382f4..2f4b60750dc 100644 --- a/build/pkgs/sagetex/package-version.txt +++ b/build/pkgs/sagetex/package-version.txt @@ -1 +1 @@ -3.3 +3.4 From 0c2b9c231d2208bc1a3ed6099268f77ebe671dc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 14 Nov 2019 14:13:30 +0100 Subject: [PATCH 136/340] fix Texture for negative inputs --- src/sage/plot/plot3d/texture.py | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/sage/plot/plot3d/texture.py b/src/sage/plot/plot3d/texture.py index ca6eaccc717..253b9645a70 100644 --- a/src/sage/plot/plot3d/texture.py +++ b/src/sage/plot/plot3d/texture.py @@ -145,6 +145,11 @@ def Texture(id=None, **kwds): sage: Texture((.2,.3,.4)) Texture(texture..., 334c66) + Now accepting negative arguments, reduced modulo 1:: + + sage: Texture((-3/8, 1/2, 3/8)) + Texture(texture..., 9f7f5f) + Textures using other keywords:: sage: Texture(specular=0.4) @@ -176,15 +181,16 @@ def Texture(id=None, **kwds): kwds['color'] = id id = None elif isinstance(id, tuple): - kwds['color'] = id + kwds['color'] = Color(id).rgb() id = None if id is None: id = _new_global_texture_id() return Texture_class(id, **kwds) + def parse_color(info, base=None): r""" - Parses the color. + Parse the color. It transforms a valid color string into a color object and a color object into an RBG tuple of length 3. Otherwise, @@ -193,7 +199,7 @@ def parse_color(info, base=None): INPUT: - ``info`` - color, valid color str or number - - ``base`` - tuple of length 3 (optional, default: None) + - ``base`` - tuple of length 3 (optional, default: ``None``) OUTPUT: @@ -234,14 +240,17 @@ def parse_color(info, base=None): try: return Color(info) except KeyError: - raise ValueError("unknown color '%s'"%info) + raise ValueError("unknown color '%s'" % info) else: r, g, b = base # We don't want to lose the data when we split it into its respective components. - if not r: r = 1e-5 - if not g: g = 1e-5 - if not b: b = 1e-5 - return (float(info*r), float(info*g), float(info*b)) + if not r: + r = 1e-5 + if not g: + g = 1e-5 + if not b: + b = 1e-5 + return (float(info * r), float(info * g), float(info * b)) class Texture_class(WithEqualityById, SageObject): @@ -299,7 +308,9 @@ def __init__(self, id, color=(.4, .4, 1), opacity=1, ambient=0.5, diffuse=1, spe else: if len(color) == 4: opacity = color[3] - color = (float(color[0]), float(color[1]), float(color[2])) + color = (float(color[0]) % 1, + float(color[1]) % 1, + float(color[2]) % 1) self.color = color self.opacity = float(opacity) @@ -319,7 +330,7 @@ def __init__(self, id, color=(.4, .4, 1), opacity=1, ambient=0.5, diffuse=1, spe def _repr_(self): """ - Gives string representation of the Texture object. + Return a string representation of the Texture object. EXAMPLES:: From 446d90ed9f527e100995330cf473c7735633ad0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 14 Nov 2019 14:21:08 +0100 Subject: [PATCH 137/340] trac 28736 fix the Texture in a better way --- src/sage/plot/plot3d/texture.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/plot/plot3d/texture.py b/src/sage/plot/plot3d/texture.py index 253b9645a70..8da8e8cdbe1 100644 --- a/src/sage/plot/plot3d/texture.py +++ b/src/sage/plot/plot3d/texture.py @@ -308,9 +308,8 @@ def __init__(self, id, color=(.4, .4, 1), opacity=1, ambient=0.5, diffuse=1, spe else: if len(color) == 4: opacity = color[3] - color = (float(color[0]) % 1, - float(color[1]) % 1, - float(color[2]) % 1) + color = tuple(float(1) if c == 1 else float(c) % 1 + for c in color[0: 3]) self.color = color self.opacity = float(opacity) From b22ff1dae33800d2e51180c111723e82b0da73f1 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Thu, 14 Nov 2019 13:52:59 +0000 Subject: [PATCH 138/340] correct links to sagtex stuff --- src/doc/en/reference/misc/sagetex.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/doc/en/reference/misc/sagetex.rst b/src/doc/en/reference/misc/sagetex.rst index 8265cfad8b7..f83e758433f 100644 --- a/src/doc/en/reference/misc/sagetex.rst +++ b/src/doc/en/reference/misc/sagetex.rst @@ -5,7 +5,9 @@ SageTeX is a system for embedding computations and plots from Sage into LaTeX documents. It is included by default with Sage, so if you have installed Sage, you already have SageTeX. However, to get it to work, you need to make TeX aware of SageTeX. Instructions for that are in the -"Make SageTeX known to TeX" section of the `Sage installation guide -`_ (`this link -<../../installation/index.html>`_ should take you to a local copy of the -installation guide). +`Make SageTeX known to TeX +`_ +section of the `Sage tutorial +`_ (`this link +<../../tutorial/index.html>`_ should take you to a local copy of the +tutorial). From 65cf868884b29f1eaa016a0e1facf16e33d9f13f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 14 Nov 2019 15:21:22 +0100 Subject: [PATCH 139/340] remove deprecated stuff in old coercion model --- src/sage/structure/parent_old.pxd | 6 +-- src/sage/structure/parent_old.pyx | 79 +++++++------------------------ 2 files changed, 19 insertions(+), 66 deletions(-) diff --git a/src/sage/structure/parent_old.pxd b/src/sage/structure/parent_old.pxd index 2b993efddf0..54bb4753970 100644 --- a/src/sage/structure/parent_old.pxd +++ b/src/sage/structure/parent_old.pxd @@ -1,12 +1,12 @@ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 William Stein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** cimport sage.structure.parent as parent from sage.structure.coerce_dict cimport MonoDict, TripleDict diff --git a/src/sage/structure/parent_old.pyx b/src/sage/structure/parent_old.pyx index 1955a1552e5..8c77065f456 100644 --- a/src/sage/structure/parent_old.pyx +++ b/src/sage/structure/parent_old.pyx @@ -11,22 +11,21 @@ SageObject TESTS: -This came up in some subtle bug once. -:: +This came up in some subtle bug once:: sage: gp(2) + gap(3) 5 """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 William Stein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** cimport sage.structure.sage_object as sage_object import operator @@ -75,37 +74,9 @@ cdef class Parent(parent.Parent): if category is not None: self._init_category_(category) - ################################################################################# + ########################################################## # New Coercion support functionality - ################################################################################# - - def coerce_map_from_c(self, S): - """ - TESTS:: - - sage: A = J0(33) - sage: A.coerce_map_from_c(QuadraticField(3)) - doctest:...: DeprecationWarning: coerce_map_from_c is deprecated - See https://trac.sagemath.org/25236 for details. - - Check to make sure that we handle coerce maps from Python - native types correctly:: - - sage: QQ['q,t'].coerce_map_from(int) - Composite map: - From: Set of Python objects of class 'int' - To: Multivariate Polynomial Ring in q, t over Rational Field - Defn: Native morphism: - From: Set of Python objects of class 'int' - To: Rational Field - then - Polynomial base injection morphism: - From: Rational Field - To: Multivariate Polynomial Ring in q, t over Rational Field - """ - from sage.misc.superseded import deprecation - deprecation(25236, "coerce_map_from_c is deprecated") - return self.__coerce_map_from_c(S) + ########################################################## cdef __coerce_map_from_c(self, S): """ @@ -199,9 +170,9 @@ cdef class Parent(parent.Parent): else: return None - ################################################################################# + ############################################## # Coercion support functionality - ################################################################################# + ############################################## def _coerce_(self, x): # Call this from Python (do not override!) if self._element_constructor is not None: @@ -280,29 +251,13 @@ cdef class Parent(parent.Parent): self._has_coerce_map_from.set(S, ans) return ans - def has_coerce_map_from_c(self, S): - """ - Return ``True`` if there is a natural map from ``S`` to ``self``. - - Otherwise, return ``False``. - - TESTS:: - - sage: A = J0(33) - sage: A.has_coerce_map_from_c(QuadraticField(3)) - doctest:...: DeprecationWarning: has_coerce_map_from_c is deprecated - See https://trac.sagemath.org/25236 for details. - False - """ - from sage.misc.superseded import deprecation - deprecation(25236, "has_coerce_map_from_c is deprecated") - return self.__has_coerce_map_from_c(S) - def _an_element_impl(self): # override this in Python """ - Return an element of self. Want it in sufficient generality - that poorly-written functions won't work when they're not - supposed to. This is cached so doesn't have to be super fast. + Return an element of ``self``. + + Want it in sufficient generality + that poorly-written functions will not work when they are not + supposed to. This is cached so does not have to be super fast. """ check_old_coerce(self) try: @@ -324,10 +279,9 @@ cdef class Parent(parent.Parent): raise NotImplementedError(f"_an_element_ is not implemented for {self}") - ############################################################################ + ############################################################### # Coercion Compatibility Layer - ############################################################################ - + ############################################################### cpdef _coerce_map_from_(self, S): if self._element_constructor is None: return self.__coerce_map_from_c(S) @@ -348,10 +302,9 @@ cdef class Parent(parent.Parent): EXAMPLES:: - sage: R.=QQ[] + sage: R. = QQ[] sage: R._generic_convert_map(QQ).category_for() Category of sets with partial maps - """ if self._element_constructor is None: if hasattr(self, '_element_constructor_'): From 61faf0a7f7c068c885573ddff11b8c4ec4cff1a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 14 Nov 2019 19:55:37 +0100 Subject: [PATCH 140/340] trac 28737 fix detail in coercion tutorial --- src/doc/en/thematic_tutorials/coercion_and_categories.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/doc/en/thematic_tutorials/coercion_and_categories.rst b/src/doc/en/thematic_tutorials/coercion_and_categories.rst index 150602f9f34..b1441ec8796 100644 --- a/src/doc/en/thematic_tutorials/coercion_and_categories.rst +++ b/src/doc/en/thematic_tutorials/coercion_and_categories.rst @@ -133,7 +133,6 @@ This base class provides a lot more methods than a general parent:: 'algebraic_closure', 'base_extend', 'class_group', - 'coerce_map_from_c', 'content', 'derivation', 'derivation_module', @@ -145,7 +144,6 @@ This base class provides a lot more methods than a general parent:: 'gcd', 'gen', 'gens', - 'has_coerce_map_from_c', 'ideal', 'ideal_monoid', 'integral_closure', From b79ed334f04ac91aba3940de4b3d107171e51b1b Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Thu, 14 Nov 2019 21:21:06 +0000 Subject: [PATCH 141/340] test that Python output of sagetex is TeX-valid --- build/pkgs/sagetex/spkg-check | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build/pkgs/sagetex/spkg-check b/build/pkgs/sagetex/spkg-check index bc11ad4209e..91d965b87f7 100644 --- a/build/pkgs/sagetex/spkg-check +++ b/build/pkgs/sagetex/spkg-check @@ -33,9 +33,13 @@ cd src typeset example.tex checkdotsage example +typeset example.tex +typeset example.tex typeset sagetex.dtx checkdotsage sagetex +typeset sagetex.dtx +typeset sagetex.dtx # if we get here, we assume the .sage files are good, and exit successfully exit 0 From 67e5cdc2b5414bd5f1d1accfbd5d7684de21b765 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Fri, 15 Nov 2019 10:16:59 +0100 Subject: [PATCH 142/340] Trac #28564: One line doctest error fixed --- src/sage/manifolds/differentiable/tensorfield.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/manifolds/differentiable/tensorfield.py b/src/sage/manifolds/differentiable/tensorfield.py index 042ed8f09e3..94c3edf1913 100644 --- a/src/sage/manifolds/differentiable/tensorfield.py +++ b/src/sage/manifolds/differentiable/tensorfield.py @@ -267,7 +267,7 @@ class TensorField(ModuleElement): sage: s.restrict(U) == f.restrict(U) * t.restrict(U) # long time True sage: s = f*t.restrict(U); s - Tensor field of type (0,2) on the Open subset U of the 2-dimensional + Tensor field f*t of type (0,2) on the Open subset U of the 2-dimensional differentiable manifold S^2 sage: s.restrict(U) == f.restrict(U) * t.restrict(U) True From 485ed39a9482fb8336f58c778f2f6a0f847b7caa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 15 Nov 2019 10:25:22 +0100 Subject: [PATCH 143/340] fix typo "convertable" --- src/sage/calculus/calculus.py | 2 +- src/sage/geometry/toric_lattice.py | 10 +++++----- src/sage/matrix/matrix2.pyx | 2 +- src/sage/misc/functional.py | 4 ++-- .../modular/modform_hecketriangle/analytic_type.py | 10 +++++----- src/sage/symbolic/expression.pyx | 2 +- src/sage/symbolic/expression_conversions.py | 6 +++--- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index 770d5828d52..ee40c4767bc 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -592,7 +592,7 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False): Sage can currently only understand a subset of the output of Maxima, Maple and Mathematica, so even if the chosen backend can perform - the summation the result might not be convertable into a Sage + the summation the result might not be convertible into a Sage expression. """ if not is_SymbolicVariable(v): diff --git a/src/sage/geometry/toric_lattice.py b/src/sage/geometry/toric_lattice.py index 03caa7c7018..6b0b340c46f 100644 --- a/src/sage/geometry/toric_lattice.py +++ b/src/sage/geometry/toric_lattice.py @@ -1745,15 +1745,15 @@ def rank(self): def coordinate_vector(self, x, reduce=False): """ - Return coordinates of x with respect to the optimized - representation of self. + Return coordinates of ``x`` with respect to the optimized + representation of ``self``. INPUT: - - ``x`` -- element of ``self`` or convertable to ``self``. + - ``x`` -- element of ``self`` or convertible to ``self`` - - ``reduce`` -- (default: False); if True, reduce coefficients - modulo invariants. + - ``reduce`` -- (default: ``False``); if ``True``, reduce coefficients + modulo invariants OUTPUT: diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index 2b3658f7bb8..07177cd877f 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -12595,7 +12595,7 @@ cdef class Matrix(Matrix1): The base ring for the elements of the matrix needs to have a fraction field implemented and the computations that result from the indefinite factorization must be - convertable to real numbers that are comparable to zero. + convertible to real numbers that are comparable to zero. EXAMPLES: diff --git a/src/sage/misc/functional.py b/src/sage/misc/functional.py index 97099a1f624..424ba0dd1a4 100644 --- a/src/sage/misc/functional.py +++ b/src/sage/misc/functional.py @@ -18,7 +18,7 @@ # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** from __future__ import absolute_import from six.moves import range, builtins @@ -568,7 +568,7 @@ def symbolic_sum(expression, *args, **kwds): #. Sage can currently only understand a subset of the output of Maxima, Maple and Mathematica, so even if the chosen backend can perform the summation the - result might not be convertable into a Sage expression. + result might not be convertible into a Sage expression. """ if hasattr(expression, 'sum'): diff --git a/src/sage/modular/modform_hecketriangle/analytic_type.py b/src/sage/modular/modform_hecketriangle/analytic_type.py index 3d44c30e5b4..121fbada96b 100644 --- a/src/sage/modular/modform_hecketriangle/analytic_type.py +++ b/src/sage/modular/modform_hecketriangle/analytic_type.py @@ -17,7 +17,7 @@ # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** from sage.sets.set import Set @@ -211,8 +211,8 @@ def reduce_to(self, reduce_type): INPUT: - - ``reduce_type`` -- An analytic type or something which is - convertable to an analytic type. + - ``reduce_type`` -- an analytic type or something which is + convertible to an analytic type OUTPUT: @@ -241,8 +241,8 @@ def extend_by(self, extend_type): INPUT: - - ``extend_type`` -- An analytic type or something which is - convertable to an analytic type. + - ``extend_type`` -- an analytic type or something which is + convertible to an analytic type OUTPUT: diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index acb1b2a25b3..2c5967e0a87 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -12211,7 +12211,7 @@ cdef class Expression(CommutativeRingElement): #. Sage can currently only understand a subset of the output of Maxima, Maple and Mathematica, so even if the chosen backend can perform the summation the - result might not be convertable into a usable Sage expression. + result might not be convertible into a usable Sage expression. TESTS: diff --git a/src/sage/symbolic/expression_conversions.py b/src/sage/symbolic/expression_conversions.py index ad2e20ab23f..7439464eae9 100644 --- a/src/sage/symbolic/expression_conversions.py +++ b/src/sage/symbolic/expression_conversions.py @@ -1904,9 +1904,9 @@ def __init__(self, R, subs_dict=None): def symbol(self, ex): """ - All symbols appearing in the expression must either appear in *subs_dict* - or be convertable by the ring's element constructor in order for the - conversion to be successful. + All symbols appearing in the expression must either appear in + *subs_dict* or be convertible by the ring's element + constructor in order for the conversion to be successful. EXAMPLES:: From 0857ec4dfd6027a8725712631d908a62ac49eef2 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Fri, 15 Nov 2019 10:56:08 +0100 Subject: [PATCH 144/340] Trac #27784: Typos and minor code improvements --- .../differentiable/affine_connection.py | 8 +- .../differentiable/bundle_connection.py | 49 +++--- .../manifolds/differentiable/char_class.py | 146 +++++++++--------- .../manifolds/differentiable/vector_bundle.py | 12 +- 4 files changed, 101 insertions(+), 114 deletions(-) diff --git a/src/sage/manifolds/differentiable/affine_connection.py b/src/sage/manifolds/differentiable/affine_connection.py index 44cd16efc0f..c312ed137d6 100644 --- a/src/sage/manifolds/differentiable/affine_connection.py +++ b/src/sage/manifolds/differentiable/affine_connection.py @@ -428,7 +428,7 @@ def _init_derived(self): # (key: vector frame) self._curvature_forms = {} # dict. of dict. of curvature 2-forms # (key: vector frame) - self._hash_value = -1 + self._hash = -1 def _del_derived(self): r""" @@ -2341,6 +2341,6 @@ def __hash__(self): 1 """ - if self._hash_value == -1: - self._hash_value = hash(repr(self)) - return self._hash_value + if self._hash == -1: + self._hash = hash(repr(self)) + return self._hash diff --git a/src/sage/manifolds/differentiable/bundle_connection.py b/src/sage/manifolds/differentiable/bundle_connection.py index 9b8fb852f1a..501b492760f 100644 --- a/src/sage/manifolds/differentiable/bundle_connection.py +++ b/src/sage/manifolds/differentiable/bundle_connection.py @@ -40,19 +40,13 @@ #****************************************************************************** from sage.structure.sage_object import SageObject -from sage.manifolds.differentiable.vector_bundle\ - import DifferentiableVectorBundle +from sage.manifolds.differentiable.vector_bundle import DifferentiableVectorBundle class BundleConnection(SageObject): r""" An instance of this class represents a bundle connection `\nabla` on a smooth vector bundle `E \to M`. - .. NOTE:: - - Notice that this is a *very* rudimentary form of bundle connections. - A more detailed implementation is devoted to :trac:`28640`. - INPUT: - ``vbundle`` -- the vector bundle on which the connection is defined @@ -60,7 +54,7 @@ class BundleConnection(SageObject): :class:`~sage.manifolds.differentiable.vector_bundle.DifferentiableVectorBundle`) - ``name`` -- name given to the bundle connection - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the bundle - connection; if ``None``, it is set to ``name``. + connection; if ``None``, it is set to ``name`` EXAMPLES: @@ -99,15 +93,15 @@ class BundleConnection(SageObject): They certainly obey the structure equation:: - sage: omega = nab.connection_form - sage: check = [] - sage: for i in E.irange(): # long time - ....: for j in E.irange(): - ....: check.append(nab.curvature_form(i,j,e) == \ - ....: omega(i,j,e).exterior_derivative() + \ - ....: sum(omega(k,j,e).wedge(omega(i,k,e)) for k in E.irange())) - sage: check # long time - [True, True, True, True] + sage: omega = nab.connection_form + sage: check = [] + sage: for i in E.irange(): # long time + ....: for j in E.irange(): + ....: check.append(nab.curvature_form(i,j,e) == \ + ....: omega(i,j,e).exterior_derivative() + \ + ....: sum(omega(k,j,e).wedge(omega(i,k,e)) for k in E.irange())) + sage: check # long time + [True, True, True, True] """ def __init__(self, vbundle, name, latex_name=None): @@ -118,8 +112,7 @@ def __init__(self, vbundle, name, latex_name=None): sage: M = Manifold(3, 'M') sage: E = M.vector_bundle(2, 'E') - sage: from sage.manifolds.differentiable.bundle_connection import \ - BundleConnection + sage: from sage.manifolds.differentiable.bundle_connection import BundleConnection sage: nab = BundleConnection(E, 'nabla', latex_name=r'\nabla') sage: nab Bundle connection nabla on the Differentiable real vector bundle @@ -209,7 +202,7 @@ def _init_derived(self): """ self._curvature_forms = {} # dict. of dict. of curvature forms # (key: local frame) - self._hash_value = -1 + self._hash = -1 def _del_derived(self): r""" @@ -417,7 +410,7 @@ def connection_forms(self, frame=None): smodule = self._vbundle.section_module(domain=self._base_space) frame = smodule.default_frame() if frame is None: - raise ValueError("A frame must be provided!") + raise ValueError("a frame must be provided!") if frame not in self._connection_forms: # the connection forms must be computed # @@ -431,8 +424,8 @@ def connection_forms(self, frame=None): for ind, value in ocomp_store.items(): comp_store[ind] = value.restrict(frame._domain) break - # TODO: Compute transformations else: + # TODO: Compute coefficients out of known ones self._connection_forms[frame] = self._new_forms(frame) return self._connection_forms[frame] @@ -544,7 +537,7 @@ def add_connection_form(self, i, j, form, frame=None): smodule = self._vbundle.section_module(domain=self._base_space) frame = smodule.default_frame() if frame is None: - raise ValueError("A frame must be provided!") + raise ValueError("a frame must be provided!") ### # Certainly, the form must be a differential form, otherwise try to # convert: @@ -657,7 +650,7 @@ def del_other_forms(self, frame=None): smodule = self._vbundle.section_module(domain=self._base_space) frame = smodule.default_frame() if frame is None: - raise ValueError("A frame must be provided!") + raise ValueError("a frame must be provided!") if frame not in self._connection_forms: raise ValueError("the coefficients w.r.t. {}".format(frame) + " have not been defined") @@ -713,7 +706,7 @@ def curvature_form(self, i, j, frame=None): smodule = self._vbundle.section_module(domain=self._base_space) frame = smodule.default_frame() if frame is None: - raise ValueError("A frame must be provided!") + raise ValueError("a frame must be provided!") if frame not in self._curvature_forms: self._curvature_forms[frame] = {} if (i, j) not in self._curvature_forms[frame]: @@ -748,6 +741,6 @@ def __hash__(self): 1 """ - if self._hash_value == -1: - self._hash_value = hash(repr(self)) - return self._hash_value + if self._hash == -1: + self._hash = hash(repr(self)) + return self._hash diff --git a/src/sage/manifolds/differentiable/char_class.py b/src/sage/manifolds/differentiable/char_class.py index 9bf3d90094c..68ea67a86d4 100644 --- a/src/sage/manifolds/differentiable/char_class.py +++ b/src/sage/manifolds/differentiable/char_class.py @@ -2,7 +2,7 @@ Characteristic Classes Let `E \to M` be some topological vector bundle over a topological manifold `M` -and `R` be some ring. +and `R` be any ring. A *characteristic class* `c(E)` is an element of the cohomology ring `H^{*}(M, R)` such that for any continuous map `f: M \to N` the *naturality condition* is satisfied: @@ -16,8 +16,7 @@ One way to obtain and compute characteristic classes in the de Rham cohomology with coefficients in the ring `\CC` is via the so-called *Chern-Weil theory* -using the curvature of a differentiable vector bundle. This approach is used for -computation in SAGE. +using the curvature of a differentiable vector bundle. For that let `\nabla` be a connection on `E`, `e` a local frame on `E` and `\Omega` be the corresponding curvature matrix @@ -110,7 +109,7 @@ The Chern character is then given by:: - sage: ch = E.char_class('ChernChar'); ch + sage: ch = E.characteristic_class('ChernChar'); ch Characteristic class ch of additive type associated to e^x on the Differentiable complex vector bundle E -> M of rank 1 over the base space 2-dimensional Lorentzian manifold M @@ -180,7 +179,7 @@ Now, the Chern class can be constructed:: - sage: c = E.char_class('Chern'); c + sage: c = E.characteristic_class('Chern'); c Characteristic class c of multiplicative type associated to x + 1 on the Differentiable complex vector bundle gamma^1 -> CP^1 of rank 1 over the base space 2-dimensional differentiable manifold CP^1 @@ -238,7 +237,7 @@ sage: uv_to_xy = xy_to_uv.inverse() sage: eU = c_xy.frame() ; eV = c_uv.frame() sage: TM = M.tangent_bundle() - sage: e_class = TM.char_class('Euler'); e_class + sage: e_class = TM.characteristic_class('Euler'); e_class Characteristic class e of Pfaffian type associated to x on the Tangent bundle TS2 over the 2-dimensional differentiable manifold S2 @@ -302,10 +301,6 @@ As we can see, the integral coincides with the Euler characteristic of `S^2` so that our form actually represents the Euler class appropriately. -.. _documentation: - -Class Documentation -------------------- """ #****************************************************************************** @@ -319,13 +314,14 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.sage_object import SageObject +from sage.symbolic.ring import SR ################################################################################ -## Static methods +## Separate functions def _get_predefined_class(arg): r""" - Return the signature of the predefined class given by the string `arg`. + Return the signature of the predefined class given by the string ``arg``. The signature is given by a tuple following the syntax (base field, class type, name, LaTeX name, function). @@ -345,35 +341,35 @@ def _get_predefined_class(arg): """ if not isinstance(arg, str): raise TypeError("argument 'arg' must be string") - - from sage.symbolic.ring import SR # Define variable: x = SR.symbol('x') # Define dictionary. The syntax is as follows: # (field_type, class_type, name, latex_name, func) - c_dict = {} - c_dict['ChernChar'] = ('complex', 'additive', 'ch', r'\mathrm{ch}', x.exp()) - c_dict['Todd'] = ('complex', 'additive', 'Td', r'\mathrm{Td}', - x / (1 - (-x).exp())) - c_dict['Chern'] = ('complex', 'multiplicative', 'c', 'c', 1 + x) - c_dict['Pontryagin'] = ('real', 'multiplicative', 'p', 'p', 1 + x) - c_dict['AHat'] = ('real', 'multiplicative', 'A^', r'\hat{A}', - x.sqrt() / (2 * (x.sqrt() / 2).sinh())) - c_dict['Hirzebruch'] = ('real', 'multiplicative', 'L', 'L', - (x.sqrt() / x.sqrt().tanh())) - c_dict['Euler'] = ('real', 'Pfaffian', 'e', 'e', x) - # Get class from arg - try: - res = c_dict[arg] - except KeyError: + if arg == 'ChernChar': + return ('complex', 'additive', 'ch', r'\mathrm{ch}', x.exp()) + elif arg == 'Todd': + return ('complex', 'additive', 'Td', r'\mathrm{Td}', + x / (1 - (-x).exp())) + elif arg == 'Chern': + return ('complex', 'multiplicative', 'c', 'c', 1 + x) + elif arg == 'Pontryagin': + return ('real', 'multiplicative', 'p', 'p', 1 + x) + elif arg == 'AHat': + return ('real', 'multiplicative', 'A^', r'\hat{A}', + x.sqrt() / (2 * (x.sqrt() / 2).sinh())) + elif arg == 'Hirzebruch': + return ('real', 'multiplicative', 'L', 'L', + x.sqrt() / x.sqrt().tanh()) + elif arg == 'Euler': + return ('real', 'Pfaffian', 'e', 'e', x) + else: raise ValueError("the characteristic class '{}' is ".format(arg) + "not predefined yet.") - return res ################################################################################ ## Classes -class CharClass(SageObject, UniqueRepresentation): +class CharacteristicClass(UniqueRepresentation, SageObject): r""" An instance of this class represents a characteristic class on some differentiable vector bundle over the field `\RR` or `\CC`. @@ -403,14 +399,14 @@ class CharClass(SageObject, UniqueRepresentation): sage: M = Manifold(4, 'M') sage: TM = M.tangent_bundle() - sage: TM.char_class('Pontryagin') + sage: TM.characteristic_class('Pontryagin') Characteristic class p of multiplicative type associated to x + 1 on the Tangent bundle TM over the 4-dimensional differentiable manifold M - sage: TM.char_class('Hirzebruch') + sage: TM.characteristic_class('Hirzebruch') Characteristic class L of multiplicative type associated to sqrt(x)/tanh(sqrt(x)) on the Tangent bundle TM over the 4-dimensional differentiable manifold M - sage: TM.char_class('AHat') + sage: TM.characteristic_class('AHat') Characteristic class A^ of multiplicative type associated to 1/2*sqrt(x)/sinh(1/2*sqrt(x)) on the Tangent bundle TM over the 4-dimensional differentiable manifold M @@ -418,7 +414,7 @@ class CharClass(SageObject, UniqueRepresentation): The vector bundle's base field and definition domain of the characteristic class must fit together, otherwise an error message occurs:: - sage: TM.char_class('Chern') + sage: TM.characteristic_class('Chern') Traceback (most recent call last): ... ValueError: base field must be complex for class 'Chern' @@ -426,7 +422,7 @@ class must fit together, otherwise an error message occurs:: If your favourite class is not predefined yet, the associated function can be put manually:: - sage: cl = TM.char_class(1+x^2, name='cl'); cl + sage: cl = TM.characteristic_class(1+x^2, name='cl'); cl Characteristic class cl of multiplicative type associated to x^2 + 1 on the Tangent bundle TM over the 4-dimensional differentiable manifold M @@ -440,8 +436,8 @@ def __init__(self, vbundle, func, class_type='multiplicative', name=None, sage: M = Manifold(3, 'M') sage: TM = M.tangent_bundle() - sage: from sage.manifolds.differentiable.char_class import CharClass - sage: c = CharClass(TM, 1+x, name='c'); c + sage: from sage.manifolds.differentiable.char_class import CharacteristicClass + sage: c = CharacteristicClass(TM, 1+x, name='c'); c Characteristic class c of multiplicative type associated to x + 1 on the Tangent bundle TM over the 3-dimensional differentiable manifold M @@ -479,13 +475,12 @@ def _get_coeff_list(self): sage: M = Manifold(2, 'M') sage: E = M.vector_bundle(1, 'E', field='complex') - sage: c = E.char_class(1+x) + sage: c = E.characteristic_class(1+x) sage: c._get_coeff_list() [1, 1] """ - pow_range = (self._base_space._dim / 2).floor() - from sage.symbolic.ring import SR + pow_range = self._base_space._dim // 2 def_var = self._func.default_variable() # Use a complex variable without affecting the old one: new_var = SR.symbol('x_char_class_', domain='complex') @@ -505,9 +500,8 @@ def _get_coeff_list(self): self._func.subs({def_var: -new_var})) / 2 else: func = self._func.subs({def_var: new_var}) - coef = func.taylor(new_var, 0, pow_range).coefficients(sparse=False) - return coef + return func.taylor(new_var, 0, pow_range).coefficients(sparse=False) def _init_derived(self): r""" @@ -517,7 +511,7 @@ def _init_derived(self): sage: M = Manifold(2, 'M') sage: TM = M.tangent_bundle() - sage: c = TM.char_class(1+x) + sage: c = TM.characteristic_class(1+x) sage: c._init_derived() """ @@ -533,7 +527,7 @@ def _del_derived(self): sage: M = Manifold(2, 'M') sage: TM = M.tangent_bundle() - sage: c = TM.char_class(1+x) + sage: c = TM.characteristic_class(1+x) sage: c._del_derived() """ @@ -547,7 +541,7 @@ def _repr_(self): sage: M = Manifold(2, 'M') sage: TM = M.tangent_bundle() - sage: c = TM.char_class(1+x, name='c') + sage: c = TM.characteristic_class(1+x, name='c') sage: c # indirect doctest Characteristic class c of multiplicative type associated to x + 1 on the Tangent bundle TM over the 2-dimensional differentiable @@ -577,8 +571,8 @@ def _latex_(self): sage: M = Manifold(2, 'M') sage: TM = M.tangent_bundle() - sage: ch = TM.char_class(exp(x), class_type='additive', name='ch', - ....: latex_name=r'\mathrm{ch}') + sage: ch = TM.characteristic_class(exp(x), class_type='additive', name='ch', + ....: latex_name=r'\mathrm{ch}') sage: ch._latex_() '\\mathrm{ch}(TM)' @@ -593,8 +587,8 @@ def class_type(self): sage: M = Manifold(2, 'M') sage: TM = M.tangent_bundle() - sage: ch = TM.char_class(exp(x), class_type='additive', name='ch', - ....: latex_name=r'\mathrm{ch}') + sage: ch = TM.characteristic_class(exp(x), class_type='additive', name='ch', + ....: latex_name=r'\mathrm{ch}') sage: ch.class_type() 'additive' @@ -609,34 +603,34 @@ def function(self): sage: M = Manifold(2, 'M') sage: TM = M.tangent_bundle() - sage: e_class = TM.char_class('Euler') + sage: e_class = TM.characteristic_class('Euler') sage: e_class.function() x - sage: AHat = TM.char_class('AHat') + sage: AHat = TM.characteristic_class('AHat') sage: AHat.function() 1/2*sqrt(x)/sinh(1/2*sqrt(x)) - sage: c = TM.char_class(1+x, name='c') + sage: c = TM.characteristic_class(1+x, name='c') sage: c.function() x + 1 """ return self._func - def get_form(self, con, cmatrices=None): + def get_form(self, connection, cmatrices=None): r""" Return the form representing ``self`` with respect to the given - connection ``con``. + connection ``connection``. INPUT: - - ``con`` -- connection to which the form should be associated to; this + - ``connection`` -- connection to which the form should be associated to; this can be either a bundle connection as an instance of :class:`~sage.manifolds.differentiable.bundle_connection.BundleConnection` or, in case of the tensor bundle, an affine connection as an instance of :class:`~sage.manifolds.differentiable.affine_connection.AffineConnection` - ``cmatrices`` -- (default: ``None``) a dictionary of curvature matrices with local frames as keys and curvature matrices as items; if - ``None``, SAGE tries to get the curvature matrices from the connection + ``None``, Sage tries to get the curvature matrices from the connection OUTPUT: @@ -676,7 +670,7 @@ def get_form(self, con, cmatrices=None): The Chern character is then given by:: - sage: ch = E.char_class('ChernChar'); ch + sage: ch = E.characteristic_class('ChernChar'); ch Characteristic class ch of additive type associated to e^x on the Differentiable complex vector bundle E -> M of rank 1 over the base space 2-dimensional Lorentzian manifold M @@ -700,11 +694,11 @@ def get_form(self, con, cmatrices=None): """ from .bundle_connection import BundleConnection from .affine_connection import AffineConnection - if not isinstance(con, (AffineConnection, BundleConnection)): + if not isinstance(connection, (AffineConnection, BundleConnection)): raise TypeError("argument must be an affine connection on the " "manifold or bundle connection on the vector " "bundle") - if con not in self._mixed_forms: + if connection not in self._mixed_forms: if cmatrices is None: if self._class_type == 'Pfaffian': raise NotImplementedError( @@ -713,18 +707,18 @@ def get_form(self, con, cmatrices=None): "'cmatrices' to insert a dictionary of skew-symmetric " "curvature matrices by hand, instead.") cmatrices = {} - for frame in self._get_min_frames(con._coefficients.keys()): - cmatrix = [[con.curvature_form(i, j, frame) + for frame in self._get_min_frames(connection._coefficients.keys()): + cmatrix = [[connection.curvature_form(i, j, frame) for j in self._vbundle.irange()] for i in self._vbundle.irange()] cmatrices[frame] = cmatrix # Prepare mixed form: name, latex_name = self._name, self._latex_name - if name is not None and con._name is not None: - name += "(" + self._vbundle._name + ", " + con._name + ")" - if latex_name is not None and con._latex_name is not None: + if name is not None and connection._name is not None: + name += "(" + self._vbundle._name + ", " + connection._name + ")" + if latex_name is not None and connection._latex_name is not None: latex_name += "(" + self._vbundle._latex_name + ", " + \ - con._latex_name + ")" + connection._latex_name + ")" res = self._base_space.mixed_form(name=name, latex_name=latex_name) # Set name of homogeneous components: # @@ -749,16 +743,16 @@ def get_form(self, con, cmatrices=None): if self._name is not None: name = self._name + "_" + str(k / deg_dist) + \ "(" + self._vbundle._name - if con._name is not None: - name += ", " + con._name + if connection._name is not None: + name += ", " + connection._name name += ")" # LaTeX name: if self._latex_name is not None: latex_name = self._latex_name + \ r"_{" + str(k / deg_dist) + r"}" + \ r"(" + self._vbundle._latex_name - if con._latex_name is not None: - latex_name += r", " + con._latex_name + if connection._latex_name is not None: + latex_name += r", " + connection._latex_name latex_name += r")" # Set name: res[k].set_name(name=name, latex_name=latex_name) @@ -784,9 +778,9 @@ def get_form(self, con, cmatrices=None): # Set restriction: res.set_restriction(rst) - self._mixed_forms[con] = res + self._mixed_forms[connection] = res - return self._mixed_forms[con] + return self._mixed_forms[connection] def _insert_in_polynomial(self, cmatrix): r""" @@ -796,7 +790,7 @@ def _insert_in_polynomial(self, cmatrix): TESTS:: sage: M = Manifold(4, 'M') - sage: c = M.tangent_bundle().char_class('Pontryagin') + sage: c = M.tangent_bundle().characteristic_class('Pontryagin') sage: c._insert_in_polynomial(x) 1/2*x^2 + 1 @@ -819,7 +813,7 @@ def _normalize_matrix(self, cmatrix): INPUT: - - ``cmatrix`` curvature matrix + - ``cmatrix`` -- curvature matrix OUTPUT: @@ -829,7 +823,7 @@ def _normalize_matrix(self, cmatrix): sage: M = Manifold(2, 'M') sage: TM = M.tangent_bundle() - sage: c = TM.char_class(1+x) + sage: c = TM.characteristic_class(1+x) sage: c._normalize_matrix(x) -1/2*I*x/pi @@ -860,7 +854,7 @@ def _get_min_frames(self, frame_list): sage: U = M.open_subset('U'); V = M.open_subset('V') sage: e = U.vector_frame('e'); f = V.vector_frame('f') sage: g = M.vector_frame('g') - sage: c = M.tangent_bundle().char_class('Pontryagin') + sage: c = M.tangent_bundle().characteristic_class('Pontryagin') sage: c._get_min_frames([e, f, g]) {Vector frame (M, (g_0,g_1))} diff --git a/src/sage/manifolds/differentiable/vector_bundle.py b/src/sage/manifolds/differentiable/vector_bundle.py index fdeaa481d8c..13e4d84a301 100644 --- a/src/sage/manifolds/differentiable/vector_bundle.py +++ b/src/sage/manifolds/differentiable/vector_bundle.py @@ -163,7 +163,7 @@ def bundle_connection(self, name, latex_name=None): from .bundle_connection import BundleConnection return BundleConnection(self, name, latex_name) - def char_class(self, func, **kwargs): + def characteristic_class(self, func, **kwargs): r""" Return a characteristic class of the given type with respect to the given function. @@ -232,7 +232,7 @@ def char_class(self, func, **kwargs): sage: TM = M.tangent_bundle(); TM Tangent bundle TM over the 4-dimensional Lorentzian manifold M - sage: p = TM.char_class('Pontryagin'); p + sage: p = TM.characteristic_class('Pontryagin'); p Characteristic class p of multiplicative type associated to x + 1 on the Tangent bundle TM over the 4-dimensional Lorentzian manifold M sage: p.function() @@ -243,12 +243,12 @@ def char_class(self, func, **kwargs): .. SEEALSO:: More examples can be found in - :class:`~sage.manifolds.differentiable.char_class.CharClass`. + :class:`~sage.manifolds.differentiable.char_class.CharacteristicClass`. """ if self._field_type == 'neither_real_nor_complex': raise ValueError("the vector bundle must be real or complex") - from .char_class import CharClass, _get_predefined_class + from .char_class import CharacteristicClass, _get_predefined_class # Is func a predefined class? if isinstance(func, str): func_str = func @@ -265,8 +265,8 @@ def char_class(self, func, **kwargs): name = kwargs.pop('name', None) latex_name = kwargs.pop('latex_name', None) - return CharClass(self, func, class_type=class_type, name=name, - latex_name=latex_name) + return CharacteristicClass(self, func, class_type=class_type, name=name, + latex_name=latex_name) def diff_degree(self): r""" From 1db2c89cc0833f3889a97bcc73cad056872434d9 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Fri, 15 Nov 2019 11:19:42 +0100 Subject: [PATCH 145/340] Trac #27784: Line breaks --- .../manifolds/differentiable/char_class.py | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/sage/manifolds/differentiable/char_class.py b/src/sage/manifolds/differentiable/char_class.py index 68ea67a86d4..d53a9dee7b6 100644 --- a/src/sage/manifolds/differentiable/char_class.py +++ b/src/sage/manifolds/differentiable/char_class.py @@ -141,7 +141,8 @@ .. MATH:: - \left[\det\left( \sqrt{ g \left( -\frac{\Omega^2}{4 \pi^2} \right) } \right) \right] \in H^{4*}_{\mathrm{dR}}(M, \CC) + \left[\det\left( \sqrt{ g \left( -\frac{\Omega^2}{4 \pi^2} \right) } \right) + \right] \in H^{4*}_{\mathrm{dR}}(M, \CC) the *multiplicative Pontryagin g-genus*. @@ -571,8 +572,8 @@ def _latex_(self): sage: M = Manifold(2, 'M') sage: TM = M.tangent_bundle() - sage: ch = TM.characteristic_class(exp(x), class_type='additive', name='ch', - ....: latex_name=r'\mathrm{ch}') + sage: ch = TM.characteristic_class(exp(x), class_type='additive', + ....: name='ch', latex_name=r'\mathrm{ch}') sage: ch._latex_() '\\mathrm{ch}(TM)' @@ -587,8 +588,8 @@ def class_type(self): sage: M = Manifold(2, 'M') sage: TM = M.tangent_bundle() - sage: ch = TM.characteristic_class(exp(x), class_type='additive', name='ch', - ....: latex_name=r'\mathrm{ch}') + sage: ch = TM.characteristic_class(exp(x), class_type='additive', + ....: name='ch', latex_name=r'\mathrm{ch}') sage: ch.class_type() 'additive' @@ -623,8 +624,8 @@ def get_form(self, connection, cmatrices=None): INPUT: - - ``connection`` -- connection to which the form should be associated to; this - can be either a bundle connection as an instance of + - ``connection`` -- connection to which the form should be associated to; + this can be either a bundle connection as an instance of :class:`~sage.manifolds.differentiable.bundle_connection.BundleConnection` or, in case of the tensor bundle, an affine connection as an instance of :class:`~sage.manifolds.differentiable.affine_connection.AffineConnection` @@ -653,8 +654,8 @@ def get_form(self, connection, cmatrices=None): sage: M = Manifold(2, 'M', structure='Lorentzian') sage: X. = M.chart() sage: E = M.vector_bundle(1, 'E', field='complex'); E - Differentiable complex vector bundle E -> M of rank 1 over the base space - 2-dimensional Lorentzian manifold M + Differentiable complex vector bundle E -> M of rank 1 over the base + space 2-dimensional Lorentzian manifold M sage: e = E.local_frame('e') And again, we define the connection `\nabla^E` in terms of an @@ -672,8 +673,8 @@ def get_form(self, connection, cmatrices=None): sage: ch = E.characteristic_class('ChernChar'); ch Characteristic class ch of additive type associated to e^x on the - Differentiable complex vector bundle E -> M of rank 1 over the base space - 2-dimensional Lorentzian manifold M + Differentiable complex vector bundle E -> M of rank 1 over the base + space 2-dimensional Lorentzian manifold M Inserting the connection, the result is a mixed differential form with a priori non-zero components in even degrees:: From 5dd53b08816502d1b1ee00f911bc80f1b426fb00 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Fri, 15 Nov 2019 13:39:17 +0100 Subject: [PATCH 146/340] Trac #28564: raw strings for LaTeX code --- src/sage/manifolds/differentiable/tensorfield.py | 2 +- src/sage/manifolds/scalarfield.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/manifolds/differentiable/tensorfield.py b/src/sage/manifolds/differentiable/tensorfield.py index 94c3edf1913..e652950a0dc 100644 --- a/src/sage/manifolds/differentiable/tensorfield.py +++ b/src/sage/manifolds/differentiable/tensorfield.py @@ -2563,7 +2563,7 @@ def _rmul_(self, scalar): from sage.tensor.modules.format_utilities import (format_mul_txt, format_mul_latex) resu_name = format_mul_txt(scalar._name, '*', self._name) - resu_latex = format_mul_latex(scalar._latex_name, ' \cdot ', + resu_latex = format_mul_latex(scalar._latex_name, r' \cdot ', self._latex_name) resu.set_name(name=resu_name, latex_name=resu_latex) return resu diff --git a/src/sage/manifolds/scalarfield.py b/src/sage/manifolds/scalarfield.py index 4eb4043ac5b..9ff3b411f21 100644 --- a/src/sage/manifolds/scalarfield.py +++ b/src/sage/manifolds/scalarfield.py @@ -2562,7 +2562,7 @@ def _mul_(self, other): # ChartFunction multiplication: result._express[chart] = self._express[chart] * other._express[chart] result._name = format_mul_txt(self._name, '*', other._name) - result._latex_name = format_mul_latex(self._latex_name, ' \cdot ', + result._latex_name = format_mul_latex(self._latex_name, r' \cdot ', other._latex_name) return result From ebbfb16bb285b1cb3a9430eae2a5165ba7e891e2 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Fri, 15 Nov 2019 13:48:00 +0100 Subject: [PATCH 147/340] Trac #27784: manif zero forms set to unique zero + int division + documentation --- .../differentiable/bundle_connection.py | 5 +- .../manifolds/differentiable/char_class.py | 53 +++++++++---------- .../manifolds/differentiable/vector_bundle.py | 2 +- 3 files changed, 29 insertions(+), 31 deletions(-) diff --git a/src/sage/manifolds/differentiable/bundle_connection.py b/src/sage/manifolds/differentiable/bundle_connection.py index 501b492760f..eaf60146e13 100644 --- a/src/sage/manifolds/differentiable/bundle_connection.py +++ b/src/sage/manifolds/differentiable/bundle_connection.py @@ -492,7 +492,7 @@ def add_connection_form(self, i, j, form, frame=None): OUTPUT: - - connection 1-form `\omega^i_j in the given frame, as an instance of + - connection 1-form `\omega^i_j` in the given frame, as an instance of the class :class:`~sage.manifolds.differentiable.diff_form.DiffForm`; if such connection 1-form did not exist previously, it is created. See method :meth:`connection_forms` for the storage convention of the @@ -671,7 +671,8 @@ def curvature_form(self, i, j, frame=None): .. MATH:: - \Omega^j_i = \mathrm{d} \omega^j_i + \sum^n_{k=1} \omega^j_k \wedge \omega^k_i + \Omega^j_i = \mathrm{d} \omega^j_i + \sum^n_{k=1} \omega^j_k + \wedge \omega^k_i INPUT: diff --git a/src/sage/manifolds/differentiable/char_class.py b/src/sage/manifolds/differentiable/char_class.py index d53a9dee7b6..0055c13cacc 100644 --- a/src/sage/manifolds/differentiable/char_class.py +++ b/src/sage/manifolds/differentiable/char_class.py @@ -4,8 +4,8 @@ Let `E \to M` be some topological vector bundle over a topological manifold `M` and `R` be any ring. A *characteristic class* `c(E)` is an element of the cohomology ring -`H^{*}(M, R)` such that for any continuous map `f: M \to N` the *naturality -condition* is satisfied: +`H^{*}(M, R)` such that for any continuous map `f: M \to N`, where `N` is +another topological manifold, the *naturality condition* is satisfied: .. MATH:: @@ -721,8 +721,24 @@ def get_form(self, connection, cmatrices=None): latex_name += "(" + self._vbundle._latex_name + ", " + \ connection._latex_name + ")" res = self._base_space.mixed_form(name=name, latex_name=latex_name) - # Set name of homogeneous components: - # + # Begin computation: + from sage.matrix.matrix_space import MatrixSpace + for frame, cmatrix in cmatrices.items(): + # Define matrix space: + dom = frame._domain + alg = dom.mixed_form_algebra() + mspace = MatrixSpace(alg, self._rank) + # Insert "normalized" curvature matrix into polynomial: + cmatrix = mspace(cmatrix) # convert curvature matrix + ncmatrix = self._normalize_matrix(cmatrix) + rmatrix = self._insert_in_polynomial(ncmatrix) + # Compute classes: + if self._class_type == 'additive': + rst = rmatrix.trace() # mixed form + elif self._class_type == 'multiplicative': + rst = rmatrix.det() # mixed form + elif self._class_type == 'Pfaffian': + rst = rmatrix.pfaffian() # mixed form # Only even (or in the real case, by four divisible) degrees are # non-zero: if self._class_type == 'Pfaffian': @@ -732,17 +748,17 @@ def get_form(self, connection, cmatrices=None): elif self._vbundle._field_type == 'complex': deg_dist = 2 else: - # You never know... + # You never know... deg_dist = 1 # Now, define the name for each form: for k in res.irange(): if k % deg_dist != 0 or (self._class_type == 'Pfaffian' and k == 0): - res[k].set_name(name="zero", latex_name="0") - res[k]._is_zero = True + res[k] = 0 # this form is zero anyway else: + # String representation: if self._name is not None: - name = self._name + "_" + str(k / deg_dist) + \ + name = self._name + "_" + str(k // deg_dist) + \ "(" + self._vbundle._name if connection._name is not None: name += ", " + connection._name @@ -750,32 +766,13 @@ def get_form(self, connection, cmatrices=None): # LaTeX name: if self._latex_name is not None: latex_name = self._latex_name + \ - r"_{" + str(k / deg_dist) + r"}" + \ + r"_{" + str(k // deg_dist) + r"}" + \ r"(" + self._vbundle._latex_name if connection._latex_name is not None: latex_name += r", " + connection._latex_name latex_name += r")" # Set name: res[k].set_name(name=name, latex_name=latex_name) - res[k]._is_zero = False # a priori - # Begin computation: - from sage.matrix.matrix_space import MatrixSpace - for frame, cmatrix in cmatrices.items(): - # Define matrix space: - dom = frame._domain - alg = dom.mixed_form_algebra() - mspace = MatrixSpace(alg, self._rank) - # Insert "normalized" curvature matrix into polynomial: - cmatrix = mspace(cmatrix) # convert curvature matrix - ncmatrix = self._normalize_matrix(cmatrix) - rmatrix = self._insert_in_polynomial(ncmatrix) - # Compute classes: - if self._class_type == 'additive': - rst = rmatrix.trace() # mixed form - elif self._class_type == 'multiplicative': - rst = rmatrix.det() # mixed form - elif self._class_type == 'Pfaffian': - rst = rmatrix.pfaffian() # mixed form # Set restriction: res.set_restriction(rst) diff --git a/src/sage/manifolds/differentiable/vector_bundle.py b/src/sage/manifolds/differentiable/vector_bundle.py index 13e4d84a301..94479477a6c 100644 --- a/src/sage/manifolds/differentiable/vector_bundle.py +++ b/src/sage/manifolds/differentiable/vector_bundle.py @@ -209,7 +209,7 @@ def characteristic_class(self, func, **kwargs): sage: M = Manifold(4, 'M', structure='Lorentzian', start_index=1) sage: X. = M.chart() - sage: g = M.metric('g') + sage: g = M.metric() sage: g[1,1] = -1 sage: g[2,2] = 1 sage: g[3,3] = 1 From 7fb28106871deb62854a988481af4b6d280b77fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 15 Nov 2019 09:54:48 +0100 Subject: [PATCH 148/340] cleanup of "space:" in combinat --- src/sage/combinat/affine_permutation.py | 34 +++++++++---------- .../combinat/binary_recurrence_sequences.py | 26 +++++++------- src/sage/combinat/binary_tree.py | 5 ++- src/sage/combinat/combinat.py | 2 +- src/sage/combinat/crystals/alcove_path.py | 16 ++++----- src/sage/combinat/degree_sequences.pyx | 16 ++++----- src/sage/combinat/designs/design_catalog.py | 2 +- src/sage/combinat/designs/latin_squares.py | 2 +- .../orthogonal_arrays_build_recursive.py | 2 +- .../designs/steiner_quadruple_systems.py | 12 +++---- src/sage/combinat/designs/twographs.py | 4 +-- src/sage/combinat/e_one_star.py | 8 ++--- src/sage/combinat/growth.py | 2 +- src/sage/combinat/interval_posets.py | 4 +-- src/sage/combinat/matrices/latin.py | 2 +- src/sage/combinat/parallelogram_polyomino.py | 10 +++--- src/sage/combinat/partition.py | 2 +- src/sage/combinat/permutation.py | 12 +++---- src/sage/combinat/sidon_sets.py | 33 +++++++++--------- src/sage/combinat/words/finite_word.py | 8 ++--- src/sage/combinat/words/morphism.py | 4 +-- src/sage/combinat/words/paths.py | 8 ++--- src/sage/combinat/words/word_generators.py | 10 +++--- src/sage/combinat/words/words.py | 4 +-- 24 files changed, 111 insertions(+), 117 deletions(-) diff --git a/src/sage/combinat/affine_permutation.py b/src/sage/combinat/affine_permutation.py index 16f4b7b3371..fdecf4e1a4b 100644 --- a/src/sage/combinat/affine_permutation.py +++ b/src/sage/combinat/affine_permutation.py @@ -570,7 +570,7 @@ def apply_simple_reflection_left(self, i): res = self[m] % (self.k + 1) if res == i: l.append(self[m] + 1) - elif res == 0 : + elif res == 0: l.append(self[m] - 1) else: l.append(self[m]) @@ -1541,42 +1541,42 @@ def apply_simple_reflection_left(self, i): raise ValueError('index not in index set') j = self.N - i l = [] - if i != self.k and i != 0: + if i and i != self.k: for m in range(self.k): - res=self[m]%self.N - if res==i : + res = self[m] % self.N + if res == i: l.append(self[m]+1) - elif res==i+1: + elif res == i+1: l.append(self[m]-1) - elif res==j: + elif res == j: l.append(self[m]-1) - elif res==j-1: + elif res == j-1: l.append(self[m]+1) else: l.append(self[m]) elif i == 0: for m in range(self.k): - res=self[m]%self.N - if res==1: + res = self[m] % self.N + if res == 1: l.append(self[m]-3) - elif res==self.N-2: + elif res == self.N-2: l.append(self[m]+3) - elif res==2: + elif res == 2: l.append(self[m]-3) - elif res==self.N-1: + elif res == self.N-1: l.append(self[m]+3) else: l.append(self[m]) elif i == self.k: for m in range(self.k): - res=self[m]%self.N - if res==self.k: + res = self[m] % self.N + if res == self.k: l.append(self[m]+2) - elif res==self.k+2: + elif res == self.k+2: l.append(self[m]-2) - elif res==self.k-1: + elif res == self.k-1: l.append(self[m]+2) - elif res==self.k+1: + elif res == self.k+1: l.append(self[m]-2) else: l.append(self[m]) diff --git a/src/sage/combinat/binary_recurrence_sequences.py b/src/sage/combinat/binary_recurrence_sequences.py index 7d7397df47c..347d07fef4c 100644 --- a/src/sage/combinat/binary_recurrence_sequences.py +++ b/src/sage/combinat/binary_recurrence_sequences.py @@ -464,14 +464,14 @@ def period(self, m): F = F**p #replace F by F^p as now we only need to determine the factor dividing (p-1) #otherwise it will divide (p+1)(p-1) - else : + else: M = (p+1)*(p-1) p2fac = list((p+1).factor()) #factor the (p+1) and (p-1) terms separately and then combine for speed Mfac_dic = {} for i in list(p1fac + p2fac): if i[0] not in Mfac_dic: Mfac_dic[i[0]] = i[1] - else : + else: Mfac_dic[i[0]] = Mfac_dic[i[0]] + i[1] Mfac = [(i,Mfac_dic[i]) for i in Mfac_dic] @@ -503,7 +503,7 @@ def period(self, m): FF = F**perp if FF*v == v: perpe = perp - else : + else: tries = 0 while True: tries += 1 @@ -595,21 +595,21 @@ def pthpowers(self, p, Bound): if self.is_geometric() or self.is_quasigeometric(): no_powers = True - for i in range(1,6*p+1): - if _is_p_power(self(i), p) : + for i in range(1, 6*p+1): + if _is_p_power(self(i), p): no_powers = False break if no_powers: if _is_p_power(self.u0,p): return [0] return [] - else : + else: raise ValueError("The degenerate binary recurrence sequence is geometric or quasigeometric and has many pth powers.") #If the sequence is degenerate without being geometric or quasigeometric, there #may be many ``p`` th powers or no ``p`` th powers. - elif (self.b**2+4*self.c) == 0 : + elif (self.b**2+4*self.c) == 0: #This is the case if the matrix F is not diagonalizable, ie b^2 +4c = 0, and alpha/beta = 1. @@ -653,7 +653,7 @@ def pthpowers(self, p, Bound): else: - if Bound < 3 * p : + if Bound < 3 * p: powers = [] ell = p + 1 @@ -668,14 +668,14 @@ def pthpowers(self, p, Bound): for n in range(Bound): # n is the index of the a0 #Check whether a0 is a perfect power mod ell - if _is_p_power_mod(a0, p, ell) : + if _is_p_power_mod(a0, p, ell): #if a0 is a perfect power mod ell, check if nth term is ppower if _is_p_power(self(n), p): powers.append(n) a0, a1 = a1, bf*a1 + cf*a0 #step up the variables - else : + else: powers = [] #documents the indices of the sequence that provably correspond to pth powers cong = [0] #list of necessary congruences on the index for it to correspond to pth powers @@ -733,7 +733,7 @@ def pthpowers(self, p, Bound): M2 = lcm(M2,p*qq) break - else : + else: qq = next_prime_power(qq) M2 = lcm(M2,p*qq) cong = list(cong) @@ -743,7 +743,7 @@ def pthpowers(self, p, Bound): for i in cong: if i in Possible_count: Possible_count[i] = Possible_count[i] + 1 - else : + else: Possible_count[i] = 1 #Check how long each element has persisted, if it is for at least 7 cycles, @@ -952,7 +952,7 @@ def _next_good_prime(p, R, qq, patience, qqold): else: if N in R._PGoodness: R._PGoodness[N].append(R._ell) - else : + else: R._PGoodness[N] = [R._ell] return False diff --git a/src/sage/combinat/binary_tree.py b/src/sage/combinat/binary_tree.py index ba1b36f862e..07e9ec1a28d 100644 --- a/src/sage/combinat/binary_tree.py +++ b/src/sage/combinat/binary_tree.py @@ -2674,10 +2674,9 @@ def twisting_number(self): composing it. A left (resp. right) branch is maximal if it is not included in a strictly longer left (resp. right) branch. + OUTPUT: - OUTPUT : - - A list of two integers. + A list of two integers EXAMPLES:: diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index e235b9670c0..7e7411a69f7 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -1584,7 +1584,7 @@ def __iterator_from_next(self): except (TypeError, ValueError): break - if f is None or f is False : + if f is None or f is False: break else: yield f diff --git a/src/sage/combinat/crystals/alcove_path.py b/src/sage/combinat/crystals/alcove_path.py index 9e5237b3e7a..77b4a6f7113 100644 --- a/src/sage/combinat/crystals/alcove_path.py +++ b/src/sage/combinat/crystals/alcove_path.py @@ -445,7 +445,7 @@ def vertices(self): l.append((temp,x[1]+[j])) if lst2 == []: break - else : + else: lst = lst2 return [ [] ] + [i[1] for i in l] @@ -898,16 +898,14 @@ def e(self, i): J = list(self.value) positions, gi = self._gi(i) - m=max(gi) - m_index = len(gi)-1-list(reversed(gi)).index(m) # last max in gi - + m = max(gi) + m_index = len(gi)-1-list(reversed(gi)).index(m) # last max in gi - if finite_cartan_type and i==0 : + if finite_cartan_type and i == 0: M = Integer(m)/2 + Integer(1)/2 else: M = Integer(m)/2 - Integer(1)/2 - KR_test = finite_cartan_type and i==0 and m_index < len(gi) - 1 KR_test = KR_test and M >= 1 @@ -1023,18 +1021,16 @@ def f(self, i): J = list(self.value) positions, gi = self._gi(i) - m=max(gi) + m = max(gi) m_index=gi.index(m) - - if finite_cartan_type and i==0 : + if finite_cartan_type and i == 0: # python doesn't handle fractions natively M = Integer(m)/2 + Integer(1)/2 else: M = Integer(m)/2 - Integer(1)/2 - # boolean determining when to move a folding in KR case KR_test = finite_cartan_type and i == 0 KR_test = KR_test and M > 1 diff --git a/src/sage/combinat/degree_sequences.pyx b/src/sage/combinat/degree_sequences.pyx index 1e87e3ae0c3..76fbe1bc5a5 100644 --- a/src/sage/combinat/degree_sequences.pyx +++ b/src/sage/combinat/degree_sequences.pyx @@ -7,7 +7,7 @@ represent the integer sequences of length `n`:: sage: DegreeSequences(6) Degree sequences on 6 elements -With the object ``DegreeSequences(n)``, one can : +With the object ``DegreeSequences(n)``, one can: * Check whether a sequence is indeed a degree sequence :: @@ -64,13 +64,13 @@ degree sequence if and only if* `\sum_i d_i` is even and `\forall i` .. MATH:: \sum_{j\leq i}d_j \leq j(j-1) + \sum_{j>i}\min(d_j,i) -Alternatively, a degree sequence can be defined recursively : +Alternatively, a degree sequence can be defined recursively: **Havel and Hakimi:** *The sequence of integers* `d_1\geq ... \geq d_n` *is a degree sequence if and only if* `d_2-1,...,d_{d_1+1}-1, d_{d_1+2}, ...,d_n` *is also a degree sequence.* -Or equivalently : +Or equivalently: **Havel and Hakimi (bis):** *If there is a realization of an integer sequence as a graph (i.e. if the sequence is a degree sequence), then it can be realized in @@ -94,7 +94,7 @@ a current degree sequence on `n` elements into a degree sequence on `n+1` elements by adding a vertex of degree larger than those already present in the sequence. This can be seen as **reversing** the reduction operation described in Havel and Hakimi's characterization. This operation can appear in several -different ways : +different ways: * Extensions of a degree sequence that do **not** change the value of the maximum element @@ -123,7 +123,7 @@ different ways : 3, 2, 2, 2, 1 \xrightarrow{Extension} {\bf 3}, 3, (2+1), (2+1), (2+1), 1 = {\bf 3}, 3, 3, 3, 3, 1 \xrightarrow{Reduction} 3, 2, 2, 2, 1 * Extension of a degree sequence that changes the value of the maximum - element : + element: * In the general case, i.e. when the number of elements of value `\Delta,\Delta-1` is small compared to `\Delta` (i.e. the maximum @@ -338,7 +338,7 @@ class DegreeSequences: return False # Is the sum even ? - if sum(seq)%2 == 1: + if sum(seq) % 2: return False # Partial represents the left side of Erdos and Gallai's inequality, @@ -511,7 +511,7 @@ cdef void enum(int k, int M): seq[current_box] = 0 continue - # The degree of the new vertex will be taken + i + j where : + # The degree of the new vertex will be taken + i + j where: # # * i is the number of vertices taken in the *current* box # * j the number of vertices taken in the *previous* one @@ -519,7 +519,7 @@ cdef void enum(int k, int M): n_current_box = seq[current_box] n_previous_box = seq[current_box-1] - # Note to self, and others : + # Note to self, and others: # # In the following lines, there are many incrementation/decrementation # that *may* be replaced by only +1 and -1 and save some diff --git a/src/sage/combinat/designs/design_catalog.py b/src/sage/combinat/designs/design_catalog.py index 579e3e901ac..9ff77953bac 100644 --- a/src/sage/combinat/designs/design_catalog.py +++ b/src/sage/combinat/designs/design_catalog.py @@ -30,7 +30,7 @@ **Design constructors** -This module gathers the following designs : +This module gathers the following designs: .. csv-table:: :class: contentstable diff --git a/src/sage/combinat/designs/latin_squares.py b/src/sage/combinat/designs/latin_squares.py index d94f4ba6c9d..0926824cbf1 100644 --- a/src/sage/combinat/designs/latin_squares.py +++ b/src/sage/combinat/designs/latin_squares.py @@ -221,7 +221,7 @@ def mutually_orthogonal_latin_squares(k, n, partitions=False, check=True): - ``n`` (integer) -- size of the latin square. - ``partitions`` (boolean) -- a Latin Square can be seen as 3 partitions of - the `n^2` cells of the array into `n` sets of size `n`, respectively : + the `n^2` cells of the array into `n` sets of size `n`, respectively: * The partition of rows * The partition of columns diff --git a/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py b/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py index 6f63c4055c2..b6c16ceb5e6 100644 --- a/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py +++ b/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py @@ -50,7 +50,7 @@ def construction_3_3(k,n,m,i,explain_construction=False): INPUT: - - ``k,n,m,i`` (integers) such that the following designs are available : + - ``k,n,m,i`` (integers) such that the following designs are available: `OA(k,n)`, `OA(k,m)`, `OA(k,m+1)`, `OA(k,r)`. - ``explain_construction`` (boolean) -- return a string describing diff --git a/src/sage/combinat/designs/steiner_quadruple_systems.py b/src/sage/combinat/designs/steiner_quadruple_systems.py index d321e98859a..083d0ccfba0 100644 --- a/src/sage/combinat/designs/steiner_quadruple_systems.py +++ b/src/sage/combinat/designs/steiner_quadruple_systems.py @@ -29,7 +29,7 @@ Index ----- -This module's main function is the following : +This module's main function is the following: .. csv-table:: :class: contentstable @@ -38,7 +38,7 @@ | :func:`steiner_quadruple_system` | Return a Steiner Quadruple System on `n` points -This function redistributes its work among 6 constructions : +This function redistributes its work among 6 constructions: .. csv-table:: :class: contentstable @@ -723,7 +723,7 @@ def steiner_quadruple_system(n, check = False): sqs = IncidenceStructure(14, _SQS14(), copy = False, check = False) elif n == 38: sqs = IncidenceStructure(38, _SQS38(), copy = False, check = False) - elif n%12 in [4,8]: + elif n%12 in [4, 8]: nn = n // 2 sqs = two_n(steiner_quadruple_system(nn, check = False)) elif n%18 in [4,10]: @@ -732,13 +732,13 @@ def steiner_quadruple_system(n, check = False): elif (n%36) == 34: nn = (n+8) // 3 sqs = three_n_minus_eight(steiner_quadruple_system(nn, check = False)) - elif (n%36) == 26 : + elif (n%36) == 26: nn = (n+4) // 3 sqs = three_n_minus_four(steiner_quadruple_system(nn, check = False)) - elif n%24 in [2,10]: + elif n%24 in [2, 10]: nn = (n+6) // 4 sqs = four_n_minus_six(steiner_quadruple_system(nn, check = False)) - elif n%72 in [14,38]: + elif n%72 in [14, 38]: nn = (n+10) // 12 sqs = twelve_n_minus_ten(steiner_quadruple_system(nn, check = False)) else: diff --git a/src/sage/combinat/designs/twographs.py b/src/sage/combinat/designs/twographs.py index e065f01e031..2de7c09fb80 100644 --- a/src/sage/combinat/designs/twographs.py +++ b/src/sage/combinat/designs/twographs.py @@ -30,7 +30,7 @@ Index ----- -This module's methods are the following : +This module's methods are the following: .. csv-table:: :class: contentstable @@ -41,7 +41,7 @@ :meth:`~TwoGraph.complement` | returns the complement of ``self`` :meth:`~TwoGraph.descendant` | returns the descendant graph at `w` -This module's functions are the following : +This module's functions are the following: .. csv-table:: :class: contentstable diff --git a/src/sage/combinat/e_one_star.py b/src/sage/combinat/e_one_star.py index b3a1d344f49..a32cc13ddac 100644 --- a/src/sage/combinat/e_one_star.py +++ b/src/sage/combinat/e_one_star.py @@ -1000,7 +1000,7 @@ def repaint(self, cmap='Set1'): INPUT: - ``cmap`` - color map (default: ``'Set1'``). It can be one of the - following : + following: - string -- A coloring map. For available coloring map names type: ``sorted(colormaps)`` @@ -1502,9 +1502,9 @@ def __call__(self, patch, iterations=1): def __mul__(self, other): r""" - Return the product of self and other. + Return the product of ``self`` and ``other``. - The product satisfies the following rule : + The product satisfies the following rule: `E_1^*(\sigma\circ\sigma') = E_1^*(\sigma')` \circ E_1^*(\sigma)` INPUT: @@ -1513,7 +1513,7 @@ def __mul__(self, other): OUTPUT: - an instance of E1Star + an instance of E1Star EXAMPLES:: diff --git a/src/sage/combinat/growth.py b/src/sage/combinat/growth.py index 00ac832894f..d8d6c92c9b5 100644 --- a/src/sage/combinat/growth.py +++ b/src/sage/combinat/growth.py @@ -502,7 +502,7 @@ class GrowthDiagram(SageObject): a pair of digraphs `P, Q` (multiple edges being allowed) on the same set of vertices `V`, that satisfy the following conditions: - * the graphs are graded, that is, there is a function `\rho : + * the graphs are graded, that is, there is a function `\rho: V \to \NN`, such that for any edge `(v, w)` of `P` and also of `Q` we have `\rho(w) = \rho(v) + 1`, diff --git a/src/sage/combinat/interval_posets.py b/src/sage/combinat/interval_posets.py index 6b87f0e127e..de37d92a461 100644 --- a/src/sage/combinat/interval_posets.py +++ b/src/sage/combinat/interval_posets.py @@ -28,7 +28,7 @@ # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ # **************************************************************************** from __future__ import print_function from six.moves import range @@ -2077,7 +2077,7 @@ def lower_contained_intervals(self): size = self._size yield self r""" - we try to add links recursively in this order : + we try to add links recursively in this order: 1 -> 2 2 -> 3 1 -> 3 diff --git a/src/sage/combinat/matrices/latin.py b/src/sage/combinat/matrices/latin.py index 353b2431a28..7386fc2cc63 100644 --- a/src/sage/combinat/matrices/latin.py +++ b/src/sage/combinat/matrices/latin.py @@ -1463,7 +1463,7 @@ def isotopism(p): INPUT: - According to the type of input (see examples below) : + According to the type of input (see examples below): - an integer `n` -- the function returns the identity on `1,...,n`. diff --git a/src/sage/combinat/parallelogram_polyomino.py b/src/sage/combinat/parallelogram_polyomino.py index 4190563221f..47d23799100 100644 --- a/src/sage/combinat/parallelogram_polyomino.py +++ b/src/sage/combinat/parallelogram_polyomino.py @@ -527,21 +527,21 @@ def _dispatch(self, obj, dispatch_to, option, *get_values, **set_values): This global option contains all the data needed by the Parallelogram classes to draw, display in ASCII, compile in latex a parallelogram polyomino. -The available options are : +The available options are: - tikz_options : this option configurate all the information useful to generate TIKZ code. For example, color, line size, etc ... - drawing_components : this option is used to explain to the system which component of the drawing you want to draw. For example, - you can ask to draw some elements of the following list : + you can ask to draw some elements of the following list: - the diagram, - the tree inside the parallelogram polyomino, - the bounce paths inside the parallelogram polyomino, - the value of the bounce on each square of a bounce path. - display : this option is used to configurate the ASCII display. - The available options are : + The available options are: - list : (this is the default value) is used to represent PP as a list containing the upper and lower path. - drawing : this value is used to explain we want to display an array with @@ -1479,7 +1479,7 @@ def make_tree(b_tree, d): This is a technical function that converts binary tree to ordered tree with the following construction. - Add a virtual root v such that the root become : + Add a virtual root v such that the root become: - the left son of v if ``d`` is equal to 0; @@ -1488,7 +1488,7 @@ def make_tree(b_tree, d): Then now the vertices of the ordered tree are the vertices of the binary tree and the virtual root. - The edges are defined as follow : + The edges are defined as follow: - if v1 is a left (resp. right) son of v2 and v2 is a right (resp. left) son of v3, then, in the ordered tree, v2 is the father of v1; diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index d22e8bc92b4..e6f3b365dbd 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -1146,7 +1146,7 @@ def __next__(self): t = m - h + 1 next_p[h-1] = r - while t >= r : + while t >= r: h += 1 next_p[h-1] = r t -= r diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py index b79a94a3421..3d5437699dc 100644 --- a/src/sage/combinat/permutation.py +++ b/src/sage/combinat/permutation.py @@ -3921,9 +3921,9 @@ def right_permutohedron_interval_iterator(self, other): sage: Permutation([2, 1, 4, 5, 3]).right_permutohedron_interval(Permutation([2, 5, 4, 1, 3])) # indirect doctest [[2, 4, 5, 1, 3], [2, 4, 1, 5, 3], [2, 1, 4, 5, 3], [2, 1, 5, 4, 3], [2, 5, 1, 4, 3], [2, 5, 4, 1, 3]] """ - if len(self) != len(other) : + if len(self) != len(other): raise ValueError("len({}) and len({}) must be equal".format(self, other)) - if not self.permutohedron_lequal(other) : + if not self.permutohedron_lequal(other): raise ValueError("{} must be lower or equal than {} for the right permutohedron order".format(self, other)) d = DiGraph() d.add_vertices(range(1, len(self) + 1)) @@ -4985,12 +4985,12 @@ def shifted_concatenation(self, other, side = "right"): sage: Permutation([2, 4, 1, 3]).shifted_concatenation(Permutation([3, 1, 2]), "left") [7, 5, 6, 2, 4, 1, 3] """ - if side == "right" : + if side == "right": return Permutations()(list(self) + [a + len(self) for a in other]) - elif side == "left" : + elif side == "left": return Permutations()([a + len(self) for a in other] + list(self)) - else : - raise ValueError("%s must be \"left\" or \"right\"" %(side)) + else: + raise ValueError("%s must be \"left\" or \"right\"" % side) def shifted_shuffle(self, other): r""" diff --git a/src/sage/combinat/sidon_sets.py b/src/sage/combinat/sidon_sets.py index 2545f8497f4..dda3cd07d76 100644 --- a/src/sage/combinat/sidon_sets.py +++ b/src/sage/combinat/sidon_sets.py @@ -5,12 +5,12 @@ - Martin Raum (07-25-2011) """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2011 Martin Raum # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.sets.set import Set from sage.misc.all import cached_function from sage.rings.all import Integer @@ -96,19 +96,18 @@ def sidon_sets(N, g = 1): ... ValueError: g must be a positive integer """ - if not isinstance(N, (int, Integer)) or N < 1 : + if not isinstance(N, (int, Integer)) or N < 1: raise ValueError( "N must be a positive integer" ) - elif not isinstance(g, (int, Integer)) or g < 1 : + elif not isinstance(g, (int, Integer)) or g < 1: raise ValueError( "g must be a positive integer" ) - - return sidon_sets_rec(N, g = g) + return sidon_sets_rec(N, g=g) # This recursive and cached slave function is mainly here because # caching the user entry function 'sidon_sets' prevents it from # appearing in the built documentation. @cached_function -def sidon_sets_rec(N, g = 1): +def sidon_sets_rec(N, g=1): r""" Return the set of all Sidon-`g` sets that have elements less than or equal to `N` without checking the arguments. This internal function should not @@ -120,29 +119,29 @@ def sidon_sets_rec(N, g = 1): sage: sorted(sidon_sets_rec(3,2), key=str) [{1, 2, 3}, {1, 2}, {1, 3}, {1}, {2, 3}, {2}, {3}, {}] """ - if N == 1 : + if N == 1: return Set([Set([]), Set([1])]) pre_sidons = sidon_sets(N - 1, g) sidons = set(pre_sidons) - for psid in pre_sidons : + for psid in pre_sidons: psid_shift = Set([n - 1 for n in psid if n != 1] + [N - 1]) - if not psid_shift in pre_sidons : + if not psid_shift in pre_sidons: continue - if not 1 in psid : + if not 1 in psid: add_sid = True - else : + else: add_sid = True Np1_count = 0 - for n in psid : + for n in psid: if N + 1 - n in psid and 2 * n <= N + 1: Np1_count += 1 - if Np1_count >= g : + if Np1_count >= g: add_sid = False break - if add_sid : - sidons.add(Set(psid.list()+[N])) + if add_sid: + sidons.add(Set(psid.list() + [N])) return Set(sidons) diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index 8990788ea1a..a3bdb3d4339 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -2683,7 +2683,7 @@ def palindromic_lacunas_study(self, f=None): if pal in palindromes: lacunas.append(i) - else : + else: palindromes.add(pal) return lengths_lps, lacunas, palindromes @@ -2943,7 +2943,7 @@ def lengths_maximal_palindromes(self, f=None): sage: Word('abbabaab').lengths_maximal_palindromes(f) [0, 0, 2, 0, 0, 0, 2, 0, 8, 0, 2, 0, 0, 0, 2, 0, 0] """ - if f is not None : + if f is not None: from sage.combinat.words.morphism import WordMorphism if not isinstance(f, WordMorphism): f = WordMorphism(f) @@ -4299,7 +4299,7 @@ def _pos_in(self, other, p): while s <= lm - lf: for j in range(lf-1, -1, -1): a = other[s+j] - if self[j] != a : + if self[j] != a: s += max(suff[j + 1], j - occ.get(a,-1)) break else: @@ -4888,7 +4888,7 @@ def evaluation_partition(self): else: return Partition(p) - def overlap_partition(self, other, delay=0, p=None, involution=None) : + def overlap_partition(self, other, delay=0, p=None, involution=None): r""" Return the partition of the alphabet induced by the overlap of ``self`` and ``other`` with the given ``delay``. diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index 20f9b8ab110..43e808f001a 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -1582,7 +1582,7 @@ def is_primitive(self): ALGORITHM: - Exercices 8.7.8, p.281 in [1] : + Exercices 8.7.8, p.281 in [1]: (c) Let `y(M)` be the least integer `e` such that `M^e` has all positive entries. Prove that, for all primitive matrices `M`, we have `y(M) \leq (d-1)^2 + 1`. @@ -2785,7 +2785,7 @@ def rauzy_fractal_plot(self, n=None, exchange=False, eig=None, translate=None, p of the points of the fractal. - ``colormap`` - color map or dictionary (default: ``'hsv'``). - It can be one of the following : + It can be one of the following: - ``string`` - a coloring map. For available coloring map names type: ``sorted(colormaps)`` diff --git a/src/sage/combinat/words/paths.py b/src/sage/combinat/words/paths.py index 551eb6f3b26..24104313086 100644 --- a/src/sage/combinat/words/paths.py +++ b/src/sage/combinat/words/paths.py @@ -231,16 +231,16 @@ def WordPaths(alphabet, steps=None): - ``None``: In this case, the type of steps are guessed from the length of alphabet. - - 'square_grid' or 'square' : (default when size of alphabet is 4) + - 'square_grid' or 'square': (default when size of alphabet is 4) The order is : East, North, West, South. - 'triangle_grid' or 'triangle': - - 'hexagonal_grid' or 'hexagon' :(default when size of alphabet is 6) + - 'hexagonal_grid' or 'hexagon': (default when size of alphabet is 6) - - 'cube_grid' or 'cube' : + - 'cube_grid' or 'cube': - - 'north_east', 'ne' or 'NE' : (the default when size of alphabet is 2) + - 'north_east', 'ne' or 'NE': (the default when size of alphabet is 2) - 'dyck': diff --git a/src/sage/combinat/words/word_generators.py b/src/sage/combinat/words/word_generators.py index c651708a12b..7af41ef2305 100644 --- a/src/sage/combinat/words/word_generators.py +++ b/src/sage/combinat/words/word_generators.py @@ -8,7 +8,7 @@ - Sebastien Labbe (2008-12-17): merged into sage - Arnaud Bergeron (2008-12-17): merged into sage - Amy Glen (2008-12-17): merged into sage -- Sebastien Labbe (2009-12-19): Added S-adic words (:trac:`7543`) +- Sébastien Labbé (2009-12-19): Added S-adic words (:trac:`7543`) USE: @@ -41,7 +41,7 @@ sage: t = words.ThueMorseWord(); t word: 0110100110010110100101100110100110010110... """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 Franco Saliola , # Sebastien Labbe , # Arnaud Bergeron , @@ -51,8 +51,8 @@ # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import print_function from six.moves import range @@ -738,7 +738,7 @@ def CharacteristicSturmianWord(self, slope, alphabet=(0, 1), bits=None): INPUT: - - ``slope`` - the slope of the word. It can be one of the following : + - ``slope`` - the slope of the word. It can be one of the following: - real number in `]0, 1[` diff --git a/src/sage/combinat/words/words.py b/src/sage/combinat/words/words.py index e0c6c32efe0..47327fab0cf 100644 --- a/src/sage/combinat/words/words.py +++ b/src/sage/combinat/words/words.py @@ -1032,7 +1032,7 @@ def iter_morphisms(self, arg=None, codomain=None, min_length=1): INPUT: - - ``arg`` - (optional, default: None) It can be one of the following : + - ``arg`` - (optional, default: ``None``) It can be one of the following: - ``None`` - then the method iterates through all morphisms. @@ -1045,7 +1045,7 @@ def iter_morphisms(self, arg=None, codomain=None, min_length=1): ``arg`` determines the length of the word mapped to by the i-th letter of the (ordered) alphabet. - - ``codomain`` - (default: None) a combinatorial class of words. + - ``codomain`` - (default: ``None``) a combinatorial class of words. By default, ``codomain`` is ``self``. - ``min_length`` - (default: 1) nonnegative integer. If ``arg`` is From 0d4f2d83f3c532a49dd7279bb3e4472507f9a9ec Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Thu, 20 Jun 2019 00:28:02 +0200 Subject: [PATCH 149/340] 28705: fix conversion of Booleans in interfaces This fixes conversion from Sage to interfaces that do not represent Booleans as 0 and 1, such as gap, giac, fricas, lisp, macaulay2, mathematica, maxima, r. For interfaces using the Pynac symbol table, this also fixes conversion from the interface back to Sage. --- src/sage/interfaces/giac.py | 7 +++++++ src/sage/interfaces/interface.py | 12 +++++++++++- src/sage/interfaces/maxima_abstract.py | 7 +++++++ src/sage/interfaces/r.py | 14 ++++++++++++++ src/sage/symbolic/constants.py | 3 +++ 5 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/sage/interfaces/giac.py b/src/sage/interfaces/giac.py index 1311d486094..ec3012ec736 100644 --- a/src/sage/interfaces/giac.py +++ b/src/sage/interfaces/giac.py @@ -1077,6 +1077,13 @@ def _sage_(self, locals={}): list[ln(2)/(ln(2)-ln(3))] sage: L.sage() [-log(2)/(log(3) - log(2))] + + TESTS: + + Check conversion of Booleans (:trac:`28705`):: + + sage: giac('true')._sage_(), giac('false')._sage_() + (True, False) """ from sage.libs.pynac.pynac import symbol_table from sage.calculus.calculus import symbolic_expression_from_string diff --git a/src/sage/interfaces/interface.py b/src/sage/interfaces/interface.py index 768245f6bc3..147a140c610 100644 --- a/src/sage/interfaces/interface.py +++ b/src/sage/interfaces/interface.py @@ -268,6 +268,14 @@ def __call__(self, x, name=None): sage: a = gp(2); gp(a) is a True + TESTS: + + Check conversion of Booleans (:trac:`28705`):: + + sage: giac(True) + true + sage: maxima(True) + true """ cls = self._object_class() @@ -325,7 +333,9 @@ def _coerce_from_special_method(self, x): return self(x._interface_init_()) def _coerce_impl(self, x, use_special=True): - if isinstance(x, integer_types): + if isinstance(x, bool): + return self(self._true_symbol() if x else self._false_symbol()) + elif isinstance(x, integer_types): import sage.rings.all return self(sage.rings.all.Integer(x)) elif isinstance(x, float): diff --git a/src/sage/interfaces/maxima_abstract.py b/src/sage/interfaces/maxima_abstract.py index 4282536270b..ce5ab11721e 100644 --- a/src/sage/interfaces/maxima_abstract.py +++ b/src/sage/interfaces/maxima_abstract.py @@ -1226,12 +1226,19 @@ def _sage_(self): [ 1 y y^2] [ 1 1/2 1/4] + TESTS: + Check if :trac:`7661` is fixed:: sage: var('delta') delta sage: (2*delta).simplify() 2*delta + + Check conversion of Booleans (:trac:`28705`):: + + sage: maxima('true')._sage_(), maxima('false')._sage_() + (True, False) """ import sage.calculus.calculus as calculus return calculus.symbolic_expression_from_maxima_string(self.name(), diff --git a/src/sage/interfaces/r.py b/src/sage/interfaces/r.py index ad4f3bfd8a3..6b65afaac66 100644 --- a/src/sage/interfaces/r.py +++ b/src/sage/interfaces/r.py @@ -537,7 +537,21 @@ def _lazy_init(self): self._r_to_sage_converter = _setup_r_to_sage_converter() self._start() + def _coerce_impl(self, x, use_special=True): + """ + TESTS: + + Check conversion of Booleans (:trac:`28705`):: + sage: repr(r(True)) == r._true_symbol() # indirect doctest + True + """ + # We overwrite _coerce_impl here because r._true_symbol() and + # r._false_symbol() are output strings that start with "[1] " and thus + # cannot be used as input + if isinstance(x, bool): + return self('TRUE' if x else 'FALSE') + return super(R, self)._coerce_impl(x, use_special=use_special) def set_seed(self, seed=None): """ diff --git a/src/sage/symbolic/constants.py b/src/sage/symbolic/constants.py index 044ea8efc86..78e4a5a7283 100644 --- a/src/sage/symbolic/constants.py +++ b/src/sage/symbolic/constants.py @@ -233,6 +233,9 @@ register_symbol(minus_infinity, {'maxima':'minf'}) register_symbol(unsigned_infinity, {'maxima':'infinity'}) register_symbol(I, {'mathematica':'I'}) +register_symbol(True, {'giac':'true', 'mathematica':'True', 'maxima':'true'}) +register_symbol(False, {'giac':'false', 'mathematica':'False', + 'maxima':'false'}) def unpickle_Constant(class_name, name, conversions, latex, mathml, domain): From 08d341d584f8193146221d7e93247c3a27cad53b Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Sun, 30 Jun 2019 14:08:12 +0200 Subject: [PATCH 150/340] 28705: rename bool() to __bool__() in interfaces This makes the parent method `bool()` in InterfaceElement a wrapper for `__bool__()`. --- src/sage/interfaces/gap.py | 3 ++- src/sage/interfaces/gp.py | 4 +++- src/sage/interfaces/interface.py | 26 ++++++++++++++------------ src/sage/interfaces/lisp.py | 4 +++- src/sage/interfaces/maxima_abstract.py | 8 +++++--- src/sage/interfaces/polymake.py | 8 +++++--- 6 files changed, 32 insertions(+), 21 deletions(-) diff --git a/src/sage/interfaces/gap.py b/src/sage/interfaces/gap.py index bc06ecbc452..a0237b11f18 100644 --- a/src/sage/interfaces/gap.py +++ b/src/sage/interfaces/gap.py @@ -1018,7 +1018,7 @@ def _add_(self, other): # the MRO. return self._operation("+", other) - def bool(self): + def __bool__(self): """ EXAMPLES:: @@ -1032,6 +1032,7 @@ def bool(self): P = self._check_valid() return self != P(0) and repr(self) != 'false' + __nonzero__ = __bool__ def __len__(self): """ diff --git a/src/sage/interfaces/gp.py b/src/sage/interfaces/gp.py index 9e61fb7d059..304a2d418e3 100644 --- a/src/sage/interfaces/gp.py +++ b/src/sage/interfaces/gp.py @@ -956,7 +956,7 @@ def __float__(self): """ return float(pari(str(self))) - def bool(self): + def __bool__(self): """ EXAMPLES:: @@ -970,6 +970,8 @@ def bool(self): P = self._check_valid() return P.eval('%s != 0'%(self.name())) == '1' + __nonzero__ = __bool__ + def _complex_mpfr_field_(self, CC): """ Return ComplexField element of self. diff --git a/src/sage/interfaces/interface.py b/src/sage/interfaces/interface.py index 147a140c610..a133c347483 100644 --- a/src/sage/interfaces/interface.py +++ b/src/sage/interfaces/interface.py @@ -1280,13 +1280,7 @@ def __int__(self): def bool(self): """ - Return whether this element is equal to ``True``. - - NOTE: - - This method needs to be overridden if the subprocess would - not return a string representation of a boolean value unless - an explicit print command is used. + Convert this element to a boolean. EXAMPLES:: @@ -1296,13 +1290,18 @@ def bool(self): True """ - P = self._check_valid() - t = P._true_symbol() - cmd = '%s %s %s'%(self._name, P._equality_symbol(), t) - return P.eval(cmd) == t + return bool(self) def __bool__(self): """ + Return whether this element is equal to ``True``. + + .. NOTE:: + + This method needs to be overridden if the subprocess would + not return a string representation of a boolean value unless + an explicit print command is used. + EXAMPLES:: sage: bool(maxima(0)) @@ -1310,7 +1309,10 @@ def __bool__(self): sage: bool(maxima(1)) True """ - return self.bool() + P = self._check_valid() + t = P._true_symbol() + cmd = '%s %s %s'%(self._name, P._equality_symbol(), t) + return P.eval(cmd) == t __nonzero__ = __bool__ diff --git a/src/sage/interfaces/lisp.py b/src/sage/interfaces/lisp.py index 267d8299c1f..160cd29743c 100644 --- a/src/sage/interfaces/lisp.py +++ b/src/sage/interfaces/lisp.py @@ -417,7 +417,7 @@ def _cmp_(self, other): else: return 1 - def bool(self): + def __bool__(self): """ EXAMPLES:: @@ -430,6 +430,8 @@ def bool(self): """ return self != 0 + __nonzero__ = __bool__ + def _add_(self, right): """ EXAMPLES:: diff --git a/src/sage/interfaces/maxima_abstract.py b/src/sage/interfaces/maxima_abstract.py index ce5ab11721e..a16a7f1053f 100644 --- a/src/sage/interfaces/maxima_abstract.py +++ b/src/sage/interfaces/maxima_abstract.py @@ -1119,7 +1119,7 @@ def __str__(self): """ return self.display2d(onscreen=False) - def bool(self): + def __bool__(self): """ Convert ``self`` into a boolean. @@ -1129,14 +1129,16 @@ def bool(self): EXAMPLES:: - sage: maxima(0).bool() + sage: bool(maxima(0)) False - sage: maxima(1).bool() + sage: bool(maxima(1)) True """ P = self._check_valid() return P.eval('is(%s = 0);'%self.name()) == P._false_symbol() # but be careful, since for relations things like is(equal(a,b)) are what Maxima needs + __nonzero__ = __bool__ + def _richcmp_(self, other, op): """ Compare this Maxima object with ``other``. diff --git a/src/sage/interfaces/polymake.py b/src/sage/interfaces/polymake.py index 4539987caa2..11bdd5cfeff 100644 --- a/src/sage/interfaces/polymake.py +++ b/src/sage/interfaces/polymake.py @@ -1018,16 +1018,16 @@ def _cmp_(self, other): return 1 return -2 # that's supposed to be an error value. - def bool(self): + def __bool__(self): """ Return whether this polymake element is equal to ``True``. EXAMPLES:: sage: from sage.interfaces.polymake import polymake - sage: polymake(0).bool() # optional polymake + sage: bool(polymake(0)) # optional polymake False - sage: polymake(1).bool() # optional polymake + sage: bool(polymake(1)) # optional polymake True """ @@ -1036,6 +1036,8 @@ def bool(self): cmd = '{} {} {};'.format(self._name, P._equality_symbol(), t) return P.get(cmd) == t + __nonzero__ = __bool__ + def known_properties(self): """ List the names of properties that have been computed so far on this element. From 80796ad1eedda06a89570a920f212e7f6e7a878c Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Sun, 23 Jun 2019 13:01:02 +0200 Subject: [PATCH 151/340] 28705: improve default results of InterfaceElement.__bool__ --- src/sage/interfaces/interface.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/sage/interfaces/interface.py b/src/sage/interfaces/interface.py index a133c347483..5ced772cee6 100644 --- a/src/sage/interfaces/interface.py +++ b/src/sage/interfaces/interface.py @@ -1294,7 +1294,7 @@ def bool(self): def __bool__(self): """ - Return whether this element is equal to ``True``. + Return whether this element is not ``False``. .. NOTE:: @@ -1308,11 +1308,19 @@ def __bool__(self): False sage: bool(maxima(1)) True + + TESTS: + + By default this returns ``True`` for elements that are considered to be + not ``False`` by the interface (:trac:`28705`):: + + sage: bool(giac('"a"')) + True """ P = self._check_valid() - t = P._true_symbol() - cmd = '%s %s %s'%(self._name, P._equality_symbol(), t) - return P.eval(cmd) == t + cmd = '%s %s %s' % (self._name, P._equality_symbol(), + P._false_symbol()) + return P.eval(cmd) != P._true_symbol() __nonzero__ = __bool__ From 5e08e351089a468d0223a7c0b43b7f0694e44f1c Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Sun, 23 Jun 2019 13:04:45 +0200 Subject: [PATCH 152/340] 28705: fix __bool__ for Lisp and Maxima elements --- src/sage/interfaces/lisp.py | 6 +++++- src/sage/interfaces/maxima_abstract.py | 9 ++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/sage/interfaces/lisp.py b/src/sage/interfaces/lisp.py index 160cd29743c..5fa799702b6 100644 --- a/src/sage/interfaces/lisp.py +++ b/src/sage/interfaces/lisp.py @@ -427,8 +427,12 @@ def __bool__(self): False sage: bool(lisp(2)) True + sage: bool(lisp('T')) + True + sage: bool(lisp('NIL')) + False """ - return self != 0 + return self != 0 and repr(self) != 'NIL' __nonzero__ = __bool__ diff --git a/src/sage/interfaces/maxima_abstract.py b/src/sage/interfaces/maxima_abstract.py index a16a7f1053f..bb23d7dbebd 100644 --- a/src/sage/interfaces/maxima_abstract.py +++ b/src/sage/interfaces/maxima_abstract.py @@ -1133,9 +1133,16 @@ def __bool__(self): False sage: bool(maxima(1)) True + sage: bool(maxima('false')) + False + sage: bool(maxima('true')) + True """ P = self._check_valid() - return P.eval('is(%s = 0);'%self.name()) == P._false_symbol() # but be careful, since for relations things like is(equal(a,b)) are what Maxima needs + return (P.eval('is({0} = 0 or {0} = false);'.format(self.name())) + != P._true_symbol()) + # but be careful, since for relations things like is(equal(a,b)) are + # what Maxima needs __nonzero__ = __bool__ From 51cf3100317dfefe715c41191bee5c12d2b2a2e9 Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Sun, 23 Jun 2019 13:23:48 +0200 Subject: [PATCH 153/340] 28705: fix __bool__ for Macaulay2 elements --- src/sage/interfaces/macaulay2.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/sage/interfaces/macaulay2.py b/src/sage/interfaces/macaulay2.py index 7149fc3e468..5364024587e 100644 --- a/src/sage/interfaces/macaulay2.py +++ b/src/sage/interfaces/macaulay2.py @@ -1076,6 +1076,8 @@ def __mod__(self, x): def __bool__(self): """ + Return whether this Macaulay2 element is not ``False`` or not ``0``. + EXAMPLES:: sage: a = macaulay2(0) # optional - macaulay2 @@ -1083,9 +1085,22 @@ def __bool__(self): True sage: bool(a) # optional - macaulay2 False + + TESTS: + + Check that :trac:`28705` is fixed:: + + sage: t = macaulay2(True); t # optional - macaulay2 + true + sage: bool(t) # optional - macaulay2 + True + sage: bool(macaulay2('false')) # optional - macaulay2 + False + sage: bool(macaulay2('"a"')) # optional - macaulay2 + True """ P = self.parent() - return P.eval('%s == 0'%self.name()) == 'false' + return P.eval('{0}===false or {0}==0'.format(self._name)) != 'true' __nonzero__ = __bool__ From 7665bc0a93bca53d5ee644e485a8870f6ee25ac7 Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Sat, 22 Jun 2019 20:08:16 +0200 Subject: [PATCH 154/340] 28705: implement __bool__ for Mathematica elements Note that _true_symbol() and _false_symbol() should not contain whitespace, as the amount of whitespace in the output of `mathematica.eval('True')` is unreliable as it depends on the length of the output prompt counter. --- src/sage/interfaces/mathematica.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/sage/interfaces/mathematica.py b/src/sage/interfaces/mathematica.py index 10f5b69fcea..f67d955a45e 100644 --- a/src/sage/interfaces/mathematica.py +++ b/src/sage/interfaces/mathematica.py @@ -609,10 +609,10 @@ def chdir(self, dir): self.eval('SetDirectory["%s"]'%dir) def _true_symbol(self): - return ' True' + return 'True' def _false_symbol(self): - return ' False' + return 'False' def _equality_symbol(self): return '==' @@ -977,6 +977,28 @@ def _cmp_(self, other): return -1 # everything is supposed to be comparable in Python, so we define # the comparison thus when no comparable in interfaced system. + def __bool__(self): + """ + Return whether this Mathematica element is not identical to ``False``. + + EXAMPLES:: + + sage: bool(mathematica(True)) # optional - mathematica + True + sage: bool(mathematica(False)) # optional - mathematica + False + + In Mathematica, `0` cannot be used to express falsity:: + + sage: bool(mathematica(0)) # optional - mathematica + True + """ + P = self._check_valid() + cmd = '%s===%s' % (self._name, P._false_symbol()) + return P.eval(cmd).strip() != P._true_symbol() + + __nonzero__ = __bool__ + def N(self, precision=None): r""" Numerical approximation by calling Mathematica's `N[]` From 310cf9a302e28500c77f3cb0a2b23f440c43a155 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Fri, 15 Nov 2019 22:43:52 +0100 Subject: [PATCH 155/340] Trac #27784: set_restriction placed wrong --- src/sage/manifolds/differentiable/char_class.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/sage/manifolds/differentiable/char_class.py b/src/sage/manifolds/differentiable/char_class.py index 0055c13cacc..6d41652717c 100644 --- a/src/sage/manifolds/differentiable/char_class.py +++ b/src/sage/manifolds/differentiable/char_class.py @@ -721,7 +721,7 @@ def get_form(self, connection, cmatrices=None): latex_name += "(" + self._vbundle._latex_name + ", " + \ connection._latex_name + ")" res = self._base_space.mixed_form(name=name, latex_name=latex_name) - # Begin computation: + # BEGIN computation: from sage.matrix.matrix_space import MatrixSpace for frame, cmatrix in cmatrices.items(): # Define matrix space: @@ -739,8 +739,12 @@ def get_form(self, connection, cmatrices=None): rst = rmatrix.det() # mixed form elif self._class_type == 'Pfaffian': rst = rmatrix.pfaffian() # mixed form - # Only even (or in the real case, by four divisible) degrees are - # non-zero: + # Set restriction: + res.set_restriction(rst) + # END of computation + # + # Preparation to name each homogeneous component; only even (or in + # the real case, by four divisible) degrees are non-zero: if self._class_type == 'Pfaffian': deg_dist = self._rank elif self._vbundle._field_type == 'real': @@ -773,9 +777,7 @@ def get_form(self, connection, cmatrices=None): latex_name += r")" # Set name: res[k].set_name(name=name, latex_name=latex_name) - # Set restriction: - res.set_restriction(rst) - + # Add the result to the dictionary: self._mixed_forms[connection] = res return self._mixed_forms[connection] From 3fa8d85ed4e6a27388fcbe629e0dcea8017dbf47 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Sat, 16 Nov 2019 15:07:34 +0100 Subject: [PATCH 156/340] Trac 27784: Tab character removed --- src/doc/en/reference/references/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index ae850e4d6b6..7c7248358a6 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -4398,7 +4398,7 @@ REFERENCES: University Press, Princeton, 1970. .. [Roe1988] John Roe, *Elliptic operators, topology and asymptotic methods*. - 2nd edition. CRC Press, 1988. + 2nd edition. CRC Press, 1988. .. [Rog2018] Baptiste Rognerud, *Exceptional and modern intervals of the Tamari lattice*. From 4ece2a74fc48633e3a3d4fde0483f4f2a4f8c091 Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Sat, 16 Nov 2019 18:17:04 +0100 Subject: [PATCH 157/340] 28744: py3: add bytes_to_str in octave interface --- src/sage/interfaces/octave.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/interfaces/octave.py b/src/sage/interfaces/octave.py index 2c9723be9e7..d71a155f85c 100644 --- a/src/sage/interfaces/octave.py +++ b/src/sage/interfaces/octave.py @@ -147,6 +147,7 @@ import pexpect from sage.misc.misc import verbose from sage.docs.instancedoc import instancedoc +from sage.cpython.string import bytes_to_str class Octave(Expect): @@ -297,7 +298,7 @@ def _eval_line(self, line, reformat=True, allow_use_file=False, verbose("in = '%s'"%line,level=3) E.sendline(line) E.expect(self._prompt) - out = E.before + out = bytes_to_str(E.before) # debug verbose("out = '%s'"%out,level=3) except EOF: From 8bf0128209ae13f3127b8fbcbd5e939532f834bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 16 Nov 2019 19:36:49 +0100 Subject: [PATCH 158/340] further "space:" cleanup outside of combinat --- src/sage/categories/algebra_functor.py | 2 +- src/sage/categories/enumerated_sets.py | 2 +- src/sage/categories/group_algebras.py | 2 +- src/sage/coding/channel.py | 19 +++++++------ src/sage/coding/grs_code.py | 12 ++++---- src/sage/crypto/mq/rijndael_gf.py | 6 ++-- src/sage/data_structures/binary_matrix.pxi | 2 +- src/sage/groups/braid.py | 2 +- src/sage/groups/perm_gps/permgroup.py | 10 +++---- src/sage/interfaces/genus2reduction.py | 2 +- src/sage/interfaces/maxima_lib.py | 13 ++++----- src/sage/interfaces/r.py | 6 ++-- src/sage/libs/singular/function.pyx | 2 +- src/sage/libs/singular/singular.pyx | 8 +++--- src/sage/modular/btquotients/btquotient.py | 6 ++-- src/sage/modular/pollack_stevens/modsym.py | 15 +++++----- src/sage/parallel/map_reduce.py | 2 +- src/sage/parallel/parallelism.py | 8 +++--- src/sage/plot/hyperbolic_regular_polygon.py | 8 +++--- src/sage/sat/converters/polybori.py | 13 ++++----- .../elliptic_curves/ell_curve_isogeny.py | 4 +-- .../schemes/elliptic_curves/ell_local_data.py | 10 ++++--- .../schemes/elliptic_curves/padic_lseries.py | 28 +++++++++---------- src/sage/sets/disjoint_set.pyx | 10 +++---- src/sage/symbolic/expression.pyx | 8 +++--- src/sage/tensor/modules/comp.py | 24 ++++++++-------- src/sage/tensor/modules/free_module_tensor.py | 2 +- 27 files changed, 113 insertions(+), 113 deletions(-) diff --git a/src/sage/categories/algebra_functor.py b/src/sage/categories/algebra_functor.py index 4df5b39e1b0..26b9532e99f 100644 --- a/src/sage/categories/algebra_functor.py +++ b/src/sage/categories/algebra_functor.py @@ -584,7 +584,7 @@ def _apply_functor(self, base_ring): r""" Create the group algebra with given base ring over ``self.group()``. - INPUT : + INPUT: - ``base_ring`` -- the base ring of the group algebra diff --git a/src/sage/categories/enumerated_sets.py b/src/sage/categories/enumerated_sets.py index 9d5a9611ac7..2846d05cef6 100644 --- a/src/sage/categories/enumerated_sets.py +++ b/src/sage/categories/enumerated_sets.py @@ -744,7 +744,7 @@ def _iterator_from_next(self): except (TypeError, ValueError ): break - if f is None or f is False : + if f is None or f is False: break else: yield f diff --git a/src/sage/categories/group_algebras.py b/src/sage/categories/group_algebras.py index 95da9110b54..40a539179bd 100644 --- a/src/sage/categories/group_algebras.py +++ b/src/sage/categories/group_algebras.py @@ -143,7 +143,7 @@ def __init_extra__(self): ## some matrix groups assume that coercion is only valid to ## other matrix groups. This is a workaround ## call _element_constructor_ to coerce group elements - #try : + #try: self._populate_coercion_lists_(coerce_list=[self.group()]) def _latex_(self): diff --git a/src/sage/coding/channel.py b/src/sage/coding/channel.py index 257ef74ee1c..d4605319d24 100644 --- a/src/sage/coding/channel.py +++ b/src/sage/coding/channel.py @@ -37,15 +37,15 @@ specific number of erasures in each transmitted message """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 David Lucas # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from six.moves import range from sage.structure.sage_object import SageObject @@ -59,6 +59,7 @@ from sage.functions.other import binomial from copy import copy + def random_error_vector(n, F, error_positions): r""" Return a vector of length ``n`` over ``F`` filled with random non-zero coefficients @@ -98,7 +99,7 @@ def random_error_vector(n, F, error_positions): def format_interval(t): r""" - Returns a formatted string representation of ``t``. + Return a formatted string representation of ``t``. This method should be called by any representation function in Channel classes. @@ -193,7 +194,7 @@ def __init__(self, input_space, output_space): def transmit(self, message): r""" - Returns ``message``, modified accordingly with the algorithm of the channel it was + Return ``message``, modified accordingly with the algorithm of the channel it was transmitted through. Checks if ``message`` belongs to the input space, and returns an exception if not. @@ -238,7 +239,7 @@ def transmit(self, message): """ if message in self.input_space(): return self.transmit_unsafe(message) - else : + else: raise TypeError("Message must be an element of the input space for the given channel") #Alias for transmit method @@ -246,7 +247,7 @@ def transmit(self, message): def input_space(self): r""" - Returns the input space of ``self``. + Return the input space of ``self``. EXAMPLES:: @@ -260,7 +261,7 @@ def input_space(self): def output_space(self): r""" - Returns the output space of ``self``. + Return the output space of ``self``. EXAMPLES:: @@ -351,7 +352,7 @@ def __init__(self, space, number_errors): def _repr_(self): r""" - Returns a string representation of ``self``. + Return a string representation of ``self``. EXAMPLES:: diff --git a/src/sage/coding/grs_code.py b/src/sage/coding/grs_code.py index f53f31b1520..a8d9dc504df 100644 --- a/src/sage/coding/grs_code.py +++ b/src/sage/coding/grs_code.py @@ -38,15 +38,15 @@ using the key equation on syndrome polynomials """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 David Lucas # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import absolute_import from six.moves import range @@ -1242,9 +1242,9 @@ def _decode_to_code_and_message(self, r): t = (C.minimum_distance()-1) // 2 l0 = n-1-t l1 = n-1-t-(k-1) - S = matrix(C.base_field(), n, l0+l1+2, lambda i,j : - (C.evaluation_points()[i])**j if j<(l0+1) - else r_list[i]*(C.evaluation_points()[i])**(j-(l0+1))) + S = matrix(C.base_field(), n, l0+l1+2, + lambda i, j: (C.evaluation_points()[i])**j if j<(l0+1) + else r_list[i]*(C.evaluation_points()[i])**(j-(l0+1))) S = S.right_kernel() S = S.basis_matrix().row(0) R = C.base_field()['x'] diff --git a/src/sage/crypto/mq/rijndael_gf.py b/src/sage/crypto/mq/rijndael_gf.py index f6be8840faa..e1aaa1d94e1 100644 --- a/src/sage/crypto/mq/rijndael_gf.py +++ b/src/sage/crypto/mq/rijndael_gf.py @@ -516,10 +516,10 @@ def __init__(self, Nb, Nk, state_chr='a', key_chr='k'): self._all_PR = PolynomialRing(self._F, len(state_names + subkey_names), state_names + subkey_names) self.state_vrs = matrix(4, self._Nb, self._state_PR.gens()) - self.subkey_vrs_list = list(self._all_PR.gens()[4 * self._Nb:]) + fNb = 4 * self._Nb + self.subkey_vrs_list = list(self._all_PR.gens()[fNb:]) self.subkey_vrs = [matrix(4, self._Nb, - self.subkey_vrs_list[(4 * self._Nb)*i : - (4 * self._Nb)*(i+1)]) + self.subkey_vrs_list[fNb * i: fNb * (i + 1)]) for i in range(self._Nr)] self.key_vrs = column_matrix([ self.subkey_vrs[int(i / self._Nb)].column(i % 4) diff --git a/src/sage/data_structures/binary_matrix.pxi b/src/sage/data_structures/binary_matrix.pxi index 5f9437c2a63..d184c4fe770 100644 --- a/src/sage/data_structures/binary_matrix.pxi +++ b/src/sage/data_structures/binary_matrix.pxi @@ -5,7 +5,7 @@ It's almost a copy of the bitset datatype, but allows a differentiation of the rows of the matrix. That's the only advantage compared to storing all the rows of a matrix in a loooooonng bitset. -A ``binary_matrix_t`` structure contains : +A ``binary_matrix_t`` structure contains: - ``Py_ssize_t n_cols`` -- number of columns diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index 59ebc8558e5..c7a87c68cd4 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -310,7 +310,7 @@ def burau_matrix(self, var='t', reduced=False): A[-j-1, -j-1] = -t**(-1) if -j > 1: A[-j-1, -j-2] = 1 - if -j < n-1 : + if -j < n - 1: A[-j-1, -j] = t**(-1) M = M * A diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index ee1d92e3918..4bcfb5384ba 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -128,13 +128,13 @@ generators. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 William Stein # David Joyner # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import absolute_import from six.moves import range from six import integer_types @@ -3541,7 +3541,7 @@ def blocks_all(self, representatives = True): This method returns a description of *all* block systems. Hence, the output is a "list of lists of lists" or a "list of lists" depending on - the value of ``representatives``. A bit more clearly, output is : + the value of ``representatives``. A bit more clearly, output is: * A list of length (#number of different block systems) of @@ -4504,7 +4504,7 @@ def molien_series(self): 1/(x^2 - 2*x + 1) """ pi = self._libgap_().NaturalCharacter() - # because NaturalCharacter forgets about fixed points : + # because NaturalCharacter forgets about fixed points: pi += self._libgap_().TrivialCharacter() * len(self.fixed_points()) # TODO: pi is a Character from a CharacterTable on self, however libgap diff --git a/src/sage/interfaces/genus2reduction.py b/src/sage/interfaces/genus2reduction.py index 10fe535efa9..8682f2bb5d1 100644 --- a/src/sage/interfaces/genus2reduction.py +++ b/src/sage/interfaces/genus2reduction.py @@ -54,7 +54,7 @@ class is R, then the following is the meaning of The first line contains information about the stable reduction after field extension. Here are the meanings of the symbols of - stable reduction : + stable reduction: (I) The stable reduction is smooth (i.e. the curve has potentially good reduction). diff --git a/src/sage/interfaces/maxima_lib.py b/src/sage/interfaces/maxima_lib.py index 2548197dbcc..7053f351680 100644 --- a/src/sage/interfaces/maxima_lib.py +++ b/src/sage/interfaces/maxima_lib.py @@ -70,7 +70,7 @@ """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein # # Distributed under the terms of the GNU General Public License (GPL) @@ -82,10 +82,9 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** -from __future__ import print_function -from __future__ import absolute_import +# https://www.gnu.org/licenses/ +# **************************************************************************** +from __future__ import print_function, absolute_import from six import string_types from sage.symbolic.ring import SR @@ -1443,8 +1442,8 @@ def dummy_integrate(expr): sage: dummy_integrate(f.ecl()) integrate(f(x), x, 0, 10) """ - args=[max_to_sr(a) for a in cdr(expr)] - if len(args) == 4 : + args = [max_to_sr(a) for a in cdr(expr)] + if len(args) == 4: return sage.symbolic.integration.integral.definite_integral(*args, hold=True) else: diff --git a/src/sage/interfaces/r.py b/src/sage/interfaces/r.py index ad4f3bfd8a3..e269fe472e6 100644 --- a/src/sage/interfaces/r.py +++ b/src/sage/interfaces/r.py @@ -213,11 +213,11 @@ notebook analogous to the %r escape in command line or %r cell in a Sage notebook. -The interface is loaded by a cell containing the sole code : +The interface is loaded by a cell containing the sole code: "%load_ext rpy2.ipython" -After execution of this code, the %R and %%R magics are available : +After execution of this code, the %R and %%R magics are available: - %R allows the execution of a single line of R code. Data exchange is possible via the -i and -o options. Do "%R?" in a standalone cell @@ -227,7 +227,7 @@ similar options (do "%%R?" in a standalone cell for documentation). -A few important points must be noted : +A few important points must be noted: - The R interpreter launched by this interface IS (currently) DIFFERENT from the R interpreter used br other r... functions. diff --git a/src/sage/libs/singular/function.pyx b/src/sage/libs/singular/function.pyx index 7c17bd116fb..b649ab1e649 100644 --- a/src/sage/libs/singular/function.pyx +++ b/src/sage/libs/singular/function.pyx @@ -592,7 +592,7 @@ cdef class Converter(SageObject): if attributes and a in attributes: for attrib in attributes[a]: - if attrib == "isSB" : + if attrib == "isSB": val = (attributes[a][attrib]) atSet(v, omStrDup("isSB"), val, INT_CMD) setFlag(v, FLAG_STD) diff --git a/src/sage/libs/singular/singular.pyx b/src/sage/libs/singular/singular.pyx index 51251d31578..89d3c509456 100644 --- a/src/sage/libs/singular/singular.pyx +++ b/src/sage/libs/singular/singular.pyx @@ -6,15 +6,15 @@ AUTHOR: - Martin Albrecht """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005, 2006 William Stein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -############################################################################### +# https://www.gnu.org/licenses/ +# **************************************************************************** include "sage/libs/ntl/decl.pxi" @@ -507,7 +507,7 @@ cdef number *sa2si_NF(object elem, ring *_ring): cdef char *_name # the result of nlInit2gmp() is in a plain polynomial ring over QQ (not an extension ring!), - # so we hace to get/create one : + # so we have to get/create one: # # todo: reuse qqr/ get an existing Singular polynomial ring over Q. _name = omStrDup("a") diff --git a/src/sage/modular/btquotients/btquotient.py b/src/sage/modular/btquotients/btquotient.py index 1eeeb828097..410ad5f8b24 100644 --- a/src/sage/modular/btquotients/btquotient.py +++ b/src/sage/modular/btquotients/btquotient.py @@ -233,7 +233,7 @@ def __ne__(self, other): def sign(self): r""" - The direction of the edge. + Return the direction of the edge. The Bruhat-Tits quotients are directed graphs but we only store half the edges (we treat them more like unordered graphs). @@ -241,9 +241,9 @@ def sign(self): representative in the quotient (sign = +1), or to the opposite of one of the representatives (sign = -1). - OUTPUT : + OUTPUT: - an int that is +1 or -1 according to the sign of self + an int that is +1 or -1 according to the sign of ``self`` EXAMPLES:: diff --git a/src/sage/modular/pollack_stevens/modsym.py b/src/sage/modular/pollack_stevens/modsym.py index 677cd1fe346..e4d92f7f33a 100644 --- a/src/sage/modular/pollack_stevens/modsym.py +++ b/src/sage/modular/pollack_stevens/modsym.py @@ -28,16 +28,15 @@ [(-1, 0, 0), (1, 0, 0), (-9, -6, -4)] """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Robert Pollack # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#****************************************************************************** -from __future__ import print_function -from __future__ import absolute_import +# https://www.gnu.org/licenses/ +# ***************************************************************************** +from __future__ import print_function, absolute_import import operator from sage.structure.element import ModuleElement from sage.structure.richcmp import op_EQ, op_NE @@ -1386,16 +1385,16 @@ def _find_extraprec(self, p, M, alpha, check): 1) The denominators in the Hecke eigenvalue 2) the denominators appearing when solving the difference equation, - 3) those denominators who might be also present in self. + 3) those denominators who might be also present in ``self``. - INPUT : + INPUT: - ``p`` -- working prime - ``M`` -- precision - ``alpha`` -- the Up-eigenvalue - ``check`` -- whether to check that ``self`` is a `T_q` eigensymbol - OUTPUT : + OUTPUT: A tuple (newM, eisenloss, q, aq), where ``newM`` is the new precision, `q` is a prime different from `p`, and ``aq`` is the eigenvalue of `T_q` of the eigensymbol. diff --git a/src/sage/parallel/map_reduce.py b/src/sage/parallel/map_reduce.py index 0fb6091cbdf..7e377dddde0 100644 --- a/src/sage/parallel/map_reduce.py +++ b/src/sage/parallel/map_reduce.py @@ -19,7 +19,7 @@ * Apply any map/reduce kind of operation over the elements of `S` -AUTHORS : +AUTHORS: - Florent Hivert -- code, documentation (2012--2016) diff --git a/src/sage/parallel/parallelism.py b/src/sage/parallel/parallelism.py index 60489827d25..ad2dba4fbc0 100644 --- a/src/sage/parallel/parallelism.py +++ b/src/sage/parallel/parallelism.py @@ -14,14 +14,14 @@ """ -#****************************************************************************** +# ***************************************************************************** # Copyright (C) 2015 Marco Mancini # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#****************************************************************************** +# https://www.gnu.org/licenses/ +# ***************************************************************************** from __future__ import absolute_import from sage.structure.sage_object import SageObject @@ -237,7 +237,7 @@ def set(self, field=None, nproc=None): for fi in self._nproc: self.set(field=fi, nproc=nproc) else: - if field not in self._nproc : + if field not in self._nproc: raise KeyError("entry for field {} is not ".format(field) + "implemented in Parallelism") if nproc is None: diff --git a/src/sage/plot/hyperbolic_regular_polygon.py b/src/sage/plot/hyperbolic_regular_polygon.py index 132ab661a72..8b43028ffd6 100644 --- a/src/sage/plot/hyperbolic_regular_polygon.py +++ b/src/sage/plot/hyperbolic_regular_polygon.py @@ -109,13 +109,13 @@ def __init__(self, sides, i_angle, center, options): Hyperbolic regular polygon (sides=5, i_angle=1/2*pi, center=1.00000000000000*I) """ self.center = CC(center) - if self.center.imag() <= 0 : + if self.center.imag() <= 0: raise ValueError("center: %s is not a valid point in the upper half plane model of the hyperbolic plane"%(self.center)) - if sides < 3 : + if sides < 3: raise ValueError("degenerated polygons (sides<=2) are not supported") - if i_angle <=0 or i_angle >= pi: + if i_angle <= 0 or i_angle >= pi: raise ValueError("interior angle %s must be in (0, pi) interval"%(i_angle)) - if pi*(sides-2) - sides*i_angle <= 0 : + if pi*(sides-2) - sides*i_angle <= 0: raise ValueError("there exists no hyperbolic regular compact polygon, for sides=%s the interior angle must be less than %s"%(sides, pi * (sides-2) / sides)) self.sides = sides self.i_angle = i_angle diff --git a/src/sage/sat/converters/polybori.py b/src/sage/sat/converters/polybori.py index e75133d1bc2..f3516d545a2 100644 --- a/src/sage/sat/converters/polybori.py +++ b/src/sage/sat/converters/polybori.py @@ -414,12 +414,11 @@ def permutations(length, equal_zero): INPUT: - - ``length`` - the number of variables - - ``equal_zero`` - should the sum be equal to zero? + - ``length`` -- the number of variables + - ``equal_zero`` -- should the sum be equal to zero? EXAMPLES:: - sage: from sage.sat.converters.polybori import CNFEncoder sage: from sage.sat.solvers.dimacs import DIMACS sage: B. = BooleanPolynomialRing() @@ -431,13 +430,13 @@ def permutations(length, equal_zero): [[1, -1, -1], [-1, 1, -1], [-1, -1, 1], [1, 1, 1]] """ E = [] - for num_negated in range(0, length+1) : - if (((num_negated % 2) ^ ((length+1) % 2)) == equal_zero) : + for num_negated in range(length + 1): + if (((num_negated % 2) ^ ((length + 1) % 2)) == equal_zero): continue start = [] - for i in range(num_negated) : + for i in range(num_negated): start.append(1) - for i in range(length - num_negated) : + for i in range(length - num_negated): start.append(-1) E.extend(Permutations(start)) return E diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index 4102504064f..d404e0a76ba 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -144,7 +144,7 @@ def isogeny_determine_algorithm(E, kernel): """ kernel_is_list = isinstance(kernel, list) - if not kernel_is_list and kernel in E : + if not kernel_is_list and kernel in E: kernel = [kernel] kernel_is_list = True @@ -980,7 +980,7 @@ def __init__(self, E, kernel, codomain=None, degree=None, model=None, check=True if not is_EllipticCurve(E): raise ValueError("E parameter must be an EllipticCurve.") - if not isinstance(kernel, list) and kernel in E : + if not isinstance(kernel, list) and kernel in E: # a single point was given, we put it in a list # the first condition assures that [1,1] is treated as x+1 kernel = [kernel] diff --git a/src/sage/schemes/elliptic_curves/ell_local_data.py b/src/sage/schemes/elliptic_curves/ell_local_data.py index f875753f2b7..82f2938c28a 100644 --- a/src/sage/schemes/elliptic_curves/ell_local_data.py +++ b/src/sage/schemes/elliptic_curves/ell_local_data.py @@ -727,13 +727,15 @@ def _tate(self, proof = None, globally = False): else: principal_flag = False - if (K is QQ) or principal_flag : + if (K is QQ) or principal_flag: pi = P.gens_reduced()[0] - verbose("P is principal, generator pi = %s"%pi, t, 1) + verbose("P is principal, generator pi = %s" % pi, t, 1) else: pi = K.uniformizer(P, 'positive') - verbose("uniformizer pi = %s"%pi, t, 1) - pi2 = pi*pi; pi3 = pi*pi2; pi4 = pi*pi3 + verbose("uniformizer pi = %s" % pi, t, 1) + pi2 = pi * pi + pi3 = pi * pi2 + pi4 = pi * pi3 pi_neg = None prime = pi if K is QQ else P diff --git a/src/sage/schemes/elliptic_curves/padic_lseries.py b/src/sage/schemes/elliptic_curves/padic_lseries.py index a3494c4f3fb..adefa408f6f 100644 --- a/src/sage/schemes/elliptic_curves/padic_lseries.py +++ b/src/sage/schemes/elliptic_curves/padic_lseries.py @@ -176,9 +176,9 @@ def __init__(self, E, p, implementation = 'eclib', normalize='L_ratio'): if E.conductor() % (self._p)**2 == 0: raise NotImplementedError("p (=%s) must be a prime of semi-stable reduction" % p) - try : + try: E.label() - except RuntimeError : + except RuntimeError: print("Warning : Curve outside Cremona's table. Computations of modular symbol space might take very long !") self._modular_symbol = E.modular_symbol(sign=+1, @@ -306,8 +306,8 @@ def modular_symbol(self, r, sign=+1, quadratic_twist=+1): sage: lpt.modular_symbol(0) == lp.modular_symbol(0,quadratic_twist=-4) / eta True """ - if quadratic_twist == +1 : - if sign == +1 : + if quadratic_twist == +1: + if sign == +1: return self._modular_symbol(r) elif sign == -1: try: @@ -317,7 +317,7 @@ def modular_symbol(self, r, sign=+1, quadratic_twist=+1): self.__add_negative_space() m = self._negative_modular_symbol return m(r) - else : + else: D = quadratic_twist if sign == -1: raise NotImplementedError("Quadratic twists for negative modular symbols are not yet implemented.") @@ -413,10 +413,10 @@ def measure(self, a, n, prec, quadratic_twist=+1, sign = +1): alpha = self.alpha(prec=prec) z = 1/(alpha**n) w = p**(n-1) - if s == +1 : + if s == +1: f = self._modular_symbol - else : - try : + else: + try: f = self._negative_modular_symbol except (KeyError, AttributeError): if not hasattr(self, '_modular_symbol_negative'): @@ -862,9 +862,9 @@ def series(self, n=2, quadratic_twist=+1, prec=5, eta=0): raise ValueError("quadratic_twist (=%s) must be a fundamental discriminant of a quadratic field"%D) if gcd(D,self._p) != 1: raise ValueError("quadratic twist (=%s) must be coprime to p (=%s) "%(D,self._p)) - if gcd(D,self._E.conductor())!= 1: + if gcd(D, self._E.conductor()) != 1: for ell in prime_divisors(D): - if valuation(self._E.conductor(),ell) > valuation(D,ell) : + if valuation(self._E.conductor(), ell) > valuation(D, ell): raise ValueError("can not twist a curve of conductor (=%s) by the quadratic twist (=%s)."%(self._E.conductor(),D)) p = self._p @@ -1135,14 +1135,14 @@ def series(self, n=3, quadratic_twist=+1, prec=5, eta=0): else: if not D.is_squarefree() or D % 4 != 1: raise ValueError("quadratic_twist (=%s) must be a fundamental discriminant of a quadratic field" % D) - if gcd(D,self._E.conductor()) != 1: + if gcd(D, self._E.conductor()) != 1: for ell in prime_divisors(D): - if valuation(self._E.conductor(), ell) > valuation(D,ell) : + if valuation(self._E.conductor(), ell) > valuation(D, ell): raise ValueError("can not twist a curve of conductor (=%s) by the quadratic twist (=%s)." % (self._E.conductor(), D)) p = self._p eta = ZZ(eta) % (p - 1) - #if p == 2 and self._normalize : + #if p == 2 and self._normalize: #print('Warning : for p = 2 the normalization might not be correct !') if prec == 1: @@ -1480,7 +1480,7 @@ def __phi_bpr(self, prec=0): # this is the equation eq[0]*x+eq[1]*y+eq[2] == 0 # such that delta_ = delta + d^dpr*x ... eq = [(p**dpr*cs[k]) % p**k,(-p**dga*ds[k]) % p**k , (delta*cs[k]-gamma*ds[k]-cs[k-1]) % p**k ] - verbose("valuations : %s"%([x.valuation(p) for x in eq])) + verbose("valuations : %s" % ([x.valuation(p) for x in eq])) v = min([x.valuation(p) for x in eq]) if v == infinity: verbose("no new information at step k=%s"%k) diff --git a/src/sage/sets/disjoint_set.pyx b/src/sage/sets/disjoint_set.pyx index aef30cbb3ba..c3f04b80ccc 100644 --- a/src/sage/sets/disjoint_set.pyx +++ b/src/sage/sets/disjoint_set.pyx @@ -48,15 +48,15 @@ Disjoint set of hashables objects:: 'a' """ -#***************************************************************************** -# Copyright (C) 2009 Sebastien Labbe +# **************************************************************************** +# Copyright (C) 2009 Sébastien Labbé # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.rings.integer import Integer from sage.structure.sage_object cimport SageObject @@ -662,7 +662,7 @@ cdef class DisjointSet_of_hashables(DisjointSet_class): def __reduce__(self): r""" - Return a tuple of three elements : + Return a tuple of three elements: - The function :func:`DisjointSet` - Arguments for the function :func:`DisjointSet` diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index acb1b2a25b3..fd74ced40b1 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -141,7 +141,7 @@ Test if :trac:`24883` is fixed:: 1/4*((I + 1)*sqrt(2) - 2)*(-(I + 1)*sqrt(2) - 2) """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 William Stein # Copyright (C) 2008 Burcin Erocal # @@ -149,8 +149,8 @@ Test if :trac:`24883` is fixed:: # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.signals cimport sig_on, sig_off from sage.ext.cplusplus cimport ccrepr, ccreadstr @@ -10960,7 +10960,7 @@ cdef class Expression(CommutativeRingElement): Distribute some indexed operators over similar operators in order to allow further groupings or simplifications. - Implemented cases (so far) : + Implemented cases (so far): - Symbolic sum of a sum ==> sum of symbolic sums diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 8d56230d79f..3693a429d32 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -237,7 +237,7 @@ """ -#****************************************************************************** +# ***************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # Copyright (C) 2015 Michal Bejger # Copyright (C) 2015 Marco Mancini @@ -245,8 +245,8 @@ # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#****************************************************************************** +# https://www.gnu.org/licenses/ +# ***************************************************************************** from six.moves import range from sage.structure.sage_object import SageObject @@ -1560,7 +1560,7 @@ def __add__(self, other): # only to add other: result = self.copy() nproc = Parallelism().get('tensor') - if nproc != 1 : + if nproc != 1: # Parallel computation lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ind for ind in other._comp] @@ -1793,7 +1793,7 @@ def __mul__(self, other): # result: nproc = Parallelism().get('tensor') - if nproc != 1 : + if nproc != 1: # Parallel computation lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ind for ind in result.non_redundant_index_generator()] @@ -1824,7 +1824,7 @@ def paral_mul(a, local_list_ind): result = Components(self._ring, self._frame, self._nid + other._nid, self._sindex, self._output_formatter) nproc = Parallelism().get('tensor') - if nproc != 1 : + if nproc != 1: # Parallel computation lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ind for ind in self._comp] @@ -2334,7 +2334,7 @@ def make_Contraction(this,other,local_list,rev_s,rev_o,shift_o,contractions,comp return local_res for ii, val in make_Contraction(listParalInput): - for jj in val : + for jj in val: res[[jj[0]]] = jj[1] else: # sequential @@ -3454,7 +3454,7 @@ def __add__(self, other): # The symmetries/antisymmetries are identical: result = self.copy() nproc = Parallelism().get('tensor') - if nproc != 1 : + if nproc != 1: # Parallel computation lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] @@ -3509,7 +3509,7 @@ def paral_sum(a, b, local_list_ind): result = Components(self._ring, self._frame, self._nid, self._sindex, self._output_formatter) nproc = Parallelism().get('tensor') - if nproc != 1 : + if nproc != 1: # Parallel computation lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ind for ind in result.non_redundant_index_generator()] @@ -3615,7 +3615,7 @@ def __mul__(self, other): result = CompWithSym(self._ring, self._frame, self._nid + other._nid, self._sindex, self._output_formatter, sym, antisym) nproc = Parallelism().get('tensor') - if nproc != 1 : + if nproc != 1: # Parallel computation lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ind for ind in self._comp] @@ -4955,7 +4955,7 @@ def __add__(self, other): # remains only to add other: result = self.copy() nproc = Parallelism().get('tensor') - if nproc != 1 : + if nproc != 1: # parallel sum lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] @@ -5255,7 +5255,7 @@ def __add__(self, other): # only to add other: result = self.copy() nproc = Parallelism().get('tensor') - if nproc != 1 : + if nproc != 1: # Parallel computation lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ind for ind in other._comp] diff --git a/src/sage/tensor/modules/free_module_tensor.py b/src/sage/tensor/modules/free_module_tensor.py index bada148ed78..416db9cbef9 100644 --- a/src/sage/tensor/modules/free_module_tensor.py +++ b/src/sage/tensor/modules/free_module_tensor.py @@ -1137,7 +1137,7 @@ class :class:`~sage.tensor.modules.comp.Components` # loop on the new components: nproc = Parallelism().get('tensor') - if nproc != 1 : + if nproc != 1: # Parallel computation lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] ind_list = [ind for ind in new_comp.non_redundant_index_generator()] From 58199c11f61e9d2971570c0548b5408208162570 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Sun, 17 Nov 2019 11:38:40 +0100 Subject: [PATCH 159/340] Gracefully handle case where there are no default warning filters --- src/sage/all.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/all.py b/src/sage/all.py index c87c9372e97..42dca175d21 100644 --- a/src/sage/all.py +++ b/src/sage/all.py @@ -302,7 +302,10 @@ def _write_started_file(): import warnings -warnings.filters.remove(('ignore', None, DeprecationWarning, None, 0)) +try: + warnings.filters.remove(('ignore', None, DeprecationWarning, None, 0)) +except ValueError: + pass # SAGE_DEBUG=yes builds do not install default warning filters, ignore # Ignore all deprecations from IPython etc. warnings.filterwarnings('ignore', category=DeprecationWarning, module='.*(IPython|ipykernel|jupyter_client|jupyter_core|nbformat|notebook|ipywidgets|storemagic)') From 920f47ec2bb8a6096de465203c5e0f4352d379ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 17 Nov 2019 12:18:09 +0100 Subject: [PATCH 160/340] some middle-scale cleanup 'Returns' ==> 'Return' in the doc --- .../algebras/affine_nil_temperley_lieb.py | 13 ++-- src/sage/algebras/commutative_dga.py | 5 +- src/sage/algebras/free_algebra_quotient.py | 16 +++-- .../algebras/lie_algebras/free_lie_algebra.py | 8 +-- .../algebras/steenrod/steenrod_algebra.py | 12 ++-- src/sage/arith/multi_modular.pyx | 4 +- src/sage/calculus/calculus.py | 2 +- src/sage/calculus/functions.py | 7 +- src/sage/calculus/integration.pyx | 9 +-- src/sage/calculus/interpolators.pyx | 18 +++-- src/sage/calculus/riemann.pyx | 34 ++++----- src/sage/cpython/_py2_random.py | 7 +- src/sage/crypto/boolean_function.pyx | 9 ++- src/sage/crypto/mq/rijndael_gf.py | 65 ++++++++--------- src/sage/data_structures/binary_matrix.pxi | 14 ++-- src/sage/data_structures/binary_search.pyx | 7 +- .../bounded_integer_sequences.pyx | 6 +- src/sage/doctest/parsing.py | 15 ++-- src/sage/doctest/sources.py | 12 ++-- src/sage/doctest/util.py | 11 +-- .../arithmetic_dynamics/projective_ds.py | 4 +- .../dynamics/arithmetic_dynamics/wehlerK3.py | 41 ++++++----- .../complex_dynamics/mandel_julia_helper.pyx | 7 +- src/sage/env.py | 2 +- src/sage/finance/fractal.pyx | 2 +- src/sage/finance/time_series.pyx | 3 +- src/sage/homology/chain_complex_homspace.py | 8 ++- src/sage/homology/chain_complex_morphism.py | 14 ++-- src/sage/homology/examples.py | 15 ++-- src/sage/homology/simplicial_complex.py | 15 ++-- .../homology/simplicial_complex_morphism.py | 14 ++-- src/sage/lfunctions/sympow.py | 6 +- src/sage/lfunctions/zero_sums.pyx | 5 +- src/sage/matroids/basis_exchange_matroid.pyx | 13 ++-- src/sage/matroids/graphic_matroid.py | 8 +-- src/sage/matroids/utilities.py | 2 +- src/sage/media/wav.py | 71 +++++++++++-------- 37 files changed, 278 insertions(+), 226 deletions(-) diff --git a/src/sage/algebras/affine_nil_temperley_lieb.py b/src/sage/algebras/affine_nil_temperley_lieb.py index 2a7991393a5..4f38d110e1c 100644 --- a/src/sage/algebras/affine_nil_temperley_lieb.py +++ b/src/sage/algebras/affine_nil_temperley_lieb.py @@ -1,12 +1,12 @@ """ Affine nilTemperley Lieb Algebra of type A """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010 Anne Schilling # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.categories.all import AlgebrasWithBasis from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.root_system.weyl_group import WeylGroup @@ -15,9 +15,10 @@ from sage.combinat.free_module import CombinatorialFreeModule from sage.misc.cachefunc import cached_method + class AffineNilTemperleyLiebTypeA(CombinatorialFreeModule): r""" - Constructs the affine nilTemperley Lieb algebra of type `A_{n-1}^{(1)}` as used in [Pos2005]_. + Construct the affine nilTemperley Lieb algebra of type `A_{n-1}^{(1)}` as used in [Pos2005]_. INPUT: @@ -94,7 +95,7 @@ def _element_constructor_(self, w): @cached_method def one_basis(self): """ - Returns the unit of the underlying Weyl group, which index + Return the unit of the underlying Weyl group, which index the one of this algebra, as per :meth:`AlgebrasWithBasis.ParentMethods.one_basis`. @@ -171,7 +172,7 @@ def algebra_generator(self, i): def product_on_basis(self, w, w1): """ - Returns `a_w a_{w1}`, where `w` and `w1` are in the Weyl group + Return `a_w a_{w1}`, where `w` and `w1` are in the Weyl group assuming that `w` does not contain any braid relations. EXAMPLES:: diff --git a/src/sage/algebras/commutative_dga.py b/src/sage/algebras/commutative_dga.py index 5267a82b16b..754fe9158f6 100644 --- a/src/sage/algebras/commutative_dga.py +++ b/src/sage/algebras/commutative_dga.py @@ -102,6 +102,7 @@ from sage.rings.quotient_ring_element import QuotientRingElement from sage.misc.cachefunc import cached_function + def sorting_keys(element): r""" Auxiliary function to sort the elements of a basis of a Cohomology group. @@ -1208,7 +1209,7 @@ def quotient(self, I, check=True): def _coerce_map_from_(self, other): r""" - Returns ``True`` if there is a coercion map from ``R`` to ``self``. + Return ``True`` if there is a coercion map from ``R`` to ``self``. EXAMPLES:: @@ -1725,7 +1726,7 @@ def quotient(self, I, check=True): def _coerce_map_from_(self, other): r""" - Returns ``True`` if there is a coercion map from ``R`` to ``self``. + Return ``True`` if there is a coercion map from ``R`` to ``self``. EXAMPLES:: diff --git a/src/sage/algebras/free_algebra_quotient.py b/src/sage/algebras/free_algebra_quotient.py index 02b3bf0a9f9..551996793b9 100644 --- a/src/sage/algebras/free_algebra_quotient.py +++ b/src/sage/algebras/free_algebra_quotient.py @@ -55,7 +55,7 @@ # See the GNU General Public License for more details; the full text # is available at: # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** from sage.modules.free_module import FreeModule @@ -64,6 +64,7 @@ from sage.algebras.free_algebra_quotient_element import FreeAlgebraQuotientElement from sage.structure.unique_representation import UniqueRepresentation + class FreeAlgebraQuotient(UniqueRepresentation, Algebra, object): @staticmethod def __classcall__(cls, A, mons, mats, names): @@ -88,12 +89,13 @@ def __classcall__(cls, A, mons, mats, names): Element = FreeAlgebraQuotientElement def __init__(self, A, mons, mats, names): """ - Returns a quotient algebra defined via the action of a free algebra - A on a (finitely generated) free module. The input for the quotient - algebra is a list of monomials (in the underlying monoid for A) - which form a free basis for the module of A, and a list of - matrices, which give the action of the free generators of A on this - monomial basis. + Return a quotient algebra defined via the action of a free algebra + A on a (finitely generated) free module. + + The input for the quotient algebra is a list of monomials (in + the underlying monoid for A) which form a free basis for the + module of A, and a list of matrices, which give the action of + the free generators of A on this monomial basis. EXAMPLES: diff --git a/src/sage/algebras/lie_algebras/free_lie_algebra.py b/src/sage/algebras/lie_algebras/free_lie_algebra.py index 7b188647b96..3a547e1a360 100644 --- a/src/sage/algebras/lie_algebras/free_lie_algebra.py +++ b/src/sage/algebras/lie_algebras/free_lie_algebra.py @@ -11,15 +11,15 @@ - [Reu2003]_ """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013-2017 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from six import iteritems from sage.misc.abstract_method import abstract_method @@ -876,7 +876,7 @@ def __init__(self, base): def _repr_(self): r""" - Returns the representation of ``self``. + Return the representation of ``self``. EXAMPLES:: diff --git a/src/sage/algebras/steenrod/steenrod_algebra.py b/src/sage/algebras/steenrod/steenrod_algebra.py index 32d9ec9ddad..6c41164a5f8 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra.py +++ b/src/sage/algebras/steenrod/steenrod_algebra.py @@ -2173,7 +2173,7 @@ def __contains__(self, x): def basis(self, d=None): """ - Returns basis for self, either the whole basis or the basis in + Return basis for ``self``, either the whole basis or the basis in degree `d`. INPUT: @@ -3473,12 +3473,12 @@ def excess(self): """ def excess_odd(mono): """ - Excess of mono, where mono has the form ((s0, s1, ...), (r1, r2, - ...)). + Excess of mono, where mono has the form + ((s0, s1, ...), (r1, r2, ...)). - Returns the length of the first component, since that is the number - of factors, plus twice the sum of the terms in the second - component. + Return the length of the first component, since that + is the number of factors, plus twice the sum of the + terms in the second component. """ if not mono: return 0 diff --git a/src/sage/arith/multi_modular.pyx b/src/sage/arith/multi_modular.pyx index 846b8968c9f..e84720a7891 100644 --- a/src/sage/arith/multi_modular.pyx +++ b/src/sage/arith/multi_modular.pyx @@ -9,7 +9,7 @@ Utility classes for multi-modular algorithms # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** from cysignals.memory cimport check_allocarray, check_reallocarray, sig_free @@ -775,7 +775,7 @@ cdef class MultiModularBasis_base(object): def __len__(self): """ - Returns the number of moduli stored. + Return the number of moduli stored. EXAMPLES:: diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index 770d5828d52..f507bb589c9 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -419,7 +419,7 @@ ######################################################## def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False): r""" - Returns the symbolic sum `\sum_{v = a}^b expression` with respect + Return the symbolic sum `\sum_{v = a}^b expression` with respect to the variable `v` with endpoints `a` and `b`. INPUT: diff --git a/src/sage/calculus/functions.py b/src/sage/calculus/functions.py index fead49e32fd..a2c2cae2af6 100644 --- a/src/sage/calculus/functions.py +++ b/src/sage/calculus/functions.py @@ -11,9 +11,10 @@ def wronskian(*args): """ - Returns the Wronskian of the provided functions, differentiating with - respect to the given variable. If no variable is provided, - diff(f) is called for each function f. + Return the Wronskian of the provided functions, differentiating with + respect to the given variable. + + If no variable is provided, diff(f) is called for each function f. wronskian(f1,...,fn, x) returns the Wronskian of f1,...,fn, with derivatives taken with respect to x. diff --git a/src/sage/calculus/integration.pyx b/src/sage/calculus/integration.pyx index 28ddf298854..da5c3aff464 100644 --- a/src/sage/calculus/integration.pyx +++ b/src/sage/calculus/integration.pyx @@ -14,7 +14,7 @@ AUTHORS: the reference manual. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2004,2005,2006,2007 Joshua Kantor # Copyright (C) 2007 William Stein # Copyright (C) 2019 Vincent Klein @@ -23,8 +23,8 @@ AUTHORS: # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.signals cimport sig_on, sig_off from sage.rings.real_double import RDF @@ -65,12 +65,13 @@ cdef double c_f(double t, void *params): cdef double c_ff(double t, void *params): return (params)._call_c(&t) + def numerical_integral(func, a, b=None, algorithm='qag', max_points=87, params=[], eps_abs=1e-6, eps_rel=1e-6, rule=6): r""" - Returns the numerical integral of the function on the interval + Return the numerical integral of the function on the interval from a to b and an error bound. INPUT: diff --git a/src/sage/calculus/interpolators.pyx b/src/sage/calculus/interpolators.pyx index 36ee8df1f1e..a62b9e8e19d 100644 --- a/src/sage/calculus/interpolators.pyx +++ b/src/sage/calculus/interpolators.pyx @@ -8,7 +8,7 @@ AUTHORS: Development supported by NSF award No. 0702939. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009 Ethan Van Andel , # # Distributed under the terms of the GNU General Public License (GPL) @@ -20,8 +20,8 @@ Development supported by NSF award No. 0702939. # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import numpy as np cimport numpy as np @@ -96,7 +96,7 @@ cdef class PSpline: def value(self, double t): """ - Returns the derivative (speed and direction of the curve) of a + Return the derivative (speed and direction of the curve) of a given point from the parameter ``t``. INPUT: @@ -129,7 +129,7 @@ cdef class PSpline: def derivative(self, double t): """ - Returns the derivative (speed and direction of the curve) of a + Return the derivative (speed and direction of the curve) of a given point from the parameter ``t``. INPUT: @@ -249,7 +249,7 @@ cdef class CCSpline: def value(self, double t): """ - Returns the location of a given point from the parameter ``t``. + Return the location of a given point from the parameter ``t``. INPUT: @@ -281,7 +281,7 @@ cdef class CCSpline: def derivative(self, double t): """ - Returns the derivative (speed and direction of the curve) of a + Return the derivative (speed and direction of the curve) of a given point from the parameter ``t``. INPUT: @@ -294,9 +294,7 @@ cdef class CCSpline: A complex number representing the derivative at the point on the figure corresponding to the input ``t``. - EXAMPLES: - - :: + EXAMPLES:: sage: pts = [(-1, -1), (1, -1), (1, 1), (-1, 1)] sage: cs = complex_cubic_spline(pts) diff --git a/src/sage/calculus/riemann.pyx b/src/sage/calculus/riemann.pyx index dfd27266265..abae641e75c 100644 --- a/src/sage/calculus/riemann.pyx +++ b/src/sage/calculus/riemann.pyx @@ -10,7 +10,7 @@ AUTHORS: Development supported by NSF award No. 0702939. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2011 Ethan Van Andel , # # Distributed under the terms of the GNU General Public License (GPL) @@ -22,8 +22,8 @@ Development supported by NSF award No. 0702939. # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.signals cimport sig_on, sig_off @@ -382,7 +382,7 @@ cdef class Riemann_Map: def get_szego(self, int boundary=-1, absolute_value=False): """ - Returns a discretized version of the Szego kernel for each boundary + Return a discretized version of the Szego kernel for each boundary function. INPUT: @@ -456,7 +456,7 @@ cdef class Riemann_Map: def get_theta_points(self, int boundary=-1): """ - Returns an array of points of the form + Return an array of points of the form ``[t value, theta in e^(I*theta)]``, that is, a discretized version of the theta/boundary correspondence function. In other words, a point in this array [t1, t2] represents that the boundary point given by f(t1) @@ -574,12 +574,13 @@ cdef class Riemann_Map: cpdef riemann_map(self, COMPLEX_T pt): """ - Returns the Riemann mapping of a point. That is, given ``pt`` on - the interior of the mapped region, ``riemann_map`` will return - the point on the unit disk that ``pt`` maps to. Note that this - method only works for interior points; accuracy breaks down very close - to the boundary. To get boundary correspondance, use - :meth:`get_theta_points`. + Return the Riemann mapping of a point. + + That is, given ``pt`` on the interior of the mapped region, + ``riemann_map`` will return the point on the unit disk that + ``pt`` maps to. Note that this method only works for interior + points; accuracy breaks down very close to the boundary. To + get boundary correspondance, use :meth:`get_theta_points`. INPUT: @@ -662,11 +663,12 @@ cdef class Riemann_Map: cpdef inverse_riemann_map(self, COMPLEX_T pt): """ - Returns the inverse Riemann mapping of a point. That is, given ``pt`` - on the interior of the unit disc, ``inverse_riemann_map()`` will - return the point on the original region that would be Riemann - mapped to ``pt``. Note that this method does not work for multiply - connected domains. + Return the inverse Riemann mapping of a point. + + That is, given ``pt`` on the interior of the unit disc, + ``inverse_riemann_map()`` will return the point on the + original region that would be Riemann mapped to ``pt``. Note + that this method does not work for multiply connected domains. INPUT: diff --git a/src/sage/cpython/_py2_random.py b/src/sage/cpython/_py2_random.py index 2f89bb14f59..190440911d4 100644 --- a/src/sage/cpython/_py2_random.py +++ b/src/sage/cpython/_py2_random.py @@ -6,7 +6,7 @@ between Python versions, but the difference lies in higher-level methods such as `random.randint`. -See https://trac.sagemath.org/ticket/24508 +See :trac:`24508` """ # The following code was copied from @@ -270,9 +270,10 @@ def shuffle(self, x, random=None): x[i], x[j] = x[j], x[i] def sample(self, population, k): - """Chooses k unique random elements from a population sequence. + """ + Choose k unique random elements from a population sequence. - Returns a new list containing elements from the population while + Return a new list containing elements from the population while leaving the original population unchanged. The resulting list is in selection order so that all sub-slices will also be valid random samples. This allows raffle winners (the sample) to be partitioned diff --git a/src/sage/crypto/boolean_function.pyx b/src/sage/crypto/boolean_function.pyx index c1b0bb06a70..6ca784dfbff 100644 --- a/src/sage/crypto/boolean_function.pyx +++ b/src/sage/crypto/boolean_function.pyx @@ -1030,8 +1030,10 @@ cdef class BooleanFunction(SageObject): def algebraic_immunity(self, annihilator = False): """ - Returns the algebraic immunity of the Boolean function. This is the smallest - integer `i` such that there exists a non trivial annihilator for `self` or `~self`. + Return the algebraic immunity of the Boolean function. + + This is the smallest integer `i` such that there exists a non + trivial annihilator for `self` or `~self`. INPUT: @@ -1420,9 +1422,10 @@ cdef class BooleanFunctionIterator: # cryptographic Boolean function. # ########################################## + def random_boolean_function(n): """ - Returns a random Boolean function with `n` variables. + Return a random Boolean function with `n` variables. EXAMPLES:: diff --git a/src/sage/crypto/mq/rijndael_gf.py b/src/sage/crypto/mq/rijndael_gf.py index f6be8840faa..8fbb3a2f8cb 100644 --- a/src/sage/crypto/mq/rijndael_gf.py +++ b/src/sage/crypto/mq/rijndael_gf.py @@ -412,15 +412,15 @@ TypeError: keyword 'f' must be a Round_Component_Poly_Constr """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 Thomas Gagne # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import print_function, division from six import string_types @@ -432,6 +432,7 @@ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.misc.sageinspect import sage_getargspec + class RijndaelGF(SageObject): def __init__(self, Nb, Nk, state_chr='a', key_chr='k'): @@ -569,7 +570,7 @@ def __init__(self, Nb, Nk, state_chr='a', key_chr='k'): def __call__(self, text, key, algorithm='encrypt', format='hex'): r""" - Returns the encryption/decryption of ``text`` with key ``key``. + Return the encryption/decryption of ``text`` with key ``key``. INPUT: @@ -618,7 +619,7 @@ def __call__(self, text, key, algorithm='encrypt', format='hex'): def __repr__(self): r""" - Returns the string representation of ``self``. + Return the string representation of ``self``. EXAMPLES:: @@ -634,7 +635,7 @@ def __repr__(self): def block_length(self): r""" - Returns the block length of this instantiation of Rijndael-GF. + Return the block length of this instantiation of Rijndael-GF. EXAMPLES:: @@ -647,7 +648,7 @@ def block_length(self): def key_length(self): r""" - Returns the key length of this instantiation of Rijndael-GF. + Return the key length of this instantiation of Rijndael-GF. EXAMPLES:: @@ -660,7 +661,7 @@ def key_length(self): def number_rounds(self): r""" - Returns the number of rounds used in this instantiation of Rijndael-GF. + Return the number of rounds used in this instantiation of Rijndael-GF. EXAMPLES:: @@ -673,15 +674,15 @@ def number_rounds(self): def _hex_to_GF(self, H, matrix=True): r""" - Returns a matrix/list of elements of `\GF{2^8}` corresponding to ``H``. + Return a matrix/list of elements of `\GF{2^8}` corresponding to ``H``. INPUT: - ``H`` -- A hex string where every two hex characters correspond to a single element in `\GF{2^8}` - - ``matrix`` -- (default: ``True``) Returns a list if ``False``; - returns a state matrix if ``True``. + - ``matrix`` -- (default: ``True``) Return a list if ``False``; + return a state matrix if ``True``. OUTPUT: @@ -722,7 +723,7 @@ def hx_to_gf(h): def _GF_to_hex(self, GF): r""" - Returns the hex string representation of ``GF``. + Return the hex string representation of ``GF``. INPUT: @@ -790,15 +791,15 @@ def _GF_to_hex(self, GF): def _bin_to_GF(self, B, matrix=True): r""" - Returns a matrix/list of elements of `\GF{2^8}` corresponding to ``B``. + Return a matrix/list of elements of `\GF{2^8}` corresponding to ``B``. INPUT: - ``B`` -- A binary string where every eight bits correspond to a single element in `\GF{2^8}` - - ``matrix`` -- (default: ``True``) Returns a list if ``False``. - Returns a state matrix over `\GF{2^8}` if ``True``. + - ``matrix`` -- (default: ``True``) Return a list if ``False``. + Return a state matrix over `\GF{2^8}` if ``True``. OUTPUT: @@ -850,7 +851,7 @@ def bn_to_gf(b): def _GF_to_bin(self, GF): r""" - Returns the binary string representation of ``GF``. + Return the binary string representation of ``GF``. INPUT: @@ -916,7 +917,7 @@ def _GF_to_bin(self, GF): def encrypt(self, plain, key, format='hex'): r""" - Returns the plaintext ``plain`` encrypted with the key ``key``. + Return the plaintext ``plain`` encrypted with the key ``key``. INPUT: @@ -1005,7 +1006,7 @@ def encrypt(self, plain, key, format='hex'): def decrypt(self, ciphertext, key, format='hex'): r""" - Returns the ciphertext ``ciphertext`` decrypted with the key ``key``. + Return the ciphertext ``ciphertext`` decrypted with the key ``key``. INPUT: @@ -1157,7 +1158,7 @@ def _check_valid_PRmatrix(self, PRm, keyword): def expand_key(self, key): r""" - Returns the expanded key schedule from ``key``. + Return the expanded key schedule from ``key``. INPUT: @@ -1224,7 +1225,7 @@ def add_cols(col1, col2): def expand_key_poly(self, row, col, round): r""" - Returns a polynomial representing the ``row,col`` th entry of the + Return a polynomial representing the ``row,col`` th entry of the ``round`` th round key. INPUT: @@ -1315,7 +1316,7 @@ def expand_key_poly(self, row, col, round): def apply_poly(self, state, poly_constr, algorithm='encrypt', keys=None, poly_constr_attr=None): r""" - Returns a state matrix where ``poly_method`` is applied to each entry. + Return a state matrix where ``poly_method`` is applied to each entry. INPUT: @@ -1635,7 +1636,7 @@ def add_round_key_poly_constr(self): def _add_round_key_pc(self, row, col, algorithm='encrypt', round=0): r""" - Returns a polynomial representing an element of a round-key addition. + Return a polynomial representing an element of a round-key addition. INPUT: @@ -1684,7 +1685,7 @@ def _add_round_key_pc(self, row, col, algorithm='encrypt', round=0): def add_round_key(self, state, round_key): r""" - Returns the round-key addition of matrices ``state`` and ``round_key``. + Return the round-key addition of matrices ``state`` and ``round_key``. INPUT: @@ -1795,7 +1796,7 @@ def sub_bytes_poly_constr(self): def _sub_bytes_pc(self, row, col, algorithm='encrypt', no_inversion=False): r""" - Returns a polynomial representing `SubBytes(A)_{\textit{row, col}}`. + Return a polynomial representing `SubBytes(A)_{\textit{row, col}}`. INPUT: @@ -1878,7 +1879,7 @@ def _sub_bytes_pc(self, row, col, algorithm='encrypt', no_inversion=False): def _srd(self, el, algorithm='encrypt'): r""" - Returns the application of SubBytes (`S_{RD}`) to ``el``. + Return the application of SubBytes (`S_{RD}`) to ``el``. INPUT: @@ -1916,7 +1917,7 @@ def _srd(self, el, algorithm='encrypt'): def sub_bytes(self, state, algorithm='encrypt'): r""" - Returns the application of SubBytes to the state matrix ``state``. + Return the application of SubBytes to the state matrix ``state``. INPUT: @@ -1970,7 +1971,7 @@ def mix_columns_poly_constr(self): def _mix_columns_pc(self, row, col, algorithm='encrypt'): r""" - Returns a polynomial representing `MixColumns(A)_{\textit{row, col}}`. + Return a polynomial representing `MixColumns(A)_{\textit{row, col}}`. INPUT: @@ -2020,7 +2021,7 @@ def _mix_columns_pc(self, row, col, algorithm='encrypt'): def mix_columns(self, state, algorithm='encrypt'): r""" - Returns the application of MixColumns to the state matrix ``state``. + Return the application of MixColumns to the state matrix ``state``. INPUT: @@ -2072,7 +2073,7 @@ def shift_rows_poly_constr(self): def _shift_rows_pc(self, row, col, algorithm='encrypt'): r""" - Returns a polynomial representing `ShiftRows(A)_{\textit{row,col}}`. + Return a polynomial representing `ShiftRows(A)_{\textit{row,col}}`. INPUT: @@ -2123,7 +2124,7 @@ def _shift_rows_pc(self, row, col, algorithm='encrypt'): def shift_rows(self, state, algorithm='encrypt'): r""" - Returns the application of ShiftRows to the state matrix ``state``. + Return the application of ShiftRows to the state matrix ``state``. INPUT: @@ -2283,7 +2284,7 @@ def __init__(self, polynomial_constr, rgf, round_component_name=None): def __call__(self, row, col, algorithm='encrypt', **kwargs): r""" - Returns ``polynomial_constr(row, col, algorithm, **attr_dict)``. + Return ``polynomial_constr(row, col, algorithm, **attr_dict)``. INPUT: @@ -2331,7 +2332,7 @@ def __call__(self, row, col, algorithm='encrypt', **kwargs): def __repr__(self): r""" - Returns a string representation of this object. + Return a string representation of this object. EXAMPLES:: diff --git a/src/sage/data_structures/binary_matrix.pxi b/src/sage/data_structures/binary_matrix.pxi index 5f9437c2a63..f15ba5197d5 100644 --- a/src/sage/data_structures/binary_matrix.pxi +++ b/src/sage/data_structures/binary_matrix.pxi @@ -37,7 +37,7 @@ cdef inline binary_matrix_init(binary_matrix_t m, Py_ssize_t n_rows, Py_ssize_t cdef inline binary_matrix_free(binary_matrix_t m): r""" - Frees the memory allocated by the matrix + Free the memory allocated by the matrix """ cdef Py_ssize_t i @@ -60,7 +60,7 @@ cdef inline binary_matrix_fill(binary_matrix_t m, bint bit): cdef inline binary_matrix_complement(binary_matrix_t m): r""" - Complements all of the matrix' bits. + Complement all of the matrix' bits. """ cdef Py_ssize_t i for i in range(m.n_rows): @@ -68,31 +68,31 @@ cdef inline binary_matrix_complement(binary_matrix_t m): cdef inline binary_matrix_set1(binary_matrix_t m, Py_ssize_t row, Py_ssize_t col): r""" - Sets an entry to 1 + Set an entry to 1 """ bitset_add(m.rows[row], col) cdef inline binary_matrix_set0(binary_matrix_t m, Py_ssize_t row, Py_ssize_t col): r""" - Sets an entry to 0 + Set an entry to 0 """ bitset_discard(m.rows[row], col) cdef inline binary_matrix_set(binary_matrix_t m, Py_ssize_t row, Py_ssize_t col, bint value): r""" - Sets an entry + Set an entry """ bitset_set_to(m.rows[row],col,value) cdef inline bint binary_matrix_get(binary_matrix_t m, Py_ssize_t row, Py_ssize_t col): r""" - Returns the value of a given entry + Return the value of a given entry """ return bitset_in(m.rows[row], col) cdef inline binary_matrix_print(binary_matrix_t m): r""" - Prints the binary matrix + Print the binary matrix """ cdef Py_ssize_t i,j import sys diff --git a/src/sage/data_structures/binary_search.pyx b/src/sage/data_structures/binary_search.pyx index ac610398ee2..030d50266e5 100644 --- a/src/sage/data_structures/binary_search.pyx +++ b/src/sage/data_structures/binary_search.pyx @@ -3,7 +3,8 @@ cdef Py_ssize_t binary_search(Py_ssize_t* v, Py_ssize_t n, Py_ssize_t x, Py_ssize_t* ins): """ Find the position of the integer x in the array v, which has length n. - Returns -1 if x is not in the array v, and in this case ins is + + Return -1 if x is not in the array v, and in this case ins is set equal to the position where x should be inserted in order to obtain an ordered array. """ @@ -36,10 +37,12 @@ cdef Py_ssize_t binary_search(Py_ssize_t* v, Py_ssize_t n, Py_ssize_t x, Py_ssiz ins[0] = j+1 return -1 + cdef Py_ssize_t binary_search0(Py_ssize_t* v, Py_ssize_t n, Py_ssize_t x): """ Find the position of the int x in the array v, which has length n. - Returns -1 if x is not in the array v. + + Return -1 if x is not in the array v. """ if n == 0: return -1 diff --git a/src/sage/data_structures/bounded_integer_sequences.pyx b/src/sage/data_structures/bounded_integer_sequences.pyx index 2271bd58dad..2f1da5274eb 100644 --- a/src/sage/data_structures/bounded_integer_sequences.pyx +++ b/src/sage/data_structures/bounded_integer_sequences.pyx @@ -258,7 +258,7 @@ cdef inline bint biseq_startswith(biseq_t S1, biseq_t S2) except -1: cdef mp_size_t biseq_index(biseq_t S, size_t item, mp_size_t start) except -2: """ - Returns the position in ``S`` of an item in ``S[start:]``, or -1 if + Return the position in ``S`` of an item in ``S[start:]``, or -1 if ``S[start:]`` does not contain the item. """ @@ -1239,9 +1239,9 @@ cdef class BoundedIntegerSequence: cpdef BoundedIntegerSequence maximal_overlap(self, BoundedIntegerSequence other): """ - Returns ``self``'s maximal trailing sub-sequence that ``other`` starts with. + Return ``self``'s maximal trailing sub-sequence that ``other`` starts with. - Returns ``None`` if there is no overlap + Return ``None`` if there is no overlap. EXAMPLES:: diff --git a/src/sage/doctest/parsing.py b/src/sage/doctest/parsing.py index 4f9ee15fd50..9ea585e06f3 100644 --- a/src/sage/doctest/parsing.py +++ b/src/sage/doctest/parsing.py @@ -12,7 +12,7 @@ using interval arithmetic (:trac:`16889`). """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 David Roe # Robert Bradshaw # William Stein @@ -20,8 +20,8 @@ # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import print_function, absolute_import from sage.misc.six import u import six @@ -272,7 +272,7 @@ def subst(m): def parse_optional_tags(string): """ - Returns a set consisting of the optional tags from the following + Return a set consisting of the optional tags from the following set that occur in a comment on the first line of the input string. - 'long time' @@ -335,9 +335,10 @@ def parse_optional_tags(string): tags.extend(m.group(3).split() or [""]) return set(tags) + def parse_tolerance(source, want): """ - Returns a version of ``want`` marked up with the tolerance tags + Return a version of ``want`` marked up with the tolerance tags specified in ``source``. INPUT: @@ -392,6 +393,7 @@ def parse_tolerance(source, want): raise RuntimeError return want + def pre_hash(s): """ Prepends a string with its length. @@ -404,9 +406,10 @@ def pre_hash(s): """ return "%s:%s" % (len(s), s) + def get_source(example): """ - Returns the source with the leading 'sage: ' stripped off. + Return the source with the leading 'sage: ' stripped off. EXAMPLES:: diff --git a/src/sage/doctest/sources.py b/src/sage/doctest/sources.py index b9d2268de84..fd687c33dbb 100644 --- a/src/sage/doctest/sources.py +++ b/src/sage/doctest/sources.py @@ -9,15 +9,15 @@ - David Roe (2012-03-27) -- initial version, based on Robert Bradshaw's code. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 David Roe # Robert Bradshaw # William Stein # # Distributed under the terms of the GNU General Public License (GPL) # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import print_function, absolute_import import os @@ -670,7 +670,7 @@ def in_lib(self): def create_doctests(self, namespace): r""" - Returns a list of doctests for this file. + Return a list of doctests for this file. INPUT: @@ -1131,8 +1131,8 @@ def ending_docstring(self, line): def _neutralize_doctests(self, reindent): r""" - Returns a string containing the source of self, but with - doctests modified so they aren't tested. + Return a string containing the source of ``self``, but with + doctests modified so they are not tested. This function is used in creating doctests for ReST files, since docstrings of Python functions defined inside verbatim diff --git a/src/sage/doctest/util.py b/src/sage/doctest/util.py index 8cc394f5871..f980982715e 100644 --- a/src/sage/doctest/util.py +++ b/src/sage/doctest/util.py @@ -8,7 +8,7 @@ - David Roe (2012-03-27) -- initial version, based on Robert Bradshaw's code. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 David Roe # Robert Bradshaw # William Stein @@ -16,13 +16,14 @@ # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import print_function from six import iteritems from sage.misc.misc import walltime, cputime + def count_noun(number, noun, plural=None, pad_number=False, pad_noun=False): """ EXAMPLES:: @@ -457,7 +458,7 @@ def __setitem__(self, index, value): def __str__(self): """ - Returns a .-separated string giving the full name. + Return a .-separated string giving the full name. EXAMPLES:: @@ -472,7 +473,7 @@ def __str__(self): def __repr__(self): """ - Returns a .-separated string giving the full name. + Return a .-separated string giving the full name. EXAMPLES:: diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index d8850c1fac1..d9aa76d8675 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -484,7 +484,7 @@ def __copy__(self): def _number_field_from_algebraics(self): r""" - Returns a dynamical system defined over the number field of its coefficients. + Return a dynamical system defined over the number field of its coefficients. OTUPUT: dynamical system. @@ -6513,7 +6513,7 @@ def automorphism_group(self, absolute=False, iso_type=False, return_functions=Fa def all_periodic_points(self, **kwds): r""" - Returns a list of all periodic points over a finite field. + Return a list of all periodic points over a finite field. INPUT: diff --git a/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py b/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py index 71b4ca667e6..34ee7c1248e 100644 --- a/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py +++ b/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py @@ -23,7 +23,7 @@ # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** from sage.calculus.functions import jacobian @@ -233,15 +233,15 @@ def _check_satisfies_equations(self, P): def _Lcoeff(self, component, i): r""" - Returns the polynomials `L^x_i` or `L^y_i`. + Return the polynomials `L^x_i` or `L^y_i`. These polynomials are defined as: - `L^x_i` = the coefficients of `y_i` in `L(x, y)` (Component = 0) + `L^x_i` = the coefficients of `y_i` in `L(x, y)` (Component = 0) - `L^y_i` = the coefficients of `x_i` in `L(x, y)` (Component = 1) + `L^y_i` = the coefficients of `x_i` in `L(x, y)` (Component = 1) - Definition and Notation from: [CS1996]_ + Definition and Notation from: [CS1996]_ INPUT: @@ -281,15 +281,15 @@ def _Lcoeff(self, component, i): def _Qcoeff(self, component, i, j): r""" - Returns the polynomials `Q^x_{ij}` or `Q^y_{ij}`. + Return the polynomials `Q^x_{ij}` or `Q^y_{ij}`. These polynomials are defined as: - `Q^x_{ij}` = the coefficients of `y_{i}y_{j}` in `Q(x, y)` (Component = 0). + `Q^x_{ij}` = the coefficients of `y_{i}y_{j}` in `Q(x, y)` (Component = 0). - `Q^y_{ij}` = the coefficients of `x_{i}x_{j}` in `Q(x, y)` (Component = 1). + `Q^y_{ij}` = the coefficients of `x_{i}x_{j}` in `Q(x, y)` (Component = 1). - Definition and Notation from: [CS1996]_. + Definition and Notation from: [CS1996]_. INPUT: @@ -334,7 +334,7 @@ def _Qcoeff(self, component, i, j): @cached_method def Gpoly(self, component, k): r""" - Returns the G polynomials `G^*_k`. + Return the G polynomials `G^*_k`. They are defined as: `G^*_k = \left(L^*_j\right)^2Q^*_{ii}-L^*_iL^*_jQ^*_{ij}+\left(L^*_i\right)^2Q^*_{jj}`\ @@ -378,7 +378,7 @@ def Gpoly(self, component, k): @cached_method def Hpoly(self, component, i, j): r""" - Returns the H polynomials defined as `H^*_{ij}`. + Return the H polynomials defined as `H^*_{ij}`. This polynomial is defined by: @@ -1970,8 +1970,10 @@ def canonical_height(self, P, N, badprimes=None, prec=100): def fiber(self, p, component): r""" - Returns the fibers [y (component = 1) or x (Component = 0)] of a point on a - K3 Surface, will work for nondegenerate fibers only. + Return the fibers [y (component = 1) or x (Component = 0)] of + a point on a K3 Surface. + + This will work for nondegenerate fibers only. For algorithm, see [Hutz2007]_. @@ -2255,10 +2257,12 @@ def nth_iterate_psi(self, P, n, **kwds): Q = self.psi(Q, **kwds) return Q - def orbit_phi(self,P,N, **kwds): + def orbit_phi(self, P, N, **kwds): r""" - Returns the orbit of the `\phi` function defined by `\phi = \sigma_y \circ \sigma_x` - Function is defined in [CS1996]_. + Return the orbit of the `\phi` function defined by + `\phi = \sigma_y \circ \sigma_x`. + + This function is defined in [CS1996]_. INPUT: @@ -2315,9 +2319,10 @@ def orbit_phi(self,P,N, **kwds): def orbit_psi(self, P, N, **kwds): r""" - Returns the orbit of the `\psi` function defined by `\psi = \sigma_x \circ \sigma_y`. + Return the orbit of the `\psi` function defined by + `\psi = \sigma_x \circ \sigma_y`. - Function is defined in [CS1996]_. + This function is defined in [CS1996]_. INPUT: diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx index eb8ec8a57f9..317c3ea3bef 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +++ b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx @@ -145,15 +145,16 @@ def fast_mandelbrot_plot(double x_center, double y_center, double image_width, # Assign the pixel a color based on it's level. If we run out # of colors, assign it the last color in the list. if level < color_num: - pixel[col,row] = color_list[level] + pixel[col, row] = color_list[level] else: - pixel[col,row] = color_list[-1] + pixel[col, row] = color_list[-1] return M + cpdef fast_external_ray(double theta, long D=30, long S=10, long R=100, long pixel_count=500, double image_width=4, long prec=300): r""" - Returns a list of points that approximate the external ray for a given angle. + Return a list of points that approximate the external ray for a given angle. INPUT: diff --git a/src/sage/env.py b/src/sage/env.py index cf83545b6fa..d8609ad6c99 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -211,7 +211,7 @@ def _get_shared_lib_filename(libname, *additional_libnames): For distributions like Debian that use a multiarch layout, we also try the multiarch lib paths (i.e. ``/usr/lib//``). - Returns ``None`` if the file does not exist. + This returns ``None`` if the file does not exist. EXAMPLES:: diff --git a/src/sage/finance/fractal.pyx b/src/sage/finance/fractal.pyx index 90da765eaac..a553e8dbc93 100644 --- a/src/sage/finance/fractal.pyx +++ b/src/sage/finance/fractal.pyx @@ -206,7 +206,7 @@ def fractional_gaussian_noise_simulation(double H, double sigma2, N, n=1): def fractional_brownian_motion_simulation(double H, double sigma2, N, n=1): """ - Returns the partial sums of a fractional Gaussian noise simulation + Return the partial sums of a fractional Gaussian noise simulation with the same input parameters. INPUT: diff --git a/src/sage/finance/time_series.pyx b/src/sage/finance/time_series.pyx index 46e64ae69b3..75f21f0cc08 100644 --- a/src/sage/finance/time_series.pyx +++ b/src/sage/finance/time_series.pyx @@ -1672,7 +1672,8 @@ cdef class TimeSeries: def hurst_exponent(self): """ - Returns an estimate of the Hurst exponent of this time series. + Return an estimate of the Hurst exponent of this time series. + We use the algorithm from pages 61 -- 63 of [Peteres, Fractal Market Analysis (1994); see Google Books]. diff --git a/src/sage/homology/chain_complex_homspace.py b/src/sage/homology/chain_complex_homspace.py index 4bfc7e2da34..5679b275a82 100644 --- a/src/sage/homology/chain_complex_homspace.py +++ b/src/sage/homology/chain_complex_homspace.py @@ -94,16 +94,17 @@ # See the GNU General Public License for more details; the full text # is available at: # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ # #***************************************************************************** import sage.categories.homset from sage.homology.chain_complex_morphism import ChainComplexMorphism + def is_ChainComplexHomspace(x): """ - Returns ``True`` if and only if ``x`` is a morphism of chain complexes. + Return ``True`` if and only if ``x`` is a morphism of chain complexes. EXAMPLES:: @@ -115,7 +116,8 @@ def is_ChainComplexHomspace(x): True """ - return isinstance(x,ChainComplexHomspace) + return isinstance(x, ChainComplexHomspace) + class ChainComplexHomspace(sage.categories.homset.Homset): """ diff --git a/src/sage/homology/chain_complex_morphism.py b/src/sage/homology/chain_complex_morphism.py index bc3fa348a9f..885777d276e 100644 --- a/src/sage/homology/chain_complex_morphism.py +++ b/src/sage/homology/chain_complex_morphism.py @@ -47,7 +47,7 @@ # See the GNU General Public License for more details; the full text # is available at: # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ # #***************************************************************************** @@ -56,9 +56,10 @@ from sage.categories.homset import Hom from sage.categories.category_types import ChainComplexes + def is_ChainComplexMorphism(x): """ - Returns ``True`` if and only if ``x`` is a chain complex morphism. + Return ``True`` if and only if ``x`` is a chain complex morphism. EXAMPLES:: @@ -77,7 +78,8 @@ def is_ChainComplexMorphism(x): sage: is_ChainComplexMorphism(x) True """ - return isinstance(x,ChainComplexMorphism) + return isinstance(x, ChainComplexMorphism) + class ChainComplexMorphism(Morphism): """ @@ -289,7 +291,7 @@ def dual(self): def __neg__(self): """ - Returns ``-x``. + Return ``-x``. EXAMPLES:: @@ -322,7 +324,7 @@ def __neg__(self): def __add__(self,x): """ - Returns ``self + x``. + Return ``self + x``. EXAMPLES:: @@ -444,7 +446,7 @@ def __mul__(self,x): def __rmul__(self,x): """ - Returns ``x * self`` if ``x`` is an element of the base ring. + Return ``x * self`` if ``x`` is an element of the base ring. EXAMPLES:: diff --git a/src/sage/homology/examples.py b/src/sage/homology/examples.py index 90d33102ff0..4242b7b05a5 100644 --- a/src/sage/homology/examples.py +++ b/src/sage/homology/examples.py @@ -119,9 +119,10 @@ def facets_for_RP4(): facets.append(new) return facets + def facets_for_K3(): """ - Returns the facets for a minimal triangulation of the K3 surface. + Return the facets for a minimal triangulation of the K3 surface. This is a pure simplicial complex of dimension 4 with 16 vertices and 288 facets. The facets are obtained by constructing a @@ -541,9 +542,10 @@ def ComplexProjectivePlane(): [9, 7, 2, 3, 6], [7, 8, 3, 1, 4], [8, 9, 1, 2, 5]], name='Minimal triangulation of the complex projective plane') + def PseudoQuaternionicProjectivePlane(): r""" - Returns a pure simplicial complex of dimension 8 with 490 facets. + Return a pure simplicial complex of dimension 8 with 490 facets. .. WARNING:: @@ -830,9 +832,10 @@ def RealProjectiveSpace(n): return UniqueSimplicialComplex(list(facets), name='Triangulation of RP^{}'.format(n)) + def K3Surface(): """ - Returns a minimal triangulation of the K3 surface. + Return a minimal triangulation of the K3 surface. This is a pure simplicial complex of dimension 4 with 16 vertices and 288 facets. It was constructed by Casella and Kühnel @@ -950,9 +953,10 @@ def K3Surface(): (1, 2, 4, 7, 15), (2, 3, 7, 8, 16), (1, 4, 5, 6, 10)], name='Minimal triangulation of the K3 surface') + def BarnetteSphere(): r""" - Returns Barnette's triangulation of the 3-sphere. + Return Barnette's triangulation of the 3-sphere. This is a pure simplicial complex of dimension 3 with 8 vertices and 19 facets, which is a non-polytopal triangulation @@ -990,9 +994,10 @@ def BarnetteSphere(): (3,6,4,8)], name="Barnette's triangulation of the 3-sphere") + def BrucknerGrunbaumSphere(): r""" - Returns Bruckner and Grunbaum's triangulation of the 3-sphere. + Return Bruckner and Grunbaum's triangulation of the 3-sphere. This is a pure simplicial complex of dimension 3 with 8 vertices and 20 facets, which is a non-polytopal triangulation diff --git a/src/sage/homology/simplicial_complex.py b/src/sage/homology/simplicial_complex.py index d1842a1809c..bd29635767a 100644 --- a/src/sage/homology/simplicial_complex.py +++ b/src/sage/homology/simplicial_complex.py @@ -2943,7 +2943,7 @@ def all_homologies_in_list_vanish(Fs): def generated_subcomplex(self, sub_vertex_set, is_mutable=True): """ - Returns the largest sub-simplicial complex of ``self`` containing + Return the largest sub-simplicial complex of ``self`` containing exactly ``sub_vertex_set`` as vertices. :param sub_vertex_set: The sub-vertex set. @@ -3616,9 +3616,11 @@ def graph(self): def delta_complex(self, sort_simplices=False): r""" - Returns ``self`` as a `\Delta`-complex. The `\Delta`-complex - is essentially identical to the simplicial complex: it has - same simplices with the same boundaries. + Return ``self`` as a `\Delta`-complex. + + The `\Delta`-complex is essentially identical to the + simplicial complex: it has same simplices with the same + boundaries. :param sort_simplices: if ``True``, sort the list of simplices in each dimension @@ -3651,7 +3653,7 @@ def delta_complex(self, sort_simplices=False): def is_flag_complex(self): """ - Returns ``True`` if and only if ``self`` is a flag complex. + Return ``True`` if and only if ``self`` is a flag complex. A flag complex is a simplicial complex that is the largest simplicial complex on its 1-skeleton. Thus a flag complex is the clique complex @@ -4713,9 +4715,10 @@ def facets_for_RP4(): facets.append(new) return facets + def facets_for_K3(): """ - Returns the facets for a minimal triangulation of the K3 surface. + Return the facets for a minimal triangulation of the K3 surface. This is a pure simplicial complex of dimension 4 with 16 vertices and 288 facets. The facets are obtained by constructing a diff --git a/src/sage/homology/simplicial_complex_morphism.py b/src/sage/homology/simplicial_complex_morphism.py index 472dca2a5d7..65983bc9b0d 100644 --- a/src/sage/homology/simplicial_complex_morphism.py +++ b/src/sage/homology/simplicial_complex_morphism.py @@ -114,9 +114,10 @@ from sage.categories.homset import Hom from sage.categories.simplicial_complexes import SimplicialComplexes + def is_SimplicialComplexMorphism(x): """ - Returns ``True`` if and only if ``x`` is a morphism of simplicial complexes. + Return ``True`` if and only if ``x`` is a morphism of simplicial complexes. EXAMPLES:: @@ -129,7 +130,8 @@ def is_SimplicialComplexMorphism(x): True """ - return isinstance(x,SimplicialComplexMorphism) + return isinstance(x, SimplicialComplexMorphism) + class SimplicialComplexMorphism(Morphism): """ @@ -178,7 +180,7 @@ def __init__(self,f,X,Y): def __eq__(self,x): """ - Returns ``True`` if and only if ``self == x``. + Return ``True`` if and only if ``self == x``. EXAMPLES:: @@ -305,7 +307,7 @@ def _repr_defn(self): def associated_chain_complex_morphism(self,base_ring=ZZ,augmented=False,cochain=False): """ - Returns the associated chain complex morphism of ``self``. + Return the associated chain complex morphism of ``self``. EXAMPLES:: @@ -466,7 +468,7 @@ def image(self): def is_surjective(self): """ - Returns ``True`` if and only if ``self`` is surjective. + Return ``True`` if and only if ``self`` is surjective. EXAMPLES:: @@ -493,7 +495,7 @@ def is_surjective(self): def is_injective(self): """ - Returns ``True`` if and only if ``self`` is injective. + Return ``True`` if and only if ``self`` is injective. EXAMPLES:: diff --git a/src/sage/lfunctions/sympow.py b/src/sage/lfunctions/sympow.py index 1640ac4f6a9..b5626a0559e 100644 --- a/src/sage/lfunctions/sympow.py +++ b/src/sage/lfunctions/sympow.py @@ -44,7 +44,7 @@ # # Distributed under the terms of the GNU General Public License (GPL) # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ######################################################################## from __future__ import print_function, absolute_import @@ -54,6 +54,7 @@ from sage.misc.all import pager, verbose import sage.rings.all + class Sympow(SageObject): r""" Watkins Symmetric Power `L`-function Calculator @@ -68,7 +69,7 @@ class Sympow(SageObject): """ def _repr_(self): """ - Returns a string describing this calculator module + Return a string describing this calculator module """ return "Watkins Symmetric Power L-function Calculator" @@ -153,7 +154,6 @@ def L(self, E, n, prec): x = v[i+2:] return x - def Lderivs(self, E, n, prec, d): r""" Return `0^{th}` to `d^{th}` derivatives of diff --git a/src/sage/lfunctions/zero_sums.pyx b/src/sage/lfunctions/zero_sums.pyx index 3a0bb20caa3..1c52870fe71 100644 --- a/src/sage/lfunctions/zero_sums.pyx +++ b/src/sage/lfunctions/zero_sums.pyx @@ -15,7 +15,7 @@ AUTHORS: # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** from sage.structure.sage_object cimport SageObject @@ -1266,7 +1266,8 @@ cdef class LFunctionZeroSum_EllipticCurve(LFunctionZeroSum_abstract): r""" Method called by self._zerosum_sincsquared_parallel() to determine the optimal residue class breakdown when sieving for primes. - Returns a list of small primes, the product thereof, and a list of + + Return a list of small primes, the product thereof, and a list of residues coprime to the product. INPUT: diff --git a/src/sage/matroids/basis_exchange_matroid.pyx b/src/sage/matroids/basis_exchange_matroid.pyx index cf25856d746..fbe7be949ad 100644 --- a/src/sage/matroids/basis_exchange_matroid.pyx +++ b/src/sage/matroids/basis_exchange_matroid.pyx @@ -2183,7 +2183,7 @@ cdef class BasisExchangeMatroid(Matroid): cpdef _isomorphism(self, other): """ - Returns an isomorphism form ``self`` to ``other``, if one exists. + Return an isomorphism form ``self`` to ``other``, if one exists. Internal version that performs no checks on input. @@ -2425,13 +2425,16 @@ cdef class BasisExchangeMatroid(Matroid): pointerX += 1 return True + cdef bint nxksrd(bitset_s* b, long n, long k, bint succ): """ - Next size-k subset of a size-n set in a revolving-door sequence. It will - cycle through all such sets, returning each set exactly once. Each - successive set differs from the last in exactly one element. + Next size-k subset of a size-n set in a revolving-door sequence. + + It will cycle through all such sets, returning each set exactly + once. Each successive set differs from the last in exactly one + element. - Returns ``True`` if there is a next set, ``False`` otherwise. + This returns ``True`` if there is a next set, ``False`` otherwise. """ # next k-subset of n-set in a revolving-door sequence if n == k or k == 0: diff --git a/src/sage/matroids/graphic_matroid.py b/src/sage/matroids/graphic_matroid.py index 95f40b3ae58..acbec4610c2 100644 --- a/src/sage/matroids/graphic_matroid.py +++ b/src/sage/matroids/graphic_matroid.py @@ -78,15 +78,15 @@ ======= """ from __future__ import absolute_import -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2017 Zachary Gershkoff # # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from .matroid import Matroid from sage.graphs.graph import Graph @@ -297,7 +297,7 @@ def _rank(self, X): def _repr_(self): """ - Returns a string representation of the matroid. + Return a string representation of the matroid. EXAMPLES:: diff --git a/src/sage/matroids/utilities.py b/src/sage/matroids/utilities.py index e3011441325..de6efb2c64c 100644 --- a/src/sage/matroids/utilities.py +++ b/src/sage/matroids/utilities.py @@ -403,7 +403,7 @@ def spanning_forest(M): def spanning_stars(M): r""" - Returns the edges of a connected subgraph that is a union of + Return the edges of a connected subgraph that is a union of all edges incident some subset of vertices. INPUT: diff --git a/src/sage/media/wav.py b/src/sage/media/wav.py index 696e468ffa8..3b68644f791 100644 --- a/src/sage/media/wav.py +++ b/src/sage/media/wav.py @@ -24,8 +24,7 @@ - William Stein (2007-07-03): add more - Bobby Moretti (2007-07-03): add doctests """ -from __future__ import print_function -from __future__ import absolute_import +from __future__ import print_function, absolute_import from six.moves import range import math @@ -101,12 +100,12 @@ def save(self, filename='sage.wav'): Save this wave file to disk, either as a Sage sobj or as a .wav file. INPUT: - filename -- the path of the file to save. If filename ends - with 'wav', then save as a wave file, - otherwise, save a Sage object. - If no input is given, save the file as 'sage.wav'. + filename -- the path of the file to save. If filename ends + with 'wav', then save as a wave file, + otherwise, save a Sage object. + If no input is given, save the file as 'sage.wav'. """ if not filename.endswith('.wav'): SageObject.save(self, filename) @@ -139,69 +138,76 @@ def channel_data(self, n): Get the data from a given channel. INPUT: - n -- the channel number to get + + n -- the channel number to get OUTPUT: - A list of signed ints, each containing the value of a frame. + + A list of signed ints, each containing the value of a frame. """ return self._channel_data[n] - def getnchannels(self): """ - Returns the number of channels in this wave object. + Return the number of channels in this wave object. OUTPUT: - The number of channels in this wave file. + + The number of channels in this wave file. """ return self._nchannels def getsampwidth(self): """ - Returns the number of bytes per sample in this wave object. + Return the number of bytes per sample in this wave object. OUTPUT: - The number of bytes in each sample. + + The number of bytes in each sample. """ return self._width def getframerate(self): """ - Returns the number of frames per second in this wave object. + Return the number of frames per second in this wave object. OUTPUT: - The frame rate of this sound file. + + The frame rate of this sound file. """ return self._framerate def getnframes(self): """ - The total number of frames in this wave object. + Return the total number of frames in this wave object. OUTPUT: - The number of frames in this WAV. + + The number of frames in this WAV. """ return self._nframes def readframes(self, n): """ - Reads out the raw data for the first $n$ frames of this wave - object. + Read out the raw data for the first $n$ frames of this wave object. INPUT: - n -- the number of frames to return + + n -- the number of frames to return OUTPUT: - A list of bytes (in string form) representing the raw wav data. + + A list of bytes (in string form) representing the raw wav data. """ return self._bytes[:self._nframes * self._width] def getlength(self): """ - Returns the length of this file (in seconds). + Return the length of this file (in seconds). OUTPUT: - The running time of the entire WAV object. + + The running time of the entire WAV object. """ return float(self._nframes) / (self._nchannels * float(self._framerate)) @@ -322,9 +328,10 @@ def plot_raw(self, npoints=None, channel=0, plotjoined=True, **kwds): def __getitem__(self, i): """ - Returns the `i`-th frame of data in the wave, in the form of a string, + Return the `i`-th frame of data in the wave, in the form of a string, if `i` is an integer. - Returns a slice of self if `i` is a slice. + + Return a slice of self if `i` is a slice. """ if isinstance(i, slice): start, stop, step = i.indices(self._nframes) @@ -335,15 +342,17 @@ def __getitem__(self, i): def slice_seconds(self, start, stop): """ - Slices the wave from start to stop. + Slice the wave from start to stop. INPUT: - start -- the time index from which to begin the slice (in seconds) - stop -- the time index from which to end the slice (in seconds) + + start -- the time index from which to begin the slice (in seconds) + stop -- the time index from which to end the slice (in seconds) OUTPUT: - A Wave object whose data is this object's data, - sliced between the given time indices + + A Wave object whose data is this object's data, + sliced between the given time indices """ start = int(start*self.getframerate()) stop = int(stop*self.getframerate()) @@ -383,5 +392,5 @@ def convolve(self, right, channel=0): i = k.inv_fft() conv = self.__copy__() conv.set_values(list(i)) - conv._name = "convolution of %s and %s"%(self._name, right._name) + conv._name = "convolution of %s and %s" % (self._name, right._name) return conv From cd12412acbcdafaa76d48f45d6f4ddef1c1313ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 17 Nov 2019 13:27:32 +0100 Subject: [PATCH 161/340] findstat doctests --- src/sage/databases/findstat.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sage/databases/findstat.py b/src/sage/databases/findstat.py index 6fcc61b70d5..ef392dc37a8 100644 --- a/src/sage/databases/findstat.py +++ b/src/sage/databases/findstat.py @@ -1414,14 +1414,16 @@ def generating_functions(self, style="polynomial"): sage: st = findstat(18) # optional -- internet sage: st.generating_functions() # optional -- internet - {2: q + 1, + {1: 1, + 2: q + 1, 3: q^3 + 2*q^2 + 2*q + 1, 4: q^6 + 3*q^5 + 5*q^4 + 6*q^3 + 5*q^2 + 3*q + 1, 5: q^10 + 4*q^9 + 9*q^8 + 15*q^7 + 20*q^6 + 22*q^5 + 20*q^4 + 15*q^3 + 9*q^2 + 4*q + 1, 6: q^15 + 5*q^14 + 14*q^13 + 29*q^12 + 49*q^11 + 71*q^10 + 90*q^9 + 101*q^8 + 101*q^7 + 90*q^6 + 71*q^5 + 49*q^4 + 29*q^3 + 14*q^2 + 5*q + 1} sage: st.generating_functions(style="dictionary") # optional -- internet - {2: {0: 1, 1: 1}, + {1: {0: 1}, + 2: {0: 1, 1: 1}, 3: {0: 1, 1: 2, 2: 2, 3: 1}, 4: {0: 1, 1: 3, 2: 5, 3: 6, 4: 5, 5: 3, 6: 1}, 5: {0: 1, 1: 4, 2: 9, 3: 15, 4: 20, 5: 22, 6: 20, 7: 15, 8: 9, 9: 4, 10: 1}, @@ -1443,7 +1445,8 @@ def generating_functions(self, style="polynomial"): 15: 1}} sage: st.generating_functions(style="list") # optional -- internet - {2: [1, 1], + {1: [1], + 2: [1, 1], 3: [1, 2, 2, 1], 4: [1, 3, 5, 6, 5, 3, 1], 5: [1, 4, 9, 15, 20, 22, 20, 15, 9, 4, 1], @@ -1490,11 +1493,11 @@ def oeis_search(self, search_size=32, verbose=True): sage: st = findstat(18) # optional -- internet sage: st.oeis_search() # optional -- internet - Searching the OEIS for "1,1 1,2,2,1 1,3,5,6,5,3,1 1,4,9,15,20,22,20,15,9,4,1 1,5,14,29,49,71,90,101" + Searching the OEIS for "1 1,1 1,2,2,1 1,3,5,6,5,3,1 1,4,9,15,20,22,20,15,9,4,1 1,5,14,29,49,71,90,101" 0: A008302: Triangle of Mahonian numbers T(n,k)... sage: st.oeis_search(search_size=13) # optional -- internet - Searching the OEIS for "1,1 1,2,2,1 1,3,5,6,5,3,1" + Searching the OEIS for "1 1,1 1,2,2,1 1,3,5,6,5,3,1" 0: A008302: Triangle of Mahonian numbers T(n,k)... 1: A115570: Array read by rows: row n (n>= 1) gives the Betti numbers... 2: A187447: Array for all multiset choices... From e4bb884b04dd0ad2ebcbb2db4df72d3eb300ef50 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Sun, 17 Nov 2019 14:22:10 +0100 Subject: [PATCH 162/340] Trac #27784: File renamed + documentation --- src/doc/en/reference/manifolds/diff_vector_bundle.rst | 2 +- .../{char_class.py => characteristic_class.py} | 7 ++++--- src/sage/manifolds/differentiable/vector_bundle.py | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) rename src/sage/manifolds/differentiable/{char_class.py => characteristic_class.py} (99%) diff --git a/src/doc/en/reference/manifolds/diff_vector_bundle.rst b/src/doc/en/reference/manifolds/diff_vector_bundle.rst index d3cb17c9e66..5cfb22dae90 100644 --- a/src/doc/en/reference/manifolds/diff_vector_bundle.rst +++ b/src/doc/en/reference/manifolds/diff_vector_bundle.rst @@ -8,4 +8,4 @@ Differentiable Vector Bundles sage/manifolds/differentiable/bundle_connection - sage/manifolds/differentiable/char_class + sage/manifolds/differentiable/characteristic_class diff --git a/src/sage/manifolds/differentiable/char_class.py b/src/sage/manifolds/differentiable/characteristic_class.py similarity index 99% rename from src/sage/manifolds/differentiable/char_class.py rename to src/sage/manifolds/differentiable/characteristic_class.py index 6d41652717c..43df4824f4e 100644 --- a/src/sage/manifolds/differentiable/char_class.py +++ b/src/sage/manifolds/differentiable/characteristic_class.py @@ -22,7 +22,8 @@ `E` and `\Omega` be the corresponding curvature matrix (see: :meth:`~sage.manifolds.differentiable.bundle_connection.BundleConnection.curvature_form`). -Namely, if `P: \mathfrak{g} \to \CC` is an invariant polynomial, the object +Namely, if `P: \mathrm{Mat}_{n \times n}(\CC) \to \CC` is an invariant +polynomial, the object .. MATH:: @@ -331,7 +332,7 @@ def _get_predefined_class(arg): TESTS:: - sage: from sage.manifolds.differentiable.char_class import _get_predefined_class + sage: from sage.manifolds.differentiable.characteristic_class import _get_predefined_class sage: _get_predefined_class('Chern') ('complex', 'multiplicative', 'c', 'c', x + 1) sage: _get_predefined_class('Pontryagin') @@ -437,7 +438,7 @@ def __init__(self, vbundle, func, class_type='multiplicative', name=None, sage: M = Manifold(3, 'M') sage: TM = M.tangent_bundle() - sage: from sage.manifolds.differentiable.char_class import CharacteristicClass + sage: from sage.manifolds.differentiable.characteristic_class import CharacteristicClass sage: c = CharacteristicClass(TM, 1+x, name='c'); c Characteristic class c of multiplicative type associated to x + 1 on the Tangent bundle TM over the 3-dimensional differentiable diff --git a/src/sage/manifolds/differentiable/vector_bundle.py b/src/sage/manifolds/differentiable/vector_bundle.py index 94479477a6c..1430bf4f906 100644 --- a/src/sage/manifolds/differentiable/vector_bundle.py +++ b/src/sage/manifolds/differentiable/vector_bundle.py @@ -243,12 +243,12 @@ def characteristic_class(self, func, **kwargs): .. SEEALSO:: More examples can be found in - :class:`~sage.manifolds.differentiable.char_class.CharacteristicClass`. + :class:`~sage.manifolds.differentiable.characteristic_class.CharacteristicClass`. """ if self._field_type == 'neither_real_nor_complex': raise ValueError("the vector bundle must be real or complex") - from .char_class import CharacteristicClass, _get_predefined_class + from .characteristic_class import CharacteristicClass, _get_predefined_class # Is func a predefined class? if isinstance(func, str): func_str = func From 18ee6ae805eec42f12ae0a2e241eb79f17059df7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 17 Nov 2019 17:12:15 +0100 Subject: [PATCH 163/340] more fixes for findstat --- src/sage/databases/findstat.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/sage/databases/findstat.py b/src/sage/databases/findstat.py index ef392dc37a8..cb5f9711ac8 100644 --- a/src/sage/databases/findstat.py +++ b/src/sage/databases/findstat.py @@ -803,7 +803,7 @@ def __init__(self, id, first_terms=None, data=None, function=None, code="", sage sage: from sage.databases.findstat import FindStatStatistic sage: FindStatStatistic(1)._find_by_id() # optional -- internet - St000001: The number of ways to write a permutation as a minimal length product of simple transpositions. + St000001: The number of reduced words for a permutation. """ self._depth = depth self._query = None @@ -1493,14 +1493,12 @@ def oeis_search(self, search_size=32, verbose=True): sage: st = findstat(18) # optional -- internet sage: st.oeis_search() # optional -- internet - Searching the OEIS for "1 1,1 1,2,2,1 1,3,5,6,5,3,1 1,4,9,15,20,22,20,15,9,4,1 1,5,14,29,49,71,90,101" + Searching the OEIS for "1 1,1 1,2,2,1 1,3,5,6,5,3,1 1,4,9,15,20,22,20,15,9,4,1 ..." 0: A008302: Triangle of Mahonian numbers T(n,k)... sage: st.oeis_search(search_size=13) # optional -- internet - Searching the OEIS for "1 1,1 1,2,2,1 1,3,5,6,5,3,1" + Searching the OEIS for "1 1,1 1,2,2,1 ..." 0: A008302: Triangle of Mahonian numbers T(n,k)... - 1: A115570: Array read by rows: row n (n>= 1) gives the Betti numbers... - 2: A187447: Array for all multiset choices... """ from sage.databases.oeis import oeis @@ -1542,9 +1540,9 @@ def description(self): EXAMPLES:: sage: print(findstat(1).description()) # optional -- internet - The number of ways to write a permutation as a minimal length product of simple transpositions. + The number of reduced words for a permutation. - That is, the number of reduced words for the permutation. E.g., there are two reduced words for $[3,2,1] = (1,2)(2,3)(1,2) = (2,3)(1,2)(2,3)$. + This is... """ return self._description @@ -1596,7 +1594,7 @@ def name(self): EXAMPLES:: sage: findstat(1).name() # optional -- internet - 'The number of ways to write a permutation as a minimal length product of simple transpositions.' + 'The number of reduced words for a permutation.' """ # this needs to be decided how to do properly if hasattr(self,"_name"): From 3b8a69cf8b533ab373fe2af2612d4cbab345ed8e Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Sun, 17 Nov 2019 17:48:06 +0100 Subject: [PATCH 164/340] 28583: fix unicode_art for mod2 matrices This adjusts the signature of `Matrix_mod2_dense.str` to be the same as the one for `Matrix.str`. For complicated arguments, the former redirects to the latter, so now the same is done for `unicode` as well. --- src/sage/matrix/matrix_mod2_dense.pyx | 50 +++++++++++++++++++++------ 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/src/sage/matrix/matrix_mod2_dense.pyx b/src/sage/matrix/matrix_mod2_dense.pyx index 6212e664576..e8d0823831f 100644 --- a/src/sage/matrix/matrix_mod2_dense.pyx +++ b/src/sage/matrix/matrix_mod2_dense.pyx @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- """ Dense matrices over GF(2) using the M4RI library. @@ -332,28 +333,40 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse return self._zero - def str(self, rep_mapping=None, zero=None, plus_one=None, minus_one=None): + def str(self, rep_mapping=None, zero=None, plus_one=None, minus_one=None, + *, unicode=False, shape=None): r""" Return a nice string representation of the matrix. INPUT: - - ``rep_mapping`` - a dictionary or callable used to override + - ``rep_mapping`` -- a dictionary or callable used to override the usual representation of elements. For a dictionary, keys should be elements of the base ring and values the desired string representation. - - ``zero`` - string (default: ``None``); if not ``None`` use + - ``zero`` -- string (default: ``None``); if not ``None`` use the value of ``zero`` as the representation of the zero element. - - ``plus_one`` - string (default: ``None``); if not ``None`` + - ``plus_one`` -- string (default: ``None``); if not ``None`` use the value of ``plus_one`` as the representation of the one element. - - ``minus_one`` - Ignored. Only for compatibility with + - ``minus_one`` -- Ignored. Only for compatibility with generic matrices. + - ``unicode`` -- boolean (default: ``False``). + Whether to use Unicode symbols instead of ASCII symbols + for brackets and subdivision lines. + + - ``shape`` -- one of ``"square"`` or ``"round"`` (default: ``None``). + Switches between round and square brackets. + The default depends on the setting of the ``unicode`` keyword + argument. For Unicode symbols, the default is round brackets + in accordance with the TeX rendering, + while the ASCII rendering defaults to square brackets. + EXAMPLES:: sage: B = random_matrix(GF(2),3,3) @@ -371,7 +384,28 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse [0 0 0|0 0 0] sage: B.str(zero='.') '[. 1 .]\n[. 1 1]\n[. . .]' + + sage: M = matrix.identity(GF(2), 3) + sage: M.subdivide(None, 2) + sage: print(M.str(unicode=True, shape='square')) + ⎡1 0│0⎤ + ⎢0 1│0⎥ + ⎣0 0│1⎦ + sage: print(unicode_art(M)) # indirect doctest + ⎛1 0│0⎞ + ⎜0 1│0⎟ + ⎝0 0│1⎠ """ + # Set the mapping based on keyword arguments + # We ignore minus_one (it's only there for compatibility with Matrix) + if (rep_mapping is not None or zero is not None or plus_one is not None + or unicode or shape is not None): + # Shunt mappings off to the generic code since they might not be + # single characters + return matrix_dense.Matrix_dense.str(self, rep_mapping=rep_mapping, + zero=zero, plus_one=plus_one, + unicode=unicode, shape=shape) + if self._nrows == 0 or self._ncols == 0: return "[]" @@ -381,12 +415,6 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse cdef char *row_s cdef char *div_s - # Set the mapping based on keyword arguments - # We ignore minus_one (it's only there for compatibility with Matrix) - if rep_mapping is not None or zero is not None or plus_one is not None: - # Shunt mappings off to the generic code since they might not be single characters - return matrix_dense.Matrix_dense.str(self, rep_mapping=rep_mapping, zero=zero, plus_one=plus_one) - cdef list row_div, col_div if self._subdivisions is not None: row_s = empty_row From fccbd81551b5ff8c69f7b9f6c35edbf8424e8c41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 17 Nov 2019 22:13:59 +0100 Subject: [PATCH 165/340] some care for "while len" --- src/sage/algebras/steenrod/steenrod_algebra_bases.py | 6 +++--- src/sage/algebras/steenrod/steenrod_algebra_misc.py | 12 ++++++------ src/sage/doctest/sources.py | 5 +++-- .../arithmetic_dynamics/endPN_automorphism_group.py | 2 +- src/sage/geometry/lattice_polytope.py | 2 +- .../combinatorial_polyhedron/face_iterator.pyx | 2 +- src/sage/graphs/graph_generators.py | 5 +++-- src/sage/graphs/schnyder.py | 4 ++-- src/sage/groups/indexed_free_group.py | 2 +- src/sage/homology/chain_complex.py | 2 +- src/sage/interfaces/ecm.py | 2 +- src/sage/interfaces/frobby.py | 10 +++++----- src/sage/interfaces/qepcad.py | 2 +- src/sage/misc/html.py | 2 +- src/sage/modular/hecke/module.py | 12 +++++------- src/sage/parallel/use_fork.py | 4 ++-- src/sage/rings/number_field/S_unit_solver.py | 2 +- src/sage/rings/padics/padic_ZZ_pX_element.pyx | 8 ++++---- .../padics/polynomial_padic_capped_relative_dense.py | 6 +++--- src/sage/rings/polynomial/polynomial_element.pyx | 2 +- src/sage/schemes/curves/projective_curve.py | 2 +- src/sage/schemes/elliptic_curves/ell_field.py | 10 +++++----- src/sage/schemes/elliptic_curves/ell_point.py | 2 +- 23 files changed, 53 insertions(+), 53 deletions(-) diff --git a/src/sage/algebras/steenrod/steenrod_algebra_bases.py b/src/sage/algebras/steenrod/steenrod_algebra_bases.py index 89a2c090ed8..5df87a0558b 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra_bases.py +++ b/src/sage/algebras/steenrod/steenrod_algebra_bases.py @@ -586,7 +586,7 @@ def milnor_basis(n, p=2, **kwds): if not generic: for mono in WeightedIntegerVectors(n, xi_degrees(n, reverse=False)): exponents = list(mono) - while len(exponents) > 0 and exponents[-1] == 0: + while exponents and exponents[-1] == 0: exponents.pop(-1) # check profile: okay = True @@ -613,9 +613,9 @@ def milnor_basis(n, p=2, **kwds): P_result = [] for mono in WeightedIntegerVectors(dim, xi_degrees(dim, p=p, reverse=False)): p_mono = list(mono) - while len(p_mono) > 0 and p_mono[-1] == 0: + while p_mono and p_mono[-1] == 0: p_mono.pop(-1) - if len(p_mono) > 0: + if p_mono: P_result.append(p_mono) # now find the Q part of the basis element. # dimensions here are back to normal. diff --git a/src/sage/algebras/steenrod/steenrod_algebra_misc.py b/src/sage/algebras/steenrod/steenrod_algebra_misc.py index b85e893da42..3b48511eeda 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra_misc.py +++ b/src/sage/algebras/steenrod/steenrod_algebra_misc.py @@ -479,7 +479,7 @@ def normalize_profile(profile, precision=None, truncation_type='auto', p=2, gene if truncation_type == 'auto': truncation_type = 0 # remove trailing zeroes or Infinitys - while len(profile) > 0 and profile[-1] == truncation_type: + while profile and profile[-1] == truncation_type: profile = profile[:-1] new_profile = tuple(profile) elif isfunction(profile): @@ -494,7 +494,7 @@ def normalize_profile(profile, precision=None, truncation_type='auto', p=2, gene truncation_type = Infinity new_profile = [max(0, profile(i)) for i in range(1, precision)] # remove trailing zeroes or Infinitys: - while len(new_profile) > 0 and new_profile[-1] == truncation_type: + while new_profile and new_profile[-1] == truncation_type: del new_profile[-1] new_profile = tuple(new_profile) if is_valid_profile(new_profile, truncation_type, p): @@ -519,7 +519,7 @@ def normalize_profile(profile, precision=None, truncation_type='auto', p=2, gene if truncation_type == 'auto': truncation_type = 0 # remove trailing terms - while len(e) > 0 and e[-1] == truncation_type: + while e and e[-1] == truncation_type: e = e[:-1] e = tuple(e) elif isfunction(e): @@ -535,7 +535,7 @@ def normalize_profile(profile, precision=None, truncation_type='auto', p=2, gene truncation_type = Infinity e = [max(0, e(i)) for i in range(1, e_precision)] # remove trailing terms - while len(e) > 0 and e[-1] == truncation_type: + while e and e[-1] == truncation_type: del e[-1] e = tuple(e) if isinstance(k, (list, tuple)): @@ -551,10 +551,10 @@ def normalize_profile(profile, precision=None, truncation_type='auto', p=2, gene # Remove trailing ones from k if truncation_type is 'zero', # remove trailing twos if truncation_type is 'Infinity'. if truncation_type == 0: - while len(k) > 0 and k[-1] == 1: + while k and k[-1] == 1: k = k[:-1] else: - while len(k) > 0 and k[-1] == 2: + while k and k[-1] == 2: k = k[:-1] new_profile = (e, k) if is_valid_profile(new_profile, truncation_type, p, generic=True): diff --git a/src/sage/doctest/sources.py b/src/sage/doctest/sources.py index b9d2268de84..13e15901c6f 100644 --- a/src/sage/doctest/sources.py +++ b/src/sage/doctest/sources.py @@ -342,13 +342,14 @@ def _create_doctests(self, namespace, tab_okay=None): # we want to randomize even when self.randorder = 0 random.seed(self.options.randorder) randomized = [] - while len(doctests) > 0: - i = random.randint(0, len(doctests)-1) + while doctests: + i = random.randint(0, len(doctests) - 1) randomized.append(doctests.pop(i)) return randomized, extras else: return doctests, extras + class StringDocTestSource(DocTestSource): r""" This class creates doctests from a string. diff --git a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py index c139a91f1da..ddd95c45b24 100644 --- a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +++ b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py @@ -1653,7 +1653,7 @@ def automorphism_group_FF_alg3(rational_function): # case of a pair of F-rational period 2 points linear_period_2_pairs = [] - while len(linear_period_2_pts) > 0: + while linear_period_2_pts: x = linear_period_2_pts.pop(-1) if x[1] == 1 and g(x[0]) != 0: y = [phi(x[0]), F(1)] diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index 6f20643a589..f5f55efd422 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -1202,7 +1202,7 @@ def _read_nef_partitions(self, data): if line == "": raise ValueError("more data expected!") partitions = Sequence([], cr=True) - while len(line) > 0 and line.find("np=") == -1: + while line and line.find("np=") == -1: if line.find("V:") == -1: line = data.readline() continue diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx index 339747d5c64..dc981f7f34d 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx @@ -340,7 +340,7 @@ cdef class FaceIterator(SageObject): # Assumes ``visited_all`` to be some list of faces of # a polyhedron `P_2`, which contains `P` as one of its faces. - while len(facets) > 0: + while facets: one_face = faces.pop() maybe_newfaces = [one_face.intersection(face) for face in faces] diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index 8d20c952777..992b86d7dff 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -2352,7 +2352,7 @@ def check_aut(aut_gens, cut_vert, n): perm = list(range(n + 1)) seen_perms = [perm] unchecked_perms = [perm] - while len(unchecked_perms) != 0: + while unchecked_perms: perm = unchecked_perms.pop(0) for gen in aut_gens: new_perm = copy(perm) @@ -2364,6 +2364,7 @@ def check_aut(aut_gens, cut_vert, n): if new_perm[cut_vert] == n: yield new_perm + def canaug_traverse_edge(g, aut_gens, property, dig=False, loops=False, sparse=True): """ Main function for exhaustive generation. Recursive traversal of a @@ -2556,7 +2557,7 @@ def check_aut_edge(aut_gens, cut_edge, i, j, n, dig=False): perm = list(range(n)) seen_perms = [perm] unchecked_perms = [perm] - while len(unchecked_perms) != 0: + while unchecked_perms): perm = unchecked_perms.pop(0) for gen in aut_gens: new_perm = copy(perm) diff --git a/src/sage/graphs/schnyder.py b/src/sage/graphs/schnyder.py index dc11b61e4d4..241288a4de7 100644 --- a/src/sage/graphs/schnyder.py +++ b/src/sage/graphs/schnyder.py @@ -223,7 +223,7 @@ def _normal_label(g, comb_emb, external_face): labels[v2] = {(v1, v3): 2} labels[v3] = {(v1, v2): 3} - while len(contracted): + while contracted: v, new_neighbors, neighbors_to_delete = contracted.pop() # going to add back vertex v labels[v] = {} @@ -267,7 +267,7 @@ def _normal_label(g, comb_emb, external_face): angle_set = Set(angles_out_of_v1) vertices_in_order.append(l[i]) - while len(angles_out_of_v1) > 0: + while angles_out_of_v1: for angle in angles_out_of_v1: if vertices_in_order[-1] in angle: break diff --git a/src/sage/groups/indexed_free_group.py b/src/sage/groups/indexed_free_group.py index 48ec4adfd26..0d8736f3411 100644 --- a/src/sage/groups/indexed_free_group.py +++ b/src/sage/groups/indexed_free_group.py @@ -256,7 +256,7 @@ def _mul_(self, other): ret = list(self._monomial) rhs = list(other._monomial) - while len(ret) > 0 and len(rhs) > 0 and ret[-1][0] == rhs[0][0]: + while ret and rhs and ret[-1][0] == rhs[0][0]: rhs[0] = (rhs[0][0], rhs[0][1] + ret.pop()[1]) if rhs[0][1] == 0: rhs.pop(0) diff --git a/src/sage/homology/chain_complex.py b/src/sage/homology/chain_complex.py index 3d0591ac28f..001510d5e31 100644 --- a/src/sage/homology/chain_complex.py +++ b/src/sage/homology/chain_complex.py @@ -875,7 +875,7 @@ def ordered_degrees(self, start=None, exclude_first=False): if start is None: result = [] degrees = set(self._diff) - while len(degrees) > 0: + while degrees: ordered = self.ordered_degrees(degrees.pop()) degrees.difference_update(ordered) if exclude_first: diff --git a/src/sage/interfaces/ecm.py b/src/sage/interfaces/ecm.py index 9a0998af81b..3420714f8c6 100644 --- a/src/sage/interfaces/ecm.py +++ b/src/sage/interfaces/ecm.py @@ -627,7 +627,7 @@ def factor(self, n, factor_digits=None, B1=2000, proof=False, **kwds): n = self._validate(n) factors = [n] # factors that need to be factorized futher probable_prime_factors = [] # output prime factors - while len(factors) > 0: + while factors: n = factors.pop() # Step 0: Primality test diff --git a/src/sage/interfaces/frobby.py b/src/sage/interfaces/frobby.py index 2cb59b9491a..3eeb2bd28aa 100644 --- a/src/sage/interfaces/frobby.py +++ b/src/sage/interfaces/frobby.py @@ -316,12 +316,12 @@ def _parse_ideals(self, string, ring): Ideal (x*y^2*z^3, x^4*y^5*z^6) of Multivariate Polynomial Ring in x, y, z over Rational Field] """ - lines=string.split('\n') - if lines[-1]=='': + lines = string.split('\n') + if lines[-1] == '': lines.pop(-1) - matrices=[] - while len(lines)>0: - if lines[0].split()[1]=='ring': + matrices = [] + while lines: + if lines[0].split()[1] == 'ring': lines.pop(0) lines.pop(0) matrices.append('1 '+str(ring.ngens())+'\n'+'0 '*ring.ngens()+'\n') diff --git a/src/sage/interfaces/qepcad.py b/src/sage/interfaces/qepcad.py index ffa2d663acd..27954985561 100644 --- a/src/sage/interfaces/qepcad.py +++ b/src/sage/interfaces/qepcad.py @@ -690,7 +690,7 @@ def _update_command_info(): while True: cmd_line = help.readline() - while len(cmd_line.strip()) == 0: + while not cmd_line.strip(): cmd_line = help.readline() cmd_line = cmd_line.strip() if cmd_line == '@@@': diff --git a/src/sage/misc/html.py b/src/sage/misc/html.py index e0bee618e2c..e1b39432628 100644 --- a/src/sage/misc/html.py +++ b/src/sage/misc/html.py @@ -259,7 +259,7 @@ def eval(self, s, locals=None): s = str(s) s = math_parse(s) t = '' - while len(s) > 0: + while s: i = s.find('') if i == -1: t += s diff --git a/src/sage/modular/hecke/module.py b/src/sage/modular/hecke/module.py index 5b8914201a5..389ee3616c0 100644 --- a/src/sage/modular/hecke/module.py +++ b/src/sage/modular/hecke/module.py @@ -1014,19 +1014,17 @@ def decomposition(self, bound=None, anemic=True, height_guess=1, sort_by_basis = D = Sequence([], cr=True) U = [self.free_module()] p = 2 - while len(U) > 0 and p <= bound: - misc.verbose(mesg="p=%s"%p,t=time) + while U and p <= bound: + misc.verbose(mesg="p=%s" % p, t=time) if anemic: while arith.GCD(p, self.level()) != 1: p = arith.next_prime(p) - misc.verbose("Decomposition using p=%s"%p) + misc.verbose("Decomposition using p=%s" % p) t = T.hecke_operator(p).matrix() Uprime = [] for i in range(len(U)): - if self.base_ring().characteristic() == 0 and self.level()%p != 0: - is_diagonalizable = True - else: - is_diagonalizable = False + is_diagonalizable = (not self.base_ring().characteristic() and + self.level() % p) if is_rational: X = t.decomposition_of_subspace(U[i], check_restrict = False, algorithm='multimodular', diff --git a/src/sage/parallel/use_fork.py b/src/sage/parallel/use_fork.py index c3b5e59fe02..02b5cdb5be5 100644 --- a/src/sage/parallel/use_fork.py +++ b/src/sage/parallel/use_fork.py @@ -163,9 +163,9 @@ def __call__(self, f, inputs): workers = {} try: - while len(v) > 0 or len(workers) > 0: + while v or workers: # Spawn up to n subprocesses - while len(v) > 0 and len(workers) < n: + while v and len(workers) < n: v0 = v.pop(0) # Input value for the next subprocess with ContainChildren(): pid = os.fork() diff --git a/src/sage/rings/number_field/S_unit_solver.py b/src/sage/rings/number_field/S_unit_solver.py index ad5d3518493..7612ed0ddc0 100644 --- a/src/sage/rings/number_field/S_unit_solver.py +++ b/src/sage/rings/number_field/S_unit_solver.py @@ -2408,7 +2408,7 @@ def sieve_below_bound(K, S, bound = 10, bump = 10, split_primes_list=[], verbose SUK = UnitGroup(K, S=tuple(S)) initial_bound = bound - while len(split_primes_list) == 0: + while not split_primes_list: try: split_primes_list = split_primes_large_lcm(SUK, initial_bound) except ValueError: diff --git a/src/sage/rings/padics/padic_ZZ_pX_element.pyx b/src/sage/rings/padics/padic_ZZ_pX_element.pyx index 30bc44e0ea7..30b88162946 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_element.pyx +++ b/src/sage/rings/padics/padic_ZZ_pX_element.pyx @@ -300,7 +300,7 @@ cdef class pAdicZZpXElement(pAdicExtElement): else: ans[j].append(zero) for j from 0 <= j < prec: - while len(ans[j]) > 0: + while ans[j]: if ans[j][-1] == 0: ans[j].pop() else: @@ -331,19 +331,19 @@ cdef class pAdicZZpXElement(pAdicExtElement): break self.prime_pow.eis_shift(&shifter, &shifter, self.prime_pow.e, self.prime_pow.capdiv(prec - i)) zerotest = 0 - while len(ans) > 0: + while ans: if ans[-1] == zerotest: ans.pop() else: break - while len(ans) > 0: + while ans: if ans[0] == zerotest: ans.pop(0) else: break return ans - def norm(self, base = None): + def norm(self, base=None): """ Return the absolute or relative norm of this element. diff --git a/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py b/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py index 82690516b2b..ed0aae2134d 100644 --- a/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py +++ b/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py @@ -217,9 +217,9 @@ def _comp_list(self): self._list = [] polylist = self._poly.list() polylen = len(polylist) - self._list = [self.base_ring()(polylist[i], absprec = self._relprecs[i]) << self._valbase for i in range(polylen)] \ - + [self.base_ring()(0, absprec = self._relprecs[i] + self._valbase) for i in range(polylen, len(self._relprecs))] - while len(self._list) > 0 and self._list[-1]._is_exact_zero(): + self._list = [self.base_ring()(polylist[i], absprec=self._relprecs[i]) << self._valbase for i in range(polylen)] \ + + [self.base_ring()(0, absprec=self._relprecs[i] + self._valbase) for i in range(polylen, len(self._relprecs))] + while self._list and self._list[-1]._is_exact_zero(): self._list.pop() def _comp_valaddeds(self): diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 60c924c5482..fd88dffcae0 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -5908,7 +5908,7 @@ cdef class Polynomial(CommutativeAlgebraElement): for i in range(2, len(e)): v = c[i].valuation(p) s = -(v-points[-1][1])/(e[i]-points[-1][0]) - while len(slopes) > 0 and s >= slopes[-1][0]: + while slopes and s >= slopes[-1][0]: slopes = slopes[:-1] points = points[:-1] s = -(v-points[-1][1])/(e[i]-points[-1][0]) diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 49d11e9581c..b5bd3c8c3ea 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -1373,7 +1373,7 @@ def extension(self): pts = C.singular_points() H = End(C) phi = H(list(C.ambient_space().gens())) - while len(pts) > 0: + while pts: for i in range(len(pts) - 1, -1, -1): try: if C.is_ordinary_singularity(pts[i]): diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index 81894594ff8..2d441957d33 100644 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -136,13 +136,13 @@ def quadratic_twist(self, D=None): sage: E.change_ring(k2).is_isomorphic(Et.change_ring(k2)) True """ - K=self.base_ring() - char=K.characteristic() + K = self.base_ring() + char = K.characteristic() if D is None: if K.is_finite(): x = rings.polygen(K) - if char==2: + if char == 2: # We find D such that x^2+x+D is irreducible. If the # degree is odd we can take D=1; otherwise it suffices to # consider odd powers of a generator. @@ -150,14 +150,14 @@ def quadratic_twist(self, D=None): if K.degree()%2==0: D = K.gen() a = D**2 - while len((x**2+x+D).roots())>0: + while (x**2 + x + D).roots(): D *= a else: # We could take a multiplicative generator but # that might be expensive to compute; otherwise # half the elements will do D = K.random_element() - while len((x**2-D).roots())>0: + while (x**2 - D).roots(): D = K.random_element() else: raise ValueError("twisting parameter D must be specified over infinite fields.") diff --git a/src/sage/schemes/elliptic_curves/ell_point.py b/src/sage/schemes/elliptic_curves/ell_point.py index bc5ca5df699..da3fc60a761 100644 --- a/src/sage/schemes/elliptic_curves/ell_point.py +++ b/src/sage/schemes/elliptic_curves/ell_point.py @@ -1161,7 +1161,7 @@ def _divide_out(self, p): k = 0 Q = self pts = Q.division_points(p) - while len(pts) > 0: + while pts: Q = pts[0] k += 1 pts = Q.division_points(p) From c4279399bd1ab554e32db1715dd994188f1a9c4a Mon Sep 17 00:00:00 2001 From: Benjamin Hutz Date: Sun, 17 Nov 2019 16:17:59 -0600 Subject: [PATCH 166/340] 28213: minor changes from review typos fixing more doctests added --- .../arithmetic_dynamics/projective_ds.py | 95 +++++++++++++++---- 1 file changed, 76 insertions(+), 19 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index bedb550460c..046ac6451b4 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -3367,8 +3367,8 @@ def preperiodic_points(self, m, n, **kwds): :: - sage: w = QQ['w'].0 - sage: K = NumberField(w^6 - 3*w^5 + 5*w^4 - 5*w^3 + 5*w^2 - 3*w + 1,'s') + sage: R. = QQ[] + sage: K. = NumberField(w^6 - 3*w^5 + 5*w^4 - 5*w^3 + 5*w^2 - 3*w + 1) sage: P. = ProjectiveSpace(K,2) sage: f = DynamicalSystem_projective([x^2+z^2, y^2+x^2, z^2+y^2]) sage: f.preperiodic_points(0,1) @@ -3380,15 +3380,6 @@ def preperiodic_points(self, m, n, **kwds): (1 : 1 : 1), (s^5 - 2*s^4 + 2*s^3 + s : s^5 - 3*s^4 + 4*s^3 - 3*s^2 + 2*s - 1 : 1)] - :: - - sage: P. = ProjectiveSpace(QQ, 2) - sage: f = DynamicalSystem_projective([x^2, x*y, z^2]) - sage: f.preperiodic_points(2,1) - Traceback (most recent call last): - ... - TypeError: use return_scheme=True - :: sage: P. = ProjectiveSpace(QQ,1) @@ -3405,7 +3396,74 @@ def preperiodic_points(self, m, n, **kwds): sage: f = DynamicalSystem_projective([x^2-y^2, 2*(x^2-y^2), y^2-z^2], domain=X) sage: f.preperiodic_points(1,1) [(-1/4 : -1/2 : 1), (1 : 2 : 1)] + + :: + + sage: P. = ProjectiveSpace(GF(5), 2) + sage: f = DynamicalSystem_projective([x^2, y^2, z^2]) + sage: sorted(f.preperiodic_points(2,1)) + [(0 : 2 : 1), + (0 : 3 : 1), + (1 : 2 : 1), + (1 : 3 : 1), + (2 : 0 : 1), + (2 : 1 : 0), + (2 : 1 : 1), + (2 : 2 : 1), + (2 : 3 : 1), + (2 : 4 : 1), + (3 : 0 : 1), + (3 : 1 : 0), + (3 : 1 : 1), + (3 : 2 : 1), + (3 : 3 : 1), + (3 : 4 : 1), + (4 : 2 : 1), + (4 : 3 : 1)] + + :: + + sage: P. = ProjectiveSpace(GF(5), 2) + sage: f = DynamicalSystem_projective([x^2, x*y, z^2]) + sage: f.preperiodic_points(2,1, return_scheme=True) + Closed subscheme of Projective Space of dimension 2 over Finite Field of size 5 defined by: + 0, + x^8*z^4 - x^4*z^8, + x^7*y*z^4 - x^3*y*z^8 + + :: + + sage: P. = ProjectiveSpace(QQ, 1) + sage: R. = QQ[] + sage: K. = NumberField(z^4 - z^2 - 1) + sage: f = DynamicalSystem_projective([x^2 - y^2, y^2]) + sage: f.preperiodic_points(2, 1, R=K) + [(v : 1), (-v : 1)] + + TESTS:: + + sage: P. = ProjectiveSpace(QQ, 2) + sage: f = DynamicalSystem_projective([x^2, x*y, z^2]) + sage: f.preperiodic_points(2,1) + Traceback (most recent call last): + ... + TypeError: use return_scheme=True + + :: + + sage: P. = ProjectiveSpace(QQ,1) + sage: f = DynamicalSystem_projective([x^2-29/16*y^2, y^2]) + sage: f.preperiodic_points(1.2,3) + Traceback (most recent call last): + ... + TypeError: Attempt to coerce non-integral RealNumber to Integer + sage: f.preperiodic_points(1,3.1) + Traceback (most recent call last): + ... + TypeError: Attempt to coerce non-integral RealNumber to Integer """ + n = ZZ(n) + m = ZZ(m) if n <= 0: raise ValueError("a positive integer period must be specified") if m < 0: @@ -3437,9 +3495,8 @@ def preperiodic_points(self, m, n, **kwds): points = [dom(Q) for Q in X.rational_points()] good_points = [] for Q in points: - try: - Z(list(Q)) - except TypeError: + #check if point is in indeterminacy + if not all([F(list(Q)) == 0 for F in f]): good_points.append(Q) points = good_points if not minimal: @@ -3450,8 +3507,8 @@ def preperiodic_points(self, m, n, **kwds): #that only includes the points with minimal period minimal_points = [] for P in points: - orbit = [dom(P)] - Q = f(dom(P)) + orbit = [P] + Q = f(P) n_plus_m = 1 while not Q in orbit: orbit.append(Q) @@ -4878,9 +4935,9 @@ def all_periodic_points(self, **kwds): (3/2 : -1/2 : 3/2 : 1), (3/2 : 3/2 : -1/2 : 1), (3/2 : 3/2 : 3/2 : 1)] - + :: - + sage: P. = ProjectiveSpace(QQ, 3) sage: f = DynamicalSystem_projective([x^2 - (3/4)*w^2, y^2 - 3/4*w^2, z^2 - 3/4*w^2, w^2]) sage: sorted(f.all_periodic_points(period_degree_bounds=[10,10])) @@ -4899,7 +4956,7 @@ def all_periodic_points(self, **kwds): (3/2 : -1/2 : 3/2 : 1), (3/2 : 3/2 : -1/2 : 1), (3/2 : 3/2 : 3/2 : 1)] - + TESTS:: sage: P. = ProjectiveSpace(QQ, 1) From 6635fad2f2c51e5b8e99ea4da98e6b9cd26b020c Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Mon, 18 Nov 2019 00:08:18 +0100 Subject: [PATCH 167/340] Construction of a local frame on a vector bundle from a family of sections --- src/sage/manifolds/differentiable/manifold.py | 10 ++- src/sage/manifolds/vector_bundle.py | 83 ++++++++++++++----- 2 files changed, 71 insertions(+), 22 deletions(-) diff --git a/src/sage/manifolds/differentiable/manifold.py b/src/sage/manifolds/differentiable/manifold.py index 2d3c38d9abc..7f90f4a62e2 100644 --- a/src/sage/manifolds/differentiable/manifold.py +++ b/src/sage/manifolds/differentiable/manifold.py @@ -2894,8 +2894,8 @@ def vector_frame(self, *args, **kwargs): True It is also possible to create a vector frame from scratch, without - any connection with previously defined vector frames or vector fields - (the connection can be performed later via the method + connecting it to previously defined vector frames or vector fields + (this can still be performed later via the method :meth:`~sage.manifolds.differentiable.manifold.DifferentiableManifold.set_change_of_frame`):: sage: f = M.vector_frame('f'); f @@ -2956,9 +2956,13 @@ def vector_frame(self, *args, **kwargs): latex_indices=latex_indices, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) if vector_fields: + linked = False try: resu._init_from_family(vector_fields) - except ZeroDivisionError: + except ArithmeticError as err: + linked = str(err) in ["non-invertible matrix", + "input matrix must be nonsingular"] + if linked: raise ValueError("the provided vector fields are not " "linearly independent") # Adding the newly generated changes of frame to the diff --git a/src/sage/manifolds/vector_bundle.py b/src/sage/manifolds/vector_bundle.py index c2822494eea..c33026096fd 100644 --- a/src/sage/manifolds/vector_bundle.py +++ b/src/sage/manifolds/vector_bundle.py @@ -692,9 +692,7 @@ def fiber(self, point): """ return VectorBundleFiber(self, point) - def local_frame(self, symbol, latex_symbol=None, indices=None, - latex_indices=None, symbol_dual=None, - latex_symbol_dual=None, domain=None): + def local_frame(self, *args, **kwargs): r""" Define a local frame on ``self``. @@ -709,11 +707,12 @@ def local_frame(self, symbol, latex_symbol=None, indices=None, INPUT: - - ``symbol`` -- (default: ``None``) either a string, to be used as a - common base for the symbols of the sections constituting the - local frame, or a list/tuple of strings, representing the individual - symbols of the sections; can be ``None`` only if ``from_frame`` - is not ``None`` (see below) + - ``symbol`` -- either a string, to be used as a common base for the + symbols of the sections constituting the local frame, or a list/tuple + of strings, representing the individual symbols of the sections + - ``sections`` -- tuple or list of `n` linearly independent sections on + ``self`` (`n` being the dimension of ``self``) defining the local + frame; can be omitted if the local frame is created from scratch - ``latex_symbol`` -- (default: ``None``) either a string, to be used as a common base for the LaTeX symbols of the sections constituting the local frame, or a list/tuple of strings, @@ -742,37 +741,83 @@ def local_frame(self, symbol, latex_symbol=None, indices=None, EXAMPLES: - Setting a local frame on a real rank-2 vector bundle:: + + Defining a local frame from two linearly independent sections on a + real rank-2 vector bundle:: sage: M = Manifold(3, 'M', structure='top') sage: U = M.open_subset('U') + sage: X. = U.chart() sage: E = M.vector_bundle(2, 'E') - sage: e = E.local_frame('e', domain=U); e + sage: phi = E.trivialization('phi', domain=U) + sage: s0 = E.section(name='s_0', domain=U) + sage: s0[:] = 1+z^2, -2 + sage: s1 = E.section(name='s_1', domain=U) + sage: s1[:] = 1, 1+x^2 + sage: e = E.local_frame('e', (s0, s1), domain=U); e Local frame (E|_U, (e_0,e_1)) + sage: (e[0], e[1]) == (s0, s1) + True + + If the sections are not linearly independent, an error is raised:: + + sage: e = E.local_frame('z', (s0, -s0), domain=U) + Traceback (most recent call last): + ... + ValueError: the provided sections are not linearly independent + + It is also possible to create a local frame from scratch, without + connecting it to previously defined local frames or sections + (this can still be performed later via the method + :meth:`set_change_of_frame`):: + + sage: f = E.local_frame('f', domain=U); f + Local frame (E|_U, (f_0,f_1)) For a global frame, the argument ``domain`` is omitted:: - sage: f = E.local_frame('f'); f - Local frame (E|_M, (f_0,f_1)) + sage: g = E.local_frame('g'); g + Local frame (E|_M, (g_0,g_1)) .. SEEALSO:: For more options, in particular for the choice of symbols and indices, see :class:`~sage.manifolds.local_frame.LocalFrame`. - .. TODO:: - - Allow construction of a local frame from a family of local - sections, in a way similar to - :meth:`~sage.manifolds.differentiable.manifold.DifferentiableManifold.vector_frame` - """ from sage.manifolds.local_frame import LocalFrame + # Input processing + n_args = len(args) + if n_args < 1 or n_args > 2: + raise TypeError("local_frame() takes one or two positional " + "arguments, not {}".format(n_args)) + symbol = args[0] + sections = None + if n_args == 2: + sections = args[1] + latex_symbol = kwargs.pop('latex_symbol', None) + indices = kwargs.pop('indices', None) + latex_indices = kwargs.pop('latex_indices', None) + symbol_dual = kwargs.pop('symbol_dual', None) + latex_symbol_dual = kwargs.pop('latex_symbol_dual', None) + domain = kwargs.pop('domain', None) + # sec_module = self.section_module(domain=domain, force_free=True) - return LocalFrame(sec_module, symbol=symbol, latex_symbol=latex_symbol, + resu = LocalFrame(sec_module, symbol=symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) + if sections: + linked = False + try: + resu._init_from_family(sections) + except ArithmeticError as err: + linked = str(err) in ["non-invertible matrix", + "input matrix must be nonsingular"] + if linked: + raise ValueError("the provided sections are not linearly " + "independent") + return resu def section(self, *comp, **kwargs): r""" From 3d0aed69b74f580725a0504363613107407c77f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 18 Nov 2019 13:49:57 +0100 Subject: [PATCH 168/340] fix --- src/sage/graphs/graph_generators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index 992b86d7dff..3e1a600181d 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -2557,7 +2557,7 @@ def check_aut_edge(aut_gens, cut_edge, i, j, n, dig=False): perm = list(range(n)) seen_perms = [perm] unchecked_perms = [perm] - while unchecked_perms): + while unchecked_perms: perm = unchecked_perms.pop(0) for gen in aut_gens: new_perm = copy(perm) From b510b32c17cc3fc8811d6318c4bc6b016524309d Mon Sep 17 00:00:00 2001 From: Benjamin Hutz Date: Mon, 18 Nov 2019 09:53:23 -0600 Subject: [PATCH 169/340] 28213: add algorithm parameters to preperiodic --- .../arithmetic_dynamics/projective_ds.py | 55 ++++++++++--------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 046ac6451b4..735966e37ea 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -4832,20 +4832,21 @@ def all_periodic_points(self, **kwds): INPUT: kwds: - + - ``R`` -- (default: domain of dynamical system) the base ring over which the periodic points of the dynamical system are found - + - ``prime_bound`` -- (default: ``[1,20]``) a pair (list or tuple) of positive integers that represent the limits of primes to use in the reduction step or an integer that represents the upper bound - ``lifting_prime`` -- (default: 23) a prime integer; argument that specifies modulo which prime to try and perform the lifting - + - ``period_degree_bounds`` -- (default: ``[4,4]``) a pair of positive integers - (max period, max degree) for which the dynatomic polynomial should be solved for - + (max period, max degree) for which the dynatomic polynomial should be solved + for when in dimension 1 + - ``algorithm`` -- (optional) specifies which algorithm to use; current options are `dynatomic` and `lifting`; defaults to solving the dynatomic for low periods and degrees and lifts for everything else @@ -4938,24 +4939,10 @@ def all_periodic_points(self, **kwds): :: - sage: P. = ProjectiveSpace(QQ, 3) - sage: f = DynamicalSystem_projective([x^2 - (3/4)*w^2, y^2 - 3/4*w^2, z^2 - 3/4*w^2, w^2]) - sage: sorted(f.all_periodic_points(period_degree_bounds=[10,10])) - [(-1/2 : -1/2 : -1/2 : 1), - (-1/2 : -1/2 : 3/2 : 1), - (-1/2 : 3/2 : -1/2 : 1), - (-1/2 : 3/2 : 3/2 : 1), - (0 : 0 : 1 : 0), - (0 : 1 : 0 : 0), - (0 : 1 : 1 : 0), - (1 : 0 : 0 : 0), - (1 : 0 : 1 : 0), - (1 : 1 : 0 : 0), - (1 : 1 : 1 : 0), - (3/2 : -1/2 : -1/2 : 1), - (3/2 : -1/2 : 3/2 : 1), - (3/2 : 3/2 : -1/2 : 1), - (3/2 : 3/2 : 3/2 : 1)] + sage: P. = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem_projective([x^2 - 3/4*y^2, y^2]) + sage: sorted(f.all_periodic_points(period_degree_bounds=[2,2])) + [(-1/2 : 1), (1 : 0), (3/2 : 1)] TESTS:: @@ -5053,10 +5040,12 @@ def all_periodic_points(self, **kwds): periods = DS.possible_periods(prime_bound=primebound, bad_primes=badprimes, ncpus=num_cpus) PS = DS.domain() periodic = set() + N = PS.ambient_space().dimension_relative() if alg != 'lifting': for i in periods[:]: - if (alg == 'dynatomic') or (i <= pd_bounds[0] and DS.degree() <= pd_bounds[1]): + if (alg == 'dynatomic') or ((N == 1) \ + and i <= pd_bounds[0] and DS.degree() <= pd_bounds[1]): periodic.update(DS.periodic_points(i)) periods.remove(i) if not periods: @@ -5274,6 +5263,14 @@ def rational_preperiodic_points(self, **kwds): - ``ncpus`` -- (default: all cpus) number of cpus to use in parallel + - ``period_degree_bounds`` -- (default: ``[4,4]``) a pair of positive integers + (max period, max degree) for which the dynatomic polynomial should be solved + for when in dimension 1 + + - ``algorithm`` -- (optional) specifies which algorithm to use; + current options are `dynatomic` and `lifting`; defaults to solving the + dynatomic for low periods and degrees and lifts for everything else + OUTPUT: a list of rational points in projective space EXAMPLES:: @@ -5337,6 +5334,14 @@ def all_preperiodic_points(self, **kwds): - ``ncpus`` -- (default: all cpus) number of cpus to use in parallel + - ``period_degree_bounds`` -- (default: ``[4,4]``) a pair of positive integers + (max period, max degree) for which the dynatomic polynomial should be solved + for when in dimension 1 + + - ``algorithm`` -- (optional) specifies which algorithm to use; + current options are `dynatomic` and `lifting`; defaults to solving the + dynatomic for low periods and degrees and lifts for everything else + OUTPUT: a list of rational points in projective space EXAMPLES:: @@ -5452,7 +5457,7 @@ def all_preperiodic_points(self, **kwds): #find the rational preperiodic points T = DS.all_periodic_points(prime_bound=primebound, lifting_prime=p, periods=periods, bad_primes=badprimes, - ncpus=num_cpus) + ncpus=num_cpus, **kwds) preper = DS.all_rational_preimages(T) #find the preperiodic points preper = list(preper) return preper From 5c6d5fb9b8702850de160bf6e11f29aaf3d2cc0e Mon Sep 17 00:00:00 2001 From: dcoudert Date: Mon, 18 Nov 2019 17:53:30 +0100 Subject: [PATCH 170/340] trac #28756: fix failing doctests and compilation warnings --- .../numerical/backends/gurobi_backend.pyx | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/sage/numerical/backends/gurobi_backend.pyx b/src/sage/numerical/backends/gurobi_backend.pyx index fe98d7a5f90..c3863629366 100644 --- a/src/sage/numerical/backends/gurobi_backend.pyx +++ b/src/sage/numerical/backends/gurobi_backend.pyx @@ -168,7 +168,8 @@ cdef class GurobiBackend(GenericBackend): if name is None: name = b"x_" + bytes(self.ncols()) - + else: + name = str_to_bytes(name) c_name = name if upper_bound is None: @@ -182,6 +183,7 @@ cdef class GurobiBackend(GenericBackend): if coefficients is not None: + coefficients = list(coefficients) nonzeros = len(coefficients) c_indices = sig_malloc(nonzeros * sizeof(int)) c_coeff = sig_malloc(nonzeros * sizeof(double)) @@ -518,7 +520,7 @@ cdef class GurobiBackend(GenericBackend): """ if lower_bound is None and upper_bound is None: - raise ValueError("At least one of 'upper_bound' or 'lower_bound' must be set.") + raise ValueError("at least one of 'upper_bound' or 'lower_bound' must be set") coefficients = list(coefficients) cdef int n = len(coefficients) @@ -549,6 +551,10 @@ cdef class GurobiBackend(GenericBackend): else: error = GRBaddrangeconstr(self.model, n, row_i, row_values, lower_bound, upper_bound, str_to_bytes(name)) + else: + # This case is repeated here to avoid compilation warnings + raise ValueError("at least one of 'upper_bound' or 'lower_bound' must be set") + check(self.env,error) error = GRBupdatemodel(self.model) @@ -850,7 +856,7 @@ cdef class GurobiBackend(GenericBackend): if name[0] == NULL: value = "" else: - value = str(name[0]) + value = char_to_str(name[0]) return value cpdef row_name(self, int index): @@ -874,7 +880,7 @@ cdef class GurobiBackend(GenericBackend): if name[0] == NULL: value = "" else: - value = str(name[0]) + value = char_to_str(name[0]) return value cpdef bint is_variable_binary(self, int index): @@ -1152,6 +1158,8 @@ cdef class GurobiBackend(GenericBackend): raise ValueError("This parameter is not available. "+ "Enabling it may not be so hard, though.") + name = str_to_bytes(name) + if t == "int": if value is None: check(self.env, GRBgetintparam(self.env, name, tmp_int)) @@ -1167,9 +1175,9 @@ cdef class GurobiBackend(GenericBackend): elif t == "string": if value is None: check(self.env, GRBgetstrparam(self.env, name, c_name)) - return str(c_name) + return char_to_str(c_name) else: - check(self.env, GRBsetstrparam(self.env, name, value)) + check(self.env, GRBsetstrparam(self.env, name, str_to_bytes(value))) else: raise RuntimeError("This should not happen.") From 7acef4ca2f3744bdb0c78770b5013553fecaf0eb Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Wed, 16 Oct 2019 09:33:42 +0200 Subject: [PATCH 171/340] length_* -> n_ --- .../combinatorial_polyhedron/base.pxd | 8 +-- .../combinatorial_polyhedron/base.pyx | 54 +++++++++---------- .../combinatorial_face.pxd | 2 +- .../combinatorial_face.pyx | 20 +++---- .../face_iterator.pxd | 2 +- .../face_iterator.pyx | 12 ++--- 6 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd index cab80ad3bed..0a998c2ca9e 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd @@ -13,8 +13,8 @@ cdef class CombinatorialPolyhedron(SageObject): cdef tuple _H # the names of HRep, if they exist cdef tuple _equalities # stores equalities, given on input (might belong to Hrep) cdef int _dimension # stores dimension, -2 on init - cdef unsigned int _length_Hrepr # Hrepr might include equalities - cdef unsigned int _length_Vrepr # Vrepr might include rays/lines + cdef unsigned int _n_Hrepresentation # Hrepr might include equalities + cdef unsigned int _n_Vrepresentation # Vrepr might include rays/lines cdef size_t _n_facets # length Hrep without equalities cdef bint _bounded # ``True`` iff Polyhedron is bounded cdef ListOfFaces _bitrep_facets # facets in bit representation @@ -43,8 +43,8 @@ cdef class CombinatorialPolyhedron(SageObject): cdef tuple V(self) cdef tuple H(self) cdef tuple equalities(self) - cdef unsigned int length_Vrepr(self) - cdef unsigned int length_Hrepr(self) + cdef unsigned int n_Vrepresentation(self) + cdef unsigned int n_Hrepresentation(self) cdef bint is_bounded(self) cdef ListOfFaces bitrep_facets(self) cdef ListOfFaces bitrep_Vrepr(self) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index 75de6c64a2c..8dea64b26b4 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -333,9 +333,9 @@ cdef class CombinatorialPolyhedron(SageObject): # input is ``LatticePolytope`` self._bounded = True Vrepr = data.vertices() - self._length_Vrepr = len(Vrepr) + self._n_Vrepresentation = len(Vrepr) facets = data.facets() - self._length_Hrepr = len(facets) + self._n_Hrepresentation = len(facets) data = tuple(tuple(vert for vert in facet.vertices()) for facet in facets) else: @@ -380,8 +380,8 @@ cdef class CombinatorialPolyhedron(SageObject): if isinstance(data, Matrix): # Input is incidence-matrix or was converted to it. - self._length_Hrepr = data.ncols() - self._length_Vrepr = data.nrows() + self._n_Hrepresentation = data.ncols() + self._n_Vrepresentation = data.nrows() # Initializing the facets in their Bit-representation. self._bitrep_facets = incidence_matrix_to_bit_repr_of_facets(data) @@ -393,7 +393,7 @@ cdef class CombinatorialPolyhedron(SageObject): # Initialize far_face if unbounded. if not self._bounded: - self._far_face = facets_tuple_to_bit_repr_of_facets((tuple(far_face),), self._length_Vrepr) + self._far_face = facets_tuple_to_bit_repr_of_facets((tuple(far_face),), self._n_Vrepresentation) else: self._far_face = None @@ -423,16 +423,16 @@ cdef class CombinatorialPolyhedron(SageObject): if self._V is None: # Get the names of the Vrepr. Vrepr = sorted(set.union(*map(set, data))) - length_Vrepr = len(Vrepr) + n_Vrepresentation = len(Vrepr) if Vrepr != range(len(Vrepr)): self._V = tuple(Vrepr) Vinv = {v: i for i,v in enumerate(self._V)} else: # Assuming the user gave as correct names for the vertices # and labeled them instead by `0,...,n`. - length_Vrepr = len(self._V) + n_Vrepresentation = len(self._V) - self._length_Vrepr = length_Vrepr + self._n_Vrepresentation = n_Vrepresentation # Relabel the Vrepr to be `0,...,n`. if self._V is not None: @@ -442,17 +442,17 @@ cdef class CombinatorialPolyhedron(SageObject): facets = tuple(tuple(f(i) for i in j) for j in data) self._n_facets = len(facets) - self._length_Hrepr = len(facets) + self._n_Hrepresentation = len(facets) # Initializing the facets in their Bit-representation. - self._bitrep_facets = facets_tuple_to_bit_repr_of_facets(facets, length_Vrepr) + self._bitrep_facets = facets_tuple_to_bit_repr_of_facets(facets, n_Vrepresentation) # Initializing the Vrepr as their Bit-representation. - self._bitrep_Vrepr = facets_tuple_to_bit_repr_of_Vrepr(facets, length_Vrepr) + self._bitrep_Vrepr = facets_tuple_to_bit_repr_of_Vrepr(facets, n_Vrepresentation) # Initialize far_face if unbounded. if not self._bounded: - self._far_face = facets_tuple_to_bit_repr_of_facets((tuple(far_face),), length_Vrepr) + self._far_face = facets_tuple_to_bit_repr_of_facets((tuple(far_face),), n_Vrepresentation) else: self._far_face = None @@ -572,7 +572,7 @@ cdef class CombinatorialPolyhedron(SageObject): if self.V() is not None: return self.V() else: - return tuple(smallInteger(i) for i in range(self.length_Vrepr())) + return tuple(smallInteger(i) for i in range(self.n_Vrepresentation())) def Hrepresentation(self): r""" @@ -594,7 +594,7 @@ cdef class CombinatorialPolyhedron(SageObject): if self.H() is not None: return self.equalities() + self.H() else: - return tuple(smallInteger(i) for i in range(self.length_Hrepr())) + return tuple(smallInteger(i) for i in range(self.n_Hrepresentation())) def dimension(self): r""" @@ -617,8 +617,8 @@ cdef class CombinatorialPolyhedron(SageObject): # The dimension of a trivial polyhedron is assumed to contain # exactly one "vertex" and for each dimension one "line" as in # :class:`~sage.geometry.polyhedron.parent.Polyhedron_base` - self._dimension = self.length_Vrepr() - 1 - elif not self.is_bounded() or self.n_facets() <= self.length_Vrepr(): + self._dimension = self.n_Vrepresentation() - 1 + elif not self.is_bounded() or self.n_facets() <= self.n_Vrepresentation(): self._dimension = self.bitrep_facets().compute_dimension() else: # If the polyhedron has many facets, @@ -674,7 +674,7 @@ cdef class CombinatorialPolyhedron(SageObject): # Some elements in the ``Vrepr`` might not correspond to actual combinatorial vertices. return len(self.vertices()) else: - return smallInteger(self.length_Vrepr()) + return smallInteger(self.n_Vrepresentation()) def vertices(self, names=True): r""" @@ -741,9 +741,9 @@ cdef class CombinatorialPolyhedron(SageObject): # The Polyhedron has no vertex. return () if names and self.V(): - return tuple(self.V()[i] for i in range(self.length_Vrepr()) if not i in self.far_face_tuple()) + return tuple(self.V()[i] for i in range(self.n_Vrepresentation()) if not i in self.far_face_tuple()) else: - return tuple(smallInteger(i) for i in range(self.length_Vrepr()) if not i in self.far_face_tuple()) + return tuple(smallInteger(i) for i in range(self.n_Vrepresentation()) if not i in self.far_face_tuple()) def n_facets(self): r""" @@ -911,7 +911,7 @@ cdef class CombinatorialPolyhedron(SageObject): # compute the edges. if not self.is_bounded(): self._compute_edges(dual=False) - elif self.length_Vrepr() > self.n_facets()*self.n_facets(): + elif self.n_Vrepresentation() > self.n_facets()*self.n_facets(): # This is a wild estimate # that in this case it is better not to use the dual. self._compute_edges(dual=False) @@ -1093,7 +1093,7 @@ cdef class CombinatorialPolyhedron(SageObject): # compute the ridges. if not self.is_bounded(): self._compute_ridges(dual=False) - elif self.length_Vrepr()*self.length_Vrepr() < self.n_facets(): + elif self.n_Vrepresentation()*self.n_Vrepresentation() < self.n_facets(): # This is a wild estimate # that in this case it is better to use the dual. self._compute_edges(dual=True) @@ -1326,7 +1326,7 @@ cdef class CombinatorialPolyhedron(SageObject): cdef FaceIterator face_iter if dual is None: # Determine the faster way, to iterate through all faces. - if not self.is_bounded() or self.n_facets() <= self.length_Vrepr(): + if not self.is_bounded() or self.n_facets() <= self.n_Vrepresentation(): dual = False else: dual = True @@ -1560,17 +1560,17 @@ cdef class CombinatorialPolyhedron(SageObject): """ return self._equalities - cdef unsigned int length_Vrepr(self): + cdef unsigned int n_Vrepresentation(self): r""" Return the number of elements in the Vrepresentation. """ - return self._length_Vrepr + return self._n_Vrepresentation - cdef unsigned int length_Hrepr(self): + cdef unsigned int n_Hrepresentation(self): r""" Return the number of elements in the Hrepresentation. """ - return self._length_Hrepr + return self._n_Hrepresentation cdef bint is_bounded(self): r""" @@ -1614,7 +1614,7 @@ cdef class CombinatorialPolyhedron(SageObject): return 0 # There is no need to recompute the f_vector. cdef bint dual - if not self.is_bounded() or self.n_facets() <= self.length_Vrepr(): + if not self.is_bounded() or self.n_facets() <= self.n_Vrepresentation(): # In this case the non-dual approach is faster.. dual = False else: diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pxd b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pxd index 9372acae5c1..aee12405708 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pxd +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pxd @@ -24,6 +24,6 @@ cdef class CombinatorialFace(SageObject): # If ``dual == 0``, then coatoms are facets, atoms vertices and vice versa. cdef ListOfFaces atoms, coatoms - cdef size_t length_atom_repr(self) except -1 + cdef size_t n_atom_rep(self) except -1 cdef size_t set_coatom_repr(self) except -1 cdef size_t set_atom_repr(self) except -1 diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx index 852b00fa54f..dc14659889f 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx @@ -36,7 +36,7 @@ Obtain further information regarding a face:: A 2-dimensional face of a 3-dimensional combinatorial polyhedron sage: face.Vrepr() (A vertex at (0, 0, 1), A vertex at (0, 1, 0), A vertex at (1, 0, 0)) - sage: face.length_Vrepr() + sage: face.n_ambient_Vrepresentation() 3 sage: face.Hrepr(names=False) (5,) @@ -114,7 +114,7 @@ cdef class CombinatorialFace(SageObject): (A vertex at (6, 36, 216, 1296, 7776),) sage: face.Vrepr(names=False) (6,) - sage: face.length_Vrepr() + sage: face.n_ambient_Vrepresentation() 1 The Hrepresentation:: @@ -133,7 +133,7 @@ cdef class CombinatorialFace(SageObject): An inequality (-210, 317, -125, 19, -1) x + 0 >= 0) sage: face.Hrepr(names=False) (3, 4, 5, 6, 7, 8, 9, 10, 11, 18, 19) - sage: face.length_Hrepr() + sage: face.n_Hrepresentation() 11 """ def __init__(self, data, dimension=None, index=None): @@ -381,7 +381,7 @@ cdef class CombinatorialFace(SageObject): return tuple(smallInteger(self.atom_repr[i]) for i in range(length)) - def length_Vrepr(self): + def n_ambient_Vrepresentation(self): r""" Return the length of the face. @@ -392,13 +392,13 @@ cdef class CombinatorialFace(SageObject): sage: P = polytopes.cube() sage: C = CombinatorialPolyhedron(P) sage: it = C.face_iter() - sage: all(face.length_Vrepr() == len(face.Vrepr()) for face in it) + sage: all(face.n_ambient_Vrepresentation() == len(face.Vrepr()) for face in it) True """ if self._dual: return smallInteger(self.set_coatom_repr()) else: - return smallInteger(self.length_atom_repr()) + return smallInteger(self.n_atom_rep()) def Hrepr(self, names=True): r""" @@ -488,7 +488,7 @@ cdef class CombinatorialFace(SageObject): return tuple(smallInteger(self.atom_repr[i]) for i in range(length)) - def length_Hrepr(self): + def n_Hrepresentation(self): r""" Returns the length of the :meth:`Hrepr`. @@ -499,15 +499,15 @@ cdef class CombinatorialFace(SageObject): sage: P = polytopes.cube() sage: C = CombinatorialPolyhedron(P) sage: it = C.face_iter() - sage: all(face.length_Hrepr() == len(face.Hrepr()) for face in it) + sage: all(face.n_Hrepresentation() == len(face.Hrepr()) for face in it) True """ if not self._dual: return smallInteger(self.set_coatom_repr()) else: - return smallInteger(self.length_atom_repr()) + return smallInteger(self.n_atom_rep()) - cdef size_t length_atom_repr(self) except -1: + cdef size_t n_atom_rep(self) except -1: r""" Compute the number of atoms in the current face by counting the number of set bits. diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd index 1d3bacf095f..dabb063942e 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd @@ -63,6 +63,6 @@ cdef class FaceIterator(SageObject): cdef inline CombinatorialFace next_face(self) cdef inline int next_dimension(self) except -1 cdef inline int next_face_loop(self) except -1 - cdef size_t length_atom_repr(self) except -1 + cdef size_t n_atom_rep(self) except -1 cdef size_t set_coatom_repr(self) except -1 cdef size_t set_atom_repr(self) except -1 diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx index 02be3d68df7..629816f857c 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx @@ -71,7 +71,7 @@ Obtain the Vrepresentation:: sage: face = next(it) sage: face.Vrepr() (A vertex at (0, -1, 0), A vertex at (0, 0, -1), A vertex at (1, 0, 0)) - sage: face.length_Vrepr() + sage: face.n_ambient_Vrepresentation() 3 Obtain the facet-representation:: @@ -85,7 +85,7 @@ Obtain the facet-representation:: An inequality (-1, 1, 1) x + 1 >= 0) sage: face.Hrepr(names=False) (4, 5, 6, 7) - sage: face.length_Hrepr() + sage: face.n_Hrepresentation() 4 In non-dual mode one can ignore all faces contained in the current face:: @@ -608,7 +608,7 @@ cdef class FaceIterator(SageObject): sage: it = C.face_iter(dual=False) sage: n_non_simplex_faces = 1 sage: for face in it: - ....: if face.length_Vrepr() > face.dimension() + 1: + ....: if face.n_ambient_Vrepresentation() > face.dimension() + 1: ....: n_non_simplex_faces += 1 ....: else: ....: it.ignore_subfaces() @@ -641,7 +641,7 @@ cdef class FaceIterator(SageObject): sage: it = C.face_iter(dual=True) sage: n_faces_with_non_simplex_quotient = 1 sage: for face in it: - ....: if face.length_Hrepr() > C.dimension() - face.dimension() + 1: + ....: if face.n_Hrepresentation() > C.dimension() - face.dimension() + 1: ....: n_faces_with_non_simplex_quotient += 1 ....: else: ....: it.ignore_supfaces() @@ -785,12 +785,12 @@ cdef class FaceIterator(SageObject): self.first_time[self.current_dimension] = True return 0 - cdef size_t length_atom_repr(self) except -1: + cdef size_t n_atom_rep(self) except -1: r""" Compute the number of atoms in the current face by counting the number of set bits. - This is a shortcut of :class:`sage.geometry.polyhedron.combinatorial_polyhedron.combinatorial_face.CombinatorialFace.length_atom_repr` + This is a shortcut of :class:`sage.geometry.polyhedron.combinatorial_polyhedron.combinatorial_face.CombinatorialFace.n_atom_rep` """ if self.face: return count_atoms(self.face, self.face_length) From ade3dca5038214af1020f2fce167f883800a399b Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Wed, 16 Oct 2019 09:49:57 +0200 Subject: [PATCH 172/340] deprecation warnings; n_Vrepresentation -> n_ambient_Vrepresentation in CombinatorialFace --- .../combinatorial_face.pyx | 48 +++++++++++++++++-- .../face_iterator.pyx | 4 +- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx index dc14659889f..6fc20826d01 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx @@ -3,7 +3,7 @@ Combinatorial face of a polyhedron This module provides the combinatorial type of a polyhedral face. -,, SEEALSO:: +.. SEEALSO:: :mod:`sage.geometry.polyhedron.combinatorial_polyhedron.base`, :mod:`sage.geometry.polyhedron.combinatorial_polyhedron.face_iterator`. @@ -133,7 +133,7 @@ cdef class CombinatorialFace(SageObject): An inequality (-210, 317, -125, 19, -1) x + 0 >= 0) sage: face.Hrepr(names=False) (3, 4, 5, 6, 7, 8, 9, 10, 11, 18, 19) - sage: face.n_Hrepresentation() + sage: face.n_ambient_Hrepresentation() 11 """ def __init__(self, data, dimension=None, index=None): @@ -400,6 +400,26 @@ cdef class CombinatorialFace(SageObject): else: return smallInteger(self.n_atom_rep()) + def n_Vrepr(self): + r""" + .. SEEALSO:: + + :meth:`CombinatorialFace.n_ambient_Vrepresentation` + + TESTS:: + + sage: P = polytopes.cube() + sage: C = CombinatorialPolyhedron(P) + sage: it = C.face_iter() + sage: face = next(it) + sage: _ = face.n_Vrepr() + doctest:...: DeprecationWarning: the method n_Vrepr of CombinatorialFace is deprecated + See https://trac.sagemath.org/28614 for details. + """ + from sage.misc.superseded import deprecation + deprecation(28614, "the method n_Vrepr of CombinatorialFace is deprecated") + return self.n_ambient_Vrepresentation() + def Hrepr(self, names=True): r""" Return the Hrepresentation of the face. @@ -488,7 +508,7 @@ cdef class CombinatorialFace(SageObject): return tuple(smallInteger(self.atom_repr[i]) for i in range(length)) - def n_Hrepresentation(self): + def n_ambient_Hrepresentation(self): r""" Returns the length of the :meth:`Hrepr`. @@ -499,7 +519,7 @@ cdef class CombinatorialFace(SageObject): sage: P = polytopes.cube() sage: C = CombinatorialPolyhedron(P) sage: it = C.face_iter() - sage: all(face.n_Hrepresentation() == len(face.Hrepr()) for face in it) + sage: all(face.n_ambient_Hrepresentation() == len(face.Hrepr()) for face in it) True """ if not self._dual: @@ -507,6 +527,26 @@ cdef class CombinatorialFace(SageObject): else: return smallInteger(self.n_atom_rep()) + def n_Hrepr(self): + r""" + .. SEEALSO:: + + :meth:`CombinatorialFace.n_ambient_Hrepresentation` + + TESTS:: + + sage: P = polytopes.cube() + sage: C = CombinatorialPolyhedron(P) + sage: it = C.face_iter() + sage: face = next(it) + sage: _ = face.n_Hrepr() + doctest:...: DeprecationWarning: the method n_Hrepr of CombinatorialFace is deprecated + See https://trac.sagemath.org/28614 for details. + """ + from sage.misc.superseded import deprecation + deprecation(28614, "the method n_Hrepr of CombinatorialFace is deprecated") + return self.n_ambient_Hrepresentation() + cdef size_t n_atom_rep(self) except -1: r""" Compute the number of atoms in the current face by counting the diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx index 629816f857c..ab5cc519e96 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx @@ -85,7 +85,7 @@ Obtain the facet-representation:: An inequality (-1, 1, 1) x + 1 >= 0) sage: face.Hrepr(names=False) (4, 5, 6, 7) - sage: face.n_Hrepresentation() + sage: face.n_ambient_Hrepresentation() 4 In non-dual mode one can ignore all faces contained in the current face:: @@ -641,7 +641,7 @@ cdef class FaceIterator(SageObject): sage: it = C.face_iter(dual=True) sage: n_faces_with_non_simplex_quotient = 1 sage: for face in it: - ....: if face.n_Hrepresentation() > C.dimension() - face.dimension() + 1: + ....: if face.n_ambient_Hrepresentation() > C.dimension() - face.dimension() + 1: ....: n_faces_with_non_simplex_quotient += 1 ....: else: ....: it.ignore_supfaces() From 39cc0985af730981a707ae37afdf42e22473382b Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Mon, 18 Nov 2019 18:14:56 +0100 Subject: [PATCH 173/340] altered the deprecation message to be the correct one for methods --- .../combinatorial_face.pyx | 39 +++++++++++-------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx index 6fc20826d01..640ef557414 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx @@ -64,6 +64,9 @@ AUTHOR: # http://www.gnu.org/licenses/ #***************************************************************************** +from __future__ import absolute_import, division, print_function +from sage.misc.superseded import deprecated_function_alias + import numbers from sage.rings.integer cimport smallInteger from .conversions cimport bit_repr_to_Vrepr_list @@ -394,17 +397,6 @@ cdef class CombinatorialFace(SageObject): sage: it = C.face_iter() sage: all(face.n_ambient_Vrepresentation() == len(face.Vrepr()) for face in it) True - """ - if self._dual: - return smallInteger(self.set_coatom_repr()) - else: - return smallInteger(self.n_atom_rep()) - - def n_Vrepr(self): - r""" - .. SEEALSO:: - - :meth:`CombinatorialFace.n_ambient_Vrepresentation` TESTS:: @@ -413,12 +405,15 @@ cdef class CombinatorialFace(SageObject): sage: it = C.face_iter() sage: face = next(it) sage: _ = face.n_Vrepr() - doctest:...: DeprecationWarning: the method n_Vrepr of CombinatorialFace is deprecated + doctest:...: DeprecationWarning: n_Vrepr is deprecated. Please use n_ambient_Vrepresentation instead. See https://trac.sagemath.org/28614 for details. """ - from sage.misc.superseded import deprecation - deprecation(28614, "the method n_Vrepr of CombinatorialFace is deprecated") - return self.n_ambient_Vrepresentation() + if self._dual: + return smallInteger(self.set_coatom_repr()) + else: + return smallInteger(self.n_atom_rep()) + + n_Vrepr = deprecated_function_alias(28614, n_ambient_Vrepresentation) def Hrepr(self, names=True): r""" @@ -521,12 +516,24 @@ cdef class CombinatorialFace(SageObject): sage: it = C.face_iter() sage: all(face.n_ambient_Hrepresentation() == len(face.Hrepr()) for face in it) True + + TESTS:: + + sage: P = polytopes.cube() + sage: C = CombinatorialPolyhedron(P) + sage: it = C.face_iter() + sage: face = next(it) + sage: _ = face.n_Hrepr() + doctest:...: DeprecationWarning: n_Hrepr is deprecated. Please use n_ambient_Hrepresentation instead. + See https://trac.sagemath.org/28614 for details. """ if not self._dual: return smallInteger(self.set_coatom_repr()) else: return smallInteger(self.n_atom_rep()) + n_Hrepr = deprecated_function_alias(28614, n_ambient_Hrepresentation) + def n_Hrepr(self): r""" .. SEEALSO:: @@ -540,7 +547,7 @@ cdef class CombinatorialFace(SageObject): sage: it = C.face_iter() sage: face = next(it) sage: _ = face.n_Hrepr() - doctest:...: DeprecationWarning: the method n_Hrepr of CombinatorialFace is deprecated + doctest:...: DeprecationWarning: n_Hrepr is deprecated. Please use n_ambient_Hrepresentation instead. See https://trac.sagemath.org/28614 for details. """ from sage.misc.superseded import deprecation From f14e75b4b2c236618e2b6bdfb825de5d0cf50614 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Mon, 18 Nov 2019 18:19:51 +0100 Subject: [PATCH 174/340] missed a replacement --- src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index 8dea64b26b4..ec61b48ebdb 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -1653,7 +1653,7 @@ cdef class CombinatorialPolyhedron(SageObject): else: if self.is_bounded() and dim > 1 \ - and f_vector[1] < self.length_Vrepr() - len(self.far_face_tuple()): + and f_vector[1] < self.n_Vrepresentation() - len(self.far_face_tuple()): # The input seemed to be wrong. raise ValueError("not all vertices are intersections of facets") From 2b196a845ecb9b0579a60dac337ddecf6460fbfe Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Mon, 18 Nov 2019 20:51:32 +0100 Subject: [PATCH 175/340] add missing doctest --- src/sage/combinat/growth.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/sage/combinat/growth.py b/src/sage/combinat/growth.py index 94ca3ac56d8..fdb559880b8 100644 --- a/src/sage/combinat/growth.py +++ b/src/sage/combinat/growth.py @@ -489,6 +489,19 @@ from sage.graphs.digraph import DiGraph def _make_partition(l): + """ + Return the list as a partition. + + This is intended to be fast, so checks are bypassed. + + TESTS:: + + sage: p = _make_partition([3,2,1,0]); p + [3, 2, 1] + + sage: p.parent() + Partitions + """ return _Partitions.element_class(_Partitions, l) class GrowthDiagram(SageObject): From d2dcbb6d4bd5ca12e9ebef01303c17497d28fabe Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Mon, 18 Nov 2019 21:45:26 +0100 Subject: [PATCH 176/340] 28758: fix random output in giacpy_sage doctest --- src/sage/libs/giac.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sage/libs/giac.py b/src/sage/libs/giac.py index 804c157738c..078787c3572 100644 --- a/src/sage/libs/giac.py +++ b/src/sage/libs/giac.py @@ -207,9 +207,7 @@ def groebner_basis(gens, proba_epsilon=None, threads=None, prot=False, sage: P = PolynomialRing(QQ,5, 'x') # optional - giacpy_sage sage: I = ideal([P.random_element(3,7) for j in range(5)]) # optional - giacpy_sage sage: B1 = gb_giac(I.gens(),1e-16) # optional - giacpy_sage, long time (1s) - ...adding reconstructed ideal generators... - ... - Running a probabilistic check for the reconstructed Groebner basis. + ...Running a probabilistic check for the reconstructed Groebner basis. If successfull, error probability is less than 1e-16 ... sage: sage.structure.proof.all.polynomial(True) # optional - giacpy_sage sage: B2 = gb_giac(I.gens()) # optional - giacpy_sage, long time (4s) From 81e2f60b2247b473b0d2aa8c059a2211faa4ff63 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Mon, 18 Nov 2019 23:20:20 +0100 Subject: [PATCH 177/340] Minor fix in the documentation of TopologicalVectorBundle.local_frame() --- src/sage/manifolds/vector_bundle.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/manifolds/vector_bundle.py b/src/sage/manifolds/vector_bundle.py index c33026096fd..01c28aa639a 100644 --- a/src/sage/manifolds/vector_bundle.py +++ b/src/sage/manifolds/vector_bundle.py @@ -711,7 +711,7 @@ def local_frame(self, *args, **kwargs): symbols of the sections constituting the local frame, or a list/tuple of strings, representing the individual symbols of the sections - ``sections`` -- tuple or list of `n` linearly independent sections on - ``self`` (`n` being the dimension of ``self``) defining the local + ``self`` (`n` being the rank of ``self``) defining the local frame; can be omitted if the local frame is created from scratch - ``latex_symbol`` -- (default: ``None``) either a string, to be used as a common base for the LaTeX symbols of the sections From 4ad1fb8c47b183e2b534544affe7465df75c15b4 Mon Sep 17 00:00:00 2001 From: Dave Witte Morris Date: Mon, 18 Nov 2019 19:19:22 -0700 Subject: [PATCH 178/340] change "norm" to "determinant" in docstring --- src/sage/rings/polynomial/polynomial_quotient_ring_element.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py index 3994c569a4f..01364a75df4 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py @@ -662,7 +662,7 @@ def minpoly(self): def norm(self): """ - The norm of this element, which is the norm of the matrix of right + The norm of this element, which is the determinant of the matrix of right multiplication by this element. EXAMPLES:: From 769d877d2dc1b968701eb3ff8e84d4c72c356d65 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Tue, 19 Nov 2019 09:25:08 +0100 Subject: [PATCH 179/340] fix setting cache of `is_reflexive` --- src/sage/geometry/lattice_polytope.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index fe36a712f53..912db1bc77b 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -727,6 +727,21 @@ def _compute_facets(self): N(-1, -1, 0), N(-1, 1, 0) in 3-d lattice N + + Check that :trac:`28741` is fixed:: + + sage: p = LatticePolytope([], lattice=ToricLattice(3).dual()); p + -1-d lattice polytope in 3-d lattice M + sage: a = p.faces()[0][0] + sage: p = LatticePolytope([], lattice=ToricLattice(3).dual()); p + -1-d lattice polytope in 3-d lattice M + sage: a = p.faces()[0][0]; a + -1-d lattice polytope in 3-d lattice M + sage: a.facet_normals() + Empty collection + in 3-d lattice N + sage: a + -1-d lattice polytope in 3-d lattice M """ assert not hasattr(self, "_facet_normals") N = self.dual_lattice() @@ -747,7 +762,8 @@ def _compute_facets(self): # vector(ZZ, constants) is slow self._facet_constants = (ZZ**len(constants))(constants) self._facet_constants.set_immutable() - self.is_reflexive.set_cache(all(c == 1 for c in constants)) + self.is_reflexive.set_cache(self.dim() == self.lattice_dim() and + all(c == 1 for c in constants)) if self.is_reflexive(): polar = LatticePolytope( self._facet_normals, compute_vertices=False) From 3d699467a49b6f4ceb7aa5a5e5217b2b73d6ac8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 19 Nov 2019 09:50:54 +0100 Subject: [PATCH 180/340] some py3 fixes for misc --- src/sage/misc/remote_file.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/misc/remote_file.py b/src/sage/misc/remote_file.py index 31d4efd41f2..ef2d6e91725 100644 --- a/src/sage/misc/remote_file.py +++ b/src/sage/misc/remote_file.py @@ -39,17 +39,16 @@ def get_remote_file(filename, verbose=True): # import compatible with py2 and py3 from six.moves.urllib.request import Request, urlopen - req = Request(filename, headers={"User-Agent":"sage-doctest"}) + req = Request(filename, headers={"User-Agent": "sage-doctest"}) if verbose: print("Loading started") content = urlopen(req, timeout=1) - with open(temp_name, 'w') as f: + with open(temp_name, 'wb') as f: f.write(content.read()) if verbose: print("Loading ended") return temp_name - From 6c6c358737c456f643fd011936977e8d477f882a Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Tue, 19 Nov 2019 10:43:14 +0100 Subject: [PATCH 181/340] implement incidence matrix for cones --- src/sage/geometry/cone.py | 57 ++++++++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index 942ffa37a2d..51a63726f01 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -2354,9 +2354,6 @@ def face_lattice(self): S = self.linear_subspace() subspace_rays = [] atom_to_ray = [] - atom_to_facets = [] - normals = self.facet_normals() - facet_to_atoms = [[] for normal in normals] for i, ray in enumerate(self): # This try...except tests whether ray lies in S; # "ray in S" does not work because ray lies in a @@ -2367,12 +2364,6 @@ def face_lattice(self): S(ray) subspace_rays.append(i) except (TypeError, ValueError): - facets = [j for j, normal in enumerate(normals) - if ray * normal == 0] - atom_to_facets.append(facets) - atom = len(atom_to_ray) - for j in facets: - facet_to_atoms[j].append(atom) atom_to_ray.append(i) def ConeFace(atoms, facets): @@ -2389,6 +2380,15 @@ def ConeFace(atoms, facets): else: return self + # Obtain a modified version of the incidence matrix, + # with rows corresponding to rays in subspace removed. + mod_incidence_matrix = self.incidence_matrix()[atom_to_ray] + + atom_to_facets = [row.nonzero_positions() + for row in mod_incidence_matrix.rows()] + facet_to_atoms = [column.nonzero_positions() + for column in mod_incidence_matrix.columns()] + self._face_lattice = lattice_from_incidences( atom_to_facets, facet_to_atoms, ConeFace, key = id(self)) @@ -2733,6 +2733,45 @@ def facets(self): """ return self.faces(codim=1) + @cached_method + def incidence_matrix(self): + r""" + Return the incidence matrix. + + .. NOTE:: + + The columns correspond to facets/facet normals + in the order of :meth:`facet_normals`, the rows + correspond to the rays in the order of + :meth:`rays`. + + EXAMPLES:: + + sage: octant = Cone([(1,0,0), (0,1,0), (0,0,1)]) + sage: octant.incidence_matrix() + [0 1 1] + [1 0 1] + [1 1 0] + + sage: halfspace = Cone([(1,0,0), (0,1,0), (-1,-1,0), (0,0,1)]) + sage: halfspace.incidence_matrix() + [0] + [1] + [1] + [1] + [1] + """ + normals = self.facet_normals() + incidence_matrix = matrix(ZZ, self.nrays(), + len(normals), 0) + + for Hindex, normal in enumerate(self.facet_normals()): + for Vindex, ray in enumerate(self.rays()): + if normal*ray == 0: + incidence_matrix[Vindex, Hindex] = 1 + + return incidence_matrix + def intersection(self, other): r""" Compute the intersection of two cones. From b0e1893f5c4cb859de7d744b61437ae9daf9b904 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 19 Nov 2019 11:54:08 +0100 Subject: [PATCH 182/340] trac 28759 py3 fix for dot2tex+graphviz --- src/sage/combinat/posets/posets.py | 6 +++--- src/sage/graphs/graph_latex.py | 23 +++++++++++------------ 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index f1463c3184c..deac1eff88b 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -1345,9 +1345,9 @@ def _latex_(self): sage: print(P._latex_()) #optional - dot2tex graphviz \begin{tikzpicture}[>=latex,line join=bevel,] %% - \node (node_1) at (6.0...bp,5...bp) [draw,draw=none] {$2$}; - \node (node_0) at (6.0...bp,...bp) [draw,draw=none] {$1$}; - \draw [black,->] (node_0) ..controls (...bp,...bp) and (...bp,...bp) .. (node_1); + \node (node_...) at (6.0...bp,...bp) [draw,draw=none] {$...$}; + \node (node_...) at (6.0...bp,...bp) [draw,draw=none] {$...$}; + \draw [black,->] (node_...) ..controls (...bp,...bp) and (...bp,...bp) .. (node_...); % \end{tikzpicture} """ diff --git a/src/sage/graphs/graph_latex.py b/src/sage/graphs/graph_latex.py index d8e221df5b4..6cc062f127f 100644 --- a/src/sage/graphs/graph_latex.py +++ b/src/sage/graphs/graph_latex.py @@ -1333,14 +1333,14 @@ def dot2tex_picture(self): sage: print(g.latex_options().dot2tex_picture()) # optional - dot2tex graphviz \begin{tikzpicture}[>=latex,line join=bevel,] %% - \node (node_3) at (...bp,...bp) [draw,draw=none] {$\left(0, 1\right)$}; - \node (node_2) at (...bp,...bp) [draw,draw=none] {$\left(1, 0\right)$}; - \node (node_1) at (...bp,...bp) [draw,draw=none] {$\left(0, 0\right)$}; - \node (node_0) at (...bp,...bp) [draw,draw=none] {$\left(1, 1\right)$}; - \draw [black,->] (node_1) ..controls (...bp,...bp) and (...bp,...bp) .. (node_3); - \draw [black,->] (node_2) ..controls (...bp,...bp) and (...bp,...bp) .. (node_3); - \draw [black,->] (node_2) ..controls (...bp,...bp) and (...bp,...bp) .. (node_0); - \draw [black,->] (node_1) ..controls (...bp,...bp) and (...bp,...bp) .. (node_0); + \node (node_...) at (...bp,...bp) [draw,draw=none] {$\left(...\right)$}; + \node (node_...) at (...bp,...bp) [draw,draw=none] {$\left(...\right)$}; + \node (node_...) at (...bp,...bp) [draw,draw=none] {$\left(...\right)$}; + \node (node_...) at (...bp,...bp) [draw,draw=none] {$\left(...\right)$}; + \draw [black,->] (node_...) ..controls (...bp,...bp) and (...bp,...bp) .. (node_...); + \draw [black,->] (node_...) ..controls (...bp,...bp) and (...bp,...bp) .. (node_...); + \draw [black,->] (node_...) ..controls (...bp,...bp) and (...bp,...bp) .. (node_...); + \draw [black,->] (node_...) ..controls (...bp,...bp) and (...bp,...bp) .. (node_...); % \end{tikzpicture} @@ -1352,9 +1352,9 @@ def dot2tex_picture(self): sage: print(G.latex_options().dot2tex_picture()) # optional - dot2tex graphviz \begin{tikzpicture}[>=latex,line join=bevel,] %% - \node (node_1) at (...bp,...bp) [draw,draw=none] {$3333$}; - \node (node_0) at (...bp,...bp) [draw,draw=none] {$88$}; - \draw [black,->] (node_1) ..controls (...bp,...bp) and (...bp,...bp) .. (node_0); + \node (node_...) at (...bp,...bp) [draw,draw=none] {$...$}; + \node (node_...) at (...bp,...bp) [draw,draw=none] {$...$}; + \draw [black,->] (node_...) ..controls (...bp,...bp) and (...bp,...bp) .. (node_...); \definecolor{strokecol}{rgb}{0.0,0.0,0.0}; \pgfsetstrokecolor{strokecol} \draw (...bp,...bp) node {$\text{\texttt{my{\char`\_}label}}$}; @@ -1372,7 +1372,6 @@ def dot2tex_picture(self): ... \end{tikzpicture} - .. NOTE:: There is a lot of overlap between what ``tkz_picture`` and From a272cfdb26a536eeb804ca2c66bf6660c27a79b5 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Tue, 19 Nov 2019 12:39:07 +0100 Subject: [PATCH 183/340] fix coercion of polyhedra with number fields --- src/sage/geometry/polyhedron/parent.py | 47 ++++++++++++++++++-------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/src/sage/geometry/polyhedron/parent.py b/src/sage/geometry/polyhedron/parent.py index c1c5c84f5a0..fd3223c4ac4 100644 --- a/src/sage/geometry/polyhedron/parent.py +++ b/src/sage/geometry/polyhedron/parent.py @@ -672,24 +672,41 @@ def _coerce_base_ring(self, other): Rational Field sage: triangle_QQ._coerce_base_ring(0.5) Real Double Field + + TESTS: + + Test that :trac:`28770` is fixed:: + + sage: z = QQ['z'].0 + sage: K = NumberField(z^2 - 2,'s') + sage: triangle_QQ._coerce_base_ring(K) + Number Field in s with defining polynomial z^2 - 2 + sage: triangle_QQ._coerce_base_ring(K.gen()) + Number Field in s with defining polynomial z^2 - 2 """ - try: - other_ring = other.base_ring() - except AttributeError: + from sage.structure.element import Element + if isinstance(other, Element): + other = other.parent() + if hasattr(other, "is_ring") and other.is_ring(): + other_ring = other + else: try: - # other is a constant? - other_ring = other.parent() + other_ring = other.base_ring() except AttributeError: - other_ring = None - for ring in (ZZ, QQ, RDF): - try: - ring.coerce(other) - other_ring = ring - break - except TypeError: - pass - if other_ring is None: - raise TypeError('Could not coerce '+str(other)+' into ZZ, QQ, or RDF.') + try: + # other is a constant? + other_ring = other.parent() + except AttributeError: + other_ring = None + for ring in (ZZ, QQ, RDF): + try: + ring.coerce(other) + other_ring = ring + break + except TypeError: + pass + if other_ring is None: + raise TypeError('Could not coerce '+str(other)+' into ZZ, QQ, or RDF.') if not other_ring.is_exact(): other_ring = RDF # the only supported floating-point numbers for now From a0068ccbab09b0102a64c5fbe4ffaffa71b44086 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Tue, 19 Nov 2019 12:44:39 +0100 Subject: [PATCH 184/340] added a doctest for the original bug --- src/sage/geometry/polyhedron/parent.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/geometry/polyhedron/parent.py b/src/sage/geometry/polyhedron/parent.py index fd3223c4ac4..4e16b7225b4 100644 --- a/src/sage/geometry/polyhedron/parent.py +++ b/src/sage/geometry/polyhedron/parent.py @@ -683,6 +683,11 @@ def _coerce_base_ring(self, other): Number Field in s with defining polynomial z^2 - 2 sage: triangle_QQ._coerce_base_ring(K.gen()) Number Field in s with defining polynomial z^2 - 2 + + sage: z = QQ['z'].0 + sage: K = NumberField(z^2 - 2,'s') + sage: K.gen()*polytopes.simplex(backend='field') + A 3-dimensional polyhedron in (Number Field in s with defining polynomial z^2 - 2)^4 defined as the convex hull of 4 vertices """ from sage.structure.element import Element if isinstance(other, Element): From 39b32d18da54c97005b068f9021786b7b80f9c5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 19 Nov 2019 13:33:03 +0100 Subject: [PATCH 185/340] trac 28764 fix hadamard internet fetch for py3 --- src/sage/combinat/matrices/hadamard_matrix.py | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/sage/combinat/matrices/hadamard_matrix.py b/src/sage/combinat/matrices/hadamard_matrix.py index 00f5dc02e83..7a2567fe557 100644 --- a/src/sage/combinat/matrices/hadamard_matrix.py +++ b/src/sage/combinat/matrices/hadamard_matrix.py @@ -66,6 +66,7 @@ from sage.matrix.constructor import identity_matrix as I from sage.matrix.constructor import ones_matrix as J from sage.misc.unknown import Unknown +from sage.cpython.string import bytes_to_str def normalise_hadamard(H): @@ -454,16 +455,17 @@ def hadamard_matrix(n,existence=False, check=True): return M + def hadamard_matrix_www(url_file, comments=False): """ - Pulls file from Sloane's database and returns the corresponding Hadamard + Pull file from Sloane's database and return the corresponding Hadamard matrix as a Sage matrix. You must input a filename of the form "had.n.xxx.txt" as described on the webpage http://neilsloane.com/hadamard/, where "xxx" could be empty or a number of some characters. - If comments=True then the "Automorphism..." line of the had.n.xxx.txt + If ``comments=True`` then the "Automorphism..." line of the had.n.xxx.txt file is printed if it exists. Otherwise nothing is done. EXAMPLES:: @@ -495,25 +497,21 @@ def hadamard_matrix_www(url_file, comments=False): n = eval(url_file.split(".")[1]) rws = [] url = "http://neilsloane.com/hadamard/" + url_file - f = urlopen(url) - s = f.readlines() + with urlopen(url) as f: + s = [bytes_to_str(line) for line in f.readlines()] for i in range(n): - r = [] - for j in range(n): - if s[i][j] == "+": - r.append(1) - else: - r.append(-1) - rws.append(r) - f.close() + line = s[i] + rws.append([1 if line[j] == "+" else -1 for j in range(n)]) if comments: lastline = s[-1] if lastline[0] == "A": print(lastline) return matrix(rws) + _rshcd_cache = {} + def regular_symmetric_hadamard_matrix_with_constant_diagonal(n,e,existence=False): r""" Return a Regular Symmetric Hadamard Matrix with Constant Diagonal. From 1b000e1f3858c3189c2786ffb1e31265114de898 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 19 Nov 2019 15:52:16 +0100 Subject: [PATCH 186/340] trac 28760 py3 fix for databases --- src/sage/coding/databases.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/sage/coding/databases.py b/src/sage/coding/databases.py index 2c422493e1d..6f19175f4fd 100644 --- a/src/sage/coding/databases.py +++ b/src/sage/coding/databases.py @@ -156,6 +156,7 @@ def best_linear_code_in_codetables_dot_de(n, k, F, verbose=False): - David Joyner (2008-03) """ from six.moves.urllib.request import urlopen + from sage.cpython.string import bytes_to_str q = F.order() if not q in [2, 3, 4, 5, 7, 8, 9]: raise ValueError("q (=%s) must be in [2,3,4,5,7,8,9]" % q) @@ -167,16 +168,16 @@ def best_linear_code_in_codetables_dot_de(n, k, F, verbose=False): url = "http://www.codetables.de/" + "BKLC/BKLC.php" + param if verbose: print("Looking up the bounds at %s" % url) - f = urlopen(url) - s = f.read() - f.close() + with urlopen(url) as f: + s = f.read() + s = bytes_to_str(s) i = s.find("
")
     j = s.find("
") if i == -1 or j == -1: raise IOError("Error parsing data (missing pre tags).") - text = s[i+5:j].strip() - return text + return s[i+5:j].strip() + def self_orthogonal_binary_codes(n, k, b=2, parent=None, BC=None, equal=False, in_test=None): From c877e6853eda82e6b558a3b0773057ec820b7168 Mon Sep 17 00:00:00 2001 From: Benjamin Hutz Date: Tue, 19 Nov 2019 11:55:42 -0600 Subject: [PATCH 187/340] 28170: added option to use closure or splitting fields --- .../arithmetic_dynamics/generic_ds.py | 16 +- .../arithmetic_dynamics/projective_ds.py | 229 +++++++++++++++--- 2 files changed, 207 insertions(+), 38 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/generic_ds.py b/src/sage/dynamics/arithmetic_dynamics/generic_ds.py index be7e0c46d01..f0bea1c3fa0 100644 --- a/src/sage/dynamics/arithmetic_dynamics/generic_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/generic_ds.py @@ -34,7 +34,9 @@ class initialization directly. from sage.schemes.generic.morphism import SchemeMorphism_polynomial from sage.schemes.affine.affine_space import is_AffineSpace from sage.schemes.affine.affine_subscheme import AlgebraicScheme_subscheme_affine +from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField_generic from sage.rings.finite_rings.finite_field_constructor import is_FiniteField +from sage.rings.qqbar import AlgebraicField_common from sage.rings.rational_field import QQ from copy import copy @@ -395,8 +397,14 @@ def field_of_definition_critical(self, return_embedding=False, simplify_all=Fals """ ds = copy(self) space = ds.domain().ambient_space() + K = ds.base_ring() if space.dimension() != 1: raise ValueError('Ambient space of dynamical system must be either the affine line or projective line') + if isinstance(K, (AlgebraicClosureFiniteField_generic, AlgebraicField_common)): + if return_embedding: + return (K, K.hom(K)) + else: + return K if space.is_projective(): ds = ds.dehomogenize(1) f,g = ds[0].numerator(), ds[0].denominator() @@ -501,11 +509,17 @@ def field_of_definition_periodic(self, n, formal=False, return_embedding=False, """ ds = copy(self) n = int(n) + K = ds.base_ring() if n < 1: raise ValueError('`n` must be >= 1') space = ds.domain().ambient_space() if space.dimension() != 1: raise NotImplementedError("not implemented for affine or projective spaces of dimension >1") + if isinstance(K, (AlgebraicClosureFiniteField_generic, AlgebraicField_common)): + if return_embedding: + return (K, K.hom(K)) + else: + return K if space.is_projective(): ds = ds.dehomogenize(1) CR = space.coordinate_ring() @@ -519,7 +533,7 @@ def field_of_definition_periodic(self, n, formal=False, return_embedding=False, else: fn = ds.nth_iterate_map(n) f,g = fn[0].numerator(), fn[0].denominator() - poly = (f - g*x).univariate_polynomial() + poly = (f - g*x).univariate_polynomial() if is_FiniteField(ds.base_ring()): return poly.splitting_field(names, map=return_embedding) else: diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 9feed308d8a..b0b07246f24 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -3086,7 +3086,7 @@ def critical_points(self, R=None): crit_points = [P(Q) for Q in X.rational_points()] return crit_points - def is_postcritically_finite(self, err=0.01, embedding=None): + def is_postcritically_finite(self, err=0.01, use_algebraic_closure=True): r""" Determine if this dynamical system is post-critically finite. @@ -3094,14 +3094,17 @@ def is_postcritically_finite(self, err=0.01, embedding=None): point is preperiodic. The optional parameter ``err`` is passed into ``is_preperiodic()`` as part of the preperiodic check. - If ``embedding`` is ``None`` the function will use the minimal extension - containing all the critical points, as found by ``field_of_definition_critical``. + The computations can be done either over the algebraic closure of the + base field or over the minimal extension of the base field that + contains the critical points. INPUT: - ``err`` -- (default: 0.01) positive real number - - ``embedding`` -- (default: None) embedding of base ring into `\QQbar` + - ``use_algebraic_closure`` -- boolean (default: True) -- If True uses the + algebraic closure. If False, uses the smalest extension of the base field + containing all the critical points. OUTPUT: boolean @@ -3125,7 +3128,7 @@ def is_postcritically_finite(self, err=0.01, embedding=None): sage: K. = NumberField(z^8 + 3*z^6 + 3*z^4 + z^2 + 1) sage: PS. = ProjectiveSpace(K,1) sage: f = DynamicalSystem_projective([x^3+v*y^3, y^3]) - sage: f.is_postcritically_finite(embedding=K.embeddings(QQbar)[0]) # long time + sage: f.is_postcritically_finite() # long time True :: @@ -3142,22 +3145,47 @@ def is_postcritically_finite(self, err=0.01, embedding=None): sage: F = DynamicalSystem_projective([x^2 - y^2, y^2], domain=P) sage: F.is_postcritically_finite() True + + :: + + sage: P. = ProjectiveSpace(QQ,1) + sage: f = DynamicalSystem_projective([8*x^4 - 8*x^2*y^2 + y^4, y^4]) + sage: f.is_postcritically_finite(use_algebraic_closure=False) #long time + True + + :: + + sage: P. = ProjectiveSpace(QQ,1) + sage: f = DynamicalSystem_projective([x^4 - x^2*y^2 + y^4, y^4]) + sage: f.is_postcritically_finite(use_algebraic_closure=False) + False + + :: + + sage: P. = ProjectiveSpace(QQbar,1) + sage: f = DynamicalSystem_projective([x^4 - x^2*y^2, y^4]) + sage: f.is_postcritically_finite() + False """ #iteration of subschemes not yet implemented if self.domain().dimension_relative() > 1: raise NotImplementedError("only implemented in dimension 1") - #Since is_preperiodic uses heights we need to be over a numberfield K = FractionField(self.codomain().base_ring()) - if not K in NumberFields() and not K is QQbar: - raise NotImplementedError("must be over a number field or a number field order or QQbar") - - if not isinstance(K,AlgebraicClosureFiniteField_generic) and not isinstance(K,AlgebraicField_common): - if embedding is None: - embedding = self.field_of_definition_critical(return_embedding=True)[1] - F = self.change_ring(embedding) + if use_algebraic_closure: + Kbar = K.algebraic_closure() + if Kbar.has_coerce_map_from(K): + F = self.change_ring(Kbar) + else: + embeds = K.embeddings(Kbar) + if len(embeds) != 0: + F = self.change_ring(embeds[0]) + else: + raise ValueError("no embeddings of base field to algebraic closure") else: - F = self + embedding = self.field_of_definition_critical(return_embedding=True)[1] + F = self.change_ring(embedding) + crit_points = F.critical_points() pcf = True i = 0 @@ -3167,7 +3195,7 @@ def is_postcritically_finite(self, err=0.01, embedding=None): i += 1 return(pcf) - def critical_point_portrait(self, check=True, embedding=None): + def critical_point_portrait(self, check=True, use_algebraic_closure=True): r""" If this dynamical system is post-critically finite, return its critical point portrait. @@ -3176,11 +3204,17 @@ def critical_point_portrait(self, check=True, embedding=None): points. Must be dimension 1. If ``check`` is ``True``, then the map is first checked to see if it is postcritically finite. + The computations can be done either over the algebraic closure of the + base field or over the minimal extension of the base field that + contains the critical points. + INPUT: - ``check`` -- boolean (default: True) - - ``embedding`` -- embedding of base ring into `\QQbar` (default: None) + - ``use_algebraic_closure`` -- boolean (default: True) -- If True uses the + algebraic closure. If False, uses the smalest extension of the base field + containing all the critical points. OUTPUT: a digraph @@ -3190,7 +3224,7 @@ def critical_point_portrait(self, check=True, embedding=None): sage: K. = NumberField(z^6 + 2*z^5 + 2*z^4 + 2*z^3 + z^2 + 1) sage: PS. = ProjectiveSpace(K,1) sage: f = DynamicalSystem_projective([x^2+v*y^2, y^2]) - sage: f.critical_point_portrait(check=False, embedding=K.embeddings(QQbar)[0]) # long time + sage: f.critical_point_portrait(check=False) # long time Looped digraph on 6 vertices :: @@ -3216,16 +3250,51 @@ def critical_point_portrait(self, check=True, embedding=None): sage: phi = K.embeddings(QQbar)[0] sage: P. = ProjectiveSpace(K, 1) sage: f = DynamicalSystem_projective([x^2 + v*y^2, y^2]) - sage: f.critical_point_portrait(embedding=phi) + sage: f.change_ring(phi).critical_point_portrait() Looped digraph on 4 vertices + + :: + + sage: P. = ProjectiveSpace(QQ,1) + sage: f = DynamicalSystem_projective([8*x^4 - 8*x^2*y^2 + y^4, y^4]) + sage: f.critical_point_portrait(use_algebraic_closure=False) #long time + Looped digraph on 6 vertices + + :: + + sage: P. = ProjectiveSpace(QQbar,1) + sage: f = DynamicalSystem_projective([8*x^4 - 8*x^2*y^2 + y^4, y^4]) + sage: f.critical_point_portrait() #long time + Looped digraph on 6 vertices + + :: + + sage: P. = ProjectiveSpace(GF(3),1) + sage: f = DynamicalSystem_projective([x^2 + x*y - y^2, x*y]) + sage: f.critical_point_portrait(use_algebraic_closure=False) + Looped digraph on 6 vertices + sage: f.critical_point_portrait() #long time + Looped digraph on 6 vertices + """ #input checking done in is_postcritically_finite if check: - if not self.is_postcritically_finite(embedding=embedding): + if not self.is_postcritically_finite(): raise TypeError("map must be post-critically finite") - if embedding is None: + K = FractionField(self.base_ring()) + if use_algebraic_closure: + Kbar = K.algebraic_closure() + if Kbar.has_coerce_map_from(K): + F = self.change_ring(Kbar) + else: + embeds = K.embeddings(Kbar) + if len(embeds) != 0: + F = self.change_ring(embeds[0]) + else: + raise ValueError("no embeddings of base field to algebraic closure") + else: embedding = self.field_of_definition_critical(return_embedding=True)[1] - F = self.change_ring(embedding) + F = self.change_ring(embedding) crit_points = F.critical_points() N = len(crit_points) for i in range(N): @@ -3248,6 +3317,10 @@ def critical_height(self, **kwds): This must be dimension 1 and defined over a number field or number field order. + The computations can be done either over the algebraic closure of the + base field or over the minimal extension of the base field that + contains the critical points. + INPUT: kwds: @@ -3262,7 +3335,9 @@ def critical_height(self, **kwds): - ``error_bound`` -- (optional) a positive real number - - ``embedding`` -- (optional) the embedding of the base field to `\QQbar` + - ``use_algebraic_closure`` -- boolean (default: True) -- If True uses the + algebraic closure. If False, uses the smalest extension of the base field + containing all the critical points. OUTPUT: real number @@ -3287,17 +3362,35 @@ def critical_height(self, **kwds): sage: f = DynamicalSystem_projective([x^3-3/4*x*y^2 + 3/4*y^3, y^3]) sage: f.critical_height(error_bound=0.0001) 0.00000000000000000000000000000 + + :: + + sage: P. = ProjectiveSpace(QQ,1) + sage: f = DynamicalSystem_projective([x^3+3*x*y^2, y^3]) + sage: f.critical_height(use_algebraic_closure=False) + 0.000023477016733897112886491967991 + sage: f.critical_height() + 0.000023477016733897112886491967991 """ PS = self.codomain() if PS.dimension_relative() > 1: raise NotImplementedError("only implemented in dimension 1") K = FractionField(PS.base_ring()) - if not K in NumberFields() and not K is QQbar: - raise NotImplementedError("must be over a number field or a number field order or QQbar") - #doesn't really matter which we choose as Galois conjugates have the same height - emb = kwds.get("embedding", K.embeddings(QQbar)[0]) - F = self.change_ring(K).change_ring(emb) + use_algebraic_closure = kwds.get("use_algebraic_closure", True) + if use_algebraic_closure: + Kbar = K.algebraic_closure() + if Kbar.has_coerce_map_from(K): + F = self.change_ring(Kbar) + else: + embeds = K.embeddings(Kbar) + if len(embeds) != 0: + F = self.change_ring(embeds[0]) + else: + raise ValueError("no embeddings of base field to algebraic closure") + else: + embedding = self.field_of_definition_critical(return_embedding=True)[1] + F = self.change_ring(embedding) crit_points = F.critical_points() n = len(crit_points) err_bound = kwds.get("error_bound", None) @@ -3558,7 +3651,7 @@ def periodic_points(self, n, minimal=True, R=None, algorithm='variety', else: raise ValueError("algorithm must be either 'variety' or 'cyclegraph'") - def multiplier_spectra(self, n, formal=False, embedding=None, type='point'): + def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closure=True): r""" Computes the ``n`` multiplier spectra of this dynamical system. @@ -3569,6 +3662,10 @@ def multiplier_spectra(self, n, formal=False, embedding=None, type='point'): of period ``n``. The map must be defined over projective space of dimension 1 over a number field or finite field. + The computations can be done either over the algebraic closure of the + base field or over the minimal extension of the base field that + contains the critical points. + INPUT: - ``n`` -- a positive integer, the period @@ -3577,13 +3674,15 @@ def multiplier_spectra(self, n, formal=False, embedding=None, type='point'): to find the formal ``n`` multiplier spectra of this map and ``False`` specifies to find the ``n`` multiplier spectra - - ``embedding`` -- embedding of the base field into `\QQbar` - - ``type`` -- (default: ``'point'``) string; either ``'point'`` or ``'cycle'`` depending on whether you compute one multiplier per point or one per cycle - OUTPUT: a list of `\QQbar` elements + - ``use_algebraic_closure`` -- boolean (default: True) -- If True uses the + algebraic closure. If False, uses the smalest extension of the base field + containing all the critical points. + + OUTPUT: a list of field elements EXAMPLES:: @@ -3611,7 +3710,7 @@ def multiplier_spectra(self, n, formal=False, embedding=None, type='point'): sage: K. = NumberField(z^4 - 4*z^2 + 1,'z') sage: P. = ProjectiveSpace(K,1) sage: f = DynamicalSystem_projective([x^2 - w/4*y^2, y^2]) - sage: sorted(f.multiplier_spectra(2, formal=False, embedding=K.embeddings(QQbar)[0], type='cycle')) + sage: sorted(f.multiplier_spectra(2, formal=False, type='cycle')) [0, 0.0681483474218635? - 1.930649271699173?*I, 0.0681483474218635? + 1.930649271699173?*I, @@ -3635,6 +3734,52 @@ def multiplier_spectra(self, n, formal=False, embedding=None, type='point'): sage: f.multiplier_spectra(3, formal=True, type='point') [1, 1, 1, 1, 1, 1] + :: + + sage: P. = ProjectiveSpace(QQ,1) + sage: f = DynamicalSystem_projective([x^4 + 3*y^4, 4*x^2*y^2]) + sage: f.multiplier_spectra(1, use_algebraic_closure=False) + [0, + -1, + 1/128*a^5 - 13/384*a^4 + 5/96*a^3 + 1/16*a^2 + 43/128*a + 303/128, + -1/288*a^5 + 1/96*a^4 + 1/24*a^3 - 1/3*a^2 + 5/32*a - 115/32, + -5/1152*a^5 + 3/128*a^4 - 3/32*a^3 + 13/48*a^2 - 63/128*a - 227/128] + sage: f.multiplier_spectra(1) + [0, + -1, + 1.951373035591442?, + -2.475686517795721? - 0.730035681602057?*I, + -2.475686517795721? + 0.730035681602057?*I] + + :: + + sage: P. = ProjectiveSpace(GF(5),1) + sage: f = DynamicalSystem_projective([x^4 + 2*y^4, 4*x^2*y^2]) + sage: f.multiplier_spectra(1, use_algebraic_closure=False) + [0, 3*a + 3, 2*a + 1, 1, 1] + sage: f.multiplier_spectra(1) + [0, 2*z2 + 1, 3*z2 + 3, 1, 1] + + :: + + sage: P. = ProjectiveSpace(QQbar,1) + sage: f = DynamicalSystem_projective([x^5 + 3*y^5, 4*x^3*y^2]) + sage: f.multiplier_spectra(1) + [0, + -4.106544657178796?, + -7/4, + 1.985176555073911?, + -3.064315948947558? - 1.150478041113253?*I, + -3.064315948947558? + 1.150478041113253?*I] + + :: + + sage: K = GF(3).algebraic_closure() + sage: P. = ProjectiveSpace(K,1) + sage: f = DynamicalSystem_projective([x^5 + 2*y^5, 4*x^3*y^2]) + sage: f.multiplier_spectra(1) + [0, z3 + 2, z3 + 1, z3, 1, 1] + TESTS:: sage: P. = ProjectiveSpace(QQ,1) @@ -3660,12 +3805,22 @@ def multiplier_spectra(self, n, formal=False, embedding=None, type='point'): if (PS.dimension_relative() > 1): raise NotImplementedError("only implemented for dimension 1") - if embedding is None: - embedding = self.field_of_definition_periodic(n, return_embedding=True)[1] - f = self.change_ring(embedding) + K = FractionField(self.codomain().base_ring()) + if use_algebraic_closure: + Kbar = K.algebraic_closure() + if Kbar.has_coerce_map_from(K): + f = self.change_ring(Kbar) + else: + embeds = K.embeddings(Kbar) + if len(embeds) != 0: + f = self.change_ring(embeds[0]) + else: + raise ValueError("no embeddings of base field to algebraic closure") + else: + embedding = self.field_of_definition_periodic(n, formal=formal, return_embedding=True)[1] + f = self.change_ring(embedding) PS = f.domain() - if not formal: G = f.nth_iterate_map(n) F = G[0]*PS.gens()[1] - G[1]*PS.gens()[0] @@ -6240,7 +6395,7 @@ def reduce_base_field(self): class DynamicalSystem_projective_finite_field(DynamicalSystem_projective_field, SchemeMorphism_polynomial_projective_space_finite_field): - def is_postcritically_finite(self, embedding=None): + def is_postcritically_finite(self): r""" Every point is postcritically finite in a finite field. From 1969f502323ec1e1a667c31b27c8bfe49a16f48a Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Tue, 19 Nov 2019 21:08:38 +0100 Subject: [PATCH 188/340] add missing import --- src/sage/combinat/growth.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/combinat/growth.py b/src/sage/combinat/growth.py index fdb559880b8..86f6a6dd7f1 100644 --- a/src/sage/combinat/growth.py +++ b/src/sage/combinat/growth.py @@ -496,6 +496,7 @@ def _make_partition(l): TESTS:: + sage: from sage.combinat.growth import _make_partition sage: p = _make_partition([3,2,1,0]); p [3, 2, 1] From a946e6e817ccebe44f9c1b21dffeaf1339258fce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Wed, 20 Nov 2019 13:06:56 +1300 Subject: [PATCH 189/340] Update to cvxopt-1.2.3 and suitesparse 5.6.0 --- build/pkgs/cvxopt/checksums.ini | 6 +-- build/pkgs/cvxopt/package-version.txt | 2 +- build/pkgs/suitesparse/checksums.ini | 6 +-- build/pkgs/suitesparse/package-version.txt | 2 +- .../patches/01-no_cmake_project.patch | 46 +++++++++++++++---- .../suitesparse/patches/02-darwin_blas.patch | 5 +- 6 files changed, 47 insertions(+), 20 deletions(-) diff --git a/build/pkgs/cvxopt/checksums.ini b/build/pkgs/cvxopt/checksums.ini index ca0ae05037d..5e7a6fe107f 100644 --- a/build/pkgs/cvxopt/checksums.ini +++ b/build/pkgs/cvxopt/checksums.ini @@ -1,4 +1,4 @@ tarball=cvxopt-VERSION.tar.gz -sha1=43113a138e5e8f3ba42dc53ccb8c3c7501d5576b -md5=fc2546fdba2faa6c4996e9b40fce5269 -cksum=3288957477 +sha1=b16cf3b1c941d763ea0451e947e5661d38ee0473 +md5=aac3db3fc3cf11d9ad2e42d89e94ca5a +cksum=3018809057 diff --git a/build/pkgs/cvxopt/package-version.txt b/build/pkgs/cvxopt/package-version.txt index 23aa8390630..0495c4a88ca 100644 --- a/build/pkgs/cvxopt/package-version.txt +++ b/build/pkgs/cvxopt/package-version.txt @@ -1 +1 @@ -1.2.2 +1.2.3 diff --git a/build/pkgs/suitesparse/checksums.ini b/build/pkgs/suitesparse/checksums.ini index 4ff8609fb98..9516ea039ee 100644 --- a/build/pkgs/suitesparse/checksums.ini +++ b/build/pkgs/suitesparse/checksums.ini @@ -1,4 +1,4 @@ tarball=SuiteSparse-VERSION.tar.gz -sha1=2c484c8dfacfbb46b1af00c187e369c7a85d2ede -md5=d638a4369f3df0ca9e64b019af658a38 -cksum=4147428121 +sha1=3de08b5ab02610ed0446225aad2445696616fae5 +md5=af8b97cbded4cd5c6672e878bc0c37c2 +cksum=3062366378 diff --git a/build/pkgs/suitesparse/package-version.txt b/build/pkgs/suitesparse/package-version.txt index 03f488b076a..1bc788d3b6d 100644 --- a/build/pkgs/suitesparse/package-version.txt +++ b/build/pkgs/suitesparse/package-version.txt @@ -1 +1 @@ -5.3.0 +5.6.0 diff --git a/build/pkgs/suitesparse/patches/01-no_cmake_project.patch b/build/pkgs/suitesparse/patches/01-no_cmake_project.patch index 0884058370c..ccde30de327 100644 --- a/build/pkgs/suitesparse/patches/01-no_cmake_project.patch +++ b/build/pkgs/suitesparse/patches/01-no_cmake_project.patch @@ -1,40 +1,68 @@ diff --git a/Makefile b/Makefile -index 6a2ddc6..bf4b5e9 100644 +index 74941a6..70e7b68 100644 --- a/Makefile +++ b/Makefile -@@ -12,8 +12,6 @@ include SuiteSparse_config/SuiteSparse_config.mk +@@ -12,7 +12,6 @@ include SuiteSparse_config/SuiteSparse_config.mk # Compile the default rules for each package go: metis ( cd SuiteSparse_config && $(MAKE) ) -- ( cd GraphBLAS && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' ) - ( cd Mongoose && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' ) ( cd AMD && $(MAKE) ) ( cd BTF && $(MAKE) ) ( cd CAMD && $(MAKE) ) -@@ -38,8 +36,6 @@ endif +@@ -30,7 +29,6 @@ ifneq ($(GPU_CONFIG),) + ( cd GPUQREngine && $(MAKE) ) + endif + ( cd SPQR && $(MAKE) ) +- ( cd GraphBLAS && $(MAKE) JOBS=$(JOBS) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' ) + # ( cd PIRO_BAND && $(MAKE) ) + # ( cd SKYLINE_SVD && $(MAKE) ) + +@@ -38,7 +36,6 @@ endif # (note that CSparse is not installed; CXSparse is installed instead) install: metisinstall ( cd SuiteSparse_config && $(MAKE) install ) -- ( cd GraphBLAS && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' install ) - ( cd Mongoose && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' install ) ( cd AMD && $(MAKE) install ) ( cd BTF && $(MAKE) install ) ( cd CAMD && $(MAKE) install ) -@@ -116,8 +112,6 @@ endif +@@ -55,7 +52,6 @@ ifneq (,$(GPU_CONFIG)) + ( cd GPUQREngine && $(MAKE) install ) + endif + ( cd SPQR && $(MAKE) install ) +- ( cd GraphBLAS && $(MAKE) JOBS=$(JOBS) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' install ) + # ( cd PIRO_BAND && $(MAKE) install ) + # ( cd SKYLINE_SVD && $(MAKE) install ) + $(CP) README.txt $(INSTALL_DOC)/SuiteSparse_README.txt +@@ -116,7 +112,6 @@ endif # the static library library: metis ( cd SuiteSparse_config && $(MAKE) ) -- ( cd GraphBLAS && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' library ) - ( cd Mongoose && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' library ) ( cd AMD && $(MAKE) library ) ( cd BTF && $(MAKE) library ) ( cd CAMD && $(MAKE) library ) -@@ -143,8 +137,6 @@ endif +@@ -134,7 +129,6 @@ ifneq (,$(GPU_CONFIG)) + ( cd GPUQREngine && $(MAKE) library ) + endif + ( cd SPQR && $(MAKE) library ) +- ( cd GraphBLAS && $(MAKE) JOBS=$(JOBS) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' library ) + # ( cd PIRO_BAND && $(MAKE) library ) + # ( cd SKYLINE_SVD && $(MAKE) library ) + +@@ -143,7 +137,6 @@ endif # both the dynamic and static libraries. static: metis ( cd SuiteSparse_config && $(MAKE) static ) -- ( cd GraphBLAS && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' static ) - ( cd Mongoose && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' static ) ( cd AMD && $(MAKE) static ) ( cd BTF && $(MAKE) static ) ( cd CAMD && $(MAKE) static ) +@@ -161,7 +154,6 @@ ifneq (,$(GPU_CONFIG)) + ( cd GPUQREngine && $(MAKE) static ) + endif + ( cd SPQR && $(MAKE) static ) +- ( cd GraphBLAS && $(MAKE) JOBS=$(JOBS) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' static ) + # ( cd PIRO_BAND && $(MAKE) static ) + # ( cd SKYLINE_SVD && $(MAKE) static ) + diff --git a/build/pkgs/suitesparse/patches/02-darwin_blas.patch b/build/pkgs/suitesparse/patches/02-darwin_blas.patch index ed719bc8bfd..bfd0e0bc548 100644 --- a/build/pkgs/suitesparse/patches/02-darwin_blas.patch +++ b/build/pkgs/suitesparse/patches/02-darwin_blas.patch @@ -1,8 +1,8 @@ diff --git a/SuiteSparse_config/SuiteSparse_config.mk b/SuiteSparse_config/SuiteSparse_config.mk -index f991b7a..59ae6da 100644 +index 0a09188..90b2e57 100644 --- a/SuiteSparse_config/SuiteSparse_config.mk +++ b/SuiteSparse_config/SuiteSparse_config.mk -@@ -360,8 +360,8 @@ SUITESPARSE_VERSION = 5.3.0 +@@ -370,8 +370,8 @@ SUITESPARSE_VERSION = 5.6.0 # command line in the Terminal, before doing 'make': # xcode-select --install CF += -fno-common @@ -13,4 +13,3 @@ index f991b7a..59ae6da 100644 # OpenMP is not yet supported by default in clang CFOPENMP = endif - From e26e2600013bbb9bcdfc8dc70b3fe0ccac22c774 Mon Sep 17 00:00:00 2001 From: Thierry Monteil Date: Wed, 20 Nov 2019 13:17:42 +0100 Subject: [PATCH 190/340] #28763 : fix a bytes vs str Python3 issue in dimacs solver --- src/sage/sat/solvers/dimacs.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sage/sat/solvers/dimacs.py b/src/sage/sat/solvers/dimacs.py index ba361c603de..a18fc24b310 100644 --- a/src/sage/sat/solvers/dimacs.py +++ b/src/sage/sat/solvers/dimacs.py @@ -376,7 +376,6 @@ def __call__(self, assumptions=None): raise NotImplementedError("Assumptions are not supported for DIMACS based solvers.") self.write() - output_filename = None self._output = [] @@ -399,11 +398,11 @@ def __call__(self, assumptions=None): try: while process.poll() is None: - for line in iter(process.stdout.readline,''): + for line in iter(process.stdout.readline, b''): if get_verbose() or self._verbosity: print(line) sys.stdout.flush() - self._output.append(line) + self._output.append(line.decode('utf-8')) sleep(0.1) if output_filename: self._output.extend(open(output_filename).readlines()) From 321adf3cecc6dbc198ca92c2481ff832e8e6e380 Mon Sep 17 00:00:00 2001 From: Benjamin Hutz Date: Wed, 20 Nov 2019 07:38:04 -0600 Subject: [PATCH 191/340] 28170: fix from review comments --- .../dynamics/arithmetic_dynamics/projective_ds.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index b0b07246f24..c30e3c90453 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -6395,10 +6395,12 @@ def reduce_base_field(self): class DynamicalSystem_projective_finite_field(DynamicalSystem_projective_field, SchemeMorphism_polynomial_projective_space_finite_field): - def is_postcritically_finite(self): + def is_postcritically_finite(self, **kwds): r""" Every point is postcritically finite in a finite field. + INPUT: None. ``kwds`` is to parallel the overridden function + OUTPUT: the boolean ``True`` EXAMPLES:: @@ -6407,6 +6409,13 @@ def is_postcritically_finite(self): sage: f = DynamicalSystem_projective([x^2 + y^2,y^2, z^2 + y*z], domain=P) sage: f.is_postcritically_finite() True + + :: + + sage: P. = ProjectiveSpace(GF(13),1) + sage: f = DynamicalSystem_projective([x^4 - x^2*y^2 + y^4, y^4]) + sage: f.is_postcritically_finite(use_algebraic_closure=False) + True """ return True From dba0660fb3319fadcc1482a1b8db637a47678c03 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Wed, 20 Nov 2019 15:09:30 +0100 Subject: [PATCH 192/340] Trac #27784: Rank defined in documentation --- src/sage/manifolds/differentiable/characteristic_class.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_class.py b/src/sage/manifolds/differentiable/characteristic_class.py index 43df4824f4e..2b78003e0ab 100644 --- a/src/sage/manifolds/differentiable/characteristic_class.py +++ b/src/sage/manifolds/differentiable/characteristic_class.py @@ -1,8 +1,8 @@ r""" Characteristic Classes -Let `E \to M` be some topological vector bundle over a topological manifold `M` -and `R` be any ring. +Let `E \to M` be a topological vector bundle of rank `n` over a topological +manifold `M` and `R` be any ring. A *characteristic class* `c(E)` is an element of the cohomology ring `H^{*}(M, R)` such that for any continuous map `f: M \to N`, where `N` is another topological manifold, the *naturality condition* is satisfied: From 54f771b59cbacce7c58727841aa9a1a7ef15d79c Mon Sep 17 00:00:00 2001 From: Benjamin Hutz Date: Wed, 20 Nov 2019 11:44:52 -0600 Subject: [PATCH 193/340] 25701: add sieve to rational_points, clean up docs --- src/sage/schemes/generic/algebraic_scheme.py | 5 ++ src/sage/schemes/product_projective/homset.py | 46 ++++++++++++++++--- .../product_projective/rational_point.py | 43 ++++++++--------- 3 files changed, 62 insertions(+), 32 deletions(-) diff --git a/src/sage/schemes/generic/algebraic_scheme.py b/src/sage/schemes/generic/algebraic_scheme.py index 4a1b5e9b03d..d5159533934 100644 --- a/src/sage/schemes/generic/algebraic_scheme.py +++ b/src/sage/schemes/generic/algebraic_scheme.py @@ -1717,6 +1717,11 @@ def rational_points(self, **kwds): In the case of numerically approximated points, the points are returned over as points of the ambient space. + For a dimesion greater than 0 scheme, depending on bound size, either the + points in the ambient space are enumerated or a sieving algorithm lifting points + modulo primes is used. See the documention in homset for the details of the + sieving algorithm. + INPUT: kwds: diff --git a/src/sage/schemes/product_projective/homset.py b/src/sage/schemes/product_projective/homset.py index f1508cf794b..353aa4288ef 100644 --- a/src/sage/schemes/product_projective/homset.py +++ b/src/sage/schemes/product_projective/homset.py @@ -21,8 +21,10 @@ from sage.categories.fields import Fields from sage.categories.number_fields import NumberFields from sage.misc.mrange import xmrange +from sage.misc.misc_c import prod from sage.rings.finite_rings.finite_field_constructor import is_FiniteField from sage.rings.rational_field import is_RationalField +from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme from sage.schemes.generic.homset import SchemeHomset_points class SchemeHomset_points_product_projective_spaces_ring(SchemeHomset_points): @@ -76,7 +78,9 @@ def points(self, **kwds): For number fields, this uses the Doyle-Krumm algorithm 4 (algorithm 5 for imaginary quadratic) for - computing algebraic numbers up to a given height [DK2013]_. + computing algebraic numbers up to a given height [DK2013]_ or + uses the chinese remainder theorem and points modulo primes + for larger bounds. The algorithm requires floating point arithmetic, so the user is allowed to specify the precision for such calculations. @@ -117,7 +121,7 @@ def points(self, **kwds): sage: u = QQ['u'].0 sage: K = NumberField(u^2 + 1, 'v') sage: P. = ProductProjectiveSpaces([1, 1], K) - sage: P(K).points(bound=1) + sage: P(K).points(bound=1) [(-1 : 1 , -1 : 1), (-1 : 1 , -v : 1), (-1 : 1 , 0 : 1), (-1 : 1 , v : 1), (-1 : 1 , 1 : 0), (-1 : 1 , 1 : 1), (-v : 1 , -1 : 1), (-v : 1 , -v : 1), (-v : 1 , 0 : 1), (-v : 1 , v : 1), (-v : 1 , 1 : 0), (-v : 1 , 1 : 1), @@ -131,7 +135,7 @@ def points(self, **kwds): :: sage: P. = ProductProjectiveSpaces([2, 1], GF(3)) - sage: P(P.base_ring()).points() + sage: P(P.base_ring()).points() [(0 : 0 : 1 , 0 : 1), (0 : 0 : 1 , 1 : 0), (0 : 0 : 1 , 1 : 1), (0 : 0 : 1 , 2 : 1), (0 : 1 : 0 , 0 : 1), (0 : 1 : 0 , 1 : 0), (0 : 1 : 0 , 1 : 1), (0 : 1 : 0 , 2 : 1), (0 : 1 : 1 , 0 : 1), (0 : 1 : 1 , 1 : 0), (0 : 1 : 1 , 1 : 1), (0 : 1 : 1 , 2 : 1), @@ -145,8 +149,30 @@ def points(self, **kwds): (2 : 1 : 0 , 0 : 1), (2 : 1 : 0 , 1 : 0), (2 : 1 : 0 , 1 : 1), (2 : 1 : 0 , 2 : 1), (2 : 1 : 1 , 0 : 1), (2 : 1 : 1 , 1 : 0), (2 : 1 : 1 , 1 : 1), (2 : 1 : 1 , 2 : 1), (2 : 2 : 1 , 0 : 1), (2 : 2 : 1 , 1 : 0), (2 : 2 : 1 , 1 : 1), (2 : 2 : 1 , 2 : 1)] - """ - B = kwds.pop('bound', 0) + + :: + + sage: PP. = ProductProjectiveSpaces([2,1], QQ) + sage: X = PP.subscheme([x + y, u*u-v*u]) + sage: X.rational_points(bound=2) + [(-2 : 2 : 1 , 0 : 1), + (-2 : 2 : 1 , 1 : 1), + (-1 : 1 : 0 , 0 : 1), + (-1 : 1 : 0 , 1 : 1), + (-1 : 1 : 1 , 0 : 1), + (-1 : 1 : 1 , 1 : 1), + (-1/2 : 1/2 : 1 , 0 : 1), + (-1/2 : 1/2 : 1 , 1 : 1), + (0 : 0 : 1 , 0 : 1), + (0 : 0 : 1 , 1 : 1), + (1/2 : -1/2 : 1 , 0 : 1), + (1/2 : -1/2 : 1 , 1 : 1), + (1 : -1 : 1 , 0 : 1), + (1 : -1 : 1 , 1 : 1), + (2 : -2 : 1 , 0 : 1), + (2 : -2 : 1 , 1 : 1)] + """ + B = kwds.pop('bound', 0) X = self.codomain() from sage.schemes.product_projective.space import is_ProductProjectiveSpaces @@ -169,8 +195,14 @@ def points(self, **kwds): if is_RationalField(R): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified"%B) - from sage.schemes.product_projective.rational_point import enum_product_projective_rational_field - return enum_product_projective_rational_field(self, B) + # sieve should only be called for subschemes and if the bound is not very small + N = prod([k+1 for k in X.ambient_space().dimension_relative_components()]) + if isinstance(X, AlgebraicScheme_subscheme) and B**N > 5000: + from sage.schemes.product_projective.rational_point import sieve + return sieve(X, B) + else: + from sage.schemes.product_projective.rational_point import enum_product_projective_rational_field + return enum_product_projective_rational_field(self, B) elif R in NumberFields(): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified"%B) diff --git a/src/sage/schemes/product_projective/rational_point.py b/src/sage/schemes/product_projective/rational_point.py index a0e0124fd58..efa271a9dbf 100644 --- a/src/sage/schemes/product_projective/rational_point.py +++ b/src/sage/schemes/product_projective/rational_point.py @@ -301,36 +301,31 @@ def enum_product_projective_finite_field(X): def sieve(X, bound): r""" - Returns the list of all product projective, rational points on scheme ``X`` of - height up to ``bound``. - - Height of a product projective point X = (x_1, x_2,..., x_n) is given by - H_X = max(y_1, y_2,..., y_n), where H_X is height of point X and y_i's - are the normalized coordinates such that all y_i are integers and - gcd(y_1, y_2,..., y_n) = 1. + Returns the list of all rational points on scheme + ``X`` of height up to ``bound``. ALGORITHM: Main idea behind the algorithm is to find points modulo primes and then reconstruct them using chinese remainder theorem. - We find modulo primes parallely and then lift them and apply - LLL in parallel. LLL reduction is applied for each component - projective space, and finally result is merged and converted - to product projective point. + We compute the points modulo primes parallely and then lift + them via chinese remainder theorem in parallel. The LLL reduction + algorithm is applied to each component of the points, and finally + the result is merged and converted to a point on the subscheme. For the algorithm to work correctly, sufficient primes need - to be present, these are calculated using the bound given in - this([Hutz2015]_) paper. + to be chosen, these are determined using the bounds dependent + on the bound given in [Hutz2015]_. INPUT: - - ``X`` - a scheme with ambient space defined over projective space + - ``X`` - a scheme with ambient space defined over a product of projective spaces - ``bound`` - a positive integer bound OUTPUT: - - a list containing the projective rational points of ``X`` of height + - a list containing the rational points of ``X`` of height up to ``bound``, sorted EXAMPLES:: @@ -342,7 +337,6 @@ def sieve(X, bound): [(0 : 0 : 1 , 0 : 1), (0 : 0 : 1 , 1 : 1), (1/2 : -1/2 : 1 , 0 : 1), (1/2 : -1/2 : 1 , 1 : 1), (1/2 : 1/2 : 1 , 0 : 1), (1/2 : 1/2 : 1 , 1 : 1), (1 : 0 : 1 , 0 : 1), (1 : 0 : 1 , 1 : 1)] - """ if bound < 1: @@ -382,15 +376,15 @@ def sufficient_primes(x): def good_primes(B): r""" - Given the bound returns the prime whose product is greater than ``B`` - and which would take least amount of time to run main sieve algorithm + Given the bound, returns the primes whose product is greater than ``B`` + and which would take the least amount of time to run the main sieve algorithm Complexity of finding points modulo primes is assumed to be N^2 * P_max^{N}. - Complexity of lifting points and LLL() function is assumed to + Complexity of lifting points and the LLL() function is assumed to be close to (dim_max^5) * (alpha / P_max)^dim_scheme. - where alpha is product of all primes, P_max is largest prime in list, - dim_max is the max of dimension of all components, and N is dimension - of ambient space. + where alpha is the product of all primes, P_max is the largest prime in + the list, dim_max is the max dimension of all components, and N is the dimension + of the ambient space. """ M = dict() # stores optimal list of primes, corresponding to list size @@ -409,7 +403,7 @@ def good_primes(B): for i in range(current_count): current_list.append(next_prime(least)) least = current_list[-1] - # improving list of primes by taking prime less than least + # improving list of primes by taking primes less than least # this part of algorithm is used to centralize primes around `least` prod_prime = prod(current_list) least = current_list[0] @@ -437,7 +431,7 @@ def good_primes(B): def parallel_function(X, p): r""" Function used in parallel computation, computes a list of - all rational points in modulo ring. + all rational points in modulo p. """ Xp = X.change_ring(GF(p)) L = Xp.rational_points() @@ -544,4 +538,3 @@ def lift_all_points(): rat_points = lift_all_points() return sorted(rat_points) - From a8ec0ca1c519a6cc19e2d7c8112d2ff05b159b37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Wed, 20 Nov 2019 21:06:04 +0100 Subject: [PATCH 194/340] 28762: py3: fixing doctests for rst2ipynb --- src/sage/tests/cmdline.py | 112 ++++++++------------------------------ 1 file changed, 23 insertions(+), 89 deletions(-) diff --git a/src/sage/tests/cmdline.py b/src/sage/tests/cmdline.py index b5e1a4e603e..a2bff9d883b 100644 --- a/src/sage/tests/cmdline.py +++ b/src/sage/tests/cmdline.py @@ -654,77 +654,19 @@ def test_executable(args, input="", timeout=100.0, **kwds): sage: with open(input, 'w') as F: ....: _ = F.write(s) sage: L = ["sage", "--rst2ipynb", input] - sage: (out, err, ret) = test_executable(L) # optional - rst2ipynb - sage: print(out) # optional - rst2ipynb - { - "nbformat_minor": ..., - "nbformat": ..., - "cells": [ - { - "source": [ - "$$\n", - "\\def\\CC{\\bf C}\n", - "\\def\\QQ{\\bf Q}\n", - "\\def\\RR{\\bf R}\n", - "\\def\\ZZ{\\bf Z}\n", - "\\def\\NN{\\bf N}\n", - "$$" - ], - "cell_type": "markdown", - "metadata": {} - }, - { - "execution_count": null, - "cell_type": "code", - "source": [ - "2^10" - ], - "outputs": [ - { - "execution_count": 1, - "output_type": "execute_result", - "data": { - "text/plain": [ - "1024" - ] - }, - "metadata": {} - } - ], - "metadata": {} - }, - { - "execution_count": null, - "cell_type": "code", - "source": [ - "2 + 2" - ], - "outputs": [ - { - "execution_count": 1, - "output_type": "execute_result", - "data": { - "text/plain": [ - "4" - ] - }, - "metadata": {} - } - ], - "metadata": {} - } - ], - "metadata": { - "kernelspec": { - "display_name": "sagemath", - "name": "sagemath" - } - } - } - sage: err # optional - rst2ipynb - '' - sage: ret # optional - rst2ipynb + sage: (out, err, ret) = test_executable(L) # optional - rst2ipynb + sage: err # optional - rst2ipynb + '' + sage: ret # optional - rst2ipynb 0 + sage: from json import loads # optional - rst2ipynb + sage: d = loads(out) # optional - rst2ipynb + sage: sorted(d.keys()) # optional - rst2ipynb + ['cells', 'metadata', 'nbformat', 'nbformat_minor'] + sage: d['cells'][1]['source'] # optional - rst2ipynb + ['2^10'] + sage: d['cells'][2]['source'] # optional - rst2ipynb + ['2 + 2'] Test ``sage --rst2ipynb file.rst file.ipynb`` on a ReST file:: @@ -734,26 +676,18 @@ def test_executable(args, input="", timeout=100.0, **kwds): sage: with open(input, 'w') as F: ....: _ = F.write(s) sage: L = ["sage", "--rst2ipynb", input, output] - sage: test_executable(L) # optional - rst2ipynb + sage: test_executable(L) # optional - rst2ipynb ('', '', 0) - sage: print(open(output, 'r').read()) # optional - rst2ipynb - { - "nbformat_minor": ..., - "nbformat": ..., - "cells": [ - { - "source": [ - "$$\n", - "\\def\\CC{\\bf C}\n", - "\\def\\QQ{\\bf Q}\n", - ... - "metadata": { - "kernelspec": { - "display_name": "sagemath", - "name": "sagemath" - } - } - } + sage: import json # optional - rst2ipynb + sage: d = json.load(open(output,'r')) # optional - rst2ipynb + sage: type(d) # optional - rst2ipynb + + sage: sorted(d.keys()) # optional - rst2ipynb + ['cells', 'metadata', 'nbformat', 'nbformat_minor'] + sage: d['metadata'] # optional - rst2ipynb + {'kernelspec': {'display_name': 'sagemath', 'name': 'sagemath'}} + sage: d['cells'][1]['cell_type'] # optional - rst2ipynb + 'code' Test ``sage --ipynb2rst file.ipynb file.rst`` on a ipynb file:: From 90fb5c81c856e5ad91f4cfae1ceb1a213e2e2dec Mon Sep 17 00:00:00 2001 From: Benjamin Hutz Date: Wed, 20 Nov 2019 14:11:55 -0600 Subject: [PATCH 195/340] 23720: doc updates, doc test fixing, input flexibility improved --- .../dynamics/complex_dynamics/mandel_julia.py | 62 ++++++++++++------- .../complex_dynamics/mandel_julia_helper.pyx | 12 ++-- 2 files changed, 48 insertions(+), 26 deletions(-) diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia.py b/src/sage/dynamics/complex_dynamics/mandel_julia.py index c99cba08da3..743c13b6715 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia.py +++ b/src/sage/dynamics/complex_dynamics/mandel_julia.py @@ -8,7 +8,9 @@ `f_c(z)` does not diverge when iterated from `z = 0`. This set of complex numbers can be visualized by plotting each value for `c` in the complex plane. The Mandelbrot set is often an example of a fractal when plotted in the complex -plane. +plane. For general one parameter families of polynomials, the mandelbrot set +is the parameter values for which the orbits of all critical points remains +bounded. The Julia set for a given parameter `c` is the set of complex numbers for which the function `f_c(z)` is bounded under iteration. @@ -59,10 +61,10 @@ def mandelbrot_plot(f=None, **kwds): r""" - Plot of the Mandelbrot set for a general polynomial map `f_c(z)`. - - If a general polynomial map `f_c(z)` is passed, parent R must be of the - form `R. = CC[]`. + Plot of the Mandelbrot set for a one parameter family of polynomial maps. + + The family `f_c(z)` must have parent ``R`` of the + form ``R. = CC[]``. REFERENCE: @@ -70,7 +72,7 @@ def mandelbrot_plot(f=None, **kwds): INPUT: - - ``f`` -- map (optional - default: ``z^2 + c``), polynomial map used to + - ``f`` -- map (optional - default: ``z^2 + c``), polynomial family used to plot the Mandelbrot set. - ``parameter`` -- variable (optional - default: ``c``), parameter variable @@ -129,20 +131,36 @@ def mandelbrot_plot(f=None, **kwds): ``interact`` to ``True``. (This is only implemented for ``z^2 + c``):: sage: mandelbrot_plot(interact=True) - ... + interactive(children=(FloatSlider(value=0.0, description=u'Real center', max=1.0, min=-1.0, step=1e-05), + FloatSlider(value=0.0, description=u'Imag center', max=1.0, min=-1.0, step=1e-05), + FloatSlider(value=4.0, description=u'Width', max=4.0, min=1e-05, step=1e-05), + IntSlider(value=500, description=u'Iterations', max=1000), + IntSlider(value=500, description=u'Pixels', max=1000, min=10), + IntSlider(value=1, description=u'Color sep', max=20, min=1), + IntSlider(value=30, description=u'# Colors', min=1), + ColorPicker(value='#ff6347', description=u'Base color'), Output()), + _dom_classes=(u'widget-interact',)) :: sage: mandelbrot_plot(interact=True, x_center=-0.75, y_center=0.25, ....: image_width=1/2, number_of_colors=75) - ... + interactive(children=(FloatSlider(value=-0.75, description=u'Real center', max=1.0, min=-1.0, step=1e-05), + FloatSlider(value=0.25, description=u'Imag center', max=1.0, min=-1.0, step=1e-05), + FloatSlider(value=0.5, description=u'Width', max=4.0, min=1e-05, step=1e-05), + IntSlider(value=500, description=u'Iterations', max=1000), + IntSlider(value=500, description=u'Pixels', max=1000, min=10), + IntSlider(value=1, description=u'Color sep', max=20, min=1), + IntSlider(value=75, description=u'# Colors', min=1), + ColorPicker(value='#ff6347', description=u'Base color'), Output()), + _dom_classes=(u'widget-interact',)) Polynomial maps can be defined over a multivariate polynomial ring or a univariate polynomial ring tower:: sage: R. = CC[] sage: f = z^2 + c - sage: mandelbrot_plot(f) # not tested + sage: mandelbrot_plot(f) 500x500px 24-bit RGB image :: @@ -150,7 +168,7 @@ def mandelbrot_plot(f=None, **kwds): sage: B. = CC[] sage: R. = B[] sage: f = z^5 + c - sage: mandelbrot_plot(f) # not tested + sage: mandelbrot_plot(f) 500x500px 24-bit RGB image When the polynomial is defined over a multivariate polynomial ring it is @@ -158,14 +176,16 @@ def mandelbrot_plot(f=None, **kwds): sage: R. = CC[] sage: f = a^2 + b^3 - sage: mandelbrot_plot(f, parameter=b) # not tested + sage: mandelbrot_plot(f, parameter=b) 500x500px 24-bit RGB image Interact functionality is not implemented for general polynomial maps:: sage: R. = CC[] sage: f = z^3 + c - sage: mandelbrot_plot(f, interact=True) # not tested + sage: mandelbrot_plot(f, interact=True) + Traceback (most recent call last): + ... NotImplementedError: Interact only implemented for z^2 + c """ parameter = kwds.pop("parameter", None) @@ -192,10 +212,10 @@ def mandelbrot_plot(f=None, **kwds): y_center = FloatSlider(min=-1.0, max=1.0, step=EPS, value=y_center, description="Imag center"), image_width = FloatSlider(min=EPS, max=4.0, step=EPS, - value=image_width, description="Zoom"), - max_iteration = IntSlider(min=0, max=600, + value=image_width, description="Width"), + max_iteration = IntSlider(min=0, max=1000, value=max_iteration, description="Iterations"), - pixel_count = IntSlider(min=10, max=600, + pixel_count = IntSlider(min=10, max=1000, value=pixel_count, description="Pixels"), level_sep = IntSlider(min=1, max=20, value=level_sep, description="Color sep"), @@ -204,13 +224,13 @@ def mandelbrot_plot(f=None, **kwds): base_color = ColorPicker(value=Color(base_color).html_color(), description="Base color"), ) - + if f is None: # Quadratic map f = z^2 + c - + if interacts: return interact(**widgets).widget(fast_mandelbrot_plot) - + else: return fast_mandelbrot_plot(x_center, y_center, image_width, max_iteration, pixel_count, level_sep, number_of_colors, @@ -552,10 +572,10 @@ def julia_plot(c=-1, y_center = FloatSlider(min=-1.0, max=1.0, step=EPS, value=y_center, description="Imag center"), image_width = FloatSlider(min=EPS, max=4.0, step=EPS, - value=image_width, description="Zoom"), - max_iteration = IntSlider(min=0, max=600, + value=image_width, description="Width"), + max_iteration = IntSlider(min=0, max=1000, value=max_iteration, description="Iterations"), - pixel_count = IntSlider(min=10, max=600, + pixel_count = IntSlider(min=10, max=1000, value=pixel_count, description="Pixels"), level_sep = IntSlider(min=1, max=20, value=level_sep, description="Color sep"), diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx index c6c4a4d1ea3..953d5e9b613 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +++ b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx @@ -79,12 +79,12 @@ cpdef fast_mandelbrot_plot(double x_center, double y_center, - ``x_center`` -- double, real part of the center point in the complex plane. - ``y_center`` -- double, imaginary part of the center point in the complex - plane. + plane. - ``image_width`` -- double, width of the image in the complex plane. - ``max_iteration`` -- long, maximum number of iterations the map `Q_c(z)` - considered. + considered. - ``pixel_count`` -- long, side length of image in number of pixels. @@ -624,11 +624,11 @@ cpdef polynomial_mandelbrot(f, parameter=None, double x_center=0, double y_center=0, image_width=4, int max_iteration=50, int pixel_count=500, int level_sep=1, int color_num=30, base_color=Color('red')): r""" - Plots the Mandelbrot set in the complex plane for a general polynomial map. + Plots the Mandelbrot set in the complex plane for a family of polynomial maps. INPUT: - - ``f`` -- polynomial map defined over the multivariate polynomial ring in + - ``f`` -- a one parameter family of polynomial maps defined over the multivariate polynomial ring in z, c over the Complex field. - ``parameter`` -- designates which variable is used as the parameter. @@ -701,6 +701,8 @@ cpdef polynomial_mandelbrot(f, parameter=None, double x_center=0, elif P.base_ring().base_ring() is CC: if is_FractionField(P.base_ring()): raise NotImplementedError("coefficients must be polynomials in the parameter") + phi = P.flattening_morphism() + f = phi(f) parameter = P.base_ring().gen() variable = P.gen() @@ -736,7 +738,7 @@ cpdef polynomial_mandelbrot(f, parameter=None, double x_center=0, if len(R.gens()) > 2: return NotImplementedError("Base ring must have only 2 variables") z, c = R.gens() - f = R(f) + f = R(str(f)) S = PolynomialRing(f.base_ring(), 'x,y,J,cr,ci') x,y,J,cr,ci = S.gens() S2 = S.quotient_ring(J**2+1) From 6fdc67db8d8ae65393a38df5d3c1ea688946907d Mon Sep 17 00:00:00 2001 From: Benjamin Hutz Date: Wed, 20 Nov 2019 14:26:07 -0600 Subject: [PATCH 196/340] 25701: added algorithm parameter --- src/sage/schemes/product_projective/homset.py | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/sage/schemes/product_projective/homset.py b/src/sage/schemes/product_projective/homset.py index 353aa4288ef..d4b71c27923 100644 --- a/src/sage/schemes/product_projective/homset.py +++ b/src/sage/schemes/product_projective/homset.py @@ -97,6 +97,9 @@ def points(self, **kwds): - ``precision`` - the precision to use for computing the elements of bounded height of number fields. + - ``algorithm`` - either 'sieve' or 'enumerate' algorithms can be used over `QQ`. If + not specified, enumerate is used only for small height bounds. + OUTPUT: - a list of rational points of a projective scheme @@ -171,6 +174,13 @@ def points(self, **kwds): (1 : -1 : 1 , 1 : 1), (2 : -2 : 1 , 0 : 1), (2 : -2 : 1 , 1 : 1)] + + better to enumerate with low codimension:: + + sage: PP. = ProductProjectiveSpaces([2,1,2], QQ) + sage: X = PP.subscheme([x*u^2*a, b*z*u*v,z*v^2*c ]) + sage: len(X.rational_points(bound=1, algorithm='enumerate')) + 232 """ B = kwds.pop('bound', 0) X = self.codomain() @@ -195,14 +205,24 @@ def points(self, **kwds): if is_RationalField(R): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified"%B) - # sieve should only be called for subschemes and if the bound is not very small - N = prod([k+1 for k in X.ambient_space().dimension_relative_components()]) - if isinstance(X, AlgebraicScheme_subscheme) and B**N > 5000: + alg = kwds.pop('algorithm', None) + if alg is None: + # sieve should only be called for subschemes and if the bound is not very small + N = prod([k+1 for k in X.ambient_space().dimension_relative_components()]) + if isinstance(X, AlgebraicScheme_subscheme) and B**N > 5000: + from sage.schemes.product_projective.rational_point import sieve + return sieve(X, B) + else: + from sage.schemes.product_projective.rational_point import enum_product_projective_rational_field + return enum_product_projective_rational_field(self, B) + elif alg == 'sieve': from sage.schemes.product_projective.rational_point import sieve return sieve(X, B) - else: + elif alg == 'enumerate': from sage.schemes.product_projective.rational_point import enum_product_projective_rational_field return enum_product_projective_rational_field(self, B) + else: + raise ValueError("algorithm must be 'sieve' or 'enumerate'") elif R in NumberFields(): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified"%B) From 6a1d52713be3d0b5d94b4f1c90dba2cedbb56228 Mon Sep 17 00:00:00 2001 From: Benjamin Hutz Date: Wed, 20 Nov 2019 14:38:52 -0600 Subject: [PATCH 197/340] 23720: minor update --- src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx index 953d5e9b613..11b77cfa00f 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +++ b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx @@ -684,7 +684,6 @@ cpdef polynomial_mandelbrot(f, parameter=None, double x_center=0, I = CDF.gen() constant_c = True - # Is this needed in cython file also? This parsing is done in python file. if parameter is None: c = var('c') parameter = c @@ -754,7 +753,7 @@ cpdef polynomial_mandelbrot(f, parameter=None, double x_center=0, try: df = f.derivative(z).univariate_polynomial() critical_pts = df.roots(multiplicities=False) - + constant_c = True except: constant_c = False From d0f4e951532d1d7b26c6554bd6a00d6b58662a87 Mon Sep 17 00:00:00 2001 From: Benjamin Hutz Date: Wed, 20 Nov 2019 14:55:00 -0600 Subject: [PATCH 198/340] 23720: update doctest --- src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx index 11b77cfa00f..0ea4cc86ff3 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +++ b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx @@ -667,8 +667,8 @@ cpdef polynomial_mandelbrot(f, parameter=None, double x_center=0, :: sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import polynomial_mandelbrot - sage: B. = CC[] - sage: R. = B[] + sage: B. = CC[] + sage: R. = B[] sage: f = z^4 - z + c sage: polynomial_mandelbrot(f, pixel_count=100) 100x100px 24-bit RGB image From a1bee7a0e89378dc8769e57e966b26681235c830 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Wed, 20 Nov 2019 22:54:57 +0100 Subject: [PATCH 199/340] Make ScalarField.__eq__() more robust --- src/sage/manifolds/scalarfield.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/manifolds/scalarfield.py b/src/sage/manifolds/scalarfield.py index 87141cd0b14..8ac72252c7e 100644 --- a/src/sage/manifolds/scalarfield.py +++ b/src/sage/manifolds/scalarfield.py @@ -1277,7 +1277,7 @@ def __eq__(self, other): return False try: other = self.parent()(other) # conversion to a scalar field - except TypeError: + except Exception: return False if other._domain != self._domain: return False From 0c4e9b260f5cb014d66ce68bc4c0506f4004fa57 Mon Sep 17 00:00:00 2001 From: Paul Fili Date: Wed, 20 Nov 2019 16:08:11 -0600 Subject: [PATCH 200/340] Fixed error, clears LCM of denominators always, GCD as appropriate --- .../schemes/projective/projective_morphism.py | 43 ++++++++++++++----- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index f6b49c1336a..7085f46448e 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -719,9 +719,10 @@ def scale_by(self, t): def normalize_coordinates(self): """ - Scales by 1/gcd of the coordinate functions. + Ensures that this morphism has integral coefficients, and, + if the number field has a GCD, then it ensures that the + coefficients have no common factor. - Scales to clear any denominators from the coefficients. Also, makes the leading coefficients of the first polynomial positive. This is done in place. @@ -770,29 +771,51 @@ def normalize_coordinates(self): sage: K. = QuadraticField(5) sage: P. = ProjectiveSpace(K, 1) sage: f = DynamicalSystem([w*x^2 + (1/5*w)*y^2, w*y^2]) - sage: f.normalize_coordinates();f + sage: f.normalize_coordinates(); f Dynamical System of Projective Space of dimension 1 over Number Field in w with defining polynomial x^2 - 5 with w = 2.236067977499790? Defn: Defined on coordinates by sending (x : y) to (5*x^2 + y^2 : 5*y^2) - .. NOTE:: gcd raises an error if the base_ring does not support gcds. + :: + + sage: R. = PolynomialRing(ZZ) + sage: K. = NumberField(t^3 - 11) + sage: a = 7/(b-1) + sage: P. = ProjectiveSpace(K, 1) + sage: f = DynamicalSystem_projective([a*y^2 - (a*y-x)^2, y^2]) + sage: f.normalize_coordinates(); f + Dynamical System of Projective Space of dimension 1 over Number Field in b with defining polynomial t^3 - 11 + Defn: Defined on coordinates by sending (x : y) to + (-100*x^2 + (140*b^2 + 140*b + 140)*x*y + (-77*b^2 - 567*b - 1057)*y^2 : 100*y^2) + """ + # clear any denominators from the coefficients + N = self.codomain().ambient_space().dimension_relative() + 1 + LCM = lcm([self[i].denominator() for i in range(N)]) + self.scale_by(LCM) + + R = self.domain().base_ring() + + # There are cases, such as the example above over GF(7), + # where we want to compute GCDs, but NOT in the case + # where R is a NumberField of class number > 1. + if R in NumberFields: + if R.class_number() > 1: + return + + # R is a Number Field with class number 1 (i.e., a UFD) then + # we can compute GCDs, so we attempt to remove any common factors. + GCD = gcd(self[0], self[1]) index = 2 - R = self.domain().base_ring() - N = self.codomain().ambient_space().dimension_relative() + 1 while GCD != 1 and index < N: GCD = gcd(GCD, self[index]) index += +1 if GCD != 1: self.scale_by(R(1) / GCD) - #clears any denominators from the coefficients - LCM = lcm([self[i].denominator() for i in range(N)]) - self.scale_by(LCM) - #scales by 1/gcd of the coefficients. if R in _NumberFields: O = R.maximal_order() From e7f6676cdbdc48a53967f740009ea29a4e1f34aa Mon Sep 17 00:00:00 2001 From: kevin lui Date: Wed, 14 Aug 2019 15:08:13 -0700 Subject: [PATCH 201/340] added precision argument to elliptic_j --- src/sage/functions/special.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index 9e573519901..80800ff2538 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -298,7 +298,7 @@ def _print_latex_(self, n, m, theta, phi): ####### elliptic functions and integrals -def elliptic_j(z): +def elliptic_j(z, prec = 53): r""" Returns the elliptic modular `j`-function evaluated at `z`. @@ -335,12 +335,13 @@ def elliptic_j(z): sage: tau = (1 + sqrt(-163))/2 sage: (-elliptic_j(tau.n(100)).real().round())^(1/3) 640320 - + sage: (-elliptic_j(tau, 100).real().round())^(1/3) + 640320 """ CC = z.parent() from sage.rings.complex_field import is_ComplexField if not is_ComplexField(CC): - CC = ComplexField() + CC = ComplexField(prec) try: z = CC(z) except ValueError: From 2c20be9327bc6a43414b63767cc0c369be62b46f Mon Sep 17 00:00:00 2001 From: Gerardo Zelaya Eufemia Date: Fri, 6 Sep 2019 15:28:37 -0700 Subject: [PATCH 202/340] corrected all klui suggestions except pari input precision --- src/sage/functions/special.py | 77 ++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index 80800ff2538..b522339426f 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -298,56 +298,59 @@ def _print_latex_(self, n, m, theta, phi): ####### elliptic functions and integrals -def elliptic_j(z, prec = 53): - r""" - Returns the elliptic modular `j`-function evaluated at `z`. +def elliptic_j(z, prec=53): + r""" + Returns the elliptic modular `j`-function evaluated at `z`. + + INPUT: - INPUT: + - ``z`` (complex) -- a complex number with positive imaginary part. - - ``z`` (complex) -- a complex number with positive imaginary part. + - ``prec`` (default: 53) -- precision in bits for the complex field. - OUTPUT: + OUTPUT: - (complex) The value of `j(z)`. + (complex) The value of `j(z)`. - ALGORITHM: + ALGORITHM: - Calls the ``pari`` function ``ellj()``. + Calls the ``pari`` function ``ellj()``. - AUTHOR: + AUTHOR: - John Cremona + John Cremona - EXAMPLES:: + EXAMPLES:: - sage: elliptic_j(CC(i)) - 1728.00000000000 - sage: elliptic_j(sqrt(-2.0)) - 8000.00000000000 - sage: z = ComplexField(100)(1,sqrt(11))/2 - sage: elliptic_j(z) - -32768.000... - sage: elliptic_j(z).real().round() - -32768 + sage: elliptic_j(CC(i)) + 1728.00000000000 + sage: elliptic_j(sqrt(-2.0)) + 8000.00000000000 + sage: z = ComplexField(100)(1,sqrt(11))/2 + sage: elliptic_j(z) + -32768.000... + sage: elliptic_j(z).real().round() + -32768 :: - sage: tau = (1 + sqrt(-163))/2 - sage: (-elliptic_j(tau.n(100)).real().round())^(1/3) - 640320 - sage: (-elliptic_j(tau, 100).real().round())^(1/3) - 640320 - """ - CC = z.parent() - from sage.rings.complex_field import is_ComplexField - if not is_ComplexField(CC): - CC = ComplexField(prec) - try: - z = CC(z) - except ValueError: - raise ValueError("elliptic_j only defined for complex arguments.") - from sage.libs.all import pari - return CC(pari(z).ellj()) + sage: tau = (1 + sqrt(-163))/2 + sage: (-elliptic_j(tau.n(100)).real().round())^(1/3) + 640320 + sage: (-elliptic_j(tau, 100).real().round())^(1/3) + 640320 + """ + + CC = z.parent() + from sage.rings.complex_field import is_ComplexField + if not is_ComplexField(CC): + CC = ComplexField(prec) + try: + z = CC(z) + except ValueError: + raise ValueError("elliptic_j only defined for complex arguments.") + from sage.libs.all import pari + return CC(pari(z).ellj()) #### elliptic integrals From da83b875841f19f6a381163368d6e0cee3dc4da0 Mon Sep 17 00:00:00 2001 From: Gerardo Zelaya Eufemia Date: Fri, 6 Sep 2019 15:41:45 -0700 Subject: [PATCH 203/340] corrected trailing spaces --- src/sage/functions/special.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index b522339426f..d3d9c090b02 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -306,7 +306,7 @@ def elliptic_j(z, prec=53): - ``z`` (complex) -- a complex number with positive imaginary part. - - ``prec`` (default: 53) -- precision in bits for the complex field. + - ``prec`` (default: 53) -- precision in bits for the complex field. OUTPUT: From fbb4f8342971ad694a14884c381fd393daf71e85 Mon Sep 17 00:00:00 2001 From: Gerardo Zelaya Eufemia Date: Fri, 6 Sep 2019 16:07:14 -0700 Subject: [PATCH 204/340] added example explanation --- src/sage/functions/special.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index d3d9c090b02..cd6ad1e8836 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -337,6 +337,15 @@ def elliptic_j(z, prec=53): sage: tau = (1 + sqrt(-163))/2 sage: (-elliptic_j(tau.n(100)).real().round())^(1/3) 640320 + + This shows the need of higher precision than the default one: + + sage: -elliptic_j(tau) + 2.62537412640767e17 - 732.558854258998*I + sage: -elliptic_j(tau,75) + 2.625374126407680000000e17 - 0.0001309913593909879441262*I + sage: -elliptic_j(tau,100) + 2.6253741264076799999999999999e17 - 1.3012822400356887122945119790e-12*I sage: (-elliptic_j(tau, 100).real().round())^(1/3) 640320 """ From ec1d6f96bf9a246b92ee486b6934eecf745e58c3 Mon Sep 17 00:00:00 2001 From: Gerardo Zelaya Eufemia Date: Fri, 6 Sep 2019 16:18:17 -0700 Subject: [PATCH 205/340] corrected explanation of example --- src/sage/functions/special.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index cd6ad1e8836..21d40dd5e7d 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -338,7 +338,8 @@ def elliptic_j(z, prec=53): sage: (-elliptic_j(tau.n(100)).real().round())^(1/3) 640320 - This shows the need of higher precision than the default one: + This example shows the need for higher precision than the default one of + the `complex field`, see :trac:`28355`:: sage: -elliptic_j(tau) 2.62537412640767e17 - 732.558854258998*I From 6cf63903e4241bb7b2aa921777151e2dca9b0e81 Mon Sep 17 00:00:00 2001 From: Gerardo Zelaya Eufemia Date: Fri, 6 Sep 2019 16:22:09 -0700 Subject: [PATCH 206/340] corrected explanation of example --- src/sage/functions/special.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index 21d40dd5e7d..c02a13ed279 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -339,7 +339,7 @@ def elliptic_j(z, prec=53): 640320 This example shows the need for higher precision than the default one of - the `complex field`, see :trac:`28355`:: + the `ComplexField`, see :trac:`28355`:: sage: -elliptic_j(tau) 2.62537412640767e17 - 732.558854258998*I From 73272639d4a2ca2b6027ab6d643fb841f1a8285c Mon Sep 17 00:00:00 2001 From: Gerardo Zelaya Eufemia Date: Mon, 9 Sep 2019 19:20:49 -0700 Subject: [PATCH 207/340] corrected line 309 indentation --- src/sage/functions/special.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index c02a13ed279..7341c20d686 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -306,7 +306,7 @@ def elliptic_j(z, prec=53): - ``z`` (complex) -- a complex number with positive imaginary part. - - ``prec`` (default: 53) -- precision in bits for the complex field. + - ``prec`` (default: 53) -- precision in bits for the complex field. OUTPUT: From 5a871a9f32d6c6c7d13c9675a8d20c07230269ac Mon Sep 17 00:00:00 2001 From: kevin lui Date: Sun, 13 Oct 2019 13:10:42 -0700 Subject: [PATCH 208/340] Add a rel tol to pass failing numerical doctests on 32-bit machines --- src/sage/functions/special.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index 7341c20d686..671f6c1cd8d 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -342,11 +342,11 @@ def elliptic_j(z, prec=53): the `ComplexField`, see :trac:`28355`:: sage: -elliptic_j(tau) - 2.62537412640767e17 - 732.558854258998*I + 2.62537412640767e17 - 732.558854258998*I # rel tol 1e-2 sage: -elliptic_j(tau,75) - 2.625374126407680000000e17 - 0.0001309913593909879441262*I + 2.625374126407680000000e17 - 0.0001309913593909879441262*I # rel tol 1e-2 sage: -elliptic_j(tau,100) - 2.6253741264076799999999999999e17 - 1.3012822400356887122945119790e-12*I + 2.6253741264076799999999999999e17 - 1.3012822400356887122945119790e-12*I # rel tol 1e-2 sage: (-elliptic_j(tau, 100).real().round())^(1/3) 640320 """ From 58ba0e8ed3f0e007b67b07c3fc9f1c80ca21cffb Mon Sep 17 00:00:00 2001 From: kevin lui Date: Wed, 20 Nov 2019 21:43:40 -0800 Subject: [PATCH 209/340] Fix doctest location of rel/abs tol flag --- src/sage/functions/special.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index 671f6c1cd8d..3ae0d4e4eea 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -341,12 +341,12 @@ def elliptic_j(z, prec=53): This example shows the need for higher precision than the default one of the `ComplexField`, see :trac:`28355`:: - sage: -elliptic_j(tau) - 2.62537412640767e17 - 732.558854258998*I # rel tol 1e-2 - sage: -elliptic_j(tau,75) - 2.625374126407680000000e17 - 0.0001309913593909879441262*I # rel tol 1e-2 - sage: -elliptic_j(tau,100) - 2.6253741264076799999999999999e17 - 1.3012822400356887122945119790e-12*I # rel tol 1e-2 + sage: -elliptic_j(tau) # rel tol 1e-2 + 2.62537412640767e17 - 732.558854258998*I + sage: -elliptic_j(tau,75) # rel tol 1e-2 + 2.625374126407680000000e17 - 0.0001309913593909879441262*I + sage: -elliptic_j(tau,100) # rel tol 1e-2 + 2.6253741264076799999999999999e17 - 1.3012822400356887122945119790e-12*I sage: (-elliptic_j(tau, 100).real().round())^(1/3) 640320 """ From 943c908cac6a4b41dd21ef3e5aaa15d33f5611a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 21 Nov 2019 14:02:01 +0100 Subject: [PATCH 210/340] fix opacity for add_condition of mono-coloured plot3d --- src/sage/plot/plot3d/index_face_set.pyx | 29 ++++++++++++++----------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/sage/plot/plot3d/index_face_set.pyx b/src/sage/plot/plot3d/index_face_set.pyx index f6b704dc639..b20ef332da7 100644 --- a/src/sage/plot/plot3d/index_face_set.pyx +++ b/src/sage/plot/plot3d/index_face_set.pyx @@ -1107,9 +1107,12 @@ cdef class IndexFaceSet(PrimitiveObject): index += 2 if local_colored: - return IndexFaceSet(face_list, point_list, texture_list=texture_list) + return IndexFaceSet(face_list, point_list, + texture_list=texture_list) else: - return IndexFaceSet(face_list, point_list, texture=texture) + opacity = texture.opacity + return IndexFaceSet(face_list, point_list, texture=texture, + opacity=opacity) def tachyon_repr(self, render_params): """ @@ -1393,15 +1396,15 @@ cdef class IndexFaceSet(PrimitiveObject): point_c_mul(&dual.vs[i], dual.vs[i], 1.0/face.n) # Now compute the new face - for j from 0 <= j < face.n: + for j in range(face.n): if j == 0: - incoming = face.vertices[face.n-1] + incoming = face.vertices[face.n - 1] else: - incoming = face.vertices[j-1] - if j == face.n-1: + incoming = face.vertices[j - 1] + if j == face.n - 1: outgoing = face.vertices[0] else: - outgoing = face.vertices[j+1] + outgoing = face.vertices[j + 1] dd = dual_faces[face.vertices[j]] dd[incoming] = i, outgoing @@ -1544,9 +1547,9 @@ cdef class EdgeIter: face = self.set._faces[self.i] else: if self.j == 0: - P = self.set.vs[face.vertices[face.n-1]] + P = self.set.vs[face.vertices[face.n - 1]] else: - P = self.set.vs[face.vertices[self.j-1]] + P = self.set.vs[face.vertices[self.j - 1]] Q = self.set.vs[face.vertices[self.j]] self.j += 1 if self.set.enclosed: # Every edge appears exactly twice, once in each orientation. @@ -1613,10 +1616,10 @@ def sticker(face, width, hover): """ n = len(face) edges = [] - for i from 0 <= i < n: - edges.append(vector(RDF, [face[i-1][0] - face[i][0], - face[i-1][1] - face[i][1], - face[i-1][2] - face[i][2]])) + for i in range(n): + edges.append(vector(RDF, [face[i - 1][0] - face[i][0], + face[i - 1][1] - face[i][1], + face[i - 1][2] - face[i][2]])) sticker = [] for i in range(n): v = -edges[i] From ad26e751eddec1f0b5b4eb76021e79ae2bc6cc2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 21 Nov 2019 20:18:21 +0100 Subject: [PATCH 211/340] trac 28783 adding a doctest --- src/sage/plot/plot3d/index_face_set.pyx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sage/plot/plot3d/index_face_set.pyx b/src/sage/plot/plot3d/index_face_set.pyx index b20ef332da7..dc725a2cdd2 100644 --- a/src/sage/plot/plot3d/index_face_set.pyx +++ b/src/sage/plot/plot3d/index_face_set.pyx @@ -1009,6 +1009,18 @@ cdef class IndexFaceSet(PrimitiveObject): return x*x+y*y < 1 sphinx_plot(P.add_condition(cut)) + TESTS: + + One test for preservation of transparency :trac:`28783`:: + + sage: x,y,z = var('x,y,z') + sage: P = plot3d(cos(x*y),(x,-2,2),(y,-2,2),color='red',opacity=0.1) + sage: def condi(x,y,z): + ....: return not(x*x+y*y <= 1) + sage: Q = P.add_condition(condi, 8) + sage: 'd 0.1' in Q.mtl_str() + True + .. TODO:: - Use a dichotomy to search for the place where to cut, From fde06be72bb5613443a10f625ed6f115ad75c32f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 21 Nov 2019 20:25:49 +0100 Subject: [PATCH 212/340] trac 28783 better doctest for opacity --- src/sage/plot/plot3d/index_face_set.pyx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/plot/plot3d/index_face_set.pyx b/src/sage/plot/plot3d/index_face_set.pyx index dc725a2cdd2..eca1a86594a 100644 --- a/src/sage/plot/plot3d/index_face_set.pyx +++ b/src/sage/plot/plot3d/index_face_set.pyx @@ -1018,7 +1018,8 @@ cdef class IndexFaceSet(PrimitiveObject): sage: def condi(x,y,z): ....: return not(x*x+y*y <= 1) sage: Q = P.add_condition(condi, 8) - sage: 'd 0.1' in Q.mtl_str() + sage: L = Q.json_repr(Q.default_render_params()) + sage: '"opacity":0.1' in L[-1] True .. TODO:: From 1d1e4eaee5ee42864bed95a9ce10f38f2a7a95d3 Mon Sep 17 00:00:00 2001 From: LBrunswic Date: Thu, 21 Nov 2019 22:02:06 +0100 Subject: [PATCH 213/340] Implementation of multiple symmetries for tensor with indices as well as convention checks --- .../tensor/modules/tensor_with_indices.py | 146 +++++++++--------- 1 file changed, 74 insertions(+), 72 deletions(-) diff --git a/src/sage/tensor/modules/tensor_with_indices.py b/src/sage/tensor/modules/tensor_with_indices.py index 1d9b68a66f0..b7ad8581364 100644 --- a/src/sage/tensor/modules/tensor_with_indices.py +++ b/src/sage/tensor/modules/tensor_with_indices.py @@ -17,6 +17,7 @@ #****************************************************************************** from sage.structure.sage_object import SageObject +import re class TensorWithIndices(SageObject): r""" @@ -183,83 +184,84 @@ def __init__(self, tensor, indices): # version of the original tensor (True if # symmetries or contractions are indicated in the # indices) + + # Check wether the usual convention for indices, symetries and + # contractions are respected. This includes restrictions on the + # indices symbols used, non nested (anti)symmetries, + # (co/contra)variant identification of repeated indices, as well + # as checking the number of covariant and contravariant indices. + # Latex notations '{' and '}' are totally ignored. + # "^{ijkl}_{ib(cd)}" + # For now authorized symbol list only includes a-z and A-Z + # Suppress all '{' and '}' coming from LaTeX notations: indices = indices.replace('{','').replace('}','') - # Suppress the first '^': - if indices[0] == '^': - indices = indices[1:] - if '^' in indices: - raise IndexError("the contravariant indices must be placed first") - con_cov = indices.split('_') - con = con_cov[0] - - # Contravariant indices - # --------------------- - # Search for (anti)symmetries: - if '(' in con: - sym1 = con.index('(') - sym2 = con.index(')')-2 - if con.find('(', sym1+1) != -1 or '[' in con: - raise NotImplementedError("Multiple symmetries are not " + - "treated yet.") - self._tensor = self._tensor.symmetrize(*range(sym1, sym2+1)) - self._changed = True # self does no longer contain the original tensor - con = con.replace('(','').replace(')','') - if '[' in con: - sym1 = con.index('[') - sym2 = con.index(']')-2 - if con.find('[', sym1+1) != -1 or '(' in con: - raise NotImplementedError("multiple symmetries are not " + - "treated yet") - self._tensor = self._tensor.antisymmetrize(*range(sym1, sym2+1)) - self._changed = True # self does no longer contain the original tensor - con = con.replace('[','').replace(']','') - if len(con) != self._tensor._tensor_type[0]: + + # Check index notation conventions and parse indices + allowed_pattern = r"(\([a-zA-Z.]{2,}\)|\[[a-zA-Z.]{2,}\]|[a-zA-Z.]+)*" + con_then_cov = r"^\^"+ allowed_pattern +r"(\_"+allowed_pattern+r"|)$" + cov_then_con = r"^\_"+ allowed_pattern +r"(\^"+allowed_pattern+r"|)$" + if re.match(con_then_cov,indices) is None and re.match(cov_then_con,indices) is None: + raise ValueError("Index conventions not satisfied") + elif re.match(con_then_cov,indices): + try: + con,cov = indices[1:].split("_") + except ValueError: + con = indices[1:] + cov="" + else: + try: + cov,con = indices[1:].split("^") + except ValueError: + cov = indices[1:] + con="" + + # Check number of (co/contra)variant indices + if len(con.replace("(","").replace(")","").replace("[","").replace("]",""))!=tensor._tensor_type[0]: raise IndexError("number of contravariant indices not compatible " + "with the tensor type") + if len(cov.replace("(","").replace(")","").replace("[","").replace("]",""))!=tensor._tensor_type[1]: + raise IndexError("number of covavariant indices not compatible " + + "with the tensor type") + + #Apply (anti)symmetrizations on contravariant indices + first_sym_regex = r"(\(|\[)[a-zA-Z]*[)\]]" + while re.search(first_sym_regex,con): + first_sym = re.search(first_sym_regex,con) + sym1 = first_sym.span()[0] + sym2 = first_sym.span()[1]-1 + if first_sym.groups()[0] == "(": + self._tensor = self._tensor.symmetrize(*range( + sym1, + sym2-1 + )) + else: + self._tensor = self._tensor.antisymmetrize(*range( + sym1, + sym2-1 + )) + self._changed = True # self does no longer contain the original tensor + con = con[:sym1]+con[sym1+1:sym2]+con[sym2+1:] self._con = con - - # Covariant indices - # ----------------- - if len(con_cov) == 1: - if tensor._tensor_type[1] != 0: - raise IndexError("number of covariant indices not compatible " + - "with the tensor type") - self._cov = '' - elif len(con_cov) == 2: - cov = con_cov[1] - # Search for (anti)symmetries: - if '(' in cov: - sym1 = cov.index('(') - sym2 = cov.index(')')-2 - if cov.find('(', sym1+1) != -1 or '[' in cov: - raise NotImplementedError("multiple symmetries are not " + - "treated yet") - csym1 = sym1 + self._tensor._tensor_type[0] - csym2 = sym2 + self._tensor._tensor_type[0] - self._tensor = self._tensor.symmetrize(*range(csym1, csym2+1)) - self._changed = True # self does no longer contain the original - # tensor - cov = cov.replace('(','').replace(')','') - if '[' in cov: - sym1 = cov.index('[') - sym2 = cov.index(']')-2 - if cov.find('[', sym1+1) != -1 or '(' in cov: - raise NotImplementedError("multiple symmetries are not " + - "treated yet") - csym1 = sym1 + self._tensor._tensor_type[0] - csym2 = sym2 + self._tensor._tensor_type[0] - self._tensor = self._tensor.antisymmetrize( - *range(csym1, csym2+1)) - self._changed = True # self does no longer contain the original - # tensor - cov = cov.replace('[','').replace(']','') - if len(cov) != tensor._tensor_type[1]: - raise IndexError("number of covariant indices not " + - "compatible with the tensor type") - self._cov = cov - else: - raise IndexError("too many '_' in the list of indices") + + #Apply (anti)symmetrizations on contravariant indices + while re.search(first_sym_regex,cov): + first_sym = re.search(first_sym_regex,cov) + sym1 = first_sym.span()[0] + sym2 = first_sym.span()[1]-1 + if first_sym.groups()[0] == "(": + self._tensor = self._tensor.symmetrize(*range( + self._tensor._tensor_type[0] + sym1, + self._tensor._tensor_type[0] + sym2-1 + )) + else: + self._tensor = self._tensor.antisymmetrize(*range( + self._tensor._tensor_type[0] + sym1, + self._tensor._tensor_type[0] + sym2-1 + )) + self._changed = True # self does no longer contain the original tensor + cov = cov[:sym1]+cov[sym1+1:sym2]+cov[sym2+1:] + self._cov = cov # Treatment of possible self-contractions: # --------------------------------------- From e23d5c514ed9e6f6f6d0e7252b6b085ee8d98b5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Fri, 22 Nov 2019 10:26:27 +1300 Subject: [PATCH 214/340] adding cvxopt testsuite with nose --- build/pkgs/cvxopt/dependencies | 2 +- build/pkgs/cvxopt/spkg-check | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 build/pkgs/cvxopt/spkg-check diff --git a/build/pkgs/cvxopt/dependencies b/build/pkgs/cvxopt/dependencies index df63b3adf76..d86041c7d51 100644 --- a/build/pkgs/cvxopt/dependencies +++ b/build/pkgs/cvxopt/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) numpy $(BLAS) gsl glpk suitesparse | pkgconfig pip matplotlib +$(PYTHON) numpy $(BLAS) gsl glpk suitesparse | pkgconfig pip nose matplotlib matplotlib is needed to test cvxopt (i.e., if SAGE_CHECK=yes). See #12742. diff --git a/build/pkgs/cvxopt/spkg-check b/build/pkgs/cvxopt/spkg-check new file mode 100644 index 00000000000..ecb9ebcb76b --- /dev/null +++ b/build/pkgs/cvxopt/spkg-check @@ -0,0 +1,22 @@ +if [ -z "$SAGE_LOCAL" ]; then + echo >&2 "SAGE_LOCAL undefined ... exiting" + echo >&2 "Maybe run 'sage --sh'?" + exit 1 +fi + +cd src + +if ! command -v nosetests ; then + echo >&2 'Testing cvxopt requires the package nose to be installed' + exit 1 +fi + +echo "Testing cvxopt..." + +nosetests + +if [ $? -ne 0 ]; then + echo >&2 "Error running self tests." + exit 1 +fi + From 59c86e3ed784136ff1b9026a6b89b5625ec14052 Mon Sep 17 00:00:00 2001 From: LBrunswic Date: Thu, 21 Nov 2019 22:51:38 +0100 Subject: [PATCH 215/340] Adding check to raise exception on repeated indices of same type. Implementation of multiple contractions --- .../tensor/modules/tensor_with_indices.py | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/sage/tensor/modules/tensor_with_indices.py b/src/sage/tensor/modules/tensor_with_indices.py index b7ad8581364..084e7f42e4c 100644 --- a/src/sage/tensor/modules/tensor_with_indices.py +++ b/src/sage/tensor/modules/tensor_with_indices.py @@ -215,15 +215,18 @@ def __init__(self, tensor, indices): except ValueError: cov = indices[1:] con="" - + con_without_sym = (con.replace("(","").replace(")","").replace("[","").replace("]","")) + cov_without_sym = (cov.replace("(","").replace(")","").replace("[","").replace("]","")) + if len(con_without_sym)!=len(set(con_without_sym)) or len(cov_without_sym)!=len(set(cov_without_sym)): + raise ValueError("Index conventions not satisfied : repeated indices of same type") # Check number of (co/contra)variant indices - if len(con.replace("(","").replace(")","").replace("[","").replace("]",""))!=tensor._tensor_type[0]: + if len(con_without_sym)!=tensor._tensor_type[0]: raise IndexError("number of contravariant indices not compatible " + "with the tensor type") - if len(cov.replace("(","").replace(")","").replace("[","").replace("]",""))!=tensor._tensor_type[1]: + if len(cov_without_sym)!=tensor._tensor_type[1]: raise IndexError("number of covavariant indices not compatible " + "with the tensor type") - + #Apply (anti)symmetrizations on contravariant indices first_sym_regex = r"(\(|\[)[a-zA-Z]*[)\]]" while re.search(first_sym_regex,con): @@ -265,19 +268,21 @@ def __init__(self, tensor, indices): # Treatment of possible self-contractions: # --------------------------------------- - contraction_pairs = [] + contraction_pair_list = [] for ind in self._con: if ind != '.' and ind in self._cov: pos1 = self._con.index(ind) pos2 = self._tensor._tensor_type[0] + self._cov.index(ind) - contraction_pairs.append((pos1, pos2)) - if len(contraction_pairs) > 1: - raise NotImplementedError("multiple self-contractions are not " + - "implemented yet") - if len(contraction_pairs) == 1: - pos1 = contraction_pairs[0][0] - pos2 = contraction_pairs[0][1] + contraction_pair_list.append([pos1, pos2]) + while contraction_pair_list: + pos1, pos2 = contraction_pair_list.pop() self._tensor = self._tensor.trace(pos1, pos2) + for contraction_pair in contraction_pair_list: + if contraction_pair[0]> pos1: + contraction_pair[0]=contraction_pair[0]-1 + if contraction_pair[1]> pos2: + contraction_pair[1]=contraction_pair[1]-1 + contraction_pair[1]=contraction_pair[1]-1 self._changed = True # self does no longer contain the original # tensor ind = self._con[pos1] From 4b9a565daccfb8312b00efa9a86a9c47080ffe41 Mon Sep 17 00:00:00 2001 From: LBrunswic Date: Fri, 22 Nov 2019 12:37:28 +0100 Subject: [PATCH 216/340] The convention without leading '^' for contravariant indices is now accepted as is used to. A regex corrected. doctest added to illustrate new functionalities. --- .../tensor/modules/tensor_with_indices.py | 69 ++++++++++++++++--- 1 file changed, 59 insertions(+), 10 deletions(-) diff --git a/src/sage/tensor/modules/tensor_with_indices.py b/src/sage/tensor/modules/tensor_with_indices.py index 084e7f42e4c..7263e2e4e07 100644 --- a/src/sage/tensor/modules/tensor_with_indices.py +++ b/src/sage/tensor/modules/tensor_with_indices.py @@ -102,7 +102,15 @@ class TensorWithIndices(SageObject): no symmetry; antisymmetry: (2, 3) sage: s == t.antisymmetrize(2,3) True - + + On can also perform multiple symetrization-antisymetrizations + + sage: aa = a*a + sage: aa["(..)(..)"] == aa.symmetrize(0,1).symmetrize(2,3) + True + sage: aa == aa["(..)(..)"]+aa["[..][..]"]+aa["(..)[..]"]+aa["[..](..)"] + True + Another example of an operation indicated by indices is a contraction:: sage: s = t['^ki_kj'] ; s # contraction on the repeated index k @@ -136,6 +144,10 @@ class TensorWithIndices(SageObject): sage: s = a['^kl'] * b['_kl'] ; s 105 + sage: s == (a*b)['^kl_kl'] + True + sage: s == (a*b)['_kl^kl'] + True sage: s == a.contract(0,1, b, 0,1) True @@ -155,7 +167,40 @@ class TensorWithIndices(SageObject): -a^ij sage: -t['ij_kl'] -t^ij_kl - + + Conventions are checked and non acceptable indices raise + ValueError, for instance : + + sage: try: + ....: a["([..])"] # Nested symmetries + ....: except ValueError as e: + ....: print(e) + Index conventions not satisfied + + sage: try: + ....: a["(.."] # Unbalanced parenthis + ....: except ValueError as e: + ....: print(e) + Index conventions not satisfied + + sage: try: + ....: a["ii"] # Repeated indices of the same type + ....: except ValueError as e: + ....: print(e) + Index conventions not satisfied : repeated indices of same type + + sage: try: + ....: (a*a)["^(ij)^(kl)"] # Multiple indices group of the same type + ....: except ValueError as e: + ....: print(e) + Index conventions not satisfied + + sage: try: + ....: a["^éa"] # accentuated index name + ....: except ValueError as e: + ....: print(e) + Index conventions not satisfied + """ def __init__(self, tensor, indices): r""" @@ -199,26 +244,30 @@ def __init__(self, tensor, indices): # Check index notation conventions and parse indices allowed_pattern = r"(\([a-zA-Z.]{2,}\)|\[[a-zA-Z.]{2,}\]|[a-zA-Z.]+)*" - con_then_cov = r"^\^"+ allowed_pattern +r"(\_"+allowed_pattern+r"|)$" - cov_then_con = r"^\_"+ allowed_pattern +r"(\^"+allowed_pattern+r"|)$" + con_then_cov = r"^(\^|)" + allowed_pattern + r"(\_"+allowed_pattern + r"|)$" + cov_then_con = r"^\_" + allowed_pattern + r"(\^"+allowed_pattern + r"|)$" if re.match(con_then_cov,indices) is None and re.match(cov_then_con,indices) is None: raise ValueError("Index conventions not satisfied") elif re.match(con_then_cov,indices): try: - con,cov = indices[1:].split("_") + con,cov = indices.replace("^","").split("_") except ValueError: - con = indices[1:] - cov="" + con = indices.replace("^","") + cov = "" else: try: cov,con = indices[1:].split("^") except ValueError: cov = indices[1:] - con="" + con = "" + con_without_sym = (con.replace("(","").replace(")","").replace("[","").replace("]","")) cov_without_sym = (cov.replace("(","").replace(")","").replace("[","").replace("]","")) - if len(con_without_sym)!=len(set(con_without_sym)) or len(cov_without_sym)!=len(set(cov_without_sym)): + if len(con_without_sym) != len(set(con_without_sym))+max(con_without_sym.count(".")-1,0): + raise ValueError("Index conventions not satisfied : repeated indices of same type") + if len(cov_without_sym) != len(set(cov_without_sym))+max(cov_without_sym.count(".")-1,0): raise ValueError("Index conventions not satisfied : repeated indices of same type") + # Check number of (co/contra)variant indices if len(con_without_sym)!=tensor._tensor_type[0]: raise IndexError("number of contravariant indices not compatible " + @@ -228,7 +277,7 @@ def __init__(self, tensor, indices): "with the tensor type") #Apply (anti)symmetrizations on contravariant indices - first_sym_regex = r"(\(|\[)[a-zA-Z]*[)\]]" + first_sym_regex = r"(\(|\[)[a-zA-Z.]*[)\]]" while re.search(first_sym_regex,con): first_sym = re.search(first_sym_regex,con) sym1 = first_sym.span()[0] From f5ccd322de18f06d60c7b2173591ecc4ab630baf Mon Sep 17 00:00:00 2001 From: paulmasson Date: Fri, 22 Nov 2019 15:29:52 -0800 Subject: [PATCH 217/340] Update Three.js examples --- .../plot3d/threejs_examples/helix.html | 249 +++++++++++++++--- .../plot3d/threejs_examples/spheres.html | 247 ++++++++++++++--- .../plot3d/threejs_examples/template.html | 2 +- 3 files changed, 426 insertions(+), 72 deletions(-) diff --git a/src/doc/en/reference/plot3d/threejs_examples/helix.html b/src/doc/en/reference/plot3d/threejs_examples/helix.html index 27f499c7f1f..60b6045d217 100644 --- a/src/doc/en/reference/plot3d/threejs_examples/helix.html +++ b/src/doc/en/reference/plot3d/threejs_examples/helix.html @@ -9,31 +9,40 @@ - - - + + + +
ⓘ +
+
Save as PNG
+
Save as HTML
+
Get Viewpoint
+
Close Menu
+
+ diff --git a/src/doc/en/reference/plot3d/threejs_examples/spheres.html b/src/doc/en/reference/plot3d/threejs_examples/spheres.html index 826e4af3843..6ca7ff2f38e 100644 --- a/src/doc/en/reference/plot3d/threejs_examples/spheres.html +++ b/src/doc/en/reference/plot3d/threejs_examples/spheres.html @@ -9,25 +9,34 @@ - - - + + + +
ⓘ +
+
Save as PNG
+
Save as HTML
+
Get Viewpoint
+
Close Menu
+
+ diff --git a/src/doc/en/reference/plot3d/threejs_examples/template.html b/src/doc/en/reference/plot3d/threejs_examples/template.html index 2d9cc99809e..3ae675a246c 100644 --- a/src/doc/en/reference/plot3d/threejs_examples/template.html +++ b/src/doc/en/reference/plot3d/threejs_examples/template.html @@ -1,5 +1,5 @@ \ No newline at end of file From 2ad0ec07c1dfb35b355e16e243f5c51ca5d9f988 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Sat, 23 Nov 2019 10:00:25 +0100 Subject: [PATCH 218/340] removed `from __future__` import in pyx files --- src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx | 1 - .../polyhedron/combinatorial_polyhedron/combinatorial_face.pyx | 1 - .../geometry/polyhedron/combinatorial_polyhedron/conversions.pyx | 1 - .../polyhedron/combinatorial_polyhedron/list_of_faces.pyx | 1 - 4 files changed, 4 deletions(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index ec61b48ebdb..a67c902fe24 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -83,7 +83,6 @@ AUTHOR: # https://www.gnu.org/licenses/ # **************************************************************************** -from __future__ import absolute_import, division, print_function import numbers from sage.rings.integer import Integer from sage.graphs.graph import Graph diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx index 640ef557414..45b18d87360 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx @@ -64,7 +64,6 @@ AUTHOR: # http://www.gnu.org/licenses/ #***************************************************************************** -from __future__ import absolute_import, division, print_function from sage.misc.superseded import deprecated_function_alias import numbers diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx index f76a7583c3a..300b699b4ec 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx @@ -66,7 +66,6 @@ AUTHOR: # http://www.gnu.org/licenses/ #***************************************************************************** -from __future__ import absolute_import, division from sage.structure.element import is_Matrix from libc.string cimport memset diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx index 32972d51e56..f20416a74f5 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx @@ -80,7 +80,6 @@ AUTHOR: # http://www.gnu.org/licenses/ #***************************************************************************** -from __future__ import absolute_import, division from sage.structure.element import is_Matrix from cysignals.signals cimport sig_on, sig_off From 9469fb61df67cbdb033224e5ea48f6229f4bc4b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 23 Nov 2019 14:34:30 +0100 Subject: [PATCH 219/340] https in README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 48225d864a5..e25634ebf9b 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ > "Creating a Viable Open Source Alternative to > Magma, Maple, Mathematica, and MATLAB" -> Copyright (C) 2005-2018 The Sage Development Team +> Copyright (C) 2005-2019 The Sage Development Team https://www.sagemath.org @@ -17,14 +17,14 @@ and functions list the authors. Getting Started --------------- -If you downloaded a [binary](http://www.sagemath.org/download.html) +If you downloaded a [binary](https://www.sagemath.org/download.html) (i.e. a version of SageMath prepared for a specific operating system), Sage is ready to start -- just open a terminal in the directory where you extracted the binary archive and type: ./sage -If you downloaded the [sources](http://www.sagemath.org/download-source.html), +If you downloaded the [sources](https://www.sagemath.org/download-source.html), please read below on how to build Sage and work around common issues. If you have questions or encounter problems, please do not hesitate @@ -177,7 +177,7 @@ More Detailed Instructions to Build from Source several jobs in parallel, while the `SAGE_CHECK` environment variable controls whether to perform more tests during the installation. For an in-depth discussion of environment variables for building Sage, see - [the installation guide](http://doc.sagemath.org/html/en/installation/source.html#environment-variables). + [the installation guide](https://doc.sagemath.org/html/en/installation/source.html#environment-variables). On a machine with 4 processors, say, typing `export MAKE="make -j4"` will configure the build script to perform a parallel compilation of @@ -221,7 +221,7 @@ More Detailed Instructions to Build from Source Note: if you built for Python 3, you can instead run `make ptest-python3`. -1. The HTML version of the [documentation](http://doc.sagemath.org/html/en/index.html) +1. The HTML version of the [documentation](https://doc.sagemath.org/html/en/index.html) is built during the compilation process of Sage and resides in the directory `local/share/doc/sage/html/`. From 1091b53fa4503b8c09e48a84065405c3aaeaa663 Mon Sep 17 00:00:00 2001 From: aodesky Date: Wed, 20 Nov 2019 16:23:29 -0500 Subject: [PATCH 220/340] Correct formatting/misprints in doctests. Change variable name `iteration_level` in julia_plot() `level_sep` to conform with mandelbrot_plot(). --- .../dynamics/complex_dynamics/mandel_julia.py | 20 +++---------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia.py b/src/sage/dynamics/complex_dynamics/mandel_julia.py index b3198fd7acb..61c99cef869 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia.py +++ b/src/sage/dynamics/complex_dynamics/mandel_julia.py @@ -96,7 +96,7 @@ def mandelbrot_plot(f=None, **kwds): - ``base_color`` -- RGB color (optional - default: ``[40, 40, 40]``) color used to determine the coloring of set. - - ``iteration_level`` -- long (optional - default: 1) number of iterations + - ``level_sep`` -- long (optional - default: 1) number of iterations between each color level. - ``number_of_colors`` -- long (optional - default: 30) number of colors @@ -104,20 +104,6 @@ def mandelbrot_plot(f=None, **kwds): - ``interact`` -- boolean (optional - default: ``False``), controls whether plot will have interactive functionality. -======= - image in number of pixels. - - - ``base_color`` -- Hex color (optional - default: ``tomato``) color - used to determine the coloring of set. - - - ``level_sep`` -- long (optional - default: 1) number of iterations - between each color level. - - - ``number_of_colors`` -- long (optional - default: 30) number of colors - used to plot image. - - - ``interact`` -- boolean (optional - default: ``False``), controls whether - plot will have interactive functionality. OUTPUT: @@ -337,7 +323,7 @@ def external_ray(theta, **kwds): points on the external ray. - ``ray_color`` -- RGB color (optional - default: ``[255, 255, 255]``) color - of the external ray(s). + of the external ray(s). OUTPUT: @@ -556,7 +542,7 @@ def julia_plot(c=-1, **kwds): max_iteration = kwds.pop("max_iteration", 500) pixel_count = kwds.pop("pixel_count", 500) base_color = kwds.pop("base_color", 'steelblue') - iteration_level = kwds.pop("iteration_level", 1) + level_sep= kwds.pop("level_sep", 1) number_of_colors = kwds.pop("number_of_colors", 30) interact = kwds.pop("interact", False) From a1f5bde4f8f6e0cd29e7e8f91c0ae70a8bf70b6d Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Sat, 23 Nov 2019 19:31:34 +0100 Subject: [PATCH 221/340] 28793: fix sporadic doctest failure for matrix space Occasionally, due to collisions, the density of the matrix will be a bit smaller, so this makes the doctest more robust. --- src/sage/matrix/matrix_space.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index ad485238dee..fe74d667a1c 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -1982,8 +1982,8 @@ def _an_element_(self): Check that this works for sparse matrices:: sage: M = MatrixSpace(ZZ, 1000, 1000, sparse=True).an_element() - sage: M.density() - 99/1000000 + sage: 96 <= M.density() * 10^6 <= 99 + True """ from .args import MatrixArgs dim = self.dimension() From 24fe9f40933492970258ec3afc821e55a81b930c Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Sat, 23 Nov 2019 19:31:41 +0100 Subject: [PATCH 222/340] 28793: fix random output in another giacpy_sage doctest --- 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 f8b4d77f678..22f29ee5965 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -3901,7 +3901,7 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal sage: A9=PolynomialRing(QQ,9,'x') # optional - giacpy_sage sage: I9=sage.rings.ideal.Katsura(A9) # optional - giacpy_sage sage: I9.groebner_basis("giac",proba_epsilon=1e-7) # optional - giacpy_sage, long time (3s) - Running a probabilistic check for the reconstructed Groebner basis... + ...Running a probabilistic check for the reconstructed Groebner basis... Polynomial Sequence with 143 Polynomials in 9 Variables The list of available Giac options is provided at :func:`sage.libs.giac.groebner_basis`. From 0823e29c5fa02815c71a23f770f8ee226eec7c76 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Sat, 23 Nov 2019 21:56:30 +0100 Subject: [PATCH 223/340] Minor corrections for #28784 --- .../tensor/modules/tensor_with_indices.py | 142 +++++++++--------- 1 file changed, 70 insertions(+), 72 deletions(-) diff --git a/src/sage/tensor/modules/tensor_with_indices.py b/src/sage/tensor/modules/tensor_with_indices.py index 7263e2e4e07..c7399a63ec7 100644 --- a/src/sage/tensor/modules/tensor_with_indices.py +++ b/src/sage/tensor/modules/tensor_with_indices.py @@ -1,9 +1,11 @@ +# -*- coding: utf-8 -*- r""" Index notation for tensors AUTHORS: - Eric Gourgoulhon, Michal Bejger (2014-2015): initial version +- Léo Brunswic (2019): add multiple symmetries and multiple contractions """ #****************************************************************************** @@ -102,15 +104,15 @@ class TensorWithIndices(SageObject): no symmetry; antisymmetry: (2, 3) sage: s == t.antisymmetrize(2,3) True - - On can also perform multiple symetrization-antisymetrizations - + + On can also perform multiple symmetrization-antisymmetrizations:: + sage: aa = a*a - sage: aa["(..)(..)"] == aa.symmetrize(0,1).symmetrize(2,3) + sage: aa['(..)(..)'] == aa.symmetrize(0,1).symmetrize(2,3) True - sage: aa == aa["(..)(..)"]+aa["[..][..]"]+aa["(..)[..]"]+aa["[..](..)"] + sage: aa == aa['(..)(..)'] + aa['[..][..]'] + aa['(..)[..]'] + aa['[..](..)'] True - + Another example of an operation indicated by indices is a contraction:: sage: s = t['^ki_kj'] ; s # contraction on the repeated index k @@ -167,40 +169,31 @@ class TensorWithIndices(SageObject): -a^ij sage: -t['ij_kl'] -t^ij_kl - - Conventions are checked and non acceptable indices raise - ValueError, for instance : - - sage: try: - ....: a["([..])"] # Nested symmetries - ....: except ValueError as e: - ....: print(e) - Index conventions not satisfied - - sage: try: - ....: a["(.."] # Unbalanced parenthis - ....: except ValueError as e: - ....: print(e) - Index conventions not satisfied - - sage: try: - ....: a["ii"] # Repeated indices of the same type - ....: except ValueError as e: - ....: print(e) - Index conventions not satisfied : repeated indices of same type - - sage: try: - ....: (a*a)["^(ij)^(kl)"] # Multiple indices group of the same type - ....: except ValueError as e: - ....: print(e) - Index conventions not satisfied - - sage: try: - ....: a["^éa"] # accentuated index name - ....: except ValueError as e: - ....: print(e) - Index conventions not satisfied - + + Conventions are checked and non acceptable indices raise ``ValueError``, + for instance:: + + sage: a['([..])'] # nested symmetries + Traceback (most recent call last): + ... + ValueError: index conventions not satisfied + sage: a['(..'] # unbalanced parenthis + Traceback (most recent call last): + ... + ValueError: index conventions not satisfied + sage: a['ii'] # repeated indices of the same type + Traceback (most recent call last): + ... + ValueError: index conventions not satisfied: repeated indices of same type + sage: (a*a)['^(ij)^(kl)'] # multiple indices group of the same type + Traceback (most recent call last): + ... + ValueError: index conventions not satisfied + sage: a["^éa"] # accentuated index name + Traceback (most recent call last): + ... + ValueError: index conventions not satisfied + """ def __init__(self, tensor, indices): r""" @@ -229,25 +222,26 @@ def __init__(self, tensor, indices): # version of the original tensor (True if # symmetries or contractions are indicated in the # indices) - - # Check wether the usual convention for indices, symetries and - # contractions are respected. This includes restrictions on the - # indices symbols used, non nested (anti)symmetries, - # (co/contra)variant identification of repeated indices, as well + + # Check wether the usual convention for indices, symmetries and + # contractions are respected. This includes restrictions on the + # indices symbols used, non nested (anti)symmetries, + # (co/contra)variant identification of repeated indices, as well # as checking the number of covariant and contravariant indices. # Latex notations '{' and '}' are totally ignored. # "^{ijkl}_{ib(cd)}" # For now authorized symbol list only includes a-z and A-Z - + # Suppress all '{' and '}' coming from LaTeX notations: indices = indices.replace('{','').replace('}','') - + # Check index notation conventions and parse indices allowed_pattern = r"(\([a-zA-Z.]{2,}\)|\[[a-zA-Z.]{2,}\]|[a-zA-Z.]+)*" - con_then_cov = r"^(\^|)" + allowed_pattern + r"(\_"+allowed_pattern + r"|)$" - cov_then_con = r"^\_" + allowed_pattern + r"(\^"+allowed_pattern + r"|)$" - if re.match(con_then_cov,indices) is None and re.match(cov_then_con,indices) is None: - raise ValueError("Index conventions not satisfied") + con_then_cov = r"^(\^|)" + allowed_pattern + r"(\_" + allowed_pattern + r"|)$" + cov_then_con = r"^\_" + allowed_pattern + r"(\^" + allowed_pattern + r"|)$" + if (re.match(con_then_cov,indices) is None + and re.match(cov_then_con,indices) is None): + raise ValueError("index conventions not satisfied") elif re.match(con_then_cov,indices): try: con,cov = indices.replace("^","").split("_") @@ -260,23 +254,27 @@ def __init__(self, tensor, indices): except ValueError: cov = indices[1:] con = "" - + con_without_sym = (con.replace("(","").replace(")","").replace("[","").replace("]","")) cov_without_sym = (cov.replace("(","").replace(")","").replace("[","").replace("]","")) - if len(con_without_sym) != len(set(con_without_sym))+max(con_without_sym.count(".")-1,0): - raise ValueError("Index conventions not satisfied : repeated indices of same type") - if len(cov_without_sym) != len(set(cov_without_sym))+max(cov_without_sym.count(".")-1,0): - raise ValueError("Index conventions not satisfied : repeated indices of same type") - + if len(con_without_sym) != len(set(con_without_sym)) \ + + max(con_without_sym.count(".")-1, 0): + raise ValueError("index conventions not satisfied: " + "repeated indices of same type") + if len(cov_without_sym) != len(set(cov_without_sym)) \ + + max(cov_without_sym.count(".")-1, 0): + raise ValueError("index conventions not satisfied: " + "repeated indices of same type") + # Check number of (co/contra)variant indices - if len(con_without_sym)!=tensor._tensor_type[0]: - raise IndexError("number of contravariant indices not compatible " + + if len(con_without_sym) != tensor._tensor_type[0]: + raise IndexError("number of contravariant indices not compatible " "with the tensor type") - if len(cov_without_sym)!=tensor._tensor_type[1]: - raise IndexError("number of covavariant indices not compatible " + + if len(cov_without_sym) != tensor._tensor_type[1]: + raise IndexError("number of covavariant indices not compatible " "with the tensor type") - - #Apply (anti)symmetrizations on contravariant indices + + # Apply (anti)symmetrizations on contravariant indices first_sym_regex = r"(\(|\[)[a-zA-Z.]*[)\]]" while re.search(first_sym_regex,con): first_sym = re.search(first_sym_regex,con) @@ -293,10 +291,10 @@ def __init__(self, tensor, indices): sym2-1 )) self._changed = True # self does no longer contain the original tensor - con = con[:sym1]+con[sym1+1:sym2]+con[sym2+1:] + con = con[:sym1] + con[sym1+1:sym2] + con[sym2+1:] self._con = con - - #Apply (anti)symmetrizations on contravariant indices + + # Apply (anti)symmetrizations on covariant indices while re.search(first_sym_regex,cov): first_sym = re.search(first_sym_regex,cov) sym1 = first_sym.span()[0] @@ -312,7 +310,7 @@ def __init__(self, tensor, indices): self._tensor._tensor_type[0] + sym2-1 )) self._changed = True # self does no longer contain the original tensor - cov = cov[:sym1]+cov[sym1+1:sym2]+cov[sym2+1:] + cov = cov[:sym1] + cov[sym1+1:sym2] + cov[sym2+1:] self._cov = cov # Treatment of possible self-contractions: @@ -327,11 +325,11 @@ def __init__(self, tensor, indices): pos1, pos2 = contraction_pair_list.pop() self._tensor = self._tensor.trace(pos1, pos2) for contraction_pair in contraction_pair_list: - if contraction_pair[0]> pos1: - contraction_pair[0]=contraction_pair[0]-1 - if contraction_pair[1]> pos2: - contraction_pair[1]=contraction_pair[1]-1 - contraction_pair[1]=contraction_pair[1]-1 + if contraction_pair[0] > pos1: + contraction_pair[0] = contraction_pair[0]-1 + if contraction_pair[1] > pos2: + contraction_pair[1] = contraction_pair[1]-1 + contraction_pair[1] = contraction_pair[1]-1 self._changed = True # self does no longer contain the original # tensor ind = self._con[pos1] From 3013354903be7147e51c9dd7957428a281c801df Mon Sep 17 00:00:00 2001 From: LBrunswic Date: Sun, 24 Nov 2019 01:18:22 +0100 Subject: [PATCH 224/340] Marginal modifications --- src/sage/tensor/modules/tensor_with_indices.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/tensor/modules/tensor_with_indices.py b/src/sage/tensor/modules/tensor_with_indices.py index c7399a63ec7..d0c6f9416ad 100644 --- a/src/sage/tensor/modules/tensor_with_indices.py +++ b/src/sage/tensor/modules/tensor_with_indices.py @@ -105,7 +105,7 @@ class TensorWithIndices(SageObject): sage: s == t.antisymmetrize(2,3) True - On can also perform multiple symmetrization-antisymmetrizations:: + One can also perform multiple symmetrization-antisymmetrizations:: sage: aa = a*a sage: aa['(..)(..)'] == aa.symmetrize(0,1).symmetrize(2,3) @@ -250,9 +250,9 @@ def __init__(self, tensor, indices): cov = "" else: try: - cov,con = indices[1:].split("^") + cov,con = indices.replace("_","").split("^") except ValueError: - cov = indices[1:] + cov = indices.replace("_","") con = "" con_without_sym = (con.replace("(","").replace(")","").replace("[","").replace("]","")) From 0d2c7258fc3619037a18deeab915f8e473094bd8 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Sun, 24 Nov 2019 14:59:51 +0100 Subject: [PATCH 225/340] Properly check for overflow when attempting to convert Python int to C long --- src/sage/arith/long.pxd | 30 ++++++++++++++++++- src/sage/rings/finite_rings/integer_mod.pyx | 8 ++--- .../polynomial_integer_dense_flint.pyx | 10 +++---- 3 files changed, 38 insertions(+), 10 deletions(-) diff --git a/src/sage/arith/long.pxd b/src/sage/arith/long.pxd index c7a1d8e0211..0d9ca427e84 100644 --- a/src/sage/arith/long.pxd +++ b/src/sage/arith/long.pxd @@ -13,7 +13,7 @@ Fast conversion of Python objects to C long # http://www.gnu.org/licenses/ #***************************************************************************** -from libc.limits cimport LONG_MIN +from libc.limits cimport LONG_MIN, LONG_MAX from cpython.object cimport Py_SIZE from cpython.int cimport PyInt_AS_LONG @@ -261,3 +261,31 @@ cdef inline bint integer_check_long_py(x, long* value, int* err): # 4 digits or more: guaranteed overflow err[0] = ERR_OVERFLOW return 1 + + +cdef inline bint is_small_python_int(obj): + """ + Test whether Python object is a small Python integer + + Meaning that that it can be converted to a C long. In Python 2, this is equvialent to it being + the ``int`` Python type. In Python 3, the ``int`` Python type has unlimited precision so we need + to check its range. + + EXAMPLES:: + + sage: cython(''' + ....: from sage.arith.long cimport is_small_python_int + ....: def is_small_wrapper(x): + ....: return is_small_python_int(x) + ....: ''') + sage: is_small_wrapper(int(3)) + True + sage: is_small_wrapper(ZZ(3)) # not a Python int + False + sage: import sys + sage: is_small_wrapper(int(sys.maxsize)) # does fit into C long + True + sage: is_small_wrapper(int(sys.maxsize + 1)) # does not fit into C long + False + """ + return (type(obj) is int) and (LONG_MIN <= obj <= LONG_MAX) diff --git a/src/sage/rings/finite_rings/integer_mod.pyx b/src/sage/rings/finite_rings/integer_mod.pyx index 253dcca0af3..76f0d3ed655 100644 --- a/src/sage/rings/finite_rings/integer_mod.pyx +++ b/src/sage/rings/finite_rings/integer_mod.pyx @@ -86,7 +86,8 @@ import operator cdef bint use_32bit_type(int_fast64_t modulus): return modulus <= INTEGER_MOD_INT32_LIMIT -from sage.arith.long cimport integer_check_long, integer_check_long_py, ERR_OVERFLOW +from sage.arith.long cimport ( + integer_check_long, integer_check_long_py, is_small_python_int, ERR_OVERFLOW) import sage.rings.rational as rational from sage.libs.pari.all import pari, PariError @@ -3635,9 +3636,8 @@ cdef class IntegerMod_int64(IntegerMod_abstract): cdef int mpz_pow_helper(mpz_t res, mpz_t base, object exp, mpz_t modulus) except -1: cdef bint invert = False cdef long long_exp - - if type(exp) is int: - long_exp = PyInt_AS_LONG(exp) + if is_small_python_int(exp): + long_exp = exp if long_exp < 0: long_exp = -long_exp invert = True diff --git a/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx b/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx index cf0d3efc414..3efe1e4c228 100644 --- a/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx @@ -38,7 +38,7 @@ include "sage/libs/ntl/decl.pxi" from cpython.int cimport PyInt_AS_LONG from sage.libs.gmp.mpz cimport * -from sage.arith.long cimport pyobject_to_long +from sage.arith.long cimport pyobject_to_long, is_small_python_int from sage.rings.polynomial.polynomial_element cimport Polynomial from sage.structure.element cimport ModuleElement, Element @@ -239,7 +239,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): # now fill them in for ii, a in x: i = ii[0] if type(ii) is tuple else ii - if type(a) is int: + if is_small_python_int(a): sig_on() fmpz_poly_set_coeff_si(self.__poly, i, a) sig_off() @@ -277,7 +277,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): sig_off() for i from 0 <= i < len(x): a = x[i] - if type(a) is int: + if is_small_python_int(a): sig_on() fmpz_poly_set_coeff_si(self.__poly, i, a) sig_off() @@ -396,7 +396,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): ( x0).__poly) sig_off() return f - if isinstance(x0, int): + if is_small_python_int(x0): z = Integer.__new__(Integer) sig_on() fmpz_init(a_fmpz) @@ -408,7 +408,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): fmpz_clear(z_fmpz) sig_off() return z - if isinstance(x0, long): + if isinstance(x0, (int, long)): x0 = Integer(x0) if isinstance(x0, Integer): a = x0 From 975fec3464c264960339b626818a3c541d9e1537 Mon Sep 17 00:00:00 2001 From: aodesky Date: Sun, 24 Nov 2019 11:42:49 -0500 Subject: [PATCH 226/340] Implement Julia set plotting for general polynomial maps. Add documentation to the Julia plotting functionality in mandel_julia_helper.pyx. --- .../dynamics/complex_dynamics/mandel_julia.py | 215 +++++++++++++----- .../complex_dynamics/mandel_julia_helper.pyx | 22 +- 2 files changed, 172 insertions(+), 65 deletions(-) diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia.py b/src/sage/dynamics/complex_dynamics/mandel_julia.py index 61c99cef869..8f5454bf9f6 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia.py +++ b/src/sage/dynamics/complex_dynamics/mandel_julia.py @@ -38,6 +38,7 @@ convert_to_pixels, get_line, fast_julia_plot, + general_julia, polynomial_mandelbrot, julia_helper) from sage.dynamics.arithmetic_dynamics.generic_ds import DynamicalSystem @@ -431,31 +432,31 @@ def external_ray(theta, **kwds): pixel[int(k[0]), int(k[1])] = tuple(ray_color) return M -def julia_plot(c=-1, **kwds): +def julia_plot(f=None, **kwds): r""" - Plots the Julia set of a given complex `c` value. Users can specify whether - they would like to display the Mandelbrot side by side with the Julia set. + Plots the Julia set of a given polynomial ``f``. Users can specify whether + they would like to display the Mandelbrot side by side with the Julia set + with the ``mandelbrot`` argument. If ``f`` is not specified, this method + defaults to `f(z) = z^2-1`. - The Julia set of a given `c` value is the set of complex numbers for which - the function `Q_c(z)=z^2+c` is bounded under iteration. The Julia set can + The Julia set of a polynomial ``f`` is the set of complex numbers `z` for + which the function `f(z)` is bounded under iteration. The Julia set can be visualized by plotting each point in the set in the complex plane. Julia sets are examples of fractals when plotted in the complex plane. ALGORITHM: - Define the map `Q_c(z) = z^2 + c` for some `c \in \mathbb{C}`. For every - `p \in \mathbb{C}`, if `|Q_{c}^{k}(p)| > 2` for some `k \geq 0`, - then `Q_{c}^{n}(p) \to \infty`. Let `N` be the maximum number of iterations. - Compute the first `N` points on the orbit of `p` under `Q_c`. If for - any `k < N`, `|Q_{c}^{k}(p)| > 2`, we stop the iteration and assign a color + For every `p \in \mathbb{C}`, if `|f^{k}(p)| > 2` for some `k \geq 0`, + then `f^{n}(p) \to \infty`. Let `N` be the maximum number of iterations. + Compute the first `N` points on the orbit of `p` under `f`. If for + any `k < N`, `|f^{k}(p)| > 2`, we stop the iteration and assign a color to the point `p` based on how quickly `p` escaped to infinity under - iteration of `Q_c`. If `|Q_{c}^{i}(p)| \leq 2` for all `i \leq N`, we assume + iteration of `f`. If `|f^{i}(p)| \leq 2` for all `i \leq N`, we assume `p` is in the Julia set and assign the point `p` the color black. INPUT: - - ``c`` -- complex (optional - default: ``-1``), complex point `c` that - determines the Julia set. + - ``f`` -- input polynomial (optional - default: ``z^2 - 1``). - ``period`` -- list (optional - default: ``None``), returns the Julia set for a random `c` value with the given (formal) cycle structure. @@ -477,7 +478,7 @@ def julia_plot(c=-1, **kwds): in the complex plane. - ``max_iteration`` -- long (optional - default: ``500``), maximum number - of iterations the map `Q_c(z)`. + of iterations the map `f(z)`. - ``pixel_count`` -- long (optional - default: ``500``), side length of image in number of pixels. @@ -498,8 +499,15 @@ def julia_plot(c=-1, **kwds): 24-bit RGB image of the Julia set in the complex plane. + .. TODO:: + + Implement the interactive mode for general one-parameter families + of polynomials `f_c(z)`. + EXAMPLES:: + The default ``f`` is `z^2 - 1`. + sage: julia_plot() 1001x500px 24-bit RGB image @@ -508,12 +516,27 @@ def julia_plot(c=-1, **kwds): sage: julia_plot(mandelbrot=False) 500x500px 24-bit RGB image + :: + + sage: R. = CC[] + sage: f = z^3 - z + 1 + sage: julia_plot(f) + 500x500px 24-bit RGB image + To display an interactive plot of the Julia set in the Notebook, - set ``interact`` to ``True``:: + set ``interact`` to ``True``. (This is only implemented for polynomials of + the form ``f = z^2 + c``):: sage: julia_plot(interact=True) interactive(children=(FloatSlider(value=-1.0, description=u'Real c'... + :: + + sage: R. = CC[] + sage: f = z^2 + 1/2 + sage: julia_plot(f,interact=True) + interactive(children=(FloatSlider(value=0.5, description=u'Real c'... + To return the Julia set of a random `c` value with (formal) cycle structure `(2,3)`, set ``period = [2,3]``:: @@ -531,8 +554,35 @@ def julia_plot(c=-1, **kwds): ....: c_values = [k[0] for k in L] ....: for c in c_values: ....: julia_plot(c) + + Polynomial maps can be defined over a polynomial ring or a fraction field, + so long as ``f`` is polynomial:: + + sage: R. = CC[] + sage: f = z^2 - 1 + sage: julia_plot(f) + 1001x500px 24-bit RGB image + + :: + + sage: R. = CC[] + sage: K = R.fraction_field(); z = K.gen() + sage: f = z^2-1 + sage: julia_plot(f) + 1001x500px 24-bit RGB image + + Interact functionality is not implemented if the polynomial is not of the + form `f = z^2 + c`:: + + sage: R. = CC[] + sage: f = z^3 + 1 + sage: julia_plot(f, interact=True) + Traceback (most recent call last): + ... + NotImplementedError: The interactive plot is only implemented for ... """ + # extract keyword arguments period = kwds.pop("period", None) mandelbrot = kwds.pop("mandelbrot", True) point_color = kwds.pop("point_color", 'tomato') @@ -544,64 +594,103 @@ def julia_plot(c=-1, **kwds): base_color = kwds.pop("base_color", 'steelblue') level_sep= kwds.pop("level_sep", 1) number_of_colors = kwds.pop("number_of_colors", 30) - interact = kwds.pop("interact", False) + interacts = kwds.pop("interact", False) - if period: - R = PolynomialRing(QQ, 'c') + f_is_default_after_all=None + + if period: # pick a random c with the specified period + R = PolynomialRing(CC, 'c') c = R.gen() x, y = ProjectiveSpace(R, 1, 'x,y').gens() - f = DynamicalSystem([x**2 + c * y**2, y**2]) - L = f.dynatomic_polynomial(period).subs({x: 0, y: 1}).roots(ring=CC) + F = DynamicalSystem([x**2 + c * y**2, y**2]) + L = F.dynatomic_polynomial(period).subs({x: 0, y: 1}).roots(ring=CC) c = L[randint(0, len(L) - 1)][0] - c = CC(c) - c_real = c.real() - c_imag = c.imag() - base_color = Color(base_color) point_color = Color(point_color) EPS = 0.00001 - if interact: - from ipywidgets.widgets import FloatSlider, IntSlider, ColorPicker, interact - widgets = dict( - c_real = FloatSlider(min=-2.0, max=2.0, step=EPS, - value=c_real, description="Real c"), - c_imag = FloatSlider(min=-2.0, max=2.0, step=EPS, - value=c_imag, description="Imag c"), - x_center = FloatSlider(min=-1.0, max=1.0, step=EPS, - value=x_center, description="Real center"), - y_center = FloatSlider(min=-1.0, max=1.0, step=EPS, - value=y_center, description="Imag center"), - image_width = FloatSlider(min=EPS, max=4.0, step=EPS, - value=image_width, description="Width"), - max_iteration = IntSlider(min=0, max=1000, - value=max_iteration, description="Iterations"), - pixel_count = IntSlider(min=10, max=1000, - value=pixel_count, description="Pixels"), - level_sep = IntSlider(min=1, max=20, + if f is not None and period is None: # f user-specified and no period given + + # try to coerce f to live in a polynomial ring + S = PolynomialRing(CC,names='z'); z = S.gen() + try: + f_poly = S(f) + except TypeError: + R = f.parent() + if not (R.is_integral_domain() and + (CC.is_subring(R) or CDF.is_subring(R))): + raise ValueError('Given `f` must be a complex polynomial.') + else: + raise NotImplementedError( + 'Julia sets not implemented for rational functions.' + ) + + if (f_poly - z*z) in CC: # f is specified and of the form z^2 + c. + f_is_default_after_all = True + c = f_poly - z*z + else: # f is specified and not of the form z^2 + c + if interacts: + raise NotImplementedError( + "The interactive plot is only implemented for " + "polynomials of the form f = z^2 + c." + ) + else: + return general_julia(f_poly, x_center, y_center, + image_width, max_iteration, + pixel_count, level_sep, + number_of_colors, base_color) + + # otherwise we can use fast_julia_plot for z^2 + c + if f_is_default_after_all or f is None or period is not None: + + # specify default c = -1 value if f and period were not specified + if not f_is_default_after_all and period is None: + c = -1 + + c = CC(c) + c_real = c.real() + c_imag = c.imag() + + if interacts: # set widgets + from ipywidgets.widgets import FloatSlider, IntSlider, \ + ColorPicker, interact + widgets = dict( + c_real = FloatSlider(min=-2.0, max=2.0, step=EPS, + value=c_real, description="Real c"), + c_imag = FloatSlider(min=-2.0, max=2.0, step=EPS, + value=c_imag, description="Imag c"), + x_center = FloatSlider(min=-1.0, max=1.0, step=EPS, + value=x_center, description="Real center"), + y_center = FloatSlider(min=-1.0, max=1.0, step=EPS, + value=y_center, description="Imag center"), + image_width = FloatSlider(min=EPS, max=4.0, step=EPS, + value=image_width, description="Width"), + max_iteration = IntSlider(min=0, max=1000, + value=max_iteration, description="Iterations"), + pixel_count = IntSlider(min=10, max=1000, + value=pixel_count, description="Pixels"), + level_sep = IntSlider(min=1, max=20, value=level_sep, description="Color sep"), - color_num = IntSlider(min=1, max=100, + color_num = IntSlider(min=1, max=100, value=number_of_colors, description="# Colors"), - base_color = ColorPicker(value=base_color.html_color(), - description="Base color"), - ) - if mandelbrot: - widgets["point_color"] = ColorPicker(value=point_color.html_color(), - description="Point color") - return interact(**widgets).widget(julia_helper) - else: - return interact(**widgets).widget(fast_julia_plot) - - if mandelbrot: - return julia_helper(c_real, c_imag, x_center, y_center, - image_width, max_iteration, pixel_count, - level_sep, - number_of_colors, base_color, point_color) + base_color = ColorPicker(value=base_color.html_color(), + description="Base color"), + ) + if mandelbrot: + widgets["point_color"] = ColorPicker(value=point_color.html_color(), + description="Point color") + return interact(**widgets).widget(julia_helper) + else: + return interact(**widgets).widget(fast_julia_plot) + elif mandelbrot: # non-interactive with mandelbrot + return julia_helper(c_real, c_imag, x_center, y_center, + image_width, max_iteration, pixel_count, + level_sep, number_of_colors, base_color, + point_color) + else: # non-interactive without mandelbrot + return fast_julia_plot(c_real, c_imag, x_center, y_center, + image_width, max_iteration, pixel_count, + level_sep, number_of_colors, base_color) - else: - return fast_julia_plot(c_real, c_imag, x_center, y_center, - image_width, max_iteration, pixel_count, - level_sep, - number_of_colors, base_color) diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx index c56bc80e91c..5152010cd3b 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +++ b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx @@ -918,8 +918,26 @@ cpdef general_julia(f, double x_center=0, double y_center=0, image_width=4, int max_iteration=50, int pixel_count=500, int level_sep=1, int color_num=30, base_color=[50,50,50]): r""" - Plots Julia sets for General Polynomials - TODO: Add documentation + Plots Julia sets for general polynomials. + + EXAMPLES:: + + sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import general_julia + sage: from sage.plot.colors import Color + sage: R. = CC[] + sage: f = z^3 - z + 1 + sage: general_julia(f) + 500x500px 24-bit RGB image + + :: + + sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import general_julia + sage: from sage.plot.colors import Color + sage: R. = CC[] + sage: f = z^5 - 1 + sage: general_julia(f) + 500x500px 24-bit RGB image + """ cdef: From ebaf4e9801dfcd7b37469043ccb3045f4711c0ce Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Sun, 24 Nov 2019 17:20:39 +0100 Subject: [PATCH 227/340] Fix 32-bit py3-specific tests --- src/doc/en/developer/coding_basics.rst | 5 ++++- src/sage/graphs/generators/random.py | 5 ++++- src/sage/libs/pynac/pynac.pyx | 15 ++++++++++----- src/sage/rings/padics/CR_template.pxi | 9 ++++++--- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/doc/en/developer/coding_basics.rst b/src/doc/en/developer/coding_basics.rst index 9c2e4799c26..aa7ad0f6f21 100644 --- a/src/doc/en/developer/coding_basics.rst +++ b/src/doc/en/developer/coding_basics.rst @@ -1121,7 +1121,10 @@ framework. Here is a comprehensive list: 64-bit machines. Note that this particular flag is to be applied on the **output** lines, not the input lines:: - sage: hash(2^31 + 2^13) + sage: hash(2^31 + 2^13) # py3 + 8193 # 32-bit + 2147491840 # 64-bit + sage: hash(2^31 + 2^13) # py2 -2147475456 # 32-bit 2147491840 # 64-bit diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index 8a793169606..3b128c7ae1f 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -697,7 +697,10 @@ 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) - sage: G.order(), G.size() + sage: G.order(), G.size() # py3 + (7, 9) # 64-bit + (7, 10) # 32-bit + sage: G.order(), G.size() # py2 (7, 9) sage: C7 = graphs.CycleGraph(7) sage: G.subgraph_search(C7) diff --git a/src/sage/libs/pynac/pynac.pyx b/src/sage/libs/pynac/pynac.pyx index 081006a6ae1..94df1967c8b 100644 --- a/src/sage/libs/pynac/pynac.pyx +++ b/src/sage/libs/pynac/pynac.pyx @@ -287,11 +287,16 @@ cdef subs_args_to_PyTuple(const GExMap& map, unsigned options, const GExVector& ....: print("len(args): %s, types: %s"%(len(args), str(list(map(type, args))))) ....: return args[-1] sage: tfunc = TFunc() - sage: tfunc(x).subs(x=1) - len(args): 3, types: [, - , # 64-bit - , # 32-bit - ] + sage: tfunc(x).subs(x=1) # py3 + len(args): 3, types: [, + , + ] + x + sage: tfunc(x).subs(x=1) # py2 + len(args): 3, types: [, + , # 64-bit + , # 32-bit + ] x """ from sage.symbolic.ring import SR diff --git a/src/sage/rings/padics/CR_template.pxi b/src/sage/rings/padics/CR_template.pxi index b985e40fcf6..31269291c16 100644 --- a/src/sage/rings/padics/CR_template.pxi +++ b/src/sage/rings/padics/CR_template.pxi @@ -1510,9 +1510,12 @@ cdef class CRElement(pAdicTemplateElement): sage: hash(R(17)) #indirect doctest 17 - sage: hash(R(-1)) - 1977822444 # 32-bit - 95367431640624 # 64-bit + sage: hash(R(-1)) # py3 + 1977844648 # 32-bit + 95367431640624 # 64-bit + sage: hash(R(-1)) # py2 + 1977822444 # 32-bit + 95367431640624 # 64-bit """ if exactzero(self.ordp): return 0 From 84c8f64fbce56af7b35ba790567310ca652c17b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 24 Nov 2019 18:40:47 +0100 Subject: [PATCH 228/340] trac 28797 some 32-bit python fixes in combinat --- src/sage/combinat/partition_algebra.py | 12 +++++------- src/sage/combinat/subset.py | 6 +++--- src/sage/matroids/linear_matroid.pyx | 6 ++++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/sage/combinat/partition_algebra.py b/src/sage/combinat/partition_algebra.py index 5496588a292..6556b03ba8e 100644 --- a/src/sage/combinat/partition_algebra.py +++ b/src/sage/combinat/partition_algebra.py @@ -1459,15 +1459,13 @@ def __iter__(self): """ TESTS:: - sage: L = list(SetPartitionsPRk(2.5)); L - [{{-3, 3}, {-2}, {-1}, {1}, {2}}, {{-3, 3}, {-2}, {-1, 1}, {2}}, - {{-3, 3}, {-2, 1}, {-1}, {2}}, {{-3, 3}, {-2}, {-1, 2}, {1}}, - {{-3, 3}, {-2, 2}, {-1}, {1}}, {{-3, 3}, {-2, 2}, {-1, 1}}] - sage: len(L) + sage: next(iter(SetPartitionsPRk(2.5))) + {{-3, 3}, {-2}, {-1}, {1}, {2}} + sage: len(list(SetPartitionsPRk(2.5))) 6 """ - positives = Set(range(1, self.k+1)) - negatives = Set( [ -i for i in positives ] ) + positives = Set(range(1, self.k + 1)) + negatives = Set(-i for i in positives) yield self.element_class(self, to_set_partition([[self.k+1, -self.k-1]],k=self.k+1)) for n in range(1,self.k+1): diff --git a/src/sage/combinat/subset.py b/src/sage/combinat/subset.py index 850d4683a8b..0b71bc08cf8 100644 --- a/src/sage/combinat/subset.py +++ b/src/sage/combinat/subset.py @@ -144,7 +144,7 @@ def Subsets(s, k=None, submultiset=False): {}, {{2}, {1, 2, 3}, {}, {3}, {1, 2}}, {{1, 2, 3}, {}, {1}}, {{2}, {2, 3}, {}, {1, 2}}} - sage: S3.unrank(14123091480) # py3 + sage: S3.unrank(14123091480) # py3 #random {{{2}, {1, 2, 3}, {1, 2}, {3}, {}}, {{1, 2, 3}, {2}, {1}, {1, 3}}, {{}, {2}, {2, 3}, {1, 2}}, @@ -157,7 +157,7 @@ def Subsets(s, k=None, submultiset=False): 278826214642518400 sage: T.unrank(1441231049) # py2 {{{3}, {1, 2}, {}, {2, 3}, {1}, {1, 3}, ..., {{2, 3}, {}}, {{}}} - sage: T.unrank(1441231049) # py3 + sage: T.unrank(1441231049) # py3 # random {{{1, 2, 3}, {2}, {2, 3}}, {{3}, {1, 3}, ..., {3}, {1}, {}, {1, 3}}} """ if k is not None: @@ -205,7 +205,7 @@ class Subsets_s(Parent): {{1, 2}, {}, {0, 2}, {1}, {0, 1, 2}, {2}}, {{1, 2}, {0}}, {{1, 2}, {0, 1}, {0, 1, 2}, {1}}, {{0, 2}, {1}}} - sage: S.unrank(3149254230) # py3 + sage: S.unrank(3149254230) # py3 #random {{{1}, {0, 2}}, {{0, 1, 2}, {0, 1}, {1}, {1, 2}}, {{2}, {1, 2}, {0, 1, 2}, {0, 2}, {1}, {}}, {{1, 2}, {0}}, diff --git a/src/sage/matroids/linear_matroid.pyx b/src/sage/matroids/linear_matroid.pyx index 0330595de54..e72f7748d9e 100644 --- a/src/sage/matroids/linear_matroid.pyx +++ b/src/sage/matroids/linear_matroid.pyx @@ -2344,9 +2344,11 @@ cdef class LinearMatroid(BasisExchangeMatroid): [{0: 1, 1: 1, 2: 1}] sage: N = Matroid(ring=QQ, ....: reduced_matrix=[[-1, -1, 0], [1, 0, -1], [0, 1, 1]]) - sage: N.linear_extension_chains(F=[0, 1], simple=True, + sage: L = N.linear_extension_chains(F=[0, 1], simple=True, ....: fundamentals=set([1, -1, 1/2, 2])) - [{0: 1, 1: 1}, {0: -1/2, 1: 1}, {0: -2, 1: 1}] + sage: result = [{0: 1, 1: 1}, {0: -1/2, 1: 1}, {0: -2, 1: 1}] + sage: all(D in L for D in result) + True """ if F is None: FI = self.basis() From e9f1fc9ef188a54634dcdd2784935bc1943ff309 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 24 Nov 2019 21:06:14 +0100 Subject: [PATCH 229/340] trac 28795 fix a typo --- src/sage/arith/long.pxd | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/sage/arith/long.pxd b/src/sage/arith/long.pxd index 0d9ca427e84..887c6fde677 100644 --- a/src/sage/arith/long.pxd +++ b/src/sage/arith/long.pxd @@ -2,7 +2,7 @@ r""" Fast conversion of Python objects to C long """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 Vincent Delecroix <20100.delecroix@gmail.com> # Copyright (C) 2017 Jeroen Demeyer # @@ -10,8 +10,8 @@ Fast conversion of Python objects to C long # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from libc.limits cimport LONG_MIN, LONG_MAX @@ -265,11 +265,12 @@ cdef inline bint integer_check_long_py(x, long* value, int* err): cdef inline bint is_small_python_int(obj): """ - Test whether Python object is a small Python integer + Test whether Python object is a small Python integer. - Meaning that that it can be converted to a C long. In Python 2, this is equvialent to it being - the ``int`` Python type. In Python 3, the ``int`` Python type has unlimited precision so we need - to check its range. + Meaning that that it can be converted to a C long. In Python 2, + this is equivalent to it being the ``int`` Python type. In Python + 3, the ``int`` Python type has unlimited precision so we need to + check its range. EXAMPLES:: From e4897316eefc095e48b0c4da5ce735d751cf1cca Mon Sep 17 00:00:00 2001 From: Benjamin Hutz Date: Sun, 24 Nov 2019 14:33:30 -0600 Subject: [PATCH 230/340] 23720: fix issue with parameter initialization --- src/sage/dynamics/complex_dynamics/mandel_julia.py | 7 +++++-- .../dynamics/complex_dynamics/mandel_julia_helper.pyx | 9 +++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia.py b/src/sage/dynamics/complex_dynamics/mandel_julia.py index 743c13b6715..0ae179aa058 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia.py +++ b/src/sage/dynamics/complex_dynamics/mandel_julia.py @@ -253,8 +253,11 @@ def mandelbrot_plot(f=None, **kwds): elif P.base_ring().base_ring() is CC or P.base_ring().base_ring() is CDF: if is_FractionField(P.base_ring()): raise NotImplementedError("coefficients must be polynomials in the parameter") - variable = P.gen() - parameter = P.base_ring().gen() + phi = P.flattening_morphism() + f = phi(f) + gen_list = list(f.parent().gens()) + parameter = gen_list.pop(gen_list.index(parameter)) + variable = gen_list.pop() elif P.base_ring() in FunctionFields(): raise NotImplementedError("coefficients must be polynomials in the parameter") diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx index 0ea4cc86ff3..546a4e7c5bc 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +++ b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx @@ -702,14 +702,15 @@ cpdef polynomial_mandelbrot(f, parameter=None, double x_center=0, raise NotImplementedError("coefficients must be polynomials in the parameter") phi = P.flattening_morphism() f = phi(f) - parameter = P.base_ring().gen() - variable = P.gen() + gen_list = list(f.parent().gens()) + parameter = gen_list.pop(gen_list.index(parameter)) + variable = gen_list.pop() elif P.base_ring() in FunctionFields(): raise NotImplementedError("coefficients must be polynomials in the parameter") else: - return ValueError("base ring must be a complex field") + raise ValueError("base ring must be a complex field") # Make sure image_width is positive image_width = abs(image_width) @@ -735,7 +736,7 @@ cpdef polynomial_mandelbrot(f, parameter=None, double x_center=0, # Split function into real and imaginary parts R = PolynomialRing(CC, [variable,parameter]) if len(R.gens()) > 2: - return NotImplementedError("Base ring must have only 2 variables") + raise NotImplementedError("Base ring must have only 2 variables") z, c = R.gens() f = R(str(f)) S = PolynomialRing(f.base_ring(), 'x,y,J,cr,ci') From 69a593b10bd313e5012b670a09a95d3dcb12b6e2 Mon Sep 17 00:00:00 2001 From: "E. Madison Bray" Date: Mon, 25 Nov 2019 16:35:45 +0100 Subject: [PATCH 231/340] Trac #28801: Support local file URLs in script tags on more browsers in Windows. The following approach seems to work equally well on Chrome, Firefox, and, yes, Edge. --- src/sage/repl/rich_output/backend_ipython.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/repl/rich_output/backend_ipython.py b/src/sage/repl/rich_output/backend_ipython.py index 8bf4861a353..44ba8fce416 100644 --- a/src/sage/repl/rich_output/backend_ipython.py +++ b/src/sage/repl/rich_output/backend_ipython.py @@ -423,7 +423,9 @@ def threejs_offline_scripts(self): if sys.platform == 'cygwin': import cygwin - scripts = [cygwin.cygpath(script, 'w') for script in scripts] + def normpath(p): + return 'file:///' + cygwin.cygpath(p, 'w').replace('\\', '/') + scripts = [normpath(script) for script in scripts] return '\n'.join(''.format(script) for script in scripts) From e2338cf91cb1f0eedf44d64e931c8039bbb488b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 25 Nov 2019 17:37:10 +0100 Subject: [PATCH 232/340] better error message for old noteboook under python3 --- src/bin/sage-notebook | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/bin/sage-notebook b/src/bin/sage-notebook index d2302370c2e..4fbba045387 100755 --- a/src/bin/sage-notebook +++ b/src/bin/sage-notebook @@ -249,6 +249,12 @@ if __name__ == '__main__': logger.info('Main parser got arguments %s', args) logger.info('Passing on to notebook implementation: %s', unknown) + if sys.version_info.major == 3 and args.notebook == "sagenb": + logger.critical('trying to use old notebook under Python 3') + print('old notebook not working under Python 3, use Jupyter notebook') + print('see https://wiki.sagemath.org/Python3-Switch') + sys.exit(1) + try: launcher = notebook_launcher[args.notebook] except KeyError: From 9a23dea695425aebfdbe6e1f21bddcc4d6286910 Mon Sep 17 00:00:00 2001 From: aodesky Date: Mon, 25 Nov 2019 12:06:59 -0500 Subject: [PATCH 233/340] Modify TODO block for julia_plot. Fix formatting error with documentation. --- src/sage/dynamics/complex_dynamics/mandel_julia.py | 5 +++-- src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia.py b/src/sage/dynamics/complex_dynamics/mandel_julia.py index 8f5454bf9f6..71eb3a0af97 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia.py +++ b/src/sage/dynamics/complex_dynamics/mandel_julia.py @@ -41,6 +41,7 @@ general_julia, polynomial_mandelbrot, julia_helper) + from sage.dynamics.arithmetic_dynamics.generic_ds import DynamicalSystem from sagenb.notebook.interact import (interact, slider, @@ -504,9 +505,9 @@ def julia_plot(f=None, **kwds): Implement the interactive mode for general one-parameter families of polynomials `f_c(z)`. - EXAMPLES:: + EXAMPLES: - The default ``f`` is `z^2 - 1`. + The default ``f`` is `z^2 - 1`:: sage: julia_plot() 1001x500px 24-bit RGB image diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx index 5152010cd3b..e0c18697480 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +++ b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx @@ -920,7 +920,9 @@ cpdef general_julia(f, double x_center=0, double y_center=0, image_width=4, r""" Plots Julia sets for general polynomials. - EXAMPLES:: + EXAMPLES: + + :: sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import general_julia sage: from sage.plot.colors import Color From a028f89b818fa5380ad02ab5a9b20cd870d0623c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Tue, 26 Nov 2019 11:59:55 +1300 Subject: [PATCH 234/340] remove sagenb from DOC_DEPENDENCIES --- build/make/deps | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/make/deps b/build/make/deps index 36c7d615f31..f9bc4711ad4 100644 --- a/build/make/deps +++ b/build/make/deps @@ -216,7 +216,7 @@ $(SAGE_EXTCODE)/%: $(SAGE_SRC)/ext/% # Building the documentation has many dependencies, because all # documented modules are imported and because we use matplotlib to # produce plots. -DOC_DEPENDENCIES = sagelib $(inst_sphinx) $(inst_sagenb) \ +DOC_DEPENDENCIES = sagelib $(inst_sphinx) \ | $(SAGERUNTIME) $(inst_maxima) $(inst_networkx) $(inst_scipy) $(inst_sympy) \ $(inst_matplotlib) $(inst_pillow) $(inst_mathjax) $(inst_mpmath) \ $(inst_ipykernel) $(inst_jupyter_client) $(inst_conway_polynomials) \ From e234ff5c34332e6c3c31a0c9b3bf62e73fc504e7 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Mon, 25 Nov 2019 20:51:05 -0800 Subject: [PATCH 235/340] trac 28805: tag some tests "# py2" --- src/sage/tests/cmdline.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/tests/cmdline.py b/src/sage/tests/cmdline.py index b5e1a4e603e..cd343e41503 100644 --- a/src/sage/tests/cmdline.py +++ b/src/sage/tests/cmdline.py @@ -826,8 +826,8 @@ def test_executable(args, input="", timeout=100.0, **kwds): sage: input = tmp_filename(ext='.rst') sage: with open(input, 'w') as F: ....: _ = F.write(s) - sage: (out, err, ret) = test_executable(["sage", "--rst2txt", input]) - sage: print(out) + sage: (out, err, ret) = test_executable(["sage", "--rst2txt", input]) # py2 + sage: print(out) # py2 {{{id=0| 2^10 /// @@ -841,7 +841,7 @@ def test_executable(args, input="", timeout=100.0, **kwds): }}} sage: err # py2 '' - sage: ret + sage: ret # py2 0 Test ``sage --rst2txt file.rst file.txt`` on a ReST file:: @@ -851,9 +851,9 @@ def test_executable(args, input="", timeout=100.0, **kwds): sage: output = tmp_filename(ext='.txt') sage: with open(input, 'w') as F: ....: _ = F.write(s) - sage: test_executable(["sage", "--rst2txt", input, output]) + sage: test_executable(["sage", "--rst2txt", input, output]) # py2 ('', ..., 0) - sage: print(open(output, 'r').read()) + sage: print(open(output, 'r').read()) # py2 {{{id=0| 2^10 /// From d48a21c149cc90f8a2703945e64fdfe9a80b59ed Mon Sep 17 00:00:00 2001 From: Release Manager Date: Wed, 27 Nov 2019 00:24:57 +0100 Subject: [PATCH 236/340] Updated SageMath version to 9.0.beta7 --- VERSION.txt | 2 +- build/pkgs/configure/checksums.ini | 6 +++--- build/pkgs/configure/package-version.txt | 2 +- src/bin/sage-version.sh | 6 +++--- src/sage/version.py | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index c57211e9a13..ab3a5777d77 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 9.0.beta6, Release Date: 2019-11-18 +SageMath version 9.0.beta7, Release Date: 2019-11-26 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index de2a5c95ca1..d63d3fc32dd 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=d1e0b2e6a9793d5bf342e73d8f38c13b46da45fb -md5=52072cb5dfe0facf7192cc54a146d53b -cksum=3603615845 +sha1=ab91b79f255de3311461ed21e05d7a8eacd7495a +md5=8919ee3aea8aa02f9a3c15365102b59c +cksum=3707653135 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index c47dea057dc..9bd54bb21ec 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -0061b88c3662b70fe625350e47e48032144204e8 +22426a509ba10c4bd870bc2497624d362478d466 diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 78d70093464..e4a6863d454 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -1,5 +1,5 @@ # Sage version information for shell scripts # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='9.0.beta6' -SAGE_RELEASE_DATE='2019-11-18' -SAGE_VERSION_BANNER='SageMath version 9.0.beta6, Release Date: 2019-11-18' +SAGE_VERSION='9.0.beta7' +SAGE_RELEASE_DATE='2019-11-26' +SAGE_VERSION_BANNER='SageMath version 9.0.beta7, Release Date: 2019-11-26' diff --git a/src/sage/version.py b/src/sage/version.py index 5e7c0792958..66cb3a91cbc 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 = '9.0.beta6' -date = '2019-11-18' -banner = 'SageMath version 9.0.beta6, Release Date: 2019-11-18' +version = '9.0.beta7' +date = '2019-11-26' +banner = 'SageMath version 9.0.beta7, Release Date: 2019-11-26' From c6072354907aeea5e79ccec12826460223648a9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 27 Nov 2019 11:10:00 +0100 Subject: [PATCH 237/340] some typos --- src/sage/combinat/rsk.py | 2 +- src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx | 2 +- .../polyhedron/combinatorial_polyhedron/face_iterator.pyx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/rsk.py b/src/sage/combinat/rsk.py index c4125f2e53c..afc72c79be2 100644 --- a/src/sage/combinat/rsk.py +++ b/src/sage/combinat/rsk.py @@ -58,7 +58,7 @@ - CoRSK insertion (:class:`~sage.combinat.rsk.RuleCoRSK`), defined in [GR2018v5sol]_. - Super RSK insertion (:class:`~sage.combinat.rsk.RuleSuperRSK`), a - combiantion of row and column insertions defined in [Muth2019]_. + combination of row and column insertions defined in [Muth2019]_. Implementing your own insertion rule ------------------------------------ diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index 75de6c64a2c..6ea415bb7e1 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -1365,7 +1365,7 @@ cdef class CombinatorialPolyhedron(SageObject): .. WARNING:: - The labeling of the face lattice might depend on archicture + The labeling of the face lattice might depend on architecture and implementation. Relabeling the face lattice with :meth:`CombinatorialPolyhedron.face_by_face_lattice_index` or diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx index 02be3d68df7..0bcb33b0402 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx @@ -363,7 +363,7 @@ cdef class FaceIterator(SageObject): # and not contained in any of the ``visited_all``, # it is a facet of ``one_face``. # Any facet in ``maybe_newfaces`` of ``one_face`` - # is inlcusion maximal. + # is inclusion maximal. maybe_newfaces2 = [] for face1 in maybe_newfaces: # ``face1`` is a facet of ``one_face``, From d325740333c6d13e85d5b12b4357f4de2a2c170d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 27 Nov 2019 17:43:48 +0100 Subject: [PATCH 238/340] cleanup one file in combinat (pep, pyflakes, typo) --- .../combinat/partition_shifting_algebras.py | 41 +++++++++---------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/src/sage/combinat/partition_shifting_algebras.py b/src/sage/combinat/partition_shifting_algebras.py index cad31f2186e..2e6e59efac5 100644 --- a/src/sage/combinat/partition_shifting_algebras.py +++ b/src/sage/combinat/partition_shifting_algebras.py @@ -1,4 +1,3 @@ - # -*- coding: utf-8 -*- r""" Partition Shifting Algebras @@ -13,26 +12,20 @@ - Matthew Lancellotti, George H. Seelinger (2018): Initial version """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2018 Matthew Lancellotti # George H. Seelinger # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** -from functools import reduce - +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.combinat.free_module import CombinatorialFreeModule -from sage.categories.groups import Groups from sage.categories.sets_cat import Sets from sage.categories.algebras import Algebras from sage.structure.parent import Parent from sage.combinat.composition import Composition from sage.combinat.partition import _Partitions, Partition from sage.combinat.sf.sf import SymmetricFunctions -from sage.misc.lazy_attribute import lazy_attribute -from sage.misc.misc_c import prod from sage.misc.fast_methods import Singleton from sage.misc.cachefunc import cached_method from sage.rings.all import QQ, NonNegativeIntegerSemiring @@ -179,7 +172,7 @@ class ShiftingOperatorAlgebra(CombinatorialFreeModule): sage: elm([5, 4]) [([6, 3, 2], 1)] - The shifting operator monomials can act on a complete homogeneous symmetric + The shifting operator monomials can act on a complete homogeneous symmetric function or a Schur function:: sage: s = SymmetricFunctions(QQ['t']).s() @@ -220,7 +213,7 @@ class ShiftingOperatorAlgebra(CombinatorialFreeModule): sage: s(elm) 0 - However, not all homomorphisms are equivalent, so the action is basis + However, not all homomorphisms are equivalent, so the action is basis dependent:: sage: elm = S([3,2,1]); elm @@ -312,7 +305,7 @@ def _prepare_seq(self, seq): index = len(seq) - 1 while index >= 0 and seq[index] == 0: index -= 1 - seq = seq[:index+1] + seq = seq[:index + 1] self._indices.check(seq) return seq @@ -350,7 +343,7 @@ def product_on_basis(self, x, y): """ # Make x have the longer length if len(x) < len(y): - x,y = y,x + x, y = y, x x = list(x) # Make a mutable copy for i, val in enumerate(y): x[i] += val @@ -358,7 +351,7 @@ def product_on_basis(self, x, y): index = len(x) - 1 while index >= 0 and x[index] == 0: index -= 1 - return self.monomial(tuple(x[:index+1])) + return self.monomial(tuple(x[:index + 1])) @cached_method def one_basis(self): @@ -375,7 +368,7 @@ def one_basis(self): def _supp_to_h(self, supp): r""" - This is a helper funciton that is not meant to be called directly. + This is a helper function that is not meant to be called directly. Given the support of an element `x_1^{\gamma_1} x_2^{\gamma_2} \cdots x_\ell^{\gamma_\ell}` in the @@ -428,7 +421,8 @@ def _supp_to_s(self, gamma): s[3, 2] """ def number_of_noninversions(lis): - return sum(1 for i,val in enumerate(lis) for j in range(i + 1, len(lis)) + return sum(1 for i, val in enumerate(lis) + for j in range(i + 1, len(lis)) if val < lis[j]) # i < j is already enforced rho = list(range(len(gamma) - 1, -1, -1)) @@ -497,8 +491,11 @@ def build_and_register_conversion(self, support_map, codomain): sage: op(2*m[4,3] + 5*m[2,2] + 7*m[2]) == 2*m[5, 2] + 5*m[3, 1] True """ - precompose_map = lambda supp: support_map(supp) - module_morphism = self.module_morphism(precompose_map, codomain=codomain) + + def precompose_map(supp): + return support_map(supp) + module_morphism = self.module_morphism(precompose_map, + codomain=codomain) codomain.register_conversion(module_morphism) def ij(self, i, j): @@ -562,7 +559,7 @@ def __call__(self, operand): def add_lists(x, y): # Make x have the longer length if len(x) < len(y): - x,y = y,x + x, y = y, x x = list(x) # Make a mutable copy for i, val in enumerate(y): x[i] += val @@ -570,11 +567,11 @@ def add_lists(x, y): return [(add_lists(index, operand), coeff) for index, coeff in self] R = self.base_ring() - lift_operand = P._from_dict({P._prepare_seq(p): R(c) for p,c in operand}, coerce=False) + lift_operand = P._from_dict({P._prepare_seq(p): R(c) + for p, c in operand}, coerce=False) result = self * lift_operand operand_parent = operand.parent() try: return operand_parent(result) except TypeError: return [(list(index), coeff) for index, coeff in result] - From bc10db688ec83b6c50f01926799400a8e146f726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 27 Nov 2019 17:50:29 +0100 Subject: [PATCH 239/340] small fix in regular expression for trac warning in sage/all.py --- src/sage/all.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/all.py b/src/sage/all.py index 42dca175d21..1e36169b1b2 100644 --- a/src/sage/all.py +++ b/src/sage/all.py @@ -315,8 +315,7 @@ def _write_started_file(): message='.*collections[.]abc.*') # However, be sure to keep OUR deprecation warnings warnings.filterwarnings('default', category=DeprecationWarning, - message=r'[\s\S]*See https\?://trac.sagemath.org/[0-9]* for details.') - + message=r'[\s\S]*See https\?://trac\.sagemath\.org/[0-9]* for details.') # Set a new random number seed as the very last thing # (so that printing initial_seed() and using that seed From aa61b6eeb487368d7bbb8f0883de7c01c3a709b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 27 Nov 2019 17:57:21 +0100 Subject: [PATCH 240/340] add hash for hypergeometric motives --- src/sage/modular/hypergeometric_motive.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index 8adc5f6e5ea..4234279b41e 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -531,6 +531,18 @@ def __ne__(self, other): """ return not (self == other) + def __hash__(self): + """ + Return a hash for ``self``. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: H1 = Hyp(alpha_beta=([1/2],[0])) + sage: h = hash(H1) + """ + return hash((self._alpha, self._beta)) + # --- Parameters and invariants --- def cyclotomic_data(self): """ From 0d95ebcaf9a831ec3ecef85fffdc0eafc7a50f78 Mon Sep 17 00:00:00 2001 From: Benjamin Hutz Date: Wed, 27 Nov 2019 14:25:00 -0600 Subject: [PATCH 241/340] 23740: minor doc fixes --- src/sage/dynamics/complex_dynamics/mandel_julia.py | 14 +++++++------- .../complex_dynamics/mandel_julia_helper.pyx | 7 ++----- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia.py b/src/sage/dynamics/complex_dynamics/mandel_julia.py index 71eb3a0af97..6a6a851f9f6 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia.py +++ b/src/sage/dynamics/complex_dynamics/mandel_julia.py @@ -93,19 +93,19 @@ def mandelbrot_plot(f=None, **kwds): iterations the map ``f_c(z)``. - ``pixel_count`` -- long (optional - default: ``500``), side length of - image in number of pixels. + image in number of pixels. - ``base_color`` -- RGB color (optional - default: ``[40, 40, 40]``) color - used to determine the coloring of set. + used to determine the coloring of set. - ``level_sep`` -- long (optional - default: 1) number of iterations - between each color level. + between each color level. - ``number_of_colors`` -- long (optional - default: 30) number of colors - used to plot image. + used to plot image. - ``interact`` -- boolean (optional - default: ``False``), controls whether - plot will have interactive functionality. + plot will have interactive functionality. OUTPUT: @@ -502,8 +502,8 @@ def julia_plot(f=None, **kwds): .. TODO:: - Implement the interactive mode for general one-parameter families - of polynomials `f_c(z)`. + Implement the side-by-side Mandelbrot-Julia plots for general one-parameter families + of polynomials. EXAMPLES: diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx index e0c18697480..c73e55ee66e 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +++ b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx @@ -918,11 +918,9 @@ cpdef general_julia(f, double x_center=0, double y_center=0, image_width=4, int max_iteration=50, int pixel_count=500, int level_sep=1, int color_num=30, base_color=[50,50,50]): r""" - Plots Julia sets for general polynomials. + Plots Julia sets for general polynomials. - EXAMPLES: - - :: + EXAMPLES:: sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import general_julia sage: from sage.plot.colors import Color @@ -939,7 +937,6 @@ cpdef general_julia(f, double x_center=0, double y_center=0, image_width=4, sage: f = z^5 - 1 sage: general_julia(f) 500x500px 24-bit RGB image - """ cdef: From a755e183bc1fbda5bce13b1c71499d838207e2a0 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Wed, 27 Nov 2019 12:43:53 -0800 Subject: [PATCH 242/340] trac 28812: fix py2 doctest in libs/pynac/pynac.pyx --- src/sage/libs/pynac/pynac.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/libs/pynac/pynac.pyx b/src/sage/libs/pynac/pynac.pyx index 94df1967c8b..284cc17376d 100644 --- a/src/sage/libs/pynac/pynac.pyx +++ b/src/sage/libs/pynac/pynac.pyx @@ -293,10 +293,10 @@ cdef subs_args_to_PyTuple(const GExMap& map, unsigned options, const GExVector& ] x sage: tfunc(x).subs(x=1) # py2 - len(args): 3, types: [, - , # 64-bit - , # 32-bit - ] + len(args): 3, types: [, + , # 64-bit + , # 32-bit + ] x """ from sage.symbolic.ring import SR From c56d791b9f23dbd208b53a55e2861506eb942fe3 Mon Sep 17 00:00:00 2001 From: aodesky Date: Wed, 27 Nov 2019 15:51:20 -0500 Subject: [PATCH 243/340] 23740: Remove unused imports from sagenb. --- src/sage/dynamics/complex_dynamics/mandel_julia.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia.py b/src/sage/dynamics/complex_dynamics/mandel_julia.py index 6a6a851f9f6..7620e183682 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia.py +++ b/src/sage/dynamics/complex_dynamics/mandel_julia.py @@ -43,11 +43,6 @@ julia_helper) from sage.dynamics.arithmetic_dynamics.generic_ds import DynamicalSystem -from sagenb.notebook.interact import (interact, - slider, - input_box, - color_selector, - checkbox) from sage.plot.colors import Color from sage.repl.image import Image from sage.functions.log import logb From a3313749c83288455b3be984c5ee1865ed3fbac2 Mon Sep 17 00:00:00 2001 From: Michael Jung Date: Thu, 28 Nov 2019 12:18:10 +0100 Subject: [PATCH 244/340] Trac #27784: `g(0)=0` condition for real additive classes added in doc --- src/sage/manifolds/differentiable/characteristic_class.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/manifolds/differentiable/characteristic_class.py b/src/sage/manifolds/differentiable/characteristic_class.py index 2b78003e0ab..0f9d7db8486 100644 --- a/src/sage/manifolds/differentiable/characteristic_class.py +++ b/src/sage/manifolds/differentiable/characteristic_class.py @@ -76,8 +76,8 @@ - *Chern Character* with `f(x) = \exp(x)` -In the **real** case, let `g` be a holomorphic function around zero. Then we -call +In the **real** case, let `g` be a holomorphic function around zero with +`g(0)=0`. Then we call .. MATH:: From fc0ebd1dc9e6122473e11a6da16b21d36986b032 Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Sat, 23 Nov 2019 23:46:07 +0100 Subject: [PATCH 245/340] 28819: avoid running mathematica frontend in doctests Usually, the Mathematica interface interacts with the program `WolframKernel`. However, a few doctests related to rendering result in the frontend program `Mathematica` to be launched. This is because graphics cannot be exported without access to a frontend, according to: https://mathematica.stackexchange.com/questions/5026/generating-figures-over-remote-connection-using-terminal These instances of `Mathematica` do not always seem to get closed properly. When running a patchbot, this leads to a growing number of orphan processes of `Mathematica` which do not seem to react to a SIGTERM signal. Marking the doctests `mathematicafrontend` effectively disables them. This solution had already been applied by #23112 for one of the doctests in the file. --- src/sage/interfaces/mathematica.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/sage/interfaces/mathematica.py b/src/sage/interfaces/mathematica.py index 10f5b69fcea..b189f44ece6 100644 --- a/src/sage/interfaces/mathematica.py +++ b/src/sage/interfaces/mathematica.py @@ -949,12 +949,16 @@ def show(self, ImageSize=600): EXAMPLES:: - sage: P = mathematica('Plot[Sin[x],{x,-2Pi,4Pi}]') # optional - mathematica - sage: show(P) # optional - mathematica - sage: P.show(ImageSize=800) # optional - mathematica sage: Q = mathematica('Sin[x Cos[y]]/Sqrt[1-x^2]') # optional - mathematica sage: show(Q) # optional - mathematica + + The following example starts a Mathematica frontend to do the rendering + (:trac:`28819`):: + + sage: P = mathematica('Plot[Sin[x],{x,-2Pi,4Pi}]') # optional - mathematica + sage: show(P) # optional - mathematica mathematicafrontend + sage: P.show(ImageSize=800) # optional - mathematica mathematicafrontend """ from sage.repl.rich_output import get_display_manager dm = get_display_manager() From f4b8c13c2f7a80fbc7bfcd2e8b75ad9e49e97418 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Fri, 29 Nov 2019 11:25:31 +0000 Subject: [PATCH 246/340] convert guava interface to libgap --- src/sage/coding/guava.py | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/src/sage/coding/guava.py b/src/sage/coding/guava.py index e2570750071..649a4d0880f 100644 --- a/src/sage/coding/guava.py +++ b/src/sage/coding/guava.py @@ -17,10 +17,13 @@ - David Joyner (2009-05): added "optional package" comments, fixed some docstrings to be sphinx compatible + +- Dima Pasechnik (2019-11): port to libgap """ #***************************************************************************** # Copyright (C) 2007 David Joyner # 2006 Nick Alexander +# 2019 Dima Pasechnik # # Distributed under the terms of the GNU General Public License (GPL) # @@ -28,11 +31,10 @@ #***************************************************************************** from __future__ import absolute_import -from sage.interfaces.all import gap +from sage.libs.gap.libgap import libgap from sage.misc.randstate import current_randstate from sage.matrix.matrix_space import MatrixSpace from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF -from sage.interfaces.gap import gfq_gap_to_sage from .linear_code import LinearCode from sage.features.gap import GapPackage @@ -66,15 +68,10 @@ def QuasiQuadraticResidueCode(p): AUTHOR: David Joyner (11-2005) """ GapPackage("guava", spkg="gap_packages").require() - F = GF(2) - gap.load_package("guava") - gap.eval("C:=QQRCode(" + str(p) + ")") - gap.eval("G:=GeneratorMat(C)") - k = int(gap.eval("Length(G)")) - n = int(gap.eval("Length(G[1])")) - G = [[gfq_gap_to_sage(gap.eval("G[%s][%s]" % (i, j)), F) - for j in range(1, n + 1)] for i in range(1, k + 1)] - MS = MatrixSpace(F, k, n) + libgap.load_package("guava") + C=libgap.QQRCode(p) + G=C.GeneratorMat() + MS = MatrixSpace(GF(2), len(G), len(G[0])) return LinearCode(MS(G)) @@ -105,14 +102,9 @@ def RandomLinearCodeGuava(n, k, F): """ current_randstate().set_seed_gap() - q = F.order() GapPackage("guava", spkg="gap_packages").require() - gap.load_package("guava") - gap.eval("C:=RandomLinearCode("+str(n)+","+str(k)+", GF("+str(q)+"))") - gap.eval("G:=GeneratorMat(C)") - k = int(gap.eval("Length(G)")) - n = int(gap.eval("Length(G[1])")) - G = [[gfq_gap_to_sage(gap.eval("G[%s][%s]" % (i, j)), F) - for j in range(1, n + 1)] for i in range(1, k + 1)] - MS = MatrixSpace(F, k, n) + libgap.load_package("guava") + C=libgap.RandomLinearCode(n,k,F) + G=C.GeneratorMat() + MS = MatrixSpace(F, len(G), len(G[0])) return LinearCode(MS(G)) From 4fe43284da140f2debd4cffd1f3a246faed30221 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 29 Nov 2019 13:52:34 +0100 Subject: [PATCH 247/340] trac 28809 further details in shifting --- .../combinat/partition_shifting_algebras.py | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/sage/combinat/partition_shifting_algebras.py b/src/sage/combinat/partition_shifting_algebras.py index 2e6e59efac5..29b3e20aba5 100644 --- a/src/sage/combinat/partition_shifting_algebras.py +++ b/src/sage/combinat/partition_shifting_algebras.py @@ -59,7 +59,8 @@ def __init__(self): sage: from sage.combinat.partition_shifting_algebras import ShiftingSequenceSpace sage: S = ShiftingSequenceSpace() """ - Parent.__init__(self, facade=(tuple,), category=Sets().Infinite().Facade()) + Parent.__init__(self, facade=(tuple,), + category=Sets().Infinite().Facade()) def __contains__(self, seq): r""" @@ -83,7 +84,7 @@ def __contains__(self, seq): False """ return (isinstance(seq, tuple) and all(i in ZZ for i in seq) - and (not seq or seq[-1] != 0)) + and (not seq or seq[-1])) def check(self, seq): r""" @@ -242,7 +243,8 @@ def __init__(self, base_ring=QQ['t'], prefix='S'): """ indices = ShiftingSequenceSpace() cat = Algebras(base_ring).WithBasis() - CombinatorialFreeModule.__init__(self, base_ring, indices, prefix=prefix, + CombinatorialFreeModule.__init__(self, base_ring, indices, + prefix=prefix, bracket=False, category=cat) # Setup default conversions @@ -260,7 +262,8 @@ def _repr_(self): sage: S = ShiftingOperatorAlgebra() sage: S - Shifting Operator Algebra over Univariate Polynomial Ring in t over Rational Field + Shifting Operator Algebra over Univariate Polynomial Ring in t + over Rational Field """ return "Shifting Operator Algebra over {}".format(self.base_ring()) @@ -427,7 +430,8 @@ def number_of_noninversions(lis): rho = list(range(len(gamma) - 1, -1, -1)) combined = [g + r for g, r in zip(gamma, rho)] - if len(set(combined)) == len(combined) and all(e >= 0 for e in combined): + if len(set(combined)) == len(combined) and all(e >= 0 + for e in combined): sign = (-1) ** number_of_noninversions(combined) sort_combined = sorted(combined, reverse=True) new_gamma = [sc - r for sc, r in zip(sort_combined, rho)] @@ -491,10 +495,7 @@ def build_and_register_conversion(self, support_map, codomain): sage: op(2*m[4,3] + 5*m[2,2] + 7*m[2]) == 2*m[5, 2] + 5*m[3, 1] True """ - - def precompose_map(supp): - return support_map(supp) - module_morphism = self.module_morphism(precompose_map, + module_morphism = self.module_morphism(support_map, codomain=codomain) codomain.register_conversion(module_morphism) @@ -564,7 +565,8 @@ def add_lists(x, y): for i, val in enumerate(y): x[i] += val return x - return [(add_lists(index, operand), coeff) for index, coeff in self] + return [(add_lists(index, operand), coeff) + for index, coeff in self] R = self.base_ring() lift_operand = P._from_dict({P._prepare_seq(p): R(c) From 494e8b9a6770d914a38253cd150000282d6e6897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 29 Nov 2019 21:29:19 +0100 Subject: [PATCH 248/340] almost get rid of filter --- src/sage/combinat/finite_state_machine.py | 19 +++++++------------ src/sage/combinat/tutorial.py | 7 ------- src/sage/combinat/words/morphism.py | 3 +-- .../graphs/generators/classical_geometries.py | 2 +- src/sage/graphs/strongly_regular_db.pyx | 13 +++++++------ src/sage/libs/gap/operations.py | 2 +- src/sage/modular/btquotients/btquotient.py | 14 ++++++++++---- .../modular/btquotients/pautomorphicform.py | 12 ++++++++---- 8 files changed, 35 insertions(+), 37 deletions(-) diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index 45f15cdb5ca..0f932830332 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -5596,9 +5596,7 @@ def iter_initial_states(self): sage: [s.label() for s in F.iter_initial_states()] ['A'] """ - from six.moves import filter - return filter(lambda s:s.is_initial, self.iter_states()) - + return (s for s in self.iter_states() if s.is_initial) def final_states(self): """ @@ -5647,8 +5645,7 @@ def iter_final_states(self): sage: [s.label() for s in F.iter_final_states()] ['A', 'C'] """ - from six.moves import filter - return filter(lambda s:s.is_final, self.iter_states()) + return (s for s in self.iter_states() if s.is_final) def state(self, state): """ @@ -9151,15 +9148,13 @@ def prepone_output(self): Transition from 1 to 0: 0|0, Transition from 1 to 1: 1|1,(0, 0)] """ - from six.moves import filter - def find_common_output(state): - if any(filter( - lambda transition: not transition.word_out, - self.transitions(state))) \ - or state.is_final and not state.final_word_out: + if (any(transition for transition in self.transitions(state) + if not transition.word_out) + or state.is_final and not state.final_word_out): return tuple() - first_letters = [transition.word_out[0] for transition in self.transitions(state)] + first_letters = [transition.word_out[0] + for transition in self.transitions(state)] if state.is_final: first_letters = first_letters + [state.final_word_out[0]] if not first_letters: diff --git a/src/sage/combinat/tutorial.py b/src/sage/combinat/tutorial.py index 486b6882822..05308b2cc58 100644 --- a/src/sage/combinat/tutorial.py +++ b/src/sage/combinat/tutorial.py @@ -1272,13 +1272,6 @@ sage: list(itertools.islice(Permutations(3), int(1), int(4))) [[1, 3, 2], [2, 1, 3], [2, 3, 1]] -The itertools methods ``imap`` and ``ifilter`` have been renamed to -``map`` and ``filter`` in Python 3. You can get them also in Python 2 using:: - - sage: from six.moves import map, filter - -but they should rather be avoided, using list comprehension instead. - To apply a function to all the elements, one can do:: sage: list(z.cycle_type() for z in Permutations(3)) diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index 20f9b8ab110..1ad02abef52 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -93,7 +93,6 @@ import six from six.moves import range import itertools -from six.moves import filterfalse from sage.misc.callable_dict import CallableDict from sage.structure.sage_object import SageObject @@ -2210,7 +2209,7 @@ def has_left_conjugate(self): sage: WordMorphism('a->abbab,b->abb,c->').has_left_conjugate() True """ - I = filterfalse(FiniteWord_class.is_empty, self.images()) + I = (w for w in self.images() if not FiniteWord_class.is_empty(w)) try: letter = next(I)[0] diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index dd6e9ebdf61..031b57282b9 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -1056,7 +1056,7 @@ def T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None, F = field Theta = PG(3, 1, F, point_coordinates=1) - Pi = set(filter(lambda x: x[0]==F.zero(), Theta.ground_set())) + Pi = set(x for x in Theta.ground_set() if x[0] == F.zero()) if hyperoval is None: O = set(x for x in Pi if (x[1] + x[2] * x[3] == 0) or diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 3e3e7d58268..a71ed1b7c07 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -1972,13 +1972,14 @@ def SRG_144_39_6_12(): sage: G.is_strongly_regular(parameters=True) (144, 39, 6, 12) """ - from sage.libs.gap.libgap import libgap - g=libgap.ProjectiveGeneralLinearGroup(3,3) - ns=g.Normalizer(g.SylowSubgroup(13)) - G=g.Action(g.RightCosets(ns),libgap.OnRight) - H=G.Stabilizer(1) - for o in filter(lambda x: len(x)==39, H.Orbits()): + g = libgap.ProjectiveGeneralLinearGroup(3, 3) + ns = g.Normalizer(g.SylowSubgroup(13)) + G = g.Action(g.RightCosets(ns), libgap.OnRight) + H = G.Stabilizer(1) + for o in H.Orbits(): + if len(o) != 39: + continue h = Graph() h.add_edges(G.Orbit([1,o[0]],libgap.OnSets)) if h.is_strongly_regular(): diff --git a/src/sage/libs/gap/operations.py b/src/sage/libs/gap/operations.py index 28c38ee1fea..434d1a01511 100644 --- a/src/sage/libs/gap/operations.py +++ b/src/sage/libs/gap/operations.py @@ -102,7 +102,7 @@ def mfi(o): return any(all(IS_SUBSET_FLAGS(self.flags, fl) for fl in fls) for fls in filts) - return filter(mfi, OPERATIONS) + return (op for op in OPERATIONS if mfi(op)) def op_names(self): """ diff --git a/src/sage/modular/btquotients/btquotient.py b/src/sage/modular/btquotients/btquotient.py index 1eeeb828097..3ff07dc8fed 100644 --- a/src/sage/modular/btquotients/btquotient.py +++ b/src/sage/modular/btquotients/btquotient.py @@ -3086,7 +3086,9 @@ def _find_equivalent_vertex(self, v0, V=None, valuation=None): if valuation is None: valuation = v0.determinant().valuation(self._p) parity = valuation % 2 - for v in filter(lambda v: v.parity == parity, V): + for v in V: + if v.parity != parity: + continue g = self._are_equivalent(v0, v.rep, False, valuation + v.valuation) if g is not None: self._cached_vertices[v0] = (g, v) @@ -3135,7 +3137,9 @@ def _find_equivalent_edge(self, e0, E=None, valuation=None): E = self._edge_list else: E = [e.opposite for e in self._edge_list] - for e in filter(lambda x: x.parity == parity, E): + for e in E: + if e.parity != parity: + continue g = self._are_equivalent(e.rep, e0, True, valuation + e.valuation) if g is not None: self._cached_edges[e0] = (g, e) @@ -3542,8 +3546,10 @@ def _find_elements_in_order(self, norm, trace=None, primitive=False): if norm > 10 ** 3: verbose('Warning: norm (= %s) is quite large, this may take some time!' % norm) V = OQuadForm.vectors_by_length(norm)[norm] - W = V if not primitive else filter(lambda v: any((vi % self._p != 0 for vi in v)), V) - return W if trace is None else filter(lambda v: self._conv(v).reduced_trace() == trace, W) + W = V if not primitive else (v for v in V + if any(vi % self._p for vi in v)) + return W if trace is None else (v for v in W + if self._conv(v).reduced_trace() == trace) def _compute_quotient(self, check=True): r""" diff --git a/src/sage/modular/btquotients/pautomorphicform.py b/src/sage/modular/btquotients/pautomorphicform.py index 9ed31a7ce20..cbaca6a0114 100644 --- a/src/sage/modular/btquotients/pautomorphicform.py +++ b/src/sage/modular/btquotients/pautomorphicform.py @@ -41,7 +41,7 @@ """ from __future__ import print_function, division -from six.moves import zip, filter +from six.moves import zip from sage.modular.btquotients.btquotient import DoubleCosetReduction from sage.structure.unique_representation import UniqueRepresentation @@ -1201,7 +1201,7 @@ def basis_matrix(self): d = self._k - 1 for e in self._E: try: - g = next(filter(lambda g: g[2], S[e.label])) + g = next((g for g in S[e.label] if g[2])) C = self._U.acting_matrix(self._Sigma0(self.embed_quaternion(g[0])), d).transpose() # Warning - Need to allow the check = True C -= self._U.acting_matrix(self._Sigma0(Matrix(QQ, 2, 2, p ** g[1])), d).transpose() # Warning - Need to allow the check = True stab_conds.append([e.label, C]) @@ -1212,12 +1212,16 @@ def basis_matrix(self): self._M = Matrix(self._R, (nV + n_stab_conds) * d, nE * d, 0, sparse=True) for v in self._V: - for e in filter(lambda e: e.parity == 0, v.leaving_edges): + for e in v.leaving_edges: + if e.parity: + continue C = sum([self._U.acting_matrix(self.embed_quaternion(x[0]), d) for x in e.links], Matrix(self._R, d, d, 0)).transpose() self._M.set_block(v.label * d, e.label * d, C) - for e in filter(lambda e: e.parity == 0, v.entering_edges): + for e in v.entering_edges: + if e.parity: + continue C = sum([self._U.acting_matrix(self.embed_quaternion(x[0]), d) for x in e.opposite.links], Matrix(self._R, d, d, 0)).transpose() From 0270887508b8ef461791a195829daac7b1ed3d5c Mon Sep 17 00:00:00 2001 From: Brent Baccala Date: Fri, 29 Nov 2019 19:11:31 -0500 Subject: [PATCH 249/340] Trac #28822: use assert on a condition that should always be true --- src/sage/rings/function_field/order.py | 47 +++++++++++++------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/src/sage/rings/function_field/order.py b/src/sage/rings/function_field/order.py index 77138ab74b5..3b623ff2938 100644 --- a/src/sage/rings/function_field/order.py +++ b/src/sage/rings/function_field/order.py @@ -1182,7 +1182,7 @@ def mul_vecs(f,g): self._mul_vecs = mul_vecs # We prepare for using Kummer's theorem to decompose primes. Note - # that Kummer's theorem applies to the most of places. Here we find + # that Kummer's theorem applies to most places. Here we find # places for which the theorem does not apply. # this element is integral over k[x] and a generator of the field. @@ -1191,28 +1191,29 @@ def mul_vecs(f,g): if phi.degree() == n: break - if phi.degree() == n: - gen_vec = self._coordinate_vector(gen) - g = gen_vec.parent().gen(0) # x - gen_vec_pow = [g] - for i in range(n): - g = mul_vecs(g, gen_vec) - gen_vec_pow.append(g) - - # find places where {1,gen,...,gen^(n-1)} is not integral basis - W = V.span_of_basis([to(gen ** i) for i in range(phi.degree())]) - - supp = [] - for g in basis: - for c in W.coordinate_vector(to(g), check=False): - if not c.is_zero(): - supp += [f for f,_ in c.denominator().factor()] - supp = set(supp) - - self._kummer_gen = gen - self._kummer_gen_vec_pow = gen_vec_pow - self._kummer_polynomial = phi - self._kummer_places = supp + assert phi.degree() == n + + gen_vec = self._coordinate_vector(gen) + g = gen_vec.parent().gen(0) # x + gen_vec_pow = [g] + for i in range(n): + g = mul_vecs(g, gen_vec) + gen_vec_pow.append(g) + + # find places where {1,gen,...,gen^(n-1)} is not integral basis + W = V.span_of_basis([to(gen ** i) for i in range(phi.degree())]) + + supp = [] + for g in basis: + for c in W.coordinate_vector(to(g), check=False): + if not c.is_zero(): + supp += [f for f,_ in c.denominator().factor()] + supp = set(supp) + + self._kummer_gen = gen + self._kummer_gen_vec_pow = gen_vec_pow + self._kummer_polynomial = phi + self._kummer_places = supp def _element_constructor_(self, f): """ From fbffb36597e4fef6332ca1136381af3feddbc530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 30 Nov 2019 11:27:27 +0100 Subject: [PATCH 250/340] trac 28489 known bug in gcd for python3 on osX --- src/sage/symbolic/expression.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index acb1b2a25b3..9c36dd6fb70 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -7118,9 +7118,9 @@ cdef class Expression(CommutativeRingElement): sage: gcd(I + I*x, x^2 - 1) x + 1 sage: alg = SR(QQbar(sqrt(2) + I*sqrt(3))) - sage: gcd(alg + alg*x, x^2 - 1) + sage: gcd(alg + alg*x, x^2 - 1) # known bug (trac #28489) x + 1 - sage: gcd(alg - alg*x, x^2 - 1) + sage: gcd(alg - alg*x, x^2 - 1) # known bug (trac #28489) x - 1 sage: sqrt2 = SR(QQbar(sqrt(2))) sage: gcd(sqrt2 + x, x^2 - 2) # known bug From b1d654c0b589f3d26e97ef3520378e2343b5a5c2 Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Sat, 23 Nov 2019 23:26:18 +0100 Subject: [PATCH 251/340] 28823: fix bytes-vs-str in math-readline for mathematica_console This fixes an error when trying to evaluate anything after starting the console using Python 3: sage: mathematica.console(readline=True) --- src/bin/math-readline | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bin/math-readline b/src/bin/math-readline index 5092a489ba6..b663cb80eec 100755 --- a/src/bin/math-readline +++ b/src/bin/math-readline @@ -9,6 +9,7 @@ import sys import signal import subprocess from six.moves import input +from sage.cpython.string import str_to_bytes def child_exited(*args): global child @@ -23,7 +24,7 @@ pipe = child.stdin while True: try: line = input() - pipe.write(line + '\n') + pipe.write(str_to_bytes(line + '\n')) pipe.flush() except KeyboardInterrupt: pipe.close() From 6e263c8a21507c489e0579b81c75849893d94703 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Sat, 30 Nov 2019 14:28:11 +0100 Subject: [PATCH 252/340] Properly separate building the reference manual into bibliography and rest The problem is that the sage docbuilder is building first the references before all other ref manual parts (good), but then once more in parallel with all the rest (bad). The second build races, and we just shouldn't do that --- src/sage_setup/docbuild/__init__.py | 41 ++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/src/sage_setup/docbuild/__init__.py b/src/sage_setup/docbuild/__init__.py index 9616868ee43..128117b960f 100644 --- a/src/sage_setup/docbuild/__init__.py +++ b/src/sage_setup/docbuild/__init__.py @@ -509,21 +509,47 @@ def _output_dir(self, type, lang='en'): sage_makedirs(d) return d + def _refdir(self, lang): + return os.path.join(SAGE_DOC_SRC, lang, self.name) + + def _build_bibliography(self, lang, format, *args, **kwds): + """ + Build the bibliography only + + The bibliography references.aux is referenced by the other + manuals and needs to be built first. + """ + refdir = self._refdir(lang) + references = [ + (doc, lang, format, kwds) + args for doc in self.get_all_documents(refdir) + if doc == 'reference/references' + ] + build_many(build_ref_doc, references) + + def _build_everything_except_bibliography(self, lang, format, *args, **kwds): + """ + Build the entire reference manual except the bibliography + """ + refdir = self._refdir(lang) + non_references = [ + (doc, lang, format, kwds) + args for doc in self.get_all_documents(refdir) + if doc != 'reference/references' + ] + build_many(build_ref_doc, non_references) + def _wrapper(self, format, *args, **kwds): """ Builds reference manuals. For each language, it builds the top-level document and its components. """ for lang in LANGUAGES: - refdir = os.path.join(SAGE_DOC_SRC, lang, self.name) + refdir = self._refdir(lang) if not os.path.exists(refdir): continue - output_dir = self._output_dir(format, lang) - L = [(doc, lang, format, kwds) + args for doc in self.get_all_documents(refdir)] - if format == 'pdf' and lang == 'en': - logger.warning('Building bibliography') - getattr(ReferenceSubBuilder('reference/references', 'en'), 'pdf')(*args, **kwds) - build_many(build_ref_doc, L) + logger.info('Building bibliography') + self._build_bibliography(lang, format, *args, **kwds) + logger.info('Bibliography finished, building dependent manuals') + self._build_everything_except_bibliography(lang, format, *args, **kwds) # The html refman must be build at the end to ensure correct # merging of indexes and inventories. # Sphinx is run here in the current process (not in a @@ -553,6 +579,7 @@ def _wrapper(self, format, *args, **kwds): 'sage.css', 'sageicon.png', 'logo_sagemath.svg', 'logo_sagemath_black.svg', 'searchtools.js', 'sidebar.js', 'underscore.js'] + output_dir = self._output_dir(format, lang) sage_makedirs(os.path.join(output_dir, '_static')) for f in static_files: try: From 304ab1083272fa61098165cdbccc4c4a14371140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 30 Nov 2019 20:55:02 +0100 Subject: [PATCH 253/340] refresh the file combinat/tuple --- src/sage/combinat/tuple.py | 112 ++++++++++++++++++++++--------------- 1 file changed, 68 insertions(+), 44 deletions(-) diff --git a/src/sage/combinat/tuple.py b/src/sage/combinat/tuple.py index 40b3062d596..6b7b640bc5a 100644 --- a/src/sage/combinat/tuple.py +++ b/src/sage/combinat/tuple.py @@ -1,7 +1,7 @@ r""" Tuples """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 Mike Hansen , # # Distributed under the terms of the GNU General Public License (GPL) @@ -13,19 +13,20 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import absolute_import -from .combinat import CombinatorialClass -from sage.interfaces.all import gap +from sage.libs.gap.libgap import libgap from sage.rings.all import ZZ +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation +from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets def Tuples(S, k): """ - Returns the combinatorial class of ordered tuples of S of length - k. + Return the enumerated set of ordered tuples of S of length k. An ordered tuple of length k of set is an ordered selection with repetition and is represented by a list of length k containing @@ -35,24 +36,35 @@ def Tuples(S, k): sage: S = [1,2] sage: Tuples(S,3).list() - [[1, 1, 1], [2, 1, 1], [1, 2, 1], [2, 2, 1], [1, 1, 2], [2, 1, 2], [1, 2, 2], [2, 2, 2]] + [[1, 1, 1], [2, 1, 1], [1, 2, 1], [2, 2, 1], [1, 1, 2], + [2, 1, 2], [1, 2, 2], [2, 2, 2]] sage: mset = ["s","t","e","i","n"] sage: Tuples(mset,2).list() - [['s', 's'], ['t', 's'], ['e', 's'], ['i', 's'], ['n', 's'], ['s', 't'], ['t', 't'], - ['e', 't'], ['i', 't'], ['n', 't'], ['s', 'e'], ['t', 'e'], ['e', 'e'], ['i', 'e'], - ['n', 'e'], ['s', 'i'], ['t', 'i'], ['e', 'i'], ['i', 'i'], ['n', 'i'], ['s', 'n'], - ['t', 'n'], ['e', 'n'], ['i', 'n'], ['n', 'n']] + [['s', 's'], ['t', 's'], ['e', 's'], ['i', 's'], ['n', 's'], + ['s', 't'], ['t', 't'], ['e', 't'], ['i', 't'], ['n', 't'], + ['s', 'e'], ['t', 'e'], ['e', 'e'], ['i', 'e'], ['n', 'e'], + ['s', 'i'], ['t', 'i'], ['e', 'i'], ['i', 'i'], ['n', 'i'], + ['s', 'n'], ['t', 'n'], ['e', 'n'], ['i', 'n'], ['n', 'n']] :: sage: K.
= GF(4, 'a') - sage: mset = [x for x in K if x!=0] + sage: mset = [x for x in K if x != 0] sage: Tuples(mset,2).list() - [[a, a], [a + 1, a], [1, a], [a, a + 1], [a + 1, a + 1], [1, a + 1], [a, 1], [a + 1, 1], [1, 1]] + [[a, a], [a + 1, a], [1, a], [a, a + 1], [a + 1, a + 1], [1, a + 1], + [a, 1], [a + 1, 1], [1, 1]] """ - return Tuples_sk(S,k) + return Tuples_sk(S, k) + + +class Tuples_sk(Parent, UniqueRepresentation): + @staticmethod + def __classcall_private__(cls, S, k): + """ + Normalize input to ensure a unique representation. + """ + return super(Tuples_sk, cls).__classcall__(cls, tuple(S), k) -class Tuples_sk(CombinatorialClass): def __init__(self, S, k): """ TESTS:: @@ -63,16 +75,18 @@ def __init__(self, S, k): """ self.S = S self.k = k - self._index_list = [S.index(_) for _ in S] + self._index_list = [S.index(s) for s in S] + category = FiniteEnumeratedSets() + Parent.__init__(self, category=category) def __repr__(self): """ TESTS:: sage: repr(Tuples([1,2,3],2)) - 'Tuples of [1, 2, 3] of length 2' + 'Tuples of (1, 2, 3) of length 2' """ - return "Tuples of %s of length %s"%(self.S, self.k) + return "Tuples of %s of length %s" % (self.S, self.k) def __iter__(self): """ @@ -80,27 +94,30 @@ def __iter__(self): sage: S = [1,2] sage: Tuples(S,3).list() - [[1, 1, 1], [2, 1, 1], [1, 2, 1], [2, 2, 1], [1, 1, 2], [2, 1, 2], [1, 2, 2], [2, 2, 2]] + [[1, 1, 1], [2, 1, 1], [1, 2, 1], [2, 2, 1], [1, 1, 2], + [2, 1, 2], [1, 2, 2], [2, 2, 2]] sage: mset = ["s","t","e","i","n"] sage: Tuples(mset,2).list() - [['s', 's'], ['t', 's'], ['e', 's'], ['i', 's'], ['n', 's'], ['s', 't'], ['t', 't'], - ['e', 't'], ['i', 't'], ['n', 't'], ['s', 'e'], ['t', 'e'], ['e', 'e'], ['i', 'e'], - ['n', 'e'], ['s', 'i'], ['t', 'i'], ['e', 'i'], ['i', 'i'], ['n', 'i'], ['s', 'n'], - ['t', 'n'], ['e', 'n'], ['i', 'n'], ['n', 'n']] + [['s', 's'], ['t', 's'], ['e', 's'], ['i', 's'], ['n', 's'], + ['s', 't'], ['t', 't'], ['e', 't'], ['i', 't'], + ['n', 't'], ['s', 'e'], ['t', 'e'], ['e', 'e'], ['i', 'e'], + ['n', 'e'], ['s', 'i'], ['t', 'i'], ['e', 'i'], + ['i', 'i'], ['n', 'i'], ['s', 'n'], ['t', 'n'], ['e', 'n'], + ['i', 'n'], ['n', 'n']] """ S = self.S k = self.k import copy - if k<=0: + if k <= 0: yield [] return - if k==1: + if k == 1: for x in S: yield [x] return for s in S: - for x in Tuples_sk(S,k-1): + for x in Tuples_sk(S, k - 1): y = copy.copy(x) y.append(s) yield y @@ -116,15 +133,12 @@ def cardinality(self): sage: Tuples(S,2).cardinality() 25 """ - ans=gap.eval("NrTuples(%s,%s)"%(self._index_list,ZZ(self.k))) - return ZZ(ans) + return ZZ(libgap.NrTuples(self._index_list, ZZ(self.k))) - -def UnorderedTuples(S,k): +def UnorderedTuples(S, k): """ - Returns the combinatorial class of unordered tuples of S of length - k. + Return the enumerated set of unordered tuples of S of length k. An unordered tuple of length k of set is a unordered selection with repetitions of set and is represented by a sorted list of length k @@ -136,12 +150,20 @@ def UnorderedTuples(S,k): sage: UnorderedTuples(S,3).list() [[1, 1, 1], [1, 1, 2], [1, 2, 2], [2, 2, 2]] sage: UnorderedTuples(["a","b","c"],2).list() - [['a', 'a'], ['a', 'b'], ['a', 'c'], ['b', 'b'], ['b', 'c'], ['c', 'c']] + [['a', 'a'], ['a', 'b'], ['a', 'c'], ['b', 'b'], ['b', 'c'], + ['c', 'c']] """ - return UnorderedTuples_sk(S,k) + return UnorderedTuples_sk(S, k) + +class UnorderedTuples_sk(Parent, UniqueRepresentation): + @staticmethod + def __classcall_private__(cls, S, k): + """ + Normalize input to ensure a unique representation. + """ + return super(UnorderedTuples_sk, cls).__classcall__(cls, tuple(S), k) -class UnorderedTuples_sk(CombinatorialClass): def __init__(self, S, k): """ TESTS:: @@ -152,16 +174,18 @@ def __init__(self, S, k): """ self.S = S self.k = k - self._index_list = [S.index(_) for _ in S] + self._index_list = [S.index(s) for s in S] + category = FiniteEnumeratedSets() + Parent.__init__(self, category=category) def __repr__(self): """ TESTS:: sage: repr(UnorderedTuples([1,2,3],2)) - 'Unordered tuples of [1, 2, 3] of length 2' + 'Unordered tuples of (1, 2, 3) of length 2' """ - return "Unordered tuples of %s of length %s"%(self.S, self.k) + return "Unordered tuples of %s of length %s" % (self.S, self.k) def list(self): """ @@ -171,10 +195,11 @@ def list(self): sage: UnorderedTuples(S,3).list() [[1, 1, 1], [1, 1, 2], [1, 2, 2], [2, 2, 2]] sage: UnorderedTuples(["a","b","c"],2).list() - [['a', 'a'], ['a', 'b'], ['a', 'c'], ['b', 'b'], ['b', 'c'], ['c', 'c']] + [['a', 'a'], ['a', 'b'], ['a', 'c'], ['b', 'b'], ['b', 'c'], + ['c', 'c']] """ - ans=gap.eval("UnorderedTuples(%s,%s)"%(self._index_list,ZZ(self.k))) - return [[self.S[i] for i in l] for l in eval(ans)] + ans = libgap.UnorderedTuples(self._index_list, ZZ(self.k)) + return [[self.S[i] for i in l] for l in ans] def cardinality(self): """ @@ -184,5 +209,4 @@ def cardinality(self): sage: UnorderedTuples(S,2).cardinality() 15 """ - ans=gap.eval("NrUnorderedTuples(%s,%s)"%(self._index_list,ZZ(self.k))) - return ZZ(ans) + return ZZ(libgap.NrUnorderedTuples(self._index_list, ZZ(self.k))) From 0a1b6efa453237185abb1ed918ed020a2ce0f94f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 1 Dec 2019 10:06:06 +0100 Subject: [PATCH 254/340] trac 28825 merge class and function for tuples and unordered tuples --- src/sage/combinat/tuple.py | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/sage/combinat/tuple.py b/src/sage/combinat/tuple.py index 6b7b640bc5a..fb7bef7b1bd 100644 --- a/src/sage/combinat/tuple.py +++ b/src/sage/combinat/tuple.py @@ -24,7 +24,7 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -def Tuples(S, k): +class Tuples(Parent, UniqueRepresentation): """ Return the enumerated set of ordered tuples of S of length k. @@ -54,16 +54,17 @@ def Tuples(S, k): [[a, a], [a + 1, a], [1, a], [a, a + 1], [a + 1, a + 1], [1, a + 1], [a, 1], [a + 1, 1], [1, 1]] """ - return Tuples_sk(S, k) - - -class Tuples_sk(Parent, UniqueRepresentation): @staticmethod def __classcall_private__(cls, S, k): """ Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: T = Tuples(['l','i','t'],2); T + Tuples of ('l', 'i', 't') of length 2 """ - return super(Tuples_sk, cls).__classcall__(cls, tuple(S), k) + return super(Tuples, cls).__classcall__(cls, tuple(S), k) def __init__(self, S, k): """ @@ -117,7 +118,7 @@ def __iter__(self): return for s in S: - for x in Tuples_sk(S, k - 1): + for x in Tuples(S, k - 1): y = copy.copy(x) y.append(s) yield y @@ -136,7 +137,10 @@ def cardinality(self): return ZZ(libgap.NrTuples(self._index_list, ZZ(self.k))) -def UnorderedTuples(S, k): +Tuples_sk = Tuples + + +class UnorderedTuples(Parent, UniqueRepresentation): """ Return the enumerated set of unordered tuples of S of length k. @@ -153,16 +157,17 @@ def UnorderedTuples(S, k): [['a', 'a'], ['a', 'b'], ['a', 'c'], ['b', 'b'], ['b', 'c'], ['c', 'c']] """ - return UnorderedTuples_sk(S, k) - - -class UnorderedTuples_sk(Parent, UniqueRepresentation): @staticmethod def __classcall_private__(cls, S, k): """ Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: T = UnorderedTuples(['l','i','t'],2); T + Unordered tuples of ('l', 'i', 't') of length 2 """ - return super(UnorderedTuples_sk, cls).__classcall__(cls, tuple(S), k) + return super(UnorderedTuples, cls).__classcall__(cls, tuple(S), k) def __init__(self, S, k): """ @@ -210,3 +215,6 @@ def cardinality(self): 15 """ return ZZ(libgap.NrUnorderedTuples(self._index_list, ZZ(self.k))) + + +UnorderedTuples_sk = UnorderedTuples From b5fb7ad64025a9bc60cfcfc7073f0dca8e2ab49d Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Sun, 4 Aug 2019 15:09:11 +0200 Subject: [PATCH 255/340] 28826: fix some typos --- src/sage/categories/fields.py | 2 +- src/sage/categories/modules_with_basis.py | 2 +- src/sage/homology/chain_complex.py | 2 +- src/sage/matrix/matrix0.pyx | 8 ++++---- src/sage/misc/parser.pyx | 3 ++- src/sage/sets/finite_enumerated_set.py | 4 ++-- src/sage/structure/coerce.pyx | 2 +- src/sage/structure/global_options.py | 12 ++++++------ 8 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/sage/categories/fields.py b/src/sage/categories/fields.py index b422335d8e7..af9f1b29122 100644 --- a/src/sage/categories/fields.py +++ b/src/sage/categories/fields.py @@ -625,7 +625,7 @@ def gcd(self,other): sage: gcd(15.0,12.0) 3.00000000000000 - But for others floating point numbers, the gcd is just `0.0` or `1.0`:: + But for other floating point numbers, the gcd is just `0.0` or `1.0`:: sage: gcd(3.2, 2.18) 1.00000000000000 diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index c3e55394f5c..14790bf4b54 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -265,7 +265,7 @@ def module_morphism(self, on_basis=None, matrix=None, function=None, Only meaningful with ``on_basis``. - ``position`` -- a non-negative integer specifying which - positional argument in used as the input of the function `f` + positional argument is used as the input of the function `f` (default: 0); this is currently only used with ``on_basis``. - ``triangular`` -- (default: ``None``) ``"upper"`` or diff --git a/src/sage/homology/chain_complex.py b/src/sage/homology/chain_complex.py index 3d0591ac28f..2abee48bdf4 100644 --- a/src/sage/homology/chain_complex.py +++ b/src/sage/homology/chain_complex.py @@ -1420,7 +1420,7 @@ def _homology_generators_snf(self, d_in, d_out, d_out_rank): def betti(self, deg=None, base_ring=None): """ - The Betti number the chain complex. + The Betti number of the chain complex. That is, write the homology in this degree as a direct sum of a free module and a torsion module; the Betti number is the diff --git a/src/sage/matrix/matrix0.pyx b/src/sage/matrix/matrix0.pyx index e062ac7e639..80c43b01388 100644 --- a/src/sage/matrix/matrix0.pyx +++ b/src/sage/matrix/matrix0.pyx @@ -5267,7 +5267,7 @@ cdef class Matrix(sage.structure.element.Matrix): def __invert__(self): r""" - Return this inverse of this matrix, as a matrix over the fraction + Return the inverse of this matrix, as a matrix over the fraction field. Raises a ``ZeroDivisionError`` if the matrix has zero @@ -5335,7 +5335,7 @@ cdef class Matrix(sage.structure.element.Matrix): [1267650600228229401496703205375 422550200076076467165567735126] Matrices over p-adics. See :trac:`17272` :: - + sage: R = ZpCA(5,5,print_mode='val-unit') sage: A = matrix(R,3,3,[250,2369,1147,106,927,362,90,398,2483]) sage: A @@ -5346,8 +5346,8 @@ cdef class Matrix(sage.structure.element.Matrix): [5 * 212 + O(5^5) 3031 + O(5^5) 2201 + O(5^5)] [ 1348 + O(5^5) 5 * 306 + O(5^5) 2648 + O(5^5)] [ 1987 + O(5^5) 5 * 263 + O(5^5) 154 + O(5^5)] - - This matrix isn't invertible:: + + This matrix is not invertible:: sage: m = matrix(Zmod(9),2,[2,1,3,3]) sage: ~m diff --git a/src/sage/misc/parser.pyx b/src/sage/misc/parser.pyx index f6da5f1ce29..dc97c2c7302 100644 --- a/src/sage/misc/parser.pyx +++ b/src/sage/misc/parser.pyx @@ -228,7 +228,8 @@ cdef class Tokenizer: cdef int find(self) except -1: """ - This function actually does all the work, and extensively is tested above. + This function actually does all the work, and is extensively tested + above. """ cdef bint seen_exp, seen_decimal cdef int type diff --git a/src/sage/sets/finite_enumerated_set.py b/src/sage/sets/finite_enumerated_set.py index 972db181fc5..c55c13d00bc 100644 --- a/src/sage/sets/finite_enumerated_set.py +++ b/src/sage/sets/finite_enumerated_set.py @@ -55,7 +55,7 @@ class FiniteEnumeratedSet(UniqueRepresentation, Parent): Category of facade finite enumerated sets sage: TestSuite(S).run() - Note that being and enumerated set, the result depends on the order:: + Note that being an enumerated set, the result depends on the order:: sage: S1 = FiniteEnumeratedSet((1, 2, 3)) sage: S1 @@ -75,7 +75,7 @@ class FiniteEnumeratedSet(UniqueRepresentation, Parent): sage: S1 {1, 2, 1, 2, 2, 3} - Finaly the elements are not aware of their parent:: + Finally, the elements are not aware of their parent:: sage: S.first().parent() Integer Ring diff --git a/src/sage/structure/coerce.pyx b/src/sage/structure/coerce.pyx index bff28c93625..f8915c8545b 100644 --- a/src/sage/structure/coerce.pyx +++ b/src/sage/structure/coerce.pyx @@ -892,7 +892,7 @@ cdef class CoercionModel: .. NOTE:: - This function is accurate only in so far as analyse is kept + This function is accurate only in so far as :meth:`analyse` is kept in sync with the :meth:`bin_op` and :meth:`canonical_coercion` which are kept separate for maximal efficiency. diff --git a/src/sage/structure/global_options.py b/src/sage/structure/global_options.py index dcfc14b413d..3c9c27d1f20 100644 --- a/src/sage/structure/global_options.py +++ b/src/sage/structure/global_options.py @@ -570,7 +570,7 @@ def __repr__(self): def __add__(self, other): r""" Return the object obtained by adding ``self`` and ``other``, where - ``self`` behaves likes it's value. + ``self`` behaves like its value. EXAMPLES:: @@ -582,7 +582,7 @@ def __add__(self, other): def __radd__(self, other): r""" Return the object obtained by adding ``other`` and ``self``, where - ``self`` behaves likes it's value. + ``self`` behaves like its value. EXAMPLES:: @@ -594,7 +594,7 @@ def __radd__(self, other): def __mul__(self, other): r""" Return the object obtained by adding ``self`` and ``other``, where - ``self`` behaves likes it's value. + ``self`` behaves like its value. EXAMPLES:: @@ -606,7 +606,7 @@ def __mul__(self, other): def __rmul__(self, other): r""" Return the object obtained by r-adding ``other`` and ``self``, where - ``self`` behaves likes it's value. + ``self`` behaves like its value. EXAMPLES:: @@ -617,7 +617,7 @@ def __rmul__(self, other): def __bool__(self): r""" - Return the value of ye option interpreted as a boolean. + Return the value of this option interpreted as a boolean. EXAMPLES:: @@ -1277,7 +1277,7 @@ def __setstate__(self, state): sage: Partitions.options._reset() """ # open the options for the corresponding "parent" and copy all of - # the data from its' options class into unpickle + # the data from its options class into unpickle options_class = getattr(import_module(state['options_module']), state['option_class']) unpickle = options_class.options state.pop('option_class') From e1db2f9bdefc78821e085d54aa53338bdfc78e85 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Sun, 1 Dec 2019 19:55:06 +0100 Subject: [PATCH 256/340] Minor fixes in the documentation of symbolic functions (trac 24398) --- src/doc/en/reference/functions/index.rst | 3 +- src/sage/symbolic/function.pyx | 69 ++++++++++++++++-------- 2 files changed, 50 insertions(+), 22 deletions(-) diff --git a/src/doc/en/reference/functions/index.rst b/src/doc/en/reference/functions/index.rst index 40e45791dfa..50485a126ef 100644 --- a/src/doc/en/reference/functions/index.rst +++ b/src/doc/en/reference/functions/index.rst @@ -28,6 +28,7 @@ Built-in Functions sage/functions/min_max Please find extensive developer documentation for creating new functions -in the symbolic calculus module. +in the :doc:`Symbolic Calculus module`, in particular in +:doc:`sage/symbolic/function`. .. include:: ../footer.txt diff --git a/src/sage/symbolic/function.pyx b/src/sage/symbolic/function.pyx index 7d523c8733b..d36a0770608 100644 --- a/src/sage/symbolic/function.pyx +++ b/src/sage/symbolic/function.pyx @@ -4,36 +4,64 @@ Classes for symbolic functions To enable their usage as part of symbolic expressions, symbolic function classes are derived from one of the subclasses of :class:`Function`: - * :class:`BuiltinFunction`: the code of these functions is written in Python; many special functions are of this type, see :doc - * :class:`GinacFunction`: the code of these functions is written in C++ and part of the Pynac support library; most elementary functions are of this type - * :class:`SymbolicFunction`: symbolic functions defined on the Sage command line are of this type + * :class:`BuiltinFunction`: the code of these functions is written in Python; + many special functions are of this type, see this :doc:`list ` + * :class:`GinacFunction`: the code of these functions is written in C++ and + part of the Pynac support library; most elementary functions are of this type + * :class:`SymbolicFunction`: symbolic functions defined on the Sage command + line are of this type -Sage uses ``BuiltinFunction`` and ``GinacFunction`` for its symbolic builtin functions. Users can define any other additional ``SymbolicFunction`` through the ``function()`` factory, see :doc:`function_factory` +Sage uses ``BuiltinFunction`` and ``GinacFunction`` for its symbolic builtin +functions. Users can define any other additional ``SymbolicFunction`` through +the ``function()`` factory, see :doc:`function_factory` -Several parameters are supported by the superclass' ``__init__()`` method. Examples follow below. +Several parameters are supported by the superclass' ``__init__()`` method. +Examples follow below. * ``nargs``: the number of arguments - * ``name``: the string that is printed on the CLI; the name of the member functions that are attempted for evaluation of Sage element arguments; also the name of the Pynac function that is associated with a ``GinacFunction`` - * ``alt_name``: the second name of the member functions that are attempted for evaluation of Sage element arguments + * ``name``: the string that is printed on the CLI; the name of the member + functions that are attempted for evaluation of Sage element arguments; also + the name of the Pynac function that is associated with a ``GinacFunction`` + * ``alt_name``: the second name of the member functions that are attempted for + evaluation of Sage element arguments * ``latex_name``: what is printed when ``latex(f(...))`` is called * ``conversions``: a dict containing the function's name in other CAS - * ``evalf_params_first``: if ``False``, when floating-point evaluating the expression do not evaluate function arguments before calling the ``_evalf_()`` member of the function - * ``preserved_arg``: if nonzero, the index (starting with ``1``) of the function argument that determines the return type. Note that, e.g, ``atan2()`` uses both arguments to determine return type, through a different mechanism + * ``evalf_params_first``: if ``False``, when floating-point evaluating the + expression do not evaluate function arguments before calling the + ``_evalf_()`` member of the function + * ``preserved_arg``: if nonzero, the index (starting with ``1``) of the + function argument that determines the return type. Note that, e.g, + ``atan2()`` uses both arguments to determine return type, through a + different mechanism Function classes can define the following Python member functions: - * ``_eval_(*args)``: the only mandatory member function, evaluating the argument and returning the result; if ``None`` is returned the expression stays unevaluated - * ``_eval_numpy_(*args)``: evaluation of ``f(args)`` with arguments of numpy type - * ``_evalf_(*args, **kwds)``: called when the expression is floating-point evaluated; may receive a ``parent`` keyword specifying the expected parent of the result. If not defined an attempt is made to convert the result of ``_eval_()``. - * ``_conjugate_(*args)``, ``_real_part_(*args)``, ``_imag_part_(*args)``: return conjugate, real part, imaginary part of the expression ``f(args)`` - * ``_derivative_(*args, index)``: return derivative with respect to the parameter indexed by ``index`` (starting with 0) of ``f(args)`` - * ``_tderivative_()``: same as ``_derivative_()`` but don't apply chain rule; only one of the two functions may be defined - * ``_power_(*args, expo)``: return f(args)^expo - * ``_series_(*args, **kwds)``: return the power series at ``at`` up to ``order`` with respect to ``var`` of ``f(args)``; these three values are received in ``kwds``. If not defined the series is attempted to be computed by differentiation. + * ``_eval_(*args)``: the only mandatory member function, evaluating the + argument and returning the result; if ``None`` is returned the expression + stays unevaluated + * ``_eval_numpy_(*args)``: evaluation of ``f(args)`` with arguments of numpy + type + * ``_evalf_(*args, **kwds)``: called when the expression is floating-point + evaluated; may receive a ``parent`` keyword specifying the expected parent + of the result. If not defined an attempt is made to convert the result of + ``_eval_()``. + * ``_conjugate_(*args)``, ``_real_part_(*args)``, ``_imag_part_(*args)``: + return conjugate, real part, imaginary part of the expression ``f(args)`` + * ``_derivative_(*args, index)``: return derivative with respect to the + parameter indexed by ``index`` (starting with 0) of ``f(args)`` + * ``_tderivative_()``: same as ``_derivative_()`` but don't apply chain rule; + only one of the two functions may be defined + * ``_power_(*args, expo)``: return ``f(args)^expo`` + * ``_series_(*args, **kwds)``: return the power series at ``at`` up to + ``order`` with respect to ``var`` of ``f(args)``; these three values are + received in ``kwds``. If not defined the series is attempted to be computed + by differentiation. * ``print(*args)``: return what should be printed on the CLI with ``f(args)`` * ``print_latex(*args)``: return what should be output with ``latex(f(args))`` -The following examples are intended for Sage developers. Users can define functions interactively through the ``function()`` factory, see :doc:`function_factory` +The following examples are intended for Sage developers. Users can define +functions interactively through the ``function()`` factory, see +:doc:`function_factory`. EXAMPLES: @@ -1572,9 +1600,8 @@ PrimitiveFunction = DeprecatedSFunction def get_sfunction_from_serial(serial): """ - Returns an already created SFunction given the serial. These are - stored in the dictionary - `sage.symbolic.function.sfunction_serial_dict`. + Return an already created SFunction given the serial. These are stored in + the dictionary ``sage.symbolic.function.sfunction_serial_dict``. EXAMPLES:: From cf9673bc59b43f791747b8ff31c5f072eeab88eb Mon Sep 17 00:00:00 2001 From: Release Manager Date: Mon, 2 Dec 2019 00:04:04 +0100 Subject: [PATCH 257/340] Updated SageMath version to 9.0.beta8 --- VERSION.txt | 2 +- build/pkgs/configure/checksums.ini | 6 +++--- build/pkgs/configure/package-version.txt | 2 +- src/bin/sage-version.sh | 6 +++--- src/sage/version.py | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index ab3a5777d77..9d9a6dbdb67 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 9.0.beta7, Release Date: 2019-11-26 +SageMath version 9.0.beta8, Release Date: 2019-12-01 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index d63d3fc32dd..0ede27c8a05 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=ab91b79f255de3311461ed21e05d7a8eacd7495a -md5=8919ee3aea8aa02f9a3c15365102b59c -cksum=3707653135 +sha1=a2caaf716e5fc337d3e6cbe183b4053044a787e7 +md5=53beeb0688c649dceb5c25581b8db20b +cksum=1086485538 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 9bd54bb21ec..12817cdd87e 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -22426a509ba10c4bd870bc2497624d362478d466 +7b3f429848d4d67dfb826d57838416907bd3100d diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index e4a6863d454..8ac3783e8c5 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -1,5 +1,5 @@ # Sage version information for shell scripts # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='9.0.beta7' -SAGE_RELEASE_DATE='2019-11-26' -SAGE_VERSION_BANNER='SageMath version 9.0.beta7, Release Date: 2019-11-26' +SAGE_VERSION='9.0.beta8' +SAGE_RELEASE_DATE='2019-12-01' +SAGE_VERSION_BANNER='SageMath version 9.0.beta8, Release Date: 2019-12-01' diff --git a/src/sage/version.py b/src/sage/version.py index 66cb3a91cbc..e78f9f37b84 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 = '9.0.beta7' -date = '2019-11-26' -banner = 'SageMath version 9.0.beta7, Release Date: 2019-11-26' +version = '9.0.beta8' +date = '2019-12-01' +banner = 'SageMath version 9.0.beta8, Release Date: 2019-12-01' From fc4c5961c379e547336288077b6bf1f46bb255c6 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Mon, 2 Dec 2019 09:07:01 +0100 Subject: [PATCH 258/340] alignment fix in docs --- src/sage/geometry/polyhedron/backend_normaliz.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index ee3e3e5aebc..a9c2a6fd7ca 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -491,8 +491,8 @@ def _init_from_Vrepresentation(self, vertices, rays, lines, minimize=True, verbo INPUT: - ``vertices`` -- list of point; each point can be specified - as any iterable container of - :meth:`~sage.geometry.polyhedron.base.base_ring` elements + as any iterable container of + :meth:`~sage.geometry.polyhedron.base.base_ring` elements - ``rays`` -- list of rays; each ray can be specified as any iterable container of @@ -651,8 +651,8 @@ def _cone_from_Vrepresentation_and_Hrepresentation(self, vertices, rays, ieqs, e INPUT: - ``vertices`` -- list of point; each point can be specified - as any iterable container of - :meth:`~sage.geometry.polyhedron.base.base_ring` elements + as any iterable container of + :meth:`~sage.geometry.polyhedron.base.base_ring` elements - ``rays`` -- list of rays; each ray can be specified as any iterable container of From 469d0e2c8fb37eddf2e64628dfd8d1120dab89a0 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Mon, 2 Dec 2019 14:12:47 +0100 Subject: [PATCH 259/340] Fix hyperlinks in the documentation of symbolic functions (trac 24398) --- src/doc/en/reference/calculus/index.rst | 2 ++ src/doc/en/reference/functions/index.rst | 7 +++++-- src/sage/symbolic/function.pyx | 4 +++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/doc/en/reference/calculus/index.rst b/src/doc/en/reference/calculus/index.rst index d835cc46a14..c49c4bd8dd4 100644 --- a/src/doc/en/reference/calculus/index.rst +++ b/src/doc/en/reference/calculus/index.rst @@ -1,3 +1,5 @@ +.. _symbolic-calculus: + Symbolic Calculus ================= diff --git a/src/doc/en/reference/functions/index.rst b/src/doc/en/reference/functions/index.rst index 50485a126ef..54769b6a95e 100644 --- a/src/doc/en/reference/functions/index.rst +++ b/src/doc/en/reference/functions/index.rst @@ -1,3 +1,6 @@ +.. _special-functions: + + Functions ========= @@ -28,7 +31,7 @@ Built-in Functions sage/functions/min_max Please find extensive developer documentation for creating new functions -in the :doc:`Symbolic Calculus module`, in particular in -:doc:`sage/symbolic/function`. +in :ref:`symbolic-calculus`, in particular in the section +:ref:`Classes for symbolic functions `. .. include:: ../footer.txt diff --git a/src/sage/symbolic/function.pyx b/src/sage/symbolic/function.pyx index d36a0770608..4ab624244f8 100644 --- a/src/sage/symbolic/function.pyx +++ b/src/sage/symbolic/function.pyx @@ -1,11 +1,13 @@ r""" Classes for symbolic functions +.. _symbolic-function-classes: + To enable their usage as part of symbolic expressions, symbolic function classes are derived from one of the subclasses of :class:`Function`: * :class:`BuiltinFunction`: the code of these functions is written in Python; - many special functions are of this type, see this :doc:`list ` + many :ref:`special functions` are of this type * :class:`GinacFunction`: the code of these functions is written in C++ and part of the Pynac support library; most elementary functions are of this type * :class:`SymbolicFunction`: symbolic functions defined on the Sage command From cf9a7fad41715025d4bbfa66538e618979391c90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 2 Dec 2019 14:13:44 +0100 Subject: [PATCH 260/340] cleaning up the file dlx.py --- src/sage/combinat/dlx.py | 115 ++++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 57 deletions(-) diff --git a/src/sage/combinat/dlx.py b/src/sage/combinat/dlx.py index 2e29040d7b5..40d1f9b0330 100644 --- a/src/sage/combinat/dlx.py +++ b/src/sage/combinat/dlx.py @@ -10,9 +10,9 @@ # * Recursive search is now iterative # * Removed callback functionality # * Revamped the class to be a pythonic generator; new usage: -# for cover in DLXMatrix(ones,initialsolution): +# for cover in DLXMatrix(ones, initialsolution): # blah(cover) -# * DOCUMENTATION AND TESTS GALORE HOLYCRAP 100% COVERAGE!!!!!1!!111@%^%*QQ!@E~ +# * DOCUMENTATION AND TESTS GALORE HOLYCRAP 100% COVERAGE! # DLXMatrix class is used to store and solve an exact cover problem # with help of Dancing Links [1] technique by Donald Knuth. The @@ -32,8 +32,6 @@ # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. - - ROOTNODE = 0 # Node's attributes @@ -41,19 +39,19 @@ # INDEX is the (row) index of the node (None in the header nodes) # COLUMN/COUNT is column index on a regular node and count of nodes on # a header node -LEFT = 0 -RIGHT = 1 -UP = 2 -DOWN = 3 +LEFT = 0 +RIGHT = 1 +UP = 2 +DOWN = 3 COLUMN = 4 -INDEX = 5 -COUNT = 5 +INDEX = 5 +COUNT = 5 class DLXMatrix: def __init__(self, ones, initialsolution=None): """ - Solves the Exact Cover problem by using the Dancing Links algorithm + Solve the Exact Cover problem by using the Dancing Links algorithm described by Knuth. Consider a matrix M with entries of 0 and 1, and compute a subset @@ -104,19 +102,20 @@ def __init__(self, ones, initialsolution=None): [4, 1] [4, 2, 3] - .. note:: + .. NOTE:: - The 0 entry is reserved internally for headers in the - sparse representation, so rows and columns begin their - indexing with 1. Apologies for any heartache this - causes. Blame the original author, or fix it yourself. + The 0 entry is reserved internally for headers in the + sparse representation, so rows and columns begin their + indexing with 1. Apologies for any heartache this + causes. Blame the original author, or fix it yourself. """ - if initialsolution is None: initialsolution = [] + if initialsolution is None: + initialsolution = [] self._cursolution = [] self._nodes = [[0, 0, None, None, None, None]] self._constructmatrix(ones, initialsolution) self._level = 0 - self._stack = [(None,None)] + self._stack = [(None, None)] def __eq__(self, other): r""" @@ -143,7 +142,7 @@ def __eq__(self, other): def __iter__(self): """ - Returns self. + Return ``self``. TESTS:: @@ -157,8 +156,8 @@ def __iter__(self): def _walknodes(self, firstnode, direction): """ - Generator for iterating over all nodes in given direction (not - including firstnode). + Generator for iterating over all nodes in given ``direction`` (not + including ``firstnode``). TESTS:: @@ -176,7 +175,7 @@ def _walknodes(self, firstnode, direction): sage: count 0 """ - nodetable=self._nodes + nodetable = self._nodes n = nodetable[firstnode][direction] while n != firstnode: yield n @@ -184,16 +183,19 @@ def _walknodes(self, firstnode, direction): def _constructmatrix(self, ones, initialsolution=None): """ - Construct the (sparse) DLX matrix based on list 'ones'. The first - component in the list elements is row index (which will be returned - by solve) and the second component is list of column indexes of - ones in given row. + Construct the (sparse) DLX matrix based on list ``'ones'``. + + The first component in the list elements is row index (which + will be returned by solve) and the second component is list of + column indexes of ones in given row. 'initialsolution' is list of row indexes that are required to be part of the solution. They will be removed from the matrix. - Note: rows and cols are 1-indexed - the zero index is reserved for - the root node and column heads. + .. NOTE: + + Rows and cols are 1-indexed ; the zero index is reserved for + the root node and column heads. TESTS:: @@ -231,11 +233,12 @@ def _constructmatrix(self, ones, initialsolution=None): nodetable = self._nodes ones.sort() pruneNodes = [] - headers = [ROOTNODE] # indexes of header nodes for faster access + headers = [ROOTNODE] # indexes of header nodes for faster access for r in ones: curRow = r[0] # row index - columns = r[1] # column indexes - if len(columns) == 0: continue + columns = r[1] # column indexes + if not(columns): + continue columns.sort() # Do we need more headers? @@ -254,17 +257,16 @@ def _constructmatrix(self, ones, initialsolution=None): newind = len(nodetable) for i, c in enumerate(columns): h = headers[c] - l = newind + ((i-1) % len(columns)) - r = newind + ((i+1) % len(columns)) + l = newind + ((i - 1) % len(columns)) + r = newind + ((i + 1) % len(columns)) nodetable.append([l, r, nodetable[h][UP], h, h, curRow]) - nodetable[nodetable[h][UP]][DOWN] = newind+i - nodetable[h][UP] = newind+i + nodetable[nodetable[h][UP]][DOWN] = newind + i + nodetable[h][UP] = newind + i nodetable[h][COUNT] += 1 if curRow in initialsolution: pruneNodes.append(newind) - # Remove columns that are required to be in the solution for n in pruneNodes: self._cursolution += [nodetable[n][INDEX]] @@ -274,7 +276,7 @@ def _constructmatrix(self, ones, initialsolution=None): def _covercolumn(self, c): """ - Performs the column covering operation, as described by Knuth's + Perform the column covering operation, as described by Knuth's pseudocode:: cover(c): @@ -305,7 +307,6 @@ def _covercolumn(self, c): sage: M._nodes[three][COUNT] 0 """ - nodetable = self._nodes nodetable[nodetable[c][RIGHT]][LEFT] = nodetable[c][LEFT] nodetable[nodetable[c][LEFT]][RIGHT] = nodetable[c][RIGHT] @@ -317,7 +318,7 @@ def _covercolumn(self, c): def _uncovercolumn(self, c): """ - Performs the column uncovering operation, as described by Knuth's + Perform the column uncovering operation, as described by Knuth's pseudocode:: uncover(c): @@ -421,10 +422,10 @@ def __next__(self): [1, 2] [1, 3, 4] """ - nodetable = self._nodes # optimization: local variables are faster + nodetable = self._nodes # optimization: local variables are faster while self._level >= 0: - c,r = self._stack[self._level] + c, r = self._stack[self._level] if c is None: if nodetable[ROOTNODE][RIGHT] == ROOTNODE: self._level -= 1 @@ -437,7 +438,7 @@ def __next__(self): c = j maxcount = nodetable[j][COUNT] self._covercolumn(c) - self._stack[self._level] = (c,c) + self._stack[self._level] = (c, c) elif nodetable[r][DOWN] != c: if c != r: self._cursolution = self._cursolution[:-1] @@ -447,12 +448,12 @@ def __next__(self): self._cursolution += [nodetable[r][INDEX]] for j in self._walknodes(r, RIGHT): self._covercolumn(nodetable[j][COLUMN]) - self._stack[self._level] = (c,r) + self._stack[self._level] = (c, r) self._level += 1 if len(self._stack) == self._level: - self._stack.append((None,None)) + self._stack.append((None, None)) else: - self._stack[self._level] = (None,None) + self._stack[self._level] = (None, None) else: if c != r: self._cursolution = self._cursolution[:-1] @@ -468,7 +469,7 @@ def __next__(self): def AllExactCovers(M): """ - Utilizes A. Ajanki's DLXMatrix class to solve the exact cover + Use A. Ajanki's DLXMatrix class to solve the exact cover problem on the matrix M (treated as a dense binary matrix). EXAMPLES:: @@ -483,31 +484,31 @@ def AllExactCovers(M): [(1, 0, 1), (0, 1, 0)] """ ones = [] - r = 1 #damn 1-indexing + r = 1 # damn 1-indexing for R in M.rows(): row = [] for i in range(len(R)): if R[i]: - row.append(i+1) #damn 1-indexing - ones.append([r,row]) - r+=1 + row.append(i + 1) # damn 1-indexing + ones.append([r, row]) + r += 1 for s in DLXMatrix(ones): - yield [M.row(i-1) for i in s] #damn 1-indexing + yield [M.row(i - 1) for i in s] # damn 1-indexing + def OneExactCover(M): """ - Utilizes A. Ajanki's DLXMatrix class to solve the exact cover + Use A. Ajanki's DLXMatrix class to solve the exact cover problem on the matrix M (treated as a dense binary matrix). EXAMPLES:: - sage: M = Matrix([[1,1,0],[1,0,1],[0,1,1]]) #no exact covers - sage: print(OneExactCover(M)) - None - sage: M = Matrix([[1,1,0],[1,0,1],[0,0,1],[0,1,0]]) #two exact covers + sage: M = Matrix([[1,1,0],[1,0,1],[0,1,1]]) # no exact covers + sage: OneExactCover(M) + + sage: M = Matrix([[1,1,0],[1,0,1],[0,0,1],[0,1,0]]) # two exact covers sage: OneExactCover(M) [(1, 1, 0), (0, 0, 1)] """ - for s in AllExactCovers(M): return s From 19212a8db7f8deec0a864145b802b3aa85099d0c Mon Sep 17 00:00:00 2001 From: "Erik M. Bray" Date: Mon, 2 Dec 2019 14:41:23 +0000 Subject: [PATCH 261/340] Trac #28832: Support staged installation of suitesparse using DESTDIR. --- .../suitesparse/patches/03-buildflags.patch | 44 +++++++++++++++++++ build/pkgs/suitesparse/spkg-install | 8 +++- 2 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 build/pkgs/suitesparse/patches/03-buildflags.patch diff --git a/build/pkgs/suitesparse/patches/03-buildflags.patch b/build/pkgs/suitesparse/patches/03-buildflags.patch new file mode 100644 index 00000000000..aabd1dbc96d --- /dev/null +++ b/build/pkgs/suitesparse/patches/03-buildflags.patch @@ -0,0 +1,44 @@ +Inspired by, but not identical to the following patch from debian: +https://sources.debian.org/patches/suitesparse/1:5.6.0+dfsg-2/buildflags.patch/ + +This prepends $(DESTDIR) directly to all of $(INSTALL_LIB), $(INSTALL_INCLUDE), +and $(INSTALL_DOC), as these variables only affect where built files are copied +to, and do not affect the contents of the files. + +However, we also remove additional LDFLAGS added by this Makefile (for + -L$SAGE_LOCAL and -Wl,-rpath=$SAGE_LOCAL/lib) since we already add those +in the standard SPKG built environment. + +For https://trac.sagemath.org/ticket/28832 +--- a/SuiteSparse_config/SuiteSparse_config.mk 2019-12-02 14:21:18.956000000 +0000 ++++ b/SuiteSparse_config/SuiteSparse_config.mk 2019-12-02 14:33:49.204000000 +0000 +@@ -55,9 +55,9 @@ + # which puts the libraries in /yada/mylibs, include files in /yoda/myinc, + # and documentation in /solo/mydox. + INSTALL ?= $(SUITESPARSE) +- INSTALL_LIB ?= $(INSTALL)/lib +- INSTALL_INCLUDE ?= $(INSTALL)/include +- INSTALL_DOC ?= $(INSTALL)/share/doc/suitesparse-$(SUITESPARSE_VERSION) ++ INSTALL_LIB ?= $(DESTDIR)$(INSTALL)/lib ++ INSTALL_INCLUDE ?= $(DESTDIR)$(INSTALL)/include ++ INSTALL_DOC ?= $(DESTDIR)$(INSTALL)/share/doc/suitesparse-$(SUITESPARSE_VERSION) + + #--------------------------------------------------------------------------- + # parallel make +@@ -153,7 +153,6 @@ + # It places its shared *.so libraries in SuiteSparse/lib. + # Linux also requires the -lrt library (see below) + LDLIBS ?= -lm +- LDFLAGS += -L$(INSTALL_LIB) + + # NOTE: Use of the Intel MKL BLAS is strongly recommended. The OpenBLAS can + # result in severe performance degradation, in CHOLMOD in particular. +@@ -358,7 +357,7 @@ + + ifeq ($(UNAME),Linux) + # add the realtime library, librt, and SuiteSparse/lib +- LDLIBS += -lrt -Wl,-rpath=$(INSTALL_LIB) ++ LDLIBS += -lrt + endif + + #--------------------------------------------------------------------------- diff --git a/build/pkgs/suitesparse/spkg-install b/build/pkgs/suitesparse/spkg-install index 2ddb9e913ad..85acff88db1 100644 --- a/build/pkgs/suitesparse/spkg-install +++ b/build/pkgs/suitesparse/spkg-install @@ -1,7 +1,11 @@ cd src echo "print configuration" -$MAKE MY_METIS_LIB=none CHOLMOD_CONFIG=-DNPARTITION BLAS="$(pkg-config --libs blas)" LAPACK="$(pkg-config --libs lapack)" config INSTALL="$SAGE_LOCAL" +$MAKE MY_METIS_LIB=none CHOLMOD_CONFIG=-DNPARTITION \ + BLAS="$(pkg-config --libs blas)" LAPACK="$(pkg-config --libs lapack)" \ + INSTALL="$SAGE_LOCAL" DESTDIR="$SAGE_DESTDIR" config # build and install -$MAKE MY_METIS_LIB=none CHOLMOD_CONFIG=-DNPARTITION BLAS="$(pkg-config --libs blas)" LAPACK="$(pkg-config --libs lapack)" install INSTALL="$SAGE_LOCAL" +$MAKE MY_METIS_LIB=none CHOLMOD_CONFIG=-DNPARTITION \ + BLAS="$(pkg-config --libs blas)" LAPACK="$(pkg-config --libs lapack)" \ + INSTALL="$SAGE_LOCAL" DESTDIR="$SAGE_DESTDIR" install From 9c00054687567f83a6134a4503f9d82732f48649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 2 Dec 2019 20:48:43 +0100 Subject: [PATCH 262/340] trac 28833 adding a bunch of with open ... context managers --- src/sage/databases/jones.py | 3 +- src/sage/geometry/polyhedron/plot.py | 21 ++++++++----- src/sage/graphs/generic_graph.py | 6 ++-- src/sage/interfaces/chomp.py | 14 ++++----- src/sage/interfaces/gap.py | 10 +++--- src/sage/interfaces/giac.py | 7 ++--- src/sage/interfaces/gnuplot.py | 4 +-- src/sage/interfaces/maple.py | 5 ++- src/sage/interfaces/phc.py | 37 +++++++++++++---------- src/sage/interfaces/povray.py | 4 ++- src/sage/interfaces/psage.py | 4 +-- src/sage/interfaces/tachyon.py | 8 +++-- src/sage/lfunctions/lcalc.py | 6 ++-- src/sage/lfunctions/sympow.py | 5 +-- src/sage/libs/gap/util.pyx | 3 +- src/sage/misc/copying.py | 5 ++- src/sage/misc/explain_pickle.py | 3 +- src/sage/misc/latex.py | 16 ++++++---- src/sage/misc/log.py | 11 ++++--- src/sage/misc/sphinxify.py | 3 +- src/sage/repl/attach.py | 23 +++++++------- src/sage/repl/ipython_extension.py | 10 +++--- src/sage/rings/polynomial/groebner_fan.py | 3 +- 23 files changed, 122 insertions(+), 89 deletions(-) diff --git a/src/sage/databases/jones.py b/src/sage/databases/jones.py index 3790a855036..f7cc2b8ffdc 100644 --- a/src/sage/databases/jones.py +++ b/src/sage/databases/jones.py @@ -108,7 +108,8 @@ def _load(self, path, filename): while filename[j].isalpha() or filename[j] in [".", "_"]: j -= 1 S = sorted([eval(z) for z in filename[i:j + 1].split("-")]) - data = open(path + "/" + filename).read() + with open(path + "/" + filename) as f: + data = f.read() data = data.replace("^", "**") x = PolynomialRing(RationalField(), 'x').gen() # used next line v = eval(data) diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index 00083fe0c0c..a1235f0861a 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -1158,7 +1158,8 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=2, [x={(-0.939161cm, 0.244762cm)}, y={(0.097442cm, -0.482887cm)}, z={(0.329367cm, 0.840780cm)}, - sage: _ = open('polytope-tikz1.tex', 'w').write(Image1) # not tested + sage: with open('polytope-tikz1.tex', 'w') as f: # not tested + ....: _ = f.write(Image1) sage: P2 = Polyhedron(vertices=[[1, 1],[1, 2],[2, 1]]) sage: Image2 = P2.projection().tikz(scale=3, edge_color='blue!95!black', facet_color='orange!95!black', opacity=0.4, vertex_color='yellow', axis=True) @@ -1169,7 +1170,8 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=2, [scale=3.000000, back/.style={loosely dotted, thin}, edge/.style={color=blue!95!black, thick}, - sage: _ = open('polytope-tikz2.tex', 'w').write(Image2) # not tested + sage: with open('polytope-tikz2.tex', 'w') as f: # not tested + ....: _ = f.write(Image2) sage: P3 = Polyhedron(vertices=[[-1, -1, 2],[-1, 2, -1],[2, -1, -1]]) sage: P3 @@ -1180,9 +1182,10 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=2, [x={(0.658184cm, -0.242192cm)}, y={(-0.096240cm, 0.912008cm)}, z={(-0.746680cm, -0.331036cm)}, - sage: _ = open('polytope-tikz3.tex', 'w').write(Image3) # not tested + sage: with open('polytope-tikz3.tex', 'w') as f: # not tested + ....: _ = f.write(Image3) - sage: P=Polyhedron(vertices=[[1,1,0,0],[1,2,0,0],[2,1,0,0],[0,0,1,0],[0,0,0,1]]) + sage: P = Polyhedron(vertices=[[1,1,0,0],[1,2,0,0],[2,1,0,0],[0,0,1,0],[0,0,0,1]]) sage: P A 4-dimensional polyhedron in ZZ^4 defined as the convex hull of 5 vertices sage: P.projection().tikz() @@ -1251,8 +1254,8 @@ def _tikz_2d(self, scale, edge_color, facet_color, opacity, vertex_color, axis): [scale=3.000000, back/.style={loosely dotted, thin}, edge/.style={color=black, thick}, - sage: _ = open('polytope-tikz2.tex', 'w').write(Image) # not tested - + sage: with open('polytope-tikz2.tex', 'w') as f: # not tested + ....: _ = f.write(Image) Scientific notation is not used in the output (:trac:`16519`):: @@ -1369,7 +1372,8 @@ def _tikz_2d_in_3d(self, view, angle, scale, edge_color, facet_color, [x={(0.644647cm, -0.476559cm)}, y={(0.192276cm, 0.857859cm)}, z={(-0.739905cm, -0.192276cm)}, - sage: _ open('polytope-tikz3.tex', 'w').write(Image) # not tested + sage: with open('polytope-tikz3.tex', 'w') as f: # not tested + ....: _ = f.write(Image) sage: p = Polyhedron(vertices=[[1,0,0],[0,1,0],[0,0,1]]) sage: proj = p.projection() @@ -1497,7 +1501,8 @@ def _tikz_3d_in_3d(self, view, angle, scale, edge_color, [x={(-0.046385cm, 0.837431cm)}, y={(-0.243536cm, 0.519228cm)}, z={(0.968782cm, 0.170622cm)}, - sage: _ = open('polytope-tikz1.tex', 'w').write(Image) # not tested + sage: with open('polytope-tikz1.tex', 'w') as f: # not tested + ....: _ = f.write(Image) sage: Associahedron = Polyhedron(vertices=[[1,0,1],[1,0,0],[1,1,0],[0,0,-1],[0,1,0],[-1,0,0],[0,1,1],[0,0,1],[0,-1,0]]).polar() sage: ImageAsso = Associahedron.projection().tikz([-15,-755,-655], 116, scale=1) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 8b8c98cb152..b3bf163fd6f 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -21228,7 +21228,8 @@ def graphviz_to_file_named(self, filename, **options): sage: G = Graph({0: {1: None, 2: None}, 1: {0: None, 2: None}, 2: {0: None, 1: None, 3: 'foo'}, 3: {2: 'foo'}}, sparse=True) sage: tempfile = os.path.join(SAGE_TMP, 'temp_graphviz') sage: G.graphviz_to_file_named(tempfile, edge_labels=True) - sage: print(open(tempfile).read()) + sage: with open(tempfile) as f: + ....: print(f.read()) graph { node_0 [label="0"]; node_1 [label="1"]; @@ -21241,7 +21242,8 @@ def graphviz_to_file_named(self, filename, **options): node_2 -- node_3 [label="foo"]; } """ - open(filename, 'wt').write(self.graphviz_string(**options)) + with open(filename, 'wt') as file: + file.write(self.graphviz_string(**options)) ### Spectrum diff --git a/src/sage/interfaces/chomp.py b/src/sage/interfaces/chomp.py index 1d315302a98..308db712444 100644 --- a/src/sage/interfaces/chomp.py +++ b/src/sage/interfaces/chomp.py @@ -198,9 +198,8 @@ def __call__(self, program, complex, subcomplex=None, **kwds): raise AttributeError("Complex can not be converted to use with CHomP.") datafile = tmp_filename() - f = open(datafile, 'w') - f.write(data) - f.close() + with open(datafile, 'w') as f: + f.write(data) # # subcomplex @@ -232,9 +231,8 @@ def __call__(self, program, complex, subcomplex=None, **kwds): except AttributeError: raise AttributeError("Subcomplex can not be converted to use with CHomP.") subfile = tmp_filename() - f = open(subfile, 'w') - f.write(sub) - f.close() + with open(subfile, 'w') as f: + f.write(sub) else: subfile = '' if verbose: @@ -255,7 +253,8 @@ def __call__(self, program, complex, subcomplex=None, **kwds): print("End of CHomP output") print("") if generators: - gens = open(genfile, 'r').read() + with open(genfile, 'r') as f: + gens = f.read() if verbose: print("Generators:") print(gens) @@ -422,6 +421,7 @@ def help(self, program): from subprocess import Popen, PIPE print(Popen([program, '-h'], stdout=PIPE).communicate()[0]) + def homsimpl(complex=None, subcomplex=None, **kwds): r""" Compute the homology of a simplicial complex using the CHomP diff --git a/src/sage/interfaces/gap.py b/src/sage/interfaces/gap.py index a0237b11f18..2b1cb8aef46 100644 --- a/src/sage/interfaces/gap.py +++ b/src/sage/interfaces/gap.py @@ -480,14 +480,13 @@ def _read_in_file_command(self, filename): :: sage: filename = tmp_filename() - sage: f = open(filename, 'w') - sage: _ = f.write('xx := 22;\n') - sage: f.close() + sage: with open(filename, 'w') as f: + ....: _ = f.write('xx := 22;\n') sage: gap.read(filename) sage: gap.get('xx').strip() '22' """ - return 'Read("%s");'%filename + return 'Read("%s");' % filename def _continuation_prompt(self): """ @@ -1442,7 +1441,8 @@ def get(self, var, use_file=False): if os.path.exists(tmp): os.unlink(tmp) self.eval('PrintTo("%s", %s);'%(tmp,var), strip=False) - r = open(tmp).read() + with open(tmp) as f: + r = f.read() r = r.strip().replace("\\\n","") os.unlink(tmp) return r diff --git a/src/sage/interfaces/giac.py b/src/sage/interfaces/giac.py index ec3012ec736..1df5d6f72db 100644 --- a/src/sage/interfaces/giac.py +++ b/src/sage/interfaces/giac.py @@ -374,14 +374,13 @@ def _read_in_file_command(self, filename): :: sage: filename = tmp_filename() - sage: f = open(filename,'w') - sage: _ = f.write('xx := 22;\n') - sage: f.close() + sage: with open(filename,'w') as f: + ....: _ = f.write('xx := 22;\n') sage: giac.read(filename) sage: giac.get('xx').strip() '22' """ - return 'read "%s"'%filename + return 'read "%s"' % filename def _quit_string(self): """ diff --git a/src/sage/interfaces/gnuplot.py b/src/sage/interfaces/gnuplot.py index 69f9f506759..00d0e909361 100644 --- a/src/sage/interfaces/gnuplot.py +++ b/src/sage/interfaces/gnuplot.py @@ -179,11 +179,11 @@ def plot3d_parametric(self, f='cos(u)*(3 + v*cos(u/2)), sin(u)*(3 + v*cos(u/2)), else: self(cmd) - def interact(self, cmd): from sage.misc.all import SAGE_TMP file = os.path.join(SAGE_TMP, 'gnuplot') - open(file, 'w').write(cmd + '\n pause -1 "Press return to continue (no further rotation possible)"') + with open(file, 'w') as f: + f.write(cmd + '\n pause -1 "Press return to continue (no further rotation possible)"') os.system('sage-native-execute gnuplot -persist %s'%file) def console(self): diff --git a/src/sage/interfaces/maple.py b/src/sage/interfaces/maple.py index e67d141cf34..c3182ea7fb7 100644 --- a/src/sage/interfaces/maple.py +++ b/src/sage/interfaces/maple.py @@ -356,9 +356,8 @@ def _read_in_file_command(self, filename): :: sage: filename = tmp_filename() # optional - maple - sage: f = open(filename, 'w') # optional - maple - sage: _ = f.write('xx := 22;\n') # optional - maple - sage: f.close() # optional - maple + sage: with open(filename, 'w') as f: # optional - maple + ....: _ = f.write('xx := 22;\n') sage: maple.read(filename) # optional - maple sage: maple.get('xx').strip() # optional - maple '22' diff --git a/src/sage/interfaces/phc.py b/src/sage/interfaces/phc.py index 5a5d5079962..9e1e0e35416 100644 --- a/src/sage/interfaces/phc.py +++ b/src/sage/interfaces/phc.py @@ -251,9 +251,8 @@ def save_as_start(self, start_filename = None, sol_filter = ''): start_data += str(sol_count) + ' ' + str(var_number) + '\n' start_data += jan_bar + sol_data if start_filename is not None: - start_file = open(start_filename, 'w') - start_file.write(start_data) - start_file.close() + with open(start_filename, 'w') as start_file: + start_file.write(start_data) return start_data def classified_solution_dicts(self): @@ -445,7 +444,8 @@ def _output_from_command_list(self, command_list, polys, verbose = False): input = self._input_file(polys) if verbose: print("Writing the input file to %s" % input_filename) - open(input_filename, 'w').write(input) + with open(input_filename, 'w') as file: + file.write(input) if verbose: print("The following file will be the input polynomial file to phc.") @@ -626,9 +626,8 @@ def _path_track_file(self, start_filename_or_string, polys, input_ring, c_skew = # Probably unnecessarily redundant from the start_from function if start_filename_or_string.find('THE SOLUTIONS') != -1: start_filename = tmp_filename() - start_file = open(start_filename, 'w') - start_file.write(start_filename_or_string) - start_file.close() + with open(start_filename, 'w') as start_file: + start_file.write(start_filename_or_string) elif os.path.exists(start_filename_or_string): start_filename = start_filename_or_string else: @@ -760,7 +759,8 @@ def mixed_volume(self, polys, verbose=False): """ output_filename = self._output_from_command_list(['phc -m','4','n','n','n'], polys, verbose = verbose) - out = open(output_filename).read() + with open(output_filename) as out: + out.read() # All done out_lines = out.split('\n') for a_line in out_lines: @@ -814,9 +814,8 @@ def start_from(self, start_filename_or_string, polys, input_ring, path_track_fil if start_filename_or_string.find('THE SOLUTIONS') != -1: start_filename = tmp_filename() - start_file = open(start_filename,'w') - start_file.write(start_filename_or_string) - start_file.close() + with open(start_filename, 'w') as start_file: + start_file.write(start_filename_or_string) elif os.path.exists(start_filename_or_string): start_filename = start_filename_or_string else: @@ -826,7 +825,8 @@ def start_from(self, start_filename_or_string, polys, input_ring, path_track_fil input = self._input_file(polys) if verbose: print("Writing the input file to %s" % input_filename) - open(input_filename, 'w').write(input) + with open(input_filename, 'w') as f: + f.write(input) if verbose: print("The following file will be the input polynomial file to phc.") @@ -870,7 +870,8 @@ def start_from(self, start_filename_or_string, polys, input_ring, path_track_fil raise RuntimeError("The output file does not exist; something went wrong running phc.") # Read the output produced by PHC - out = open(output_filename).read() + with open(output_filename) as f: + out = f.read() # Delete the temporary files os.unlink(output_filename) @@ -914,7 +915,8 @@ def blackbox(self, polys, input_ring, verbose = False): input = self._input_file(polys) if verbose: print("Writing the input file to %s" % input_filename) - open(input_filename, 'w').write(input) + with open(input_filename, 'w') as f: + f.write(input) if verbose: print("The following file will be the input polynomial file to phc.") @@ -937,13 +939,16 @@ def blackbox(self, polys, input_ring, verbose = False): print(os.system('which phc') + ' PHC needs to be installed and in your path') raise RuntimeError # todo -- why? etc. - raise RuntimeError(open(log_filename).read() + "\nError running phc.") + with open(log_filename) as f: + msg = f.read() + raise RuntimeError(msg + "\nError running phc.") if not os.path.exists(output_filename): raise RuntimeError("The output file does not exist; something went wrong running phc.") # Read the output produced by PHC - out = open(output_filename).read() + with open(output_filename) as f: + out = f.read() # All done return PHC_Object(out, input_ring) diff --git a/src/sage/interfaces/povray.py b/src/sage/interfaces/povray.py index 1a7ca3a120a..7dcf963d84d 100644 --- a/src/sage/interfaces/povray.py +++ b/src/sage/interfaces/povray.py @@ -50,7 +50,9 @@ def __call__(self, pov_file, outfile='sage.ppm', block=True, **kwargs): os.system(cmd) def usage(self): - r = os.popen('povray').read() + with os.popen('povray') as f: + r = f.read() pager()(r) + povray = POVRay() diff --git a/src/sage/interfaces/psage.py b/src/sage/interfaces/psage.py index 52b26ebff7d..d998a001d25 100644 --- a/src/sage/interfaces/psage.py +++ b/src/sage/interfaces/psage.py @@ -59,9 +59,9 @@ def __init__(self, **kwds): import sage.misc.misc T = sage.misc.temporary_file.tmp_dir('sage_smp') self.__tmp_dir = T - self.__tmp = '%s/lock'%T + self.__tmp = '%s/lock' % T self._unlock() - self._unlock_code = "open('%s','w').write('__unlocked__')"%self.__tmp + self._unlock_code = "with open('%s', 'w') as f: f.write('__unlocked__')" % self.__tmp global number self._number = number diff --git a/src/sage/interfaces/tachyon.py b/src/sage/interfaces/tachyon.py index a492170cb0b..a8fc73441fc 100644 --- a/src/sage/interfaces/tachyon.py +++ b/src/sage/interfaces/tachyon.py @@ -125,7 +125,7 @@ def __call__(self, model, outfile='sage.png', verbose=1, extra_opts=''): sage: from sage.env import SAGE_EXTCODE sage: filename = os.path.join(SAGE_EXTCODE, 'doctest', 'invalid', 'syntax_error.tachyon') sage: with open(filename, 'r') as f: - ....: syntax_error = f.read() + ....: syntax_error = f.read() sage: t(syntax_error, outfile=os.devnull) Traceback (most recent call last): ... @@ -135,7 +135,8 @@ def __call__(self, model, outfile='sage.png', verbose=1, extra_opts=''): Aborting render. """ modelfile = tmp_filename(ext='.dat') - open(modelfile,'w').write(model) + with open(modelfile, 'w') as file: + file.write(model) cmd = ['tachyon', modelfile] ext = outfile[-4:].lower() if ext == '.png': @@ -174,7 +175,8 @@ def usage(self, use_pager=True): sage: t.usage(use_pager=False) Tachyon Parallel/Multiprocessor Ray Tracer Version... """ - r = os.popen('tachyon').read() + with os.popen('tachyon') as f: + r = f.read() if use_pager: pager()(r) else: diff --git a/src/sage/lfunctions/lcalc.py b/src/sage/lfunctions/lcalc.py index 47540f877a9..7bf6cc15b45 100644 --- a/src/sage/lfunctions/lcalc.py +++ b/src/sage/lfunctions/lcalc.py @@ -65,8 +65,10 @@ def _repr_(self): return "Rubinsteins L-function Calculator" def __call__(self, args): - cmd = 'lcalc %s'%args - return os.popen(cmd).read().strip() + cmd = 'lcalc %s' % args + with os.popen(cmd) as f: + res = f.read().strip() + return res def _compute_L(self, L): if isinstance(L, str): diff --git a/src/sage/lfunctions/sympow.py b/src/sage/lfunctions/sympow.py index b5626a0559e..ab697904118 100644 --- a/src/sage/lfunctions/sympow.py +++ b/src/sage/lfunctions/sympow.py @@ -77,8 +77,9 @@ def __call__(self, args): """ Used to call sympow with given args """ - cmd = 'sympow %s'%args - v = os.popen(cmd).read().strip() + cmd = 'sympow %s' % args + with os.popen(cmd) as f: + v = f.read().strip() verbose(v, level=2) return v diff --git a/src/sage/libs/gap/util.pyx b/src/sage/libs/gap/util.pyx index 6446c57f317..7f5723b6e9e 100644 --- a/src/sage/libs/gap/util.pyx +++ b/src/sage/libs/gap/util.pyx @@ -183,7 +183,8 @@ def gap_root(): # historical reasons; the best approach to setting where Sage looks for # the appropriate GAP_ROOT is to set the GAP_ROOT_DIR variable SAGE_LOCAL = sage.env.SAGE_LOCAL - gap_sh = open(os.path.join(SAGE_LOCAL, 'bin', 'gap')).read().splitlines() + with open(os.path.join(SAGE_LOCAL, 'bin', 'gap')) as f: + gap_sh = f.read().splitlines() gapdir = next(x for x in gap_sh if x.strip().startswith('GAP_ROOT')) gapdir = gapdir.split('"')[1] gapdir = gapdir.replace('$SAGE_LOCAL', SAGE_LOCAL) diff --git a/src/sage/misc/copying.py b/src/sage/misc/copying.py index ce345d8baf1..ec1b03227fb 100644 --- a/src/sage/misc/copying.py +++ b/src/sage/misc/copying.py @@ -6,6 +6,7 @@ from sage.env import SAGE_ROOT + class License: def __call__(self): pager.pager()(str(self)) @@ -14,6 +15,8 @@ def __repr__(self): return "Type license() to see the full license text." def __str__(self): - return open(os.path.join(SAGE_ROOT,'COPYING.txt')).read() + with open(os.path.join(SAGE_ROOT,'COPYING.txt')) as f: + return f.read() + license = License() diff --git a/src/sage/misc/explain_pickle.py b/src/sage/misc/explain_pickle.py index 67c0bd64601..6470f428b35 100644 --- a/src/sage/misc/explain_pickle.py +++ b/src/sage/misc/explain_pickle.py @@ -248,7 +248,8 @@ def explain_pickle(pickle=None, file=None, compress=True, **kwargs): if pickle is not None: p = pickle elif file is not None: - p = open(file).read() + with open(file) as f: + p = f.read() else: raise ValueError("Either pickle or file must be specified") diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index 507031e50b9..3ce7d4158ae 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -692,8 +692,8 @@ def _run_latex_(filename, debug=False, density=150, engine=None, png=False, do_i sage: from sage.misc.latex import _run_latex_, _latex_file_ sage: file = os.path.join(SAGE_TMP, "temp.tex") - sage: O = open(file, 'w') - sage: _ = O.write(_latex_file_([ZZ['x'], RR])); O.close() + sage: with open(file, 'w') as O: + ....: _ = O.write(_latex_file_([ZZ['x'], RR])) sage: _run_latex_(file) # random - depends on whether latex is installed 'dvi' """ @@ -861,7 +861,8 @@ def _run_latex_(filename, debug=False, density=150, engine=None, png=False, do_i if not e: print("An error occurred.") try: - print(open(base + '/' + filename + '.log').read()) + with open(base + '/' + filename + '.log') as f: + print(f.read()) except IOError: pass return "Error latexing slide." @@ -2152,7 +2153,8 @@ def view(objects, title='Sage', debug=False, sep='', tiny=False, sage: g = sage.misc.latex.latex_examples.graph() sage: latex.add_to_preamble(r"\usepackage{tkz-graph}") sage: file = os.path.join(SAGE_TMP, "temp.tex") - sage: O = open(file, 'w'); _ = O.write(_latex_file_(g)); O.close() + sage: with open(file, 'w') as O: + ....: O.write(_latex_file_(g)) sage: _run_latex_(file, engine="pdflatex") # optional - latex 'pdf' @@ -2231,7 +2233,8 @@ def view(objects, title='Sage', debug=False, sep='', tiny=False, # command line or notebook with viewer tmp = tmp_dir('sage_viewer') tex_file = os.path.join(tmp, "sage.tex") - open(tex_file,'w').write(s) + with open(tex_file, 'w') as file: + file.write(s) suffix = _run_latex_(tex_file, debug=debug, engine=engine, png=False) if suffix == "pdf": from sage.misc.viewer import pdf_viewer @@ -2303,7 +2306,8 @@ def png(x, filename, density=150, debug=False, tex_file = os.path.join(tmp, "sage.tex") png_file = os.path.join(tmp, "sage.png") # write latex string to file - open(tex_file,'w').write(s) + with open(tex_file, 'w') as file: + file.write(s) # run latex on the file, producing png output to png_file e = _run_latex_(tex_file, density=density, debug=debug, png=True, engine=engine) diff --git a/src/sage/misc/log.py b/src/sage/misc/log.py index 491e9b15381..0b396875146 100644 --- a/src/sage/misc/log.py +++ b/src/sage/misc/log.py @@ -179,9 +179,8 @@ def _update(self): # this s. Commenting out for now. #s = '# ' + '\n# '.join(str(O[m]).split('\n')) + '\n\n' self._n += 1 - A = open(self._filename,'w') - A.write(self._header() + '\n' + self._text + '\n' + self._footer()) - A.close() + with open(self._filename,'w') as A: + A.write(self._header() + '\n' + self._text + '\n' + self._footer()) self._update_plain() self._build() @@ -195,7 +194,8 @@ def _input_log_name(self): return os.path.join(self._dir, 'input-' + self._time) def _update_plain(self): - open(self._input_log_name(),'w').write(self._input_text) + with open(self._input_log_name(), 'w') as f: + f.write(self._input_text) class log_html(Log): @@ -264,7 +264,8 @@ def _get_output(self, n): except AttributeError: latex.png(x, single_png, debug=self._debug) oi = os.path.join(self._dir, 'images', 'o' + '%s.html' % n) - open(oi,'w').write('
OUTPUT:\n%s\n\n\nLATEX:\n%s
'%( + with open(oi, 'w') as file: + file.write('
OUTPUT:\n%s\n\n\nLATEX:\n%s
'%( x, L, single_png)) extra_img_opts = '' #if sage.plot.graphics.is_Graphics(x): diff --git a/src/sage/misc/sphinxify.py b/src/sage/misc/sphinxify.py index 4849c2bffa4..b9e630f4d95 100644 --- a/src/sage/misc/sphinxify.py +++ b/src/sage/misc/sphinxify.py @@ -128,7 +128,8 @@ def sphinxify(docstring, format='html'): builtins.__dict__.pop('_', None) if os.path.exists(output_name): - output = open(output_name, 'r').read() + with open(output_name, 'r') as f: + output = f.read() output = output.replace('
', '
')
 
         # Translate URLs for media from something like
diff --git a/src/sage/repl/attach.py b/src/sage/repl/attach.py
index 11967fbf963..5e60d2461d9 100644
--- a/src/sage/repl/attach.py
+++ b/src/sage/repl/attach.py
@@ -167,7 +167,8 @@ def load_attach_path(path=None, replace=False):
         ['.']
         sage: t_dir = tmp_dir()
         sage: fullpath = os.path.join(t_dir, 'test.py')
-        sage: _ = open(fullpath, 'w').write("print(37 * 3)")
+        sage: with open(fullpath, 'w') as f:
+        ....:     _ = f.write("print(37 * 3)")
 
     We put SAGE_TMP on the attach path for testing (otherwise this will
     load ``test.py`` from the current working directory if that happens
@@ -322,9 +323,9 @@ def attach(*files):
 
         sage: sage.repl.attach.reset()
         sage: t1 = tmp_filename(ext='.py')
-        sage: _ = open(t1,'w').write("print('hello world')")
+        sage: with open(t1,'w') as f: _ = f.write("print('hello world')")
         sage: t2 = tmp_filename(ext='.py')
-        sage: _ = open(t2,'w').write("print('hi there xxx')")
+        sage: with open(t2,'w') as f: _ = f.write("print('hi there xxx')")
         sage: attach(t1, t2)
         hello world
         hi there xxx
@@ -398,7 +399,7 @@ def attached_files():
 
         sage: sage.repl.attach.reset()
         sage: t = tmp_filename(ext='.py')
-        sage: _ = open(t,'w').write("print('hello world')")
+        sage: with open(t,'w') as f: _ = f.write("print('hello world')")
         sage: attach(t)
         hello world
         sage: attached_files()
@@ -424,7 +425,7 @@ def detach(filename):
 
         sage: sage.repl.attach.reset()
         sage: t = tmp_filename(ext='.py')
-        sage: _ = open(t,'w').write("print('hello world')")
+        sage: with open(t,'w') as f: _ = f.write("print('hello world')")
         sage: attach(t)
         hello world
         sage: attached_files() == [t]
@@ -438,7 +439,7 @@ def detach(filename):
         ['.']
         sage: t_dir = tmp_dir()
         sage: fullpath = os.path.join(t_dir, 'test.py')
-        sage: _ = open(fullpath, 'w').write("print(37 * 3)")
+        sage: with open(fullpath, 'w') as f: _ = f.write("print(37 * 3)")
         sage: load_attach_path(t_dir, replace=True)
         sage: attach('test.py')
         111
@@ -450,7 +451,7 @@ def detach(filename):
         sage: attach('test.py')
         111
         sage: fullpath = os.path.join(t_dir, 'test2.py')
-        sage: _ = open(fullpath, 'w').write("print(3)")
+        sage: with open(fullpath, 'w') as f: _ = f.write("print(3)")
         sage: attach('test2.py')
         3
         sage: detach(attached_files())
@@ -494,7 +495,7 @@ def reset():
 
         sage: sage.repl.attach.reset()
         sage: t = tmp_filename(ext='.py')
-        sage: _ = open(t,'w').write("print('hello world')")
+        sage: with open(t,'w') as f: _ = f.write("print('hello world')")
         sage: attach(t)
         hello world
         sage: attached_files() == [t]
@@ -527,7 +528,7 @@ def modified_file_iterator():
         sage: list(modified_file_iterator())
         []
         sage: sleep(1)   # filesystem mtime granularity
-        sage: _ = open(t, 'w').write('1')
+        sage: with open(t, 'w') as f: _ = f.write('1')
         sage: list(modified_file_iterator())
         [('/.../tmp_....py', time.struct_time(...))]
     """
@@ -568,12 +569,12 @@ def reload_attached_files_if_modified():
         sage: from sage.repl.interpreter import get_test_shell
         sage: shell = get_test_shell()
         sage: tmp = tmp_filename(ext='.py')
-        sage: _ = open(tmp, 'w').write('a = 2\n')
+        sage: with open(tmp, 'w') as f: _ = f.write('a = 2\n')
         sage: shell.run_cell('attach({0})'.format(repr(tmp)))
         sage: shell.run_cell('a')
         2
         sage: sleep(1)   # filesystem mtime granularity
-        sage: _ = open(tmp, 'w').write('a = 3\n')
+        sage: with open(tmp, 'w') as f: _ = f.write('a = 3\n')
 
     Note that the doctests are never really at the command prompt
     where the automatic reload is triggered. So we have to do it
diff --git a/src/sage/repl/ipython_extension.py b/src/sage/repl/ipython_extension.py
index fd27b43fc49..42ff76cf05e 100644
--- a/src/sage/repl/ipython_extension.py
+++ b/src/sage/repl/ipython_extension.py
@@ -46,7 +46,8 @@
     sage: bool(re.search('/[0-9]+/', TMP))
     True
     sage: tmp = os.path.join(TMP, 'run_cell.py')
-    sage: f = open(tmp, 'w'); _ = f.write('a = 2\n'); f.close()
+    sage: with open(tmp, 'w') as f:
+    ....:     f.write('a = 2\n')
     sage: shell.run_cell('%runfile '+tmp)
     sage: shell.run_cell('a')
     2
@@ -109,7 +110,8 @@ def runfile(self, s):
             sage: from sage.misc.all import tmp_dir
             sage: shell = get_test_shell()
             sage: tmp = os.path.join(tmp_dir(), 'run_cell.py')
-            sage: f = open(tmp, 'w'); _ = f.write('a = 2\n'); f.close()
+            sage: with open(tmp, 'w') as f:
+            ....:     f.write('a = 2\n')
             sage: shell.run_cell('%runfile '+tmp)
             sage: shell.run_cell('a')
             2
@@ -133,12 +135,12 @@ def attach(self, s):
             sage: from sage.repl.interpreter import get_test_shell
             sage: shell = get_test_shell()
             sage: tmp = os.path.normpath(os.path.join(SAGE_TMP, 'run_cell.py'))
-            sage: f = open(tmp, 'w'); _ = f.write('a = 2\n'); f.close()
+            sage: with open(tmp, 'w') as f: f.write('a = 2\n')
             sage: shell.run_cell('%attach ' + tmp)
             sage: shell.run_cell('a')
             2
             sage: sleep(1)  # filesystem timestamp granularity
-            sage: f = open(tmp, 'w'); _ = f.write('a = 3\n'); f.close()
+            sage: with open(tmp, 'w') as f: f.write('a = 3\n')
 
         Note that the doctests are never really at the command prompt, so
         we call the input hook manually::
diff --git a/src/sage/rings/polynomial/groebner_fan.py b/src/sage/rings/polynomial/groebner_fan.py
index 2adafe3309c..e578d86fdbc 100644
--- a/src/sage/rings/polynomial/groebner_fan.py
+++ b/src/sage/rings/polynomial/groebner_fan.py
@@ -1285,7 +1285,8 @@ def render(self, file = None, larger=False, shift=0, rgbcolor = (0,0,0), polyfil
             cmd += ' -L'
         s = self.gfan(cmd, I=self._gfan_reduced_groebner_bases().replace(' ',','), format=False)
         if file is not None:
-            open(file, 'w').write(s)
+            with open(file, 'w') as f:
+                f.write(s)
         sp = s.split('\n')
         sp2 = []
         for x in sp[9:]:

From a579a9aefdefdae106ab44f11ac88645f48f330a Mon Sep 17 00:00:00 2001
From: "John H. Palmieri" 
Date: Mon, 2 Dec 2019 13:58:47 -0800
Subject: [PATCH 263/340] trac 28834: doctesting: detect whether sagenb is
 installed and don't try to doctest it if it's not.

---
 src/sage/doctest/control.py                 |  7 ++++---
 src/sage/graphs/graph_database.py           |  2 +-
 src/sage/repl/rich_output/backend_sagenb.py | 12 ++++++------
 src/sage/tests/cmdline.py                   | 20 ++++++++++----------
 4 files changed, 21 insertions(+), 20 deletions(-)

diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py
index b5f17ec3749..d408b18efea 100644
--- a/src/sage/doctest/control.py
+++ b/src/sage/doctest/control.py
@@ -35,6 +35,7 @@
 from .reporting import DocTestReporter
 from .util import Timer, count_noun, dict_difference
 from .external import external_software, available_software
+from sage.features import PythonModule
 
 nodoctest_regex = re.compile(r'\s*(#+|%+|r"+|"+|\.\.)\s*nodoctest')
 optionaltag_regex = re.compile(r'^\w+$')
@@ -692,9 +693,9 @@ def add_files(self):
 
             sage: DD = DocTestDefaults(sagenb = True)
             sage: DC = DocTestController(DD, [])
-            sage: DC.add_files()  # py2
+            sage: DC.add_files()  # py2 # optional - sagenb
             Doctesting the Sage notebook.
-            sage: DC.files[0][-6:]  # py2
+            sage: DC.files[0][-6:]  # py2 # optional - sagenb
             'sagenb'
         """
         opj = os.path.join
@@ -741,7 +742,7 @@ def all_files():
                          filename.endswith(".rst"))):
                     self.files.append(os.path.relpath(opj(SAGE_ROOT,filename)))
         if self.options.sagenb:
-            if six.PY3:
+            if six.PY3 or not PythonModule('sagenb').is_present():
                 if not self.options.all:
                     self.log("Skipping doctesting of the Sage notebook: "
                              "not installed on Python 3")
diff --git a/src/sage/graphs/graph_database.py b/src/sage/graphs/graph_database.py
index c0a182bd412..a14cc595405 100644
--- a/src/sage/graphs/graph_database.py
+++ b/src/sage/graphs/graph_database.py
@@ -1082,7 +1082,7 @@ def interactive_query(self, display_cols, **kwds):
         EXAMPLES::
 
             sage: D = GraphDatabase()
-            sage: D.interactive_query(display_cols=['graph6', 'num_vertices', 'degree_sequence'], num_edges=5, max_degree=3)  # py2
+            sage: D.interactive_query(display_cols=['graph6', 'num_vertices', 'degree_sequence'], num_edges=5, max_degree=3)  # py2 # optional -- sagenb
             ...
 
         .. WARNING::
diff --git a/src/sage/repl/rich_output/backend_sagenb.py b/src/sage/repl/rich_output/backend_sagenb.py
index ac872f4e8e0..dc3ed1519a1 100644
--- a/src/sage/repl/rich_output/backend_sagenb.py
+++ b/src/sage/repl/rich_output/backend_sagenb.py
@@ -220,8 +220,8 @@ def save_launch_script(self):
             sage: j = SageNbOutputSceneJmol.example()
             sage: os.path.exists('sage0-size32.jmol')
             False
-            sage: j.save_launch_script()  # py2: requires sagenb
-            sage: os.path.exists('sage0-size32.jmol')  # py2
+            sage: j.save_launch_script()  # py2 # optional -- sagenb
+            sage: os.path.exists('sage0-size32.jmol')  # py2 # optional -- sagenb
             True
         """
         from sagenb.notebook.interact import SAGE_CELL_ID
@@ -246,7 +246,7 @@ def save_preview(self):
             sage: import shutil
             sage: shutil.rmtree('.jmol_images', ignore_errors=True)
             sage: j.save_preview()
-            sage: os.listdir('.jmol_images')  # py2
+            sage: os.listdir('.jmol_images')  # py2 # optional -- sagenb
             ['sage1-size32.jmol.png']
         """
         from sage.misc.misc import sage_makedirs
@@ -266,10 +266,10 @@ def embed(self):
 
             sage: from sage.repl.rich_output.backend_sagenb import SageNbOutputSceneJmol
             sage: j = SageNbOutputSceneJmol.example()
-            sage: j.embed()  # py2 - requires sagenb
-            sage: sorted(os.listdir('.'))  # py2
+            sage: j.embed()  # py2 # optional -- sagenb
+            sage: sorted(os.listdir('.'))  # py2 # optional -- sagenb
             ['.jmol_images', 'sage0-size32-....jmol.zip', 'sage0-size32.jmol']
-            sage: sorted(os.listdir('.jmol_images'))  # py2
+            sage: sorted(os.listdir('.jmol_images'))  # py2 # optional -- sagenb
             ['sage0-size32.jmol.png']
         """
         self.save_preview()
diff --git a/src/sage/tests/cmdline.py b/src/sage/tests/cmdline.py
index cd343e41503..22a2451451b 100644
--- a/src/sage/tests/cmdline.py
+++ b/src/sage/tests/cmdline.py
@@ -826,8 +826,8 @@ def test_executable(args, input="", timeout=100.0, **kwds):
         sage: input = tmp_filename(ext='.rst')
         sage: with open(input, 'w') as F:
         ....:     _ = F.write(s)
-        sage: (out, err, ret) = test_executable(["sage", "--rst2txt", input]) # py2
-        sage: print(out) # py2
+        sage: (out, err, ret) = test_executable(["sage", "--rst2txt", input]) # py2 # optional -- sagenb
+        sage: print(out) # py2 # optional -- sagenb
         {{{id=0|
         2^10
         ///
@@ -839,9 +839,9 @@ def test_executable(args, input="", timeout=100.0, **kwds):
         ///
         4
         }}}
-        sage: err # py2
+        sage: err # py2 # optional -- sagenb
         ''
-        sage: ret # py2
+        sage: ret # py2 # optional -- sagenb
         0
 
     Test ``sage --rst2txt file.rst file.txt`` on a ReST file::
@@ -851,9 +851,9 @@ def test_executable(args, input="", timeout=100.0, **kwds):
         sage: output = tmp_filename(ext='.txt')
         sage: with open(input, 'w') as F:
         ....:     _ = F.write(s)
-        sage: test_executable(["sage", "--rst2txt", input, output]) # py2
+        sage: test_executable(["sage", "--rst2txt", input, output]) # py2 # optional -- sagenb
         ('', ..., 0)
-        sage: print(open(output, 'r').read()) # py2
+        sage: print(open(output, 'r').read()) # py2 # optional -- sagenb
         {{{id=0|
         2^10
         ///
@@ -873,11 +873,11 @@ def test_executable(args, input="", timeout=100.0, **kwds):
         sage: output = tmp_filename(ext='.sws')
         sage: with open(input, 'w') as F:
         ....:     _ = F.write(s)
-        sage: test_executable(["sage", "--rst2sws", input, output]) # py2
+        sage: test_executable(["sage", "--rst2sws", input, output]) # py2 # optional -- sagenb
         ('', '', 0)
         sage: import tarfile # py2
-        sage: f = tarfile.open(output, 'r') # py2
-        sage: print(f.extractfile('sage_worksheet/worksheet.html').read()) # py2
+        sage: f = tarfile.open(output, 'r') # py2 # optional -- sagenb
+        sage: print(f.extractfile('sage_worksheet/worksheet.html').read()) # py2 # optional -- sagenb
         

Thetitle

{{{id=0| @@ -891,7 +891,7 @@ def test_executable(args, input="", timeout=100.0, **kwds): /// 4 }}} - sage: print(f.extractfile('sage_worksheet/worksheet.txt').read()) # py2 + sage: print(f.extractfile('sage_worksheet/worksheet.txt').read()) # py2 # optional -- sagenb Thetitle system:sage From 30c99c80a95bf873e6a965e6cd11bbe17726ab3e Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Mon, 2 Dec 2019 16:18:46 -0800 Subject: [PATCH 264/340] trac 28835: delete src/ext/doctest/python3-known-passing.txt and remove the corresponding parts of the Makefile. --- Makefile | 14 ++-- src/ext/doctest/python3-known-passing.txt | 82 ----------------------- 2 files changed, 6 insertions(+), 90 deletions(-) delete mode 100644 src/ext/doctest/python3-known-passing.txt diff --git a/Makefile b/Makefile index 5c3272ce1a9..351343558a1 100644 --- a/Makefile +++ b/Makefile @@ -53,9 +53,11 @@ build/make/Makefile: configure build/make/deps build/make/Makefile.in build/pkgs fi; ) # This is used to monitor progress towards Python 3 and prevent -# regressions. Should be removed after the full switch to python3 -buildbot-python3: configure - ./configure --with-python=3 +# regressions. Should be removed after the full switch to python3. +# +# As of Sage 9.0: keep the build target for backward compatibility, +# but it just runs "make". +buildbot-python3: $(MAKE) # Preemptively download all standard upstream source tarballs. @@ -145,7 +147,6 @@ fast-rebuild-clean: misc-clean TESTALL = ./sage -t --all PTESTALL = ./sage -t -p --all -PTEST_PYTHON3 = cat src/ext/doctest/python3-known-passing.txt | xargs ./sage -t --long -p # Flags for ./sage -t --all. # By default, include all tests marked 'dochtml' -- see @@ -191,9 +192,6 @@ ptestoptional: all ptestoptionallong: all $(PTESTALL) --long --logfile=logs/ptestoptionallong.log -ptest-python3: buildbot-python3 - $(PTEST_PYTHON3) --logfile=logs/ptest_python3.log - configure: configure.ac src/bin/sage-version.sh m4/*.m4 build/pkgs/*/spkg-configure.m4 ./bootstrap -d @@ -214,4 +212,4 @@ list: misc-clean bdist-clean distclean bootstrap-clean maintainer-clean \ test check testoptional testall testlong testoptionallong testallong \ ptest ptestoptional ptestall ptestlong ptestoptionallong ptestallong \ - buildbot-python3 ptest-python3 list + buildbot-python3 list diff --git a/src/ext/doctest/python3-known-passing.txt b/src/ext/doctest/python3-known-passing.txt deleted file mode 100644 index 9a0ea2e1b36..00000000000 --- a/src/ext/doctest/python3-known-passing.txt +++ /dev/null @@ -1,82 +0,0 @@ -src/doc/ -src/sage/algebras/ -src/sage/arith/ -src/sage/calculus/ -src/sage/categories/ -src/sage/coding/ -src/sage/combinat/ -src/sage/cpython/ -src/sage/crypto/ -src/sage/data_structures/ -src/sage/databases/ -src/sage/docs/ -src/sage/dynamics/ -src/sage/ext/ -src/sage/features/ -src/sage/finance/ -src/sage/functions/ -src/sage/game_theory/ -src/sage/games/ -src/sage/geometry/ -src/sage/graphs/ -src/sage/groups/ -src/sage/homology/ -src/sage/interacts/ -src/sage/interfaces/ -src/sage/knots/ -src/sage/lfunctions/ -src/sage/libs/arb/ -src/sage/libs/coxeter3/ -src/sage/libs/cremona/ -src/sage/libs/flint/ -src/sage/libs/gap/ -src/sage/libs/glpk/ -src/sage/libs/gmp/ -src/sage/libs/gsl/ -src/sage/libs/lcalc/ -src/sage/libs/linbox/ -src/sage/libs/linkages/ -src/sage/libs/lrcalc/ -src/sage/libs/mpc/ -src/sage/libs/mpfi/ -src/sage/libs/mpfr/ -src/sage/libs/mpmath/ -src/sage/libs/mwrank/ -src/sage/libs/ntl/ -src/sage/libs/pari/ -src/sage/libs/polybori/ -src/sage/libs/pynac/ -src/sage/libs/symmetrica/ -src/sage/logic/ -src/sage/manifolds/ -src/sage/matrix/ -src/sage/matroids/ -src/sage/media/ -src/sage/modular/ -src/sage/modules/ -src/sage/monoids/ -src/sage/parallel/ -src/sage/plot/ -src/sage/probability/ -src/sage/quadratic_forms/ -src/sage/quivers/ -src/sage/repl/display/ -src/sage/repl/ipython_kernel/ -src/sage/repl/rich_output/ -src/sage/rings/asymptotic/ -src/sage/rings/function_field/ -src/sage/rings/number_field/ -src/sage/rings/padics/ -src/sage/rings/polynomial/ -src/sage/rings/valuation/ -src/sage/sandpiles/ -src/sage/sat/ -src/sage/schemes/ -src/sage/server/ -src/sage/sets/ -src/sage/stats/ -src/sage/structure/ -src/sage/symbolic/ -src/sage/tensor/ -src/sage/typeset/ -src/sage_setup/ From 1db03d67c2e30b9b9ae507d7e4a6d4d15b951352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 3 Dec 2019 09:06:33 +0100 Subject: [PATCH 265/340] trac 28833 fix doctests --- src/sage/misc/latex.py | 4 ++-- src/sage/repl/ipython_extension.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index 3ce7d4158ae..7faef78699e 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -17,7 +17,7 @@ # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** from __future__ import print_function, absolute_import @@ -2154,7 +2154,7 @@ def view(objects, title='Sage', debug=False, sep='', tiny=False, sage: latex.add_to_preamble(r"\usepackage{tkz-graph}") sage: file = os.path.join(SAGE_TMP, "temp.tex") sage: with open(file, 'w') as O: - ....: O.write(_latex_file_(g)) + ....: _ = O.write(_latex_file_(g)) sage: _run_latex_(file, engine="pdflatex") # optional - latex 'pdf' diff --git a/src/sage/repl/ipython_extension.py b/src/sage/repl/ipython_extension.py index 42ff76cf05e..f44d53238e8 100644 --- a/src/sage/repl/ipython_extension.py +++ b/src/sage/repl/ipython_extension.py @@ -47,7 +47,7 @@ True sage: tmp = os.path.join(TMP, 'run_cell.py') sage: with open(tmp, 'w') as f: - ....: f.write('a = 2\n') + ....: _ = f.write('a = 2\n') sage: shell.run_cell('%runfile '+tmp) sage: shell.run_cell('a') 2 @@ -111,7 +111,7 @@ def runfile(self, s): sage: shell = get_test_shell() sage: tmp = os.path.join(tmp_dir(), 'run_cell.py') sage: with open(tmp, 'w') as f: - ....: f.write('a = 2\n') + ....: _ = f.write('a = 2\n') sage: shell.run_cell('%runfile '+tmp) sage: shell.run_cell('a') 2 @@ -135,12 +135,12 @@ def attach(self, s): sage: from sage.repl.interpreter import get_test_shell sage: shell = get_test_shell() sage: tmp = os.path.normpath(os.path.join(SAGE_TMP, 'run_cell.py')) - sage: with open(tmp, 'w') as f: f.write('a = 2\n') + sage: with open(tmp, 'w') as f: _ = f.write('a = 2\n') sage: shell.run_cell('%attach ' + tmp) sage: shell.run_cell('a') 2 sage: sleep(1) # filesystem timestamp granularity - sage: with open(tmp, 'w') as f: f.write('a = 3\n') + sage: with open(tmp, 'w') as f: _ = f.write('a = 3\n') Note that the doctests are never really at the command prompt, so we call the input hook manually:: From 5fed72f2ca292187d9438193c1680622b9b624cb Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Thu, 28 Nov 2019 23:45:20 +0000 Subject: [PATCH 266/340] use libgap instead of gap, remove no longer needed #optional also, use libgap.load_package rather than LoadPackage to automatically silence too noisy GAP convert HJ graph construction to libgap --- src/sage/graphs/generators/smallgraphs.py | 34 +++++++---------------- src/sage/graphs/strongly_regular_db.pyx | 24 +++++++--------- 2 files changed, 20 insertions(+), 38 deletions(-) diff --git a/src/sage/graphs/generators/smallgraphs.py b/src/sage/graphs/generators/smallgraphs.py index 4a0ab6383b7..7e0fda2c4e0 100644 --- a/src/sage/graphs/generators/smallgraphs.py +++ b/src/sage/graphs/generators/smallgraphs.py @@ -681,7 +681,7 @@ def HallJankoGraph(from_string=True): TESTS:: sage: gg = graphs.HallJankoGraph(from_string=False) # long time - sage: g == gg # long time + sage: g.is_isomorphic(gg) # long time True """ @@ -734,29 +734,15 @@ def HallJankoGraph(from_string=True): # The following construction is due to version 3 of the ATLAS of # Finite Group Representations, specifically the page at - # http://brauer.maths.qmul.ac.uk/Atlas/v3/permrep/J2G1-p100B0 . - - from sage.interfaces.gap import gap - gap.eval("g1 := (1,84)(2,20)(3,48)(4,56)(5,82)(6,67)(7,55)(8,41)" - "(9,35)(10,40)(11,78)(12,100)(13,49)(14,37)(15,94)(16,76)" - "(17,19)(18,44)(21,34)(22,85)(23,92)(24,57)(25,75)(26,28)" - "(27,64)(29,90)(30,97)(31,38)(32,68)(33,69)(36,53)(39,61)" - "(42,73)(43,91)(45,86)(46,81)(47,89)(50,93)(51,96)(52,72)" - "(54,74)(58,99)(59,95)(60,63)(62,83)(65,70)(66,88)(71,87)" - "(77,98)(79,80);") - - gap.eval("g2 := (1,80,22)(2,9,11)(3,53,87)(4,23,78)(5,51,18)" - "(6,37,24)(8,27,60)(10,62,47)(12,65,31)(13,64,19)" - "(14,61,52)(15,98,25)(16,73,32)(17,39,33)(20,97,58)" - "(21,96,67)(26,93,99)(28,57,35)(29,71,55)(30,69,45)" - "(34,86,82)(38,59,94)(40,43,91)(42,68,44)(46,85,89)" - "(48,76,90)(49,92,77)(50,66,88)(54,95,56)(63,74,72)" - "(70,81,75)(79,100,83);") - - gap.eval("G := Group([g1,g2]);") - edges = gap('Orbit(G,[1,5],OnSets)').sage() - g = Graph([(int(u), int(v)) for u,v in edges]) - g.relabel(range(100)) + # http://brauer.maths.qmul.ac.uk/Atlas/v5/permrep/J2G1-p100B0 . + + from sage.libs.gap.libgap import libgap + libgap.load_package("AtlasRep") # representation of HJ on 100 points + G = libgap.AtlasGroup("HJ", libgap.NrMovedPoints, 100) + edges = G.Orbit([1,5], libgap.OnSets) + g = Graph() + g.add_edges(edges) + g.relabel() g._circle_embedding(list(range(100))) g.name("Hall-Janko graph") diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 3e3e7d58268..3251b777e67 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -2239,19 +2239,17 @@ def SRG_280_135_70_60(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_280_135_70_60 - sage: g=SRG_280_135_70_60() # long time # optional - gap_packages - sage: g.is_strongly_regular(parameters=True) # long time # optional - gap_packages + sage: g=SRG_280_135_70_60() # long time + sage: g.is_strongly_regular(parameters=True) # long time (280, 135, 70, 60) """ - from sage.interfaces.gap import gap - from sage.groups.perm_gps.permgroup import PermutationGroup + from sage.libs.gap.libgap import libgap from sage.graphs.graph import Graph - gap.load_package("AtlasRep") - + libgap.load_package("AtlasRep") # A representation of J2 acting on a 3.PGL(2,9) it contains. - J2 = PermutationGroup(gap('AtlasGenerators("J2",2).generators')) - edges = J2.orbit((1,2),"OnSets") + J2 = libgap.AtlasGroup("J2", libgap.NrMovedPoints, 280) + edges = J2.Orbit([1,2], libgap.OnSets) g = Graph() g.add_edges(edges) g.relabel() @@ -2346,15 +2344,13 @@ def SRG_416_100_36_20(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_416_100_36_20 - sage: g = SRG_416_100_36_20() # optional - gap_packages # long time - sage: g.is_strongly_regular(parameters=True) # optional - gap_packages # long time + sage: g = SRG_416_100_36_20() # long time + sage: g.is_strongly_regular(parameters=True) # long time (416, 100, 36, 20) """ from sage.libs.gap.libgap import libgap - libgap.eval("SetInfoLevel(InfoWarning,0)") # silence #I warnings from GAP (without IO pkg) - libgap.LoadPackage("AtlasRep") + libgap.load_package("AtlasRep") g=libgap.AtlasGroup("G2(4)",libgap.NrMovedPoints,416) - libgap.eval("SetInfoLevel(InfoWarning,1)") # restore #I warnings h = Graph() h.add_edges(g.Orbit([1,5],libgap.OnSets)) h.relabel() @@ -2376,7 +2372,7 @@ def SRG_560_208_72_80(): (560, 208, 72, 80) """ from sage.libs.gap.libgap import libgap - libgap.LoadPackage("AtlasRep") + libgap.load_package("AtlasRep") g=libgap.AtlasGroup("Sz8",libgap.NrMovedPoints,560) h = Graph() From 2b08c1a0c8d24db69c0c4e17e5b49a1966953c1d Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Fri, 29 Nov 2019 12:46:04 +0000 Subject: [PATCH 267/340] use libgap to compute orbit lengths on edges/arcs --- src/sage/graphs/graph.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index bcb9ff1be64..8e6ace097b8 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -3083,7 +3083,7 @@ def is_edge_transitive(self): sage: P.is_edge_transitive() False """ - from sage.interfaces.gap import gap + from sage.libs.gap.libgap import libgap if not self.size(): return True @@ -3092,7 +3092,7 @@ def is_edge_transitive(self): e = next(self.edge_iterator(labels=False)) e = [A._domain_to_gap[e[0]], A._domain_to_gap[e[1]]] - return gap("OrbitLength("+str(A._gap_())+",Set(" + str(e) + "),OnSets);") == self.size() + return libgap(A).OrbitLength(e, libgap.OnSets) == self.size() @doc_index("Graph properties") def is_arc_transitive(self): @@ -3123,7 +3123,7 @@ def is_arc_transitive(self): sage: G.is_arc_transitive() False """ - from sage.interfaces.gap import gap + from sage.libs.gap.libgap import libgap if not self.size(): return True @@ -3132,7 +3132,7 @@ def is_arc_transitive(self): e = next(self.edge_iterator(labels=False)) e = [A._domain_to_gap[e[0]], A._domain_to_gap[e[1]]] - return gap("OrbitLength("+str(A._gap_())+",Set(" + str(e) + "),OnTuples);") == 2*self.size() + return libgap(A).OrbitLength(e,libgap.OnTuples) == 2*self.size() @doc_index("Graph properties") def is_half_transitive(self): From 70f67e5830912a24235683abedcb109e6b6e2a50 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Sun, 1 Dec 2019 19:09:06 +0000 Subject: [PATCH 268/340] fix for outdated code, tests for LivinstoneGraph --- src/sage/graphs/generators/smallgraphs.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/sage/graphs/generators/smallgraphs.py b/src/sage/graphs/generators/smallgraphs.py index 7e0fda2c4e0..cadf3c37055 100644 --- a/src/sage/graphs/generators/smallgraphs.py +++ b/src/sage/graphs/generators/smallgraphs.py @@ -3503,23 +3503,24 @@ def LivingstoneGraph(): EXAMPLES:: - sage: g = graphs.LivingstoneGraph() # optional - gap_packages internet - sage: g.order() # optional - gap_packages internet + sage: g = graphs.LivingstoneGraph() # optional - internet + sage: g.order() # optional - internet 266 - sage: g.size() # optional - gap_packages internet + sage: g.size() # optional - internet 1463 - sage: g.girth() # optional - gap_packages internet + sage: g.girth() # optional - internet 5 - sage: g.is_vertex_transitive() # optional - gap_packages internet + sage: g.is_vertex_transitive() # optional - internet True - sage: g.is_distance_regular() # optional - gap_packages internet + sage: g.is_distance_regular() # optional - internet True """ from sage.groups.perm_gps.permgroup_named import JankoGroup from sage.graphs.graph import Graph G = JankoGroup(1) - edges = map(tuple, G.orbit((1, 24), action="OnSets")) - return Graph(edges, name="Livingstone Graph") + g = Graph(name="Livingstone Graph") + g.add_edges(map(tuple, G.orbit((1, 24), action="OnSets"))) + return g def M22Graph(): r""" From 6489a184b7dc6d3c15a2aae87d3052c28c842f80 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 4 Dec 2019 10:00:01 +0000 Subject: [PATCH 269/340] # optional - internet tags for AtlasRep uses --- src/sage/graphs/generators/smallgraphs.py | 4 ++-- src/sage/graphs/strongly_regular_db.pyx | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/graphs/generators/smallgraphs.py b/src/sage/graphs/generators/smallgraphs.py index cadf3c37055..4f8a6732288 100644 --- a/src/sage/graphs/generators/smallgraphs.py +++ b/src/sage/graphs/generators/smallgraphs.py @@ -680,8 +680,8 @@ def HallJankoGraph(from_string=True): TESTS:: - sage: gg = graphs.HallJankoGraph(from_string=False) # long time - sage: g.is_isomorphic(gg) # long time + sage: gg = graphs.HallJankoGraph(from_string=False) # long time # optional - internet + sage: g.is_isomorphic(gg) # long time # optional - internet True """ diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 3251b777e67..997a181388d 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -2239,8 +2239,8 @@ def SRG_280_135_70_60(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_280_135_70_60 - sage: g=SRG_280_135_70_60() # long time - sage: g.is_strongly_regular(parameters=True) # long time + sage: g=SRG_280_135_70_60() # long time # optional - internet + sage: g.is_strongly_regular(parameters=True) # long time # optional - internet (280, 135, 70, 60) """ from sage.libs.gap.libgap import libgap @@ -2344,8 +2344,8 @@ def SRG_416_100_36_20(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_416_100_36_20 - sage: g = SRG_416_100_36_20() # long time - sage: g.is_strongly_regular(parameters=True) # long time + sage: g = SRG_416_100_36_20() # long time # optional - internet + sage: g.is_strongly_regular(parameters=True) # long time # optional - internet (416, 100, 36, 20) """ from sage.libs.gap.libgap import libgap From 922e99c84739becf6a71f1b354ee37041c2e4f3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 4 Dec 2019 13:27:37 +0100 Subject: [PATCH 270/340] pari version to 2.11.2 --- build/pkgs/pari/checksums.ini | 6 ++--- build/pkgs/pari/package-version.txt | 2 +- build/pkgs/pari/patches/QX_factor.patch | 28 -------------------- build/pkgs/pari/patches/red_montgomery.patch | 21 --------------- 4 files changed, 4 insertions(+), 53 deletions(-) delete mode 100644 build/pkgs/pari/patches/QX_factor.patch delete mode 100644 build/pkgs/pari/patches/red_montgomery.patch diff --git a/build/pkgs/pari/checksums.ini b/build/pkgs/pari/checksums.ini index a44cbb2e1f1..c1e512cbee7 100644 --- a/build/pkgs/pari/checksums.ini +++ b/build/pkgs/pari/checksums.ini @@ -1,4 +1,4 @@ tarball=pari-VERSION.tar.gz -sha1=6d3c19e78641b5d412adacec1913fad1c3d15c2a -md5=474d5ec6b2fca8f3ef4f747b3dca1ffd -cksum=1928664415 +sha1=49a638ebcce77b9e9e2d8305156f37e7322bc09f +md5=6afe748a472c33ae8787a5034d7742a9 +cksum=4122745815 diff --git a/build/pkgs/pari/package-version.txt b/build/pkgs/pari/package-version.txt index 0c346feaeb7..9e5bb77a3ba 100644 --- a/build/pkgs/pari/package-version.txt +++ b/build/pkgs/pari/package-version.txt @@ -1 +1 @@ -2.11.1.p2 +2.11.2 diff --git a/build/pkgs/pari/patches/QX_factor.patch b/build/pkgs/pari/patches/QX_factor.patch deleted file mode 100644 index bbe5710c0ff..00000000000 --- a/build/pkgs/pari/patches/QX_factor.patch +++ /dev/null @@ -1,28 +0,0 @@ -See https://pari.math.u-bordeaux.fr/cgi-bin/bugreport.cgi?bug=2125 - -commit 943b45c148e06bb0f2f2bd7ff14f3ef99fa6e81a -Author: Bill Allombert -Date: Tue Mar 5 14:59:43 2019 +0100 - - factor: fix 'bug in gerepile' (from Jeroen) [#2125] - - ? p1 = (289*x^4 + 1)^8; p2 = (19*x^2 + 1)^16; - ? factor(p1); - ? factor(p2); - *** at top-level: factor(p2) - *** ^---------- - *** factor: bug in gerepile, significant pointers lost, please report. - -diff --git a/src/basemath/QX_factor.c b/src/basemath/QX_factor.c -index 173b424..ee71ee5 100644 ---- a/src/basemath/QX_factor.c -+++ b/src/basemath/QX_factor.c -@@ -892,7 +892,7 @@ ZX_squff(GEN f, GEN *ex) - GEN U; - if (!dW) { set_avma(av); break; } - while ( (U = ZX_divides(T, V)) ) { k++; T = U; } -- T = gerepileupto(av, T); -+ T = gerepilecopy(av, T); - } - else - { diff --git a/build/pkgs/pari/patches/red_montgomery.patch b/build/pkgs/pari/patches/red_montgomery.patch deleted file mode 100644 index 11bf9f3395d..00000000000 --- a/build/pkgs/pari/patches/red_montgomery.patch +++ /dev/null @@ -1,21 +0,0 @@ -commit aa1ee6e0898d177e6bcf49237d82c804bc410985 -Author: Karim Belabas -Date: Tue Nov 27 15:40:16 2018 +0100 - - 47- gmp kernel: off-by-1 error in red_mongomery - - [read uninitialized memory, then ignores result] - -diff --git a/src/kernel/gmp/mp.c b/src/kernel/gmp/mp.c -index 1c30d0a..3a534f5 100644 ---- a/src/kernel/gmp/mp.c -+++ b/src/kernel/gmp/mp.c -@@ -1005,7 +1005,7 @@ red_montgomery(GEN T, GEN N, ulong inv) - } - if (carry) - { /* Td > N overflows (k+1 words), set Td := Td - N */ -- GEN NE = N + k+2; -+ GEN NE = N + k+1; - Td = Te; - Nd = Ne; - t = subll(*++Td, *++Nd); *Td = t; From f3640c29b6adcbeed6a5e6c0ac5e89a2705966d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 4 Dec 2019 10:23:09 +0100 Subject: [PATCH 271/340] adding a minimal .lgtm.yml file This allows to specify the python version, and to exclude some of the most common errors that are specific to sage see https://trac.sagemath.org/ticket/28839 --- .lgtm.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .lgtm.yml diff --git a/.lgtm.yml b/.lgtm.yml new file mode 100644 index 00000000000..52e5d90b9f0 --- /dev/null +++ b/.lgtm.yml @@ -0,0 +1,8 @@ +queries: + - exclude: py/call/wrong-named-class-argument + - exclude: py/call/wrong-number-class-arguments + - exclude: py/unsafe-cyclic-import +extraction: + python: + python_setup: + version: 3 From fd1e3bd66e37fc1a490c42b8c9adcddc4fe06f2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 4 Dec 2019 20:50:08 +0100 Subject: [PATCH 272/340] some details in doc (about .. NOTE:: etc) --- src/ext/threejs/threejs_template.html | 2 +- src/sage/categories/map.pyx | 6 +++--- src/sage/combinat/partition.py | 16 +++++++-------- .../combinat/partition_shifting_algebras.py | 2 +- src/sage/combinat/perfect_matching.py | 3 +-- .../root_system/reflection_group_complex.py | 2 +- src/sage/combinat/sf/sfa.py | 20 +++++++++---------- .../polyhedron_face_lattice.pyx | 2 +- .../graphs/graph_decompositions/tdlib.pyx | 2 +- .../groups/matrix_gps/finitely_generated.py | 4 ++-- src/sage/matroids/graphic_matroid.py | 2 +- src/sage/rings/padics/factory.py | 2 +- src/sage/rings/padics/lattice_precision.py | 10 +++++----- .../riemann_surfaces/riemann_surface.py | 8 ++++---- 14 files changed, 40 insertions(+), 41 deletions(-) diff --git a/src/ext/threejs/threejs_template.html b/src/ext/threejs/threejs_template.html index a0e6efe6093..5670792cb48 100644 --- a/src/ext/threejs/threejs_template.html +++ b/src/ext/threejs/threejs_template.html @@ -314,7 +314,7 @@ var mesh = new THREE.Mesh( geometry, material ); mesh.position.set( c.x, c.y, c.z ); - if ( transparent && json.renderOrder ) mesh.renderOrder = json.renderOrder + if ( transparent && json.renderOrder ) mesh.renderOrder = json.renderOrder; scene.add( mesh ); if ( json.showMeshGrid ) { diff --git a/src/sage/categories/map.pyx b/src/sage/categories/map.pyx index f4e8ab21be3..91598d3cd42 100644 --- a/src/sage/categories/map.pyx +++ b/src/sage/categories/map.pyx @@ -1242,7 +1242,7 @@ cdef class Map(Element): """ Return a section of self. - NOTE: + .. NOTE:: By default, it returns ``None``. You may override it in subclasses. @@ -1295,7 +1295,7 @@ cdef class Section(Map): """ A formal section of a map. - NOTE: + .. NOTE:: Call methods are not implemented for the base class ``Section``. @@ -1464,7 +1464,7 @@ cdef class FormalCompositeMap(Map): - ``first``: a map or a list of maps - ``second``: a map or None - .. NOTE:: + .. NOTE:: The intended use is of course that the codomain of the first map is contained in the domain of the second map, diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index e6f3b365dbd..e046474e857 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -1268,7 +1268,7 @@ def k_size(self, k): sage: Partition([2, 1, 1]).k_size(4) 4 - .. SEEALSO:: + .. SEEALSO:: :meth:`k_boundary`, :meth:`SkewPartition.size` """ @@ -1319,7 +1319,7 @@ def boundary(self): sage: Partition([2, 1, 1]).boundary() [(2, 0), (2, 1), (1, 1), (1, 2), (1, 3), (0, 3)] - .. SEEALSO:: + .. SEEALSO:: :meth:`k_rim`. You might have been looking for :meth:`k_boundary` instead. @@ -1384,7 +1384,7 @@ def k_rim(self, k): sage: Partition([3, 1]).k_rim(3) [(3, 0), (2, 0), (1, 0), (1, 1), (0, 1), (0, 2)] - .. SEEALSO:: + .. SEEALSO:: :meth:`k_interior`, :meth:`k_boundary`, :meth:`boundary` """ @@ -1420,7 +1420,7 @@ def k_row_lengths(self, k): sage: Partition([4, 4, 4, 3, 2]).k_row_lengths(2) [0, 1, 1, 1, 2] - .. SEEALSO:: + .. SEEALSO:: :meth:`k_column_lengths`, :meth:`k_boundary`, :meth:`SkewPartition.row_lengths`, @@ -1442,7 +1442,7 @@ def k_column_lengths(self, k): sage: Partition([4, 4, 4, 3, 2]).k_column_lengths(2) [1, 1, 1, 2] - .. SEEALSO:: + .. SEEALSO:: :meth:`k_row_lengths`, :meth:`k_boundary`, :meth:`SkewPartition.row_lengths`, @@ -1490,7 +1490,7 @@ def has_rectangle(self, h, w): sage: Partition([3]).has_rectangle(2, 3) False - .. SEEALSO:: + .. SEEALSO:: :meth:`has_k_rectangle` """ @@ -1685,7 +1685,7 @@ def next_within_bounds(self, min=[], max=None, partition_type=None): sage: Partition([3, 2, 1]).next_within_bounds(min=m, max=M) == None True - .. SEEALSO:: + .. SEEALSO:: :meth:`next` """ @@ -4345,7 +4345,7 @@ def is_core(self, k): sage: q.is_core(0) True - .. SEEALSO:: + .. SEEALSO:: :meth:`core`, :class:`Core` """ diff --git a/src/sage/combinat/partition_shifting_algebras.py b/src/sage/combinat/partition_shifting_algebras.py index 29b3e20aba5..7395fdd4776 100644 --- a/src/sage/combinat/partition_shifting_algebras.py +++ b/src/sage/combinat/partition_shifting_algebras.py @@ -454,7 +454,7 @@ def build_and_register_conversion(self, support_map, codomain): The actions on the complete homogeneous symmetric functions and on the Schur functions by morphisms are already registered. - .. WARNING:: + .. WARNING:: Because :class:`ShiftingOperatorAlgebra` inherits from :class:`UniqueRepresentation`, once you register a conversion, this diff --git a/src/sage/combinat/perfect_matching.py b/src/sage/combinat/perfect_matching.py index 4937a20a488..16924dca039 100644 --- a/src/sage/combinat/perfect_matching.py +++ b/src/sage/combinat/perfect_matching.py @@ -53,7 +53,6 @@ # Distributed under the terms of the GNU General Public License (GPL) # https://www.gnu.org/licenses/ # **************************************************************************** - from __future__ import division, print_function from six.moves import range @@ -242,7 +241,7 @@ def _latex_(self): ... \end{tikzpicture} - ..TODO:: + .. TODO:: This should probably call the latex method of :class:`SetPartition` with appropriate defaults. diff --git a/src/sage/combinat/root_system/reflection_group_complex.py b/src/sage/combinat/root_system/reflection_group_complex.py index ec66acca1b7..0567f8bf304 100644 --- a/src/sage/combinat/root_system/reflection_group_complex.py +++ b/src/sage/combinat/root_system/reflection_group_complex.py @@ -1854,7 +1854,7 @@ def fake_degrees(self): In particular, they sum to Hilbert series of the coinvariant algebra of ``self``. - ..NOTE:: + .. NOTE:: The ordering follows the one in Chevie and is not compatible with the current implementation of :meth:`irredubile_characters()`. diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index be4dd6211d1..35838d1cd01 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -407,7 +407,7 @@ def is_field(self, proof=True): def is_commutative(self): """ - Returns whether this symmetric function algebra is commutative. + Return whether this symmetric function algebra is commutative. INPUT: @@ -543,7 +543,7 @@ def _repr_(self): @cached_method def one_basis(self): r""" - Returns the empty partition, as per ``AlgebrasWithBasis.ParentMethods.one_basis`` + Return the empty partition, as per ``AlgebrasWithBasis.ParentMethods.one_basis`` INPUT: @@ -1488,7 +1488,7 @@ def degree_negation(self): def degree_zero_coefficient(self): r""" - Returns the degree zero coefficient of ``self``. + Return the degree zero coefficient of ``self``. EXAMPLES:: @@ -2456,7 +2456,7 @@ def _inner_plethysm_pnu_g(self, p_x, cache, nu): def _dual_basis_default(self): """ - Returns the default value for ``self.dual_basis()`` + Return the default value for ``self.dual_basis()`` .. SEEALSO:: :meth:`dual_basis` @@ -3839,11 +3839,11 @@ def left_padded_kronecker_product(self, x): This notion of left-padded Kronecker product can be lifted to the non-commutative symmetric functions - (:meth:`~sage.combinat.ncsf_qsym.ncsf.NonCommutativeSymmeticFunctions.Bases.ElementMethods.left_padded_kronecker_product`). + (:meth:`~sage.combinat.ncsf_qsym.ncsf.NonCommutativeSymmetricFunctions.Bases.ElementMethods.left_padded_kronecker_product`). .. WARNING:: - Don't mistake this product for the reduced Kronecker product + Do not mistake this product for the reduced Kronecker product (:meth:`reduced_kronecker_product`), which uses the Schur functions instead of the complete homogeneous functions in its definition. @@ -4361,7 +4361,7 @@ def scalar(self, x, zee=None): def scalar_qt(self, x, q = None, t = None): r""" - Returns the `q,t`-deformed standard Hall-Littlewood scalar product of + Return the `q,t`-deformed standard Hall-Littlewood scalar product of ``self`` and ``x``. INPUT: @@ -5445,7 +5445,7 @@ def character_to_frobenius_image(self, n): ################### def _lmax(x): r""" - Returns the max of ``x`` where ``x`` is a list. + Return the max of ``x`` where ``x`` is a list. If ``x`` is the empty list, ``_lmax`` returns 0. @@ -5459,9 +5459,10 @@ def _lmax(x): """ return max(x) if x else 0 + def _nonnegative_coefficients(x): r""" - Returns ``True`` if ``x`` has nonnegative coefficients. + Return ``True`` if ``x`` has nonnegative coefficients. EXAMPLES:: @@ -5480,4 +5481,3 @@ def _nonnegative_coefficients(x): return all(c >= 0 for c in x.coefficients(sparse=False)) else: return x >= 0 - diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx index 2cac35e56a2..4d8e7c77f9b 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx @@ -269,7 +269,7 @@ cdef class PolyhedronFaceLattice: Sorts ``inp`` and returns it in ``output1``. - ..WARNING:: + .. WARNING:: Input is the same as output1 or output2 diff --git a/src/sage/graphs/graph_decompositions/tdlib.pyx b/src/sage/graphs/graph_decompositions/tdlib.pyx index fea79d096ac..5ffc28685a2 100644 --- a/src/sage/graphs/graph_decompositions/tdlib.pyx +++ b/src/sage/graphs/graph_decompositions/tdlib.pyx @@ -112,7 +112,7 @@ def treedecomposition_exact(G, lb=-1): A tree decomposition of ``G`` of ``tw(G)``, if the lower bound was not greater than ``tw(G)``, otherwise a tree decomposition of ``width = lb``. - .. WARNING:: + .. WARNING:: The computation can take a lot of time for a graph `G` on more than about 30 vertices and `tw(G) > 3`. diff --git a/src/sage/groups/matrix_gps/finitely_generated.py b/src/sage/groups/matrix_gps/finitely_generated.py index c2d828d861e..d356c9cfc14 100644 --- a/src/sage/groups/matrix_gps/finitely_generated.py +++ b/src/sage/groups/matrix_gps/finitely_generated.py @@ -574,7 +574,7 @@ def as_permutation_group(self, algorithm=None, seed=None): sage: Psmaller.degree() 80 - .. NOTE:: + .. NOTE:: In this case, the "smaller" option returned an isomorphic group of lower degree. The above example used GAP's library @@ -583,7 +583,7 @@ def as_permutation_group(self, algorithm=None, seed=None): "Irreducible Maximal Finite Integral Matrix Groups" in the GAP reference manual has more details. - .. NOTE:: + .. NOTE:: Concerning the option ``algorithm='smaller'`` you should note the following from GAP documentation: "The methods used might diff --git a/src/sage/matroids/graphic_matroid.py b/src/sage/matroids/graphic_matroid.py index acbec4610c2..067753fb7fb 100644 --- a/src/sage/matroids/graphic_matroid.py +++ b/src/sage/matroids/graphic_matroid.py @@ -112,7 +112,7 @@ class GraphicMatroid(Matroid): A ``GraphicMatroid`` instance where the ground set elements are the edges of ``G``. - ..NOTE:: + .. NOTE:: If a disconnected graph is given as input, the instance of ``GraphicMatroid`` will connect the graph components and store diff --git a/src/sage/rings/padics/factory.py b/src/sage/rings/padics/factory.py index b6910b2194f..0f81744a510 100644 --- a/src/sage/rings/padics/factory.py +++ b/src/sage/rings/padics/factory.py @@ -2653,7 +2653,7 @@ def ZpLC(p, prec=None, *args, **kwds): The SOMOS sequence is the sequence defined by the recurrence: - ..MATH:: + .. MATH:: u_n = \frac {u_{n-1} u_{n-3} + u_{n-2}^2} {u_{n-4}} diff --git a/src/sage/rings/padics/lattice_precision.py b/src/sage/rings/padics/lattice_precision.py index ae3f927842c..6cb4f04d178 100644 --- a/src/sage/rings/padics/lattice_precision.py +++ b/src/sage/rings/padics/lattice_precision.py @@ -1893,7 +1893,7 @@ def _lift_to_precision(self, x, prec): The new precision lattice is computed as the intersection of the current precision lattice with the subspace - ..MATH:: + .. MATH:: p^{prec} \Z_p dx \oplus \bigoplus_{y \neq x} \Q_p dy @@ -2519,12 +2519,12 @@ def _lift_to_precision(self, x, prec): - ``prec`` -- the new precision - NOTE: + .. NOTE:: - The new precision lattice is computed as the intersection - of the current precision lattice with the subspace + The new precision lattice is computed as the intersection + of the current precision lattice with the subspace. - ..MATH:: + .. MATH:: p^{prec} \Z_p dx \oplus \bigoplus_{y \neq x} \Q_p dy diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index a1cb20567b2..1dfed9beb21 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -1394,19 +1394,19 @@ def simple_vector_line_integral(self, upstairs_edge, differentials): sage: S.simple_vector_line_integral([(0,0),(1,0)], differentials) #abs tol 0.00000001 (1.14590610929717e-16 - 0.352971844594760*I) - ..NOTE:: + .. NOTE:: Uses data that "homology_basis" initializes. """ w_of_t,Delta_z = self.make_zw_interpolator(upstairs_edge) - V = VectorSpace(self._CC,self.genus) + V = VectorSpace(self._CC, self.genus) + def integrand(t): zt,wt = w_of_t(t) dfdwt = self._fastcall_dfdw(zt,wt) return V([omega(zt,wt)/dfdwt for omega in differentials]) - I=integrate_vector(integrand,self._prec)*Delta_z - return I + return integrate_vector(integrand,self._prec)*Delta_z def cohomology_basis(self, option=1): r""" From 0c1beb6a43446d9e6058ecaca68759b82737f047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 4 Dec 2019 20:54:50 +0100 Subject: [PATCH 273/340] one more little fix --- src/sage/rings/morphism.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/morphism.pyx b/src/sage/rings/morphism.pyx index caf2900fc73..eed78a5015e 100644 --- a/src/sage/rings/morphism.pyx +++ b/src/sage/rings/morphism.pyx @@ -949,7 +949,7 @@ cdef class RingHomomorphism_coercion(RingHomomorphism): r""" A ring homomorphism that is a coercion. - .. WARNING:; + .. WARNING:: This class is obsolete. Set the category of your morphism to a subcategory of ``Rings`` instead. From 3a1ddcec5ab463ad20e85a969f8b809892768d11 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 4 Dec 2019 23:00:58 +0100 Subject: [PATCH 274/340] explicitely -> explicitly --- src/sage/combinat/root_system/type_dual.py | 2 +- src/sage/combinat/words/morphism.py | 4 ++-- src/sage/combinat/words/paths.py | 2 +- src/sage/doctest/fixtures.py | 2 +- src/sage/geometry/newton_polygon.py | 2 +- src/sage/geometry/polyhedron/base_QQ.py | 2 +- src/sage/geometry/polyhedron/base_ZZ.py | 2 +- src/sage/graphs/graph_generators.py | 6 +++--- src/sage/interfaces/fricas.py | 6 +++--- .../modform_hecketriangle/hecke_triangle_group_element.py | 2 +- src/sage/plot/graphics.py | 2 +- src/sage/plot/multigraphics.py | 2 +- src/sage/tensor/modules/finite_rank_free_module.py | 2 +- src/sage/tensor/modules/free_module_automorphism.py | 2 +- src/sage/tensor/modules/free_module_basis.py | 2 +- src/sage/tensor/modules/free_module_tensor.py | 2 +- 16 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/sage/combinat/root_system/type_dual.py b/src/sage/combinat/root_system/type_dual.py index 37fc398f2c1..885724a5eb1 100644 --- a/src/sage/combinat/root_system/type_dual.py +++ b/src/sage/combinat/root_system/type_dual.py @@ -43,7 +43,7 @@ class CartanType(cartan_type.CartanType_decorator, cartan_type.CartanType_crysta ['F', 4] relabelled by {1: 4, 2: 3, 3: 2, 4: 1} So to exercise this class we consider some non simply laced affine - Cartan types and also create explicitely `F_4^*` as a dual cartan + Cartan types and also create explicitly `F_4^*` as a dual cartan type:: sage: from sage.combinat.root_system.type_dual import CartanType as CartanTypeDual diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index 43e808f001a..2d8a449a4b8 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -247,7 +247,7 @@ class WordMorphism(SageObject): .. NOTE:: - When the domain or the codomain are not explicitely given, it is + When the domain or the codomain are not explicitly given, it is expected that the letters are comparable because the alphabets of the domain and of the codomain are sorted. @@ -278,7 +278,7 @@ class WordMorphism(SageObject): Finite words over {0, 1, 2} When the alphabet is non-sortable, the domain and/or codomain must be - explicitely given:: + explicitly given:: sage: W = FiniteWords(['a',6]) sage: d = {'a':['a',6,'a'],6:[6,6,6,'a']} diff --git a/src/sage/combinat/words/paths.py b/src/sage/combinat/words/paths.py index 24104313086..c9431ef647f 100644 --- a/src/sage/combinat/words/paths.py +++ b/src/sage/combinat/words/paths.py @@ -250,7 +250,7 @@ def WordPaths(alphabet, steps=None): EXAMPLES: - The steps can be given explicitely:: + The steps can be given explicitly:: sage: WordPaths('abc', steps=[(1,2), (-1,4), (0,-3)]) Word Paths over 3 steps diff --git a/src/sage/doctest/fixtures.py b/src/sage/doctest/fixtures.py index 259a6a65c3f..13b3fb40f19 100644 --- a/src/sage/doctest/fixtures.py +++ b/src/sage/doctest/fixtures.py @@ -58,7 +58,7 @@ def reproducible_repr(val): covered by the examples below. If a doctest requires special handling for additional types, this function may be extended appropriately. It is an error if an argument to this function has - a non-reproducible ``repr`` implementation and is not explicitely + a non-reproducible ``repr`` implementation and is not explicitly mentioned in an example case below. INPUT: diff --git a/src/sage/geometry/newton_polygon.py b/src/sage/geometry/newton_polygon.py index e470e8f4b69..08a6161da54 100644 --- a/src/sage/geometry/newton_polygon.py +++ b/src/sage/geometry/newton_polygon.py @@ -596,7 +596,7 @@ class ParentNewtonPolygon(Parent, UniqueRepresentation): sage: NP == NP2 True - except if the contrary is explicitely mentioned:: + except if the contrary is explicitly mentioned:: sage: NewtonPolygon([0, 1, 1/2, 2/3, 1/2, 2/3, 1, 2/3], sort_slopes=False) Finite Newton polygon with 4 vertices: (0, 0), (1, 0), (6, 10/3), (8, 5) diff --git a/src/sage/geometry/polyhedron/base_QQ.py b/src/sage/geometry/polyhedron/base_QQ.py index 4414c73b1b0..5917c7a262c 100644 --- a/src/sage/geometry/polyhedron/base_QQ.py +++ b/src/sage/geometry/polyhedron/base_QQ.py @@ -742,7 +742,7 @@ def _ehrhart_polynomial_latte(self, verbose=False, dual=None, Unknown command/option --bim-bam-boum=19 """ - # note: the options below are explicitely written in the function + # note: the options below are explicitly written in the function # declaration in order to keep tab completion (see #18211). kwds.update({ 'dual' : dual, diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index 598ae6db1f8..b46d21962f0 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -234,7 +234,7 @@ def _ehrhart_polynomial_latte(self, verbose=False, dual=None, Invocation: count --ehrhart-polynomial '--redundancy-check=none' --cdd '--bim-bam-boum=19' /dev/stdin Unknown command/option --bim-bam-boum=19 """ - # note: the options below are explicitely written in the function + # note: the options below are explicitly written in the function # declaration in order to keep tab completion (see #18211). kwds.update({ 'dual' : dual, diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index 3e1a600181d..14721c7ac6a 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -1405,7 +1405,7 @@ def planar_graphs(self, order, minimum_degree=None, - ``exact_connectivity`` - default: ``False`` - if ``True`` only graphs with exactly the specified connectivity will be generated. This option cannot be used with ``minimum_connectivity=3``, or if - the minimum connectivity is not explicitely set. + the minimum connectivity is not explicitly set. - ``only_bipartite`` - default: ``False`` - if ``True`` only bipartite graphs will be generated. This option cannot be used for graphs with @@ -1596,11 +1596,11 @@ def triangulations(self, order, minimum_degree=None, minimum_connectivity=None, - ``exact_connectivity`` - default: ``False`` - if ``True`` only triangulations with exactly the specified connectivity will be generated. This option cannot be used with ``minimum_connectivity=3``, or if - the minimum connectivity is not explicitely set. + the minimum connectivity is not explicitly set. - ``only_eulerian`` - default: ``False`` - if ``True`` only Eulerian triangulations will be generated. This option cannot be used if the - minimum degree is explicitely set to anything else than 4. + minimum degree is explicitly set to anything else than 4. - ``dual`` - default: ``False`` - if ``True`` return instead the planar duals of the generated graphs. diff --git a/src/sage/interfaces/fricas.py b/src/sage/interfaces/fricas.py index 616852e4d68..336cc50a155 100644 --- a/src/sage/interfaces/fricas.py +++ b/src/sage/interfaces/fricas.py @@ -1569,11 +1569,11 @@ def _convert_prod(x, y): register_symbol(_convert_sum, {'fricas': 'sum'}) register_symbol(_convert_prod, {'fricas': 'product'}) - def explicitely_not_implemented(*args): + def explicitly_not_implemented(*args): raise NotImplementedError("the translation of the FriCAS Expression '%s' to sage is not yet implemented" % args) - register_symbol(lambda *args: explicitely_not_implemented("rootOfADE"), {'fricas': 'rootOfADE'}) - register_symbol(lambda *args: explicitely_not_implemented("rootOfRec"), {'fricas': 'rootOfRec'}) + register_symbol(lambda *args: explicitly_not_implemented("rootOfADE"), {'fricas': 'rootOfADE'}) + register_symbol(lambda *args: explicitly_not_implemented("rootOfRec"), {'fricas': 'rootOfRec'}) rootOf = dict() # (variable, polynomial) rootOf_ev = dict() # variable -> (complex) algebraic number diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py index a855aef7bd6..eb0811ebc68 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py @@ -3292,7 +3292,7 @@ def slash(self, f, tau=None, k=None): try: tau = f.numerator().parent().gen() except (ValueError, TypeError, AttributeError): - raise ValueError("f={} is not a rational function or a polynomial in one variable, so tau has to be specified explicitely!".format(f)) + raise ValueError("f={} is not a rational function or a polynomial in one variable, so tau has to be specified explicitly!".format(f)) if (tau in HyperbolicPlane()): tau = tau.to_model('UHP').coordinates() diff --git a/src/sage/plot/graphics.py b/src/sage/plot/graphics.py index 31131ab2207..2a80a050a50 100644 --- a/src/sage/plot/graphics.py +++ b/src/sage/plot/graphics.py @@ -3335,7 +3335,7 @@ def inset(self, graphics, pos=None, fontsize=None): - ``fontsize`` -- (default: ``None``) integer, font size (in points) for the inset; if ``None``, the value of 6 points is used, unless - ``fontsize`` has been explicitely set in the construction of + ``fontsize`` has been explicitly set in the construction of ``graphics`` (in this case, it is not overwritten here) OUTPUT: diff --git a/src/sage/plot/multigraphics.py b/src/sage/plot/multigraphics.py index d53647ac89f..3135cebe2dd 100644 --- a/src/sage/plot/multigraphics.py +++ b/src/sage/plot/multigraphics.py @@ -654,7 +654,7 @@ def inset(self, graphics, pos=None, fontsize=None): - ``fontsize`` -- (default: ``None``) integer, font size (in points) for the inset; if ``None``, the value of 6 points is used, unless - ``fontsize`` has been explicitely set in the construction of + ``fontsize`` has been explicitly set in the construction of ``graphics`` (in this case, it is not overwritten here) OUTPUT: diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 715c0e24462..b8d048bd3a4 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1222,7 +1222,7 @@ def basis(self, symbol, latex_symbol=None, from_family=None, sage: latex(e) \left(e_{0},e_{1},e_{2}\right) - The LaTeX symbol can be set explicitely:: + The LaTeX symbol can be set explicitly:: sage: eps = M.basis('eps', latex_symbol=r'\epsilon') ; eps Basis (eps_0,eps_1,eps_2) on the Rank-3 free module M diff --git a/src/sage/tensor/modules/free_module_automorphism.py b/src/sage/tensor/modules/free_module_automorphism.py index 61ceb2e9d23..c526e24129c 100644 --- a/src/sage/tensor/modules/free_module_automorphism.py +++ b/src/sage/tensor/modules/free_module_automorphism.py @@ -244,7 +244,7 @@ class FreeModuleAutomorphism(FreeModuleTensor, MultiplicativeGroupElement): [1 3], [-1 0], [0 3] ) - To get the result as an endomorphism, one has to explicitely convert it via + To get the result as an endomorphism, one has to explicitly convert it via the parent of endomorphisms, `\mathrm{End}(M)`:: sage: s = End(M)(a+b) ; s diff --git a/src/sage/tensor/modules/free_module_basis.py b/src/sage/tensor/modules/free_module_basis.py index 8ea3c37e6ba..c174570d46c 100644 --- a/src/sage/tensor/modules/free_module_basis.py +++ b/src/sage/tensor/modules/free_module_basis.py @@ -483,7 +483,7 @@ class FreeModuleBasis(Basis_abstract): Element e_1 of the Rank-3 free module M over the Integer Ring, Element e_2 of the Rank-3 free module M over the Integer Ring) - The LaTeX symbol can be set explicitely:: + The LaTeX symbol can be set explicitly:: sage: latex(e) \left(e_{0},e_{1},e_{2}\right) diff --git a/src/sage/tensor/modules/free_module_tensor.py b/src/sage/tensor/modules/free_module_tensor.py index 8a9ce2f5576..daed9b8955b 100644 --- a/src/sage/tensor/modules/free_module_tensor.py +++ b/src/sage/tensor/modules/free_module_tensor.py @@ -2644,7 +2644,7 @@ def contract(self, *args): sage: s == a[0]*b[0] + a[1]*b[1] + a[2]*b[2] # check of the computation True - The positions of the contraction indices can be set explicitely:: + The positions of the contraction indices can be set explicitly:: sage: s == a.contract(0, b, 0) True From 14c75619f8ff530c2887bc3be109aa670ad0b6f1 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Wed, 4 Dec 2019 23:04:17 +0100 Subject: [PATCH 275/340] #28842: catch AttributeError from SymPy's RootSum --- src/sage/symbolic/integration/integral.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/sage/symbolic/integration/integral.py b/src/sage/symbolic/integration/integral.py index 414abe4d0aa..9026d31e324 100644 --- a/src/sage/symbolic/integration/integral.py +++ b/src/sage/symbolic/integration/integral.py @@ -77,6 +77,14 @@ def _eval_(self, f, x): e^x sage: indefinite_integral(exp(x), x^2) 2*(x - 1)*e^x + + TESTS: + + Check that trac:`28842` is fixed:: + + sage: integrate(1/(x^4 + x^3 + 1), x) + integrate(1/(x^4 + x^3 + 1), x) + """ # Check for x if not is_SymbolicVariable(x): @@ -92,7 +100,7 @@ def _eval_(self, f, x): for integrator in self.integrators: try: A = integrator(f, x) - except (NotImplementedError, TypeError): + except (NotImplementedError, TypeError, AttributeError): pass except ValueError: # maxima is telling us something @@ -195,7 +203,7 @@ def _eval_(self, f, x, a, b): for integrator in self.integrators: try: A = integrator(*args) - except (NotImplementedError, TypeError): + except (NotImplementedError, TypeError, AttributeError): pass except ValueError: # maxima is telling us something From e5a3f32c6cb2d62384eadf132cb182e25ef01b98 Mon Sep 17 00:00:00 2001 From: Eric Gourgoulhon Date: Thu, 5 Dec 2019 09:26:47 +0100 Subject: [PATCH 276/340] #28842: corrected trac link --- src/sage/symbolic/integration/integral.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/symbolic/integration/integral.py b/src/sage/symbolic/integration/integral.py index 9026d31e324..7035ba77624 100644 --- a/src/sage/symbolic/integration/integral.py +++ b/src/sage/symbolic/integration/integral.py @@ -80,7 +80,7 @@ def _eval_(self, f, x): TESTS: - Check that trac:`28842` is fixed:: + Check that :trac:`28842` is fixed:: sage: integrate(1/(x^4 + x^3 + 1), x) integrate(1/(x^4 + x^3 + 1), x) From 6cf82e5de5e003332ad7ff5ba363a62b565d1210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 5 Dec 2019 09:43:12 +0100 Subject: [PATCH 277/340] some details in heegner.py --- src/sage/schemes/elliptic_curves/heegner.py | 47 ++++++++++++--------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/heegner.py b/src/sage/schemes/elliptic_curves/heegner.py index db655894589..b4123adfd00 100644 --- a/src/sage/schemes/elliptic_curves/heegner.py +++ b/src/sage/schemes/elliptic_curves/heegner.py @@ -4,9 +4,9 @@ AUTHORS: - - William Stein (August 2009)-- most of the initial version +- William Stein (August 2009)-- most of the initial version - - Robert Bradshaw (July 2009) -- an early version of some specific code +- Robert Bradshaw (July 2009) -- an early version of some specific code EXAMPLES:: @@ -107,8 +107,7 @@ import sage.rings.number_field.number_field as number_field import sage.rings.all as rings from sage.rings.all import (ZZ, GF, QQ, CDF, - Integers, RealField, ComplexField, QuadraticField, - is_fundamental_discriminant) + Integers, RealField, ComplexField, QuadraticField) from sage.arith.all import (gcd, xgcd, lcm, prime_divisors, factorial, binomial) from sage.rings.factorint import factor_trial_division @@ -1133,8 +1132,10 @@ def is_kolyvagin(self): M = self.field() c = M.conductor() D = M.quadratic_field().discriminant() - if c.gcd(D) != 1: return False - if not c.is_squarefree(): return False + if c.gcd(D) != 1: + return False + if not c.is_squarefree(): + return False for p in c.prime_divisors(): if not is_inert(D,p): return False @@ -2302,8 +2303,10 @@ def is_kolyvagin_conductor(N, E, D, r, n, c): False """ ND = N*D - if ND.gcd(c) != 1: return False - if not c.is_squarefree(): return False + if ND.gcd(c) != 1: + return False + if not c.is_squarefree(): + return False P = c.prime_factors() if r is not None and len(P) != r: return False @@ -2592,7 +2595,8 @@ def points(self, beta=None): if g not in U: U.append(g) R.append(HeegnerPointOnX0N(N,D,c,f)) - if len(U) >= h: break + if len(U) >= h: + break a += 1 return tuple(sorted(R)) @@ -3490,7 +3494,7 @@ def point_exact(self, prec=53, algorithm='lll', var='a', optimize=False): f = self.x_poly_exact(prec, algorithm=algorithm) if f.degree() == 1: v = E.lift_x(-f[0], all=True) - if len(v) > 0: + if v: return v[0] g, d = make_monic(f) @@ -4163,7 +4167,7 @@ def point_exact(self, prec=53): f = x.algdep(2) K = self.quadratic_field() roots = [r[0] for r in f.roots(K)] - if len(roots) == 0: + if not roots: raise RuntimeError("insufficient precision to find exact point") if len(roots) == 1: X = roots[0] @@ -4179,7 +4183,7 @@ def point_exact(self, prec=53): Q = F.lift_x(X, all=True) if len(Q) == 1: return Q[0] - if len(Q) == 0: + if not Q: raise RuntimeError("insufficient precision") y = P[1] d = [abs(C(r[1])-y) for r in Q] @@ -5717,7 +5721,7 @@ def best_heegner_D(ell_1, ell_2): # both ell_1 and ell_2 are inert D = -5 while True: - if is_fundamental_discriminant(D) and \ + if number_field.is_fundamental_discriminant(D) and \ D % ell_1 and D % ell_2 and \ E.satisfies_heegner_hypothesis(D) and \ is_inert(D, ell_1) and is_inert(D, ell_2) and \ @@ -5761,7 +5765,8 @@ def kernel_of_reduction(ell): ell_1 = ell_1.next_prime() # compute kernel of reduction modulo ell_1 G1 = set(kernel_of_reduction(ell_1)) - if len(G1) == q: break + if len(G1) == q: + break ell_1 = ell_1.next_prime() # compute next good odd prime with distinct kernel of order q @@ -6085,8 +6090,9 @@ def class_number(D): ValueError: D (=-5) must be a fundamental discriminant """ if not number_field.is_fundamental_discriminant(D): - raise ValueError("D (=%s) must be a fundamental discriminant"%D) - return QuadraticField(D,'a').class_number() + raise ValueError("D (=%s) must be a fundamental discriminant" % D) + return QuadraticField(D, 'a').class_number() + def is_inert(D, p): r""" @@ -6236,7 +6242,8 @@ def satisfies_weak_heegner_hypothesis(N, D): """ if not number_field.is_fundamental_discriminant(D): return False - if D >= 0: return False + if D >= 0: + return False for p, e in N.factor(): if D % p == 0: if e > 1: @@ -6648,10 +6655,9 @@ def heegner_index(self, D, min_p=2, prec=5, descent_second_limit=12, verbose_mw However when we search higher, we find the points we need:: - sage: E.heegner_index(-8, descent_second_limit=16, check_rank=False) + sage: E.heegner_index(-8, descent_second_limit=16, check_rank=False) # long time 2.00000? - Two higher rank examples (of ranks 2 and 3):: sage: E = EllipticCurve('389a') @@ -7254,7 +7260,8 @@ def satisfies_heegner_hypothesis(self, D): if not number_field.is_fundamental_discriminant(D): return False D = ZZ(D) - if D >= 0: return False + if D >= 0: + return False if D.gcd(self.conductor()) != 1: return False for p, _ in self.conductor().factor(): From 727a5b00c3d7c08748484dcb400c7623569172d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 5 Dec 2019 10:12:33 +0100 Subject: [PATCH 278/340] cleaning tableau_residues.py --- src/sage/combinat/tableau_residues.py | 74 +++++++++++++++------------ 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/src/sage/combinat/tableau_residues.py b/src/sage/combinat/tableau_residues.py index 0bf2f6ff237..67d6e13a413 100644 --- a/src/sage/combinat/tableau_residues.py +++ b/src/sage/combinat/tableau_residues.py @@ -135,9 +135,9 @@ RowStandardTableauTuples_residue, RowStandardTableauTuples_residue_shape) -#-------------------------------------------------- +# ------------------------------------------------- # Residue sequences -#-------------------------------------------------- +# ------------------------------------------------- # needed for __classcall_private__ @add_metaclass(InheritComparisonClasscallMetaclass) @@ -216,7 +216,7 @@ class ResidueSequence(ClonableArray): def __classcall_private__(cls, e, multicharge, residues=None, check=True): r""" Magic to allow class to accept a list (which is not hashable) instead - of a partition (which is). At the same time we ensue that every + of a partition (which is). At the same time we ensure that every residue sequence is constructed as an ``element_class`` call of an appropriate parent. @@ -303,9 +303,10 @@ def __str__(self, join='with'): sage: ResidueSequence(3,(0,0,1),[0,0,1,1,2,2,3,3]).__str__('and') '3-residue sequence (0,0,1,1,2,2,0,0) and multicharge (0,0,1)' """ - return '{e}-residue sequence ({res}) {join} multicharge ({charge})'.format( - e=self.quantum_characteristic(), res=','.join('%s'%r for r in self), - join=join, charge=','.join('%s'%r for r in self.multicharge())) + string = '{e}-residue sequence ({res}) {join} multicharge ({charge})' + return string.format(e=self.quantum_characteristic(), + res=','.join('%s' % r for r in self), join=join, + charge=','.join('%s' % r for r in self.multicharge())) def __getitem__(self, k): r""" @@ -336,7 +337,7 @@ def __getitem__(self, k): IndexError: k must be in the range 1, 2, ..., 8 """ try: - return ClonableArray.__getitem__(self, k-1) + return ClonableArray.__getitem__(self, k - 1) except (IndexError, KeyError): raise IndexError('k must be in the range 1, 2, ..., {}'.format(len(self))) @@ -352,7 +353,7 @@ def residues(self): """ return [r for r in self] - def restrict(self,m): + def restrict(self, m): r""" Return the subsequence of this sequence of length `m`. @@ -391,36 +392,39 @@ def restrict_row(self, cell, row): sage: ResidueSequence(3, [1,0], [0,1,2,2,0,1]).restrict_row((1,1,2),1) 3-residue sequence (2,0,1,0,1) with multicharge (1,0) """ - residues = self.residues() # residue sequence - residues.reverse() # reversed residue sequence + residues = self.residues() # residue sequence + residues.reverse() # reversed residue sequence if residues[0] + row == residues[0]: - # if the residues in the two rows are the same we don't need to do - # anything special - return self.restrict(len(residues)-1) + # if the residues in the two rows are the same we do not + # need to do anything special + return self.restrict(len(residues) - 1) # determine the sets of residues, one_res and two_res, that need to be # interchanged in order to swap the corresponding rows - row_len = cell[-1] # length of the row being swapped - one_res = [0] # last row of tableau will move - two_res = [0] # will prune this entry later + row_len = cell[-1] # length of the row being swapped + one_res = [0] # last row of tableau will move + two_res = [0] # will prune this entry later try: - for c in range(1, row_len+1): + for c in range(1, row_len + 1): # residues decrease by 1 from right to left in each row - one_res.append(residues.index(residues[0]-c, one_res[c-1]+1)) - for c in range(row_len+1): - two_res.append(residues.index(residues[0]-c+row, two_res[c]+1)) + one_res.append(residues.index(residues[0] - c, + one_res[c - 1] + 1)) + for c in range(row_len + 1): + two_res.append(residues.index(residues[0] - c + row, + two_res[c] + 1)) while two_res[-1] in one_res: # entries in one_res and two_res must be disjoint - two_res[-1] = residues.index(residues[0]-c+row, two_res[-1]+1) + two_res[-1] = residues.index(residues[0] - c + row, + two_res[-1] + 1) except ValueError: return None # now add row to the residues in two_res and subtract row from those in # one_res - for c in range(row_len+1): + for c in range(row_len + 1): residues[one_res[c]] += row - residues[two_res[c+1]] -= row # jump over two_res[0] + residues[two_res[c + 1]] -= row # jump over two_res[0] # remove the first residue, reverse the order and return return ResidueSequence(self.quantum_characteristic(), @@ -463,7 +467,7 @@ def swap_residues(self, i, j): try: # we have overridden __getitem__ so that indices are 1-based but # __setitem__ is still 0-based so we need to renormalise the LHS - swap[i-1], swap[j-1] = self[j], self[i] + swap[i - 1], swap[j - 1] = self[j], self[i] except IndexError: raise IndexError('%s and %s must be between 1 and %s' % (i, j, self.size())) return swap @@ -498,7 +502,8 @@ def standard_tableaux(self, shape=None): if shape is None: return StandardTableaux_residue(residue=self) else: - return StandardTableaux_residue_shape(residue=self,shape=PartitionTuple(shape)) + return StandardTableaux_residue_shape(residue=self, + shape=PartitionTuple(shape)) def row_standard_tableaux(self, shape=None): r""" @@ -660,7 +665,7 @@ def level(self): def size(self): r""" - Return the size of the residue sequence. + Return the size of the residue sequence. This is the size, or length, of the residue sequence, which is the same as the size of the :meth:`standard_tableaux` that belong to @@ -722,7 +727,7 @@ def __init__(self, e, multicharge=(0,)): """ self._quantum_characteristic = e self._base_ring = IntegerModRing(self._quantum_characteristic) - self._multicharge=tuple(self._base_ring(i) for i in multicharge) + self._multicharge = tuple(self._base_ring(i) for i in multicharge) super(ResidueSequences, self).__init__(category=Sets()) def _repr_(self): @@ -753,7 +758,7 @@ def an_element(self): """ return self.element_class(self, self._multicharge, check=True) - def _cell_residue_level_one(self, r,c): + def _cell_residue_level_one(self, r, c): r""" Return the residue a cell of level 1. It is called indirectly via :meth:`cell_residue`. @@ -764,12 +769,13 @@ def _cell_residue_level_one(self, r,c): sage: ResidueSequences(3).cell_residue(1,0) # indirect doctest 2 """ - return self._base_ring(c-r) + return self._base_ring(c - r) - def _cell_residue_higher_levels(self, k,r,c): + def _cell_residue_higher_levels(self, k, r, c): r""" - Return the residue a cell of level greater than 1. It is called - indirectly via :meth:`cell_residue`. + Return the residue a cell of level greater than 1. + + It is called indirectly via :meth:`cell_residue`. EXAMPLES:: @@ -777,7 +783,7 @@ def _cell_residue_higher_levels(self, k,r,c): sage: ResidueSequences(3,(0,0,1)).cell_residue(2,0,0) # indirect doctest 1 """ - return self._base_ring(self._multicharge[k]+c-r) + return self._base_ring(self._multicharge[k] + c - r) @lazy_attribute def cell_residue(self, *args): @@ -851,4 +857,4 @@ def check_element(self, element): 3-residue sequence (2,0,1,1,2,2,0,0) with multicharge (0,0,1) """ if any(r not in self._base_ring for r in element): - raise ValueError('not a {}-residue sequence {}'.format(self._quantum_characteristic)) + raise ValueError('not a {}-residue sequence'.format(self._quantum_characteristic)) From 6f2e4e9f6804c0c3e3e427b8458068d601f533bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 5 Dec 2019 15:04:09 +0100 Subject: [PATCH 279/340] better unicode art for chain complex --- src/sage/homology/chain_complex.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/homology/chain_complex.py b/src/sage/homology/chain_complex.py index 001510d5e31..2bf956a1861 100644 --- a/src/sage/homology/chain_complex.py +++ b/src/sage/homology/chain_complex.py @@ -460,13 +460,13 @@ def _unicode_art_(self): sage: unicode_art(c) ⎛1⎞ d_2 d_1 ⎛4⎞ d_0 ⎜2⎟ d_-1 - 0 ⟵──── (0) ⟵──── ⎝5⎠ ⟵──── ⎝3⎠ ⟵───── 0 + 0 <──── (0) <──── ⎝5⎠ <──── ⎝3⎠ <───── 0 """ from sage.typeset.unicode_art import UnicodeArt def arrow_art(d): d_str = [u' d_{0} '.format(d)] - arrow = u' ⟵' + u'─' * (len(d_str[0]) - 3) + u' ' + arrow = u' <' + u'─' * (len(d_str[0]) - 3) + u' ' d_str.append(arrow) return UnicodeArt(d_str, baseline=0) @@ -1803,22 +1803,22 @@ def _unicode_art_(self): sage: unicode_art(C) ⎛3 0 0⎞ (0 0) ⎝0 0 0⎠ - 0 ⟵── C_2 ⟵──── C_1 ⟵────── C_0 ⟵── 0 + 0 <── C_2 <──── C_1 <────── C_0 <── 0 sage: one = matrix(ZZ, [[1]]) sage: D = ChainComplex({0: one, 2: one, 6:one}) sage: unicode_art(D) (1) (1) (0) (1) - 0 ⟵── C_7 ⟵── C_6 ⟵── 0 ... 0 ⟵── C_3 ⟵── C_2 ⟵── C_1 ⟵── C_0 ⟵── 0 + 0 <── C_7 <── C_6 <── 0 ... 0 <── C_3 <── C_2 <── C_1 <── C_0 <── 0 """ from sage.typeset.unicode_art import UnicodeArt def arrow_art(n): d_n = self.differential(n) if not d_n.nrows() or not d_n.ncols(): - return UnicodeArt([u'⟵──']) + return UnicodeArt([u'<──']) d_str = list(d_n._unicode_art_()) - arrow = u'⟵' + u'─' * (len(d_str[0]) - 1) + arrow = u'<' + u'─' * (len(d_str[0]) - 1) d_str.append(arrow) return UnicodeArt(d_str) From 5b54ee73c5fbd24e0b4bd19abd610bba202eba85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Fri, 6 Dec 2019 12:12:38 +1300 Subject: [PATCH 280/340] Re-add some LDFLAGS that are needed in suitesparse --- build/pkgs/suitesparse/patches/03-buildflags.patch | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/build/pkgs/suitesparse/patches/03-buildflags.patch b/build/pkgs/suitesparse/patches/03-buildflags.patch index aabd1dbc96d..ed1f90d4f0a 100644 --- a/build/pkgs/suitesparse/patches/03-buildflags.patch +++ b/build/pkgs/suitesparse/patches/03-buildflags.patch @@ -5,9 +5,12 @@ This prepends $(DESTDIR) directly to all of $(INSTALL_LIB), $(INSTALL_INCLUDE), and $(INSTALL_DOC), as these variables only affect where built files are copied to, and do not affect the contents of the files. -However, we also remove additional LDFLAGS added by this Makefile (for +However, we also remove some additional LDFLAGS added by this Makefile (for -L$SAGE_LOCAL and -Wl,-rpath=$SAGE_LOCAL/lib) since we already add those in the standard SPKG built environment. +Note that -L$(INSTALL_LIB) cannot be removed from LDFLAGS unless the package +is broken into components. It is necessary as the components are progressively +installed in INSTALL_LIB one after the other. For https://trac.sagemath.org/ticket/28832 --- a/SuiteSparse_config/SuiteSparse_config.mk 2019-12-02 14:21:18.956000000 +0000 @@ -25,14 +28,6 @@ For https://trac.sagemath.org/ticket/28832 #--------------------------------------------------------------------------- # parallel make -@@ -153,7 +153,6 @@ - # It places its shared *.so libraries in SuiteSparse/lib. - # Linux also requires the -lrt library (see below) - LDLIBS ?= -lm -- LDFLAGS += -L$(INSTALL_LIB) - - # NOTE: Use of the Intel MKL BLAS is strongly recommended. The OpenBLAS can - # result in severe performance degradation, in CHOLMOD in particular. @@ -358,7 +357,7 @@ ifeq ($(UNAME),Linux) From 8d795908b343506192a5f9cdcaab76a2a7624180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Fri, 6 Dec 2019 14:10:15 +1300 Subject: [PATCH 281/340] fix install_name on OS X --- .../suitesparse/patches/03-buildflags.patch | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/build/pkgs/suitesparse/patches/03-buildflags.patch b/build/pkgs/suitesparse/patches/03-buildflags.patch index ed1f90d4f0a..fd32c996127 100644 --- a/build/pkgs/suitesparse/patches/03-buildflags.patch +++ b/build/pkgs/suitesparse/patches/03-buildflags.patch @@ -11,11 +11,16 @@ in the standard SPKG built environment. Note that -L$(INSTALL_LIB) cannot be removed from LDFLAGS unless the package is broken into components. It is necessary as the components are progressively installed in INSTALL_LIB one after the other. +Because we don't install directly in the final location, install_name also becomes +wrong on OS X which means the libraries cannot be loaded. So we have to provide +a correct install_name as well. For https://trac.sagemath.org/ticket/28832 ---- a/SuiteSparse_config/SuiteSparse_config.mk 2019-12-02 14:21:18.956000000 +0000 -+++ b/SuiteSparse_config/SuiteSparse_config.mk 2019-12-02 14:33:49.204000000 +0000 -@@ -55,9 +55,9 @@ +diff --git a/SuiteSparse_config/SuiteSparse_config.mk b/SuiteSparse_config/SuiteSparse_config.mk +index 0a09188..fd1c0b0 100644 +--- a/SuiteSparse_config/SuiteSparse_config.mk ++++ b/SuiteSparse_config/SuiteSparse_config.mk +@@ -55,9 +55,9 @@ SUITESPARSE_VERSION = 5.6.0 # which puts the libraries in /yada/mylibs, include files in /yoda/myinc, # and documentation in /solo/mydox. INSTALL ?= $(SUITESPARSE) @@ -28,7 +33,7 @@ For https://trac.sagemath.org/ticket/28832 #--------------------------------------------------------------------------- # parallel make -@@ -358,7 +357,7 @@ +@@ -358,7 +358,7 @@ SUITESPARSE_VERSION = 5.6.0 ifeq ($(UNAME),Linux) # add the realtime library, librt, and SuiteSparse/lib @@ -37,3 +42,13 @@ For https://trac.sagemath.org/ticket/28832 endif #--------------------------------------------------------------------------- +@@ -463,7 +463,8 @@ else + SO_TARGET = $(LIBRARY).$(VERSION).dylib + SO_OPTS += -dynamiclib -compatibility_version $(SO_VERSION) \ + -current_version $(VERSION) \ +- -shared -undefined dynamic_lookup ++ -shared -undefined dynamic_lookup \ ++ -install_name $(INSTALL_LIB)/$(SO_MAIN) + # When a Mac *.dylib file is moved, this command is required + # to change its internal name to match its location in the filesystem: + SO_INSTALL_NAME = install_name_tool -id From efeab2f799c7d4d6b2d89e110b9ddaffc77b2712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Fri, 6 Dec 2019 19:27:06 +1300 Subject: [PATCH 282/340] correct the final path in install_name --- build/pkgs/suitesparse/patches/03-buildflags.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/suitesparse/patches/03-buildflags.patch b/build/pkgs/suitesparse/patches/03-buildflags.patch index fd32c996127..20da6535d82 100644 --- a/build/pkgs/suitesparse/patches/03-buildflags.patch +++ b/build/pkgs/suitesparse/patches/03-buildflags.patch @@ -48,7 +48,7 @@ index 0a09188..fd1c0b0 100644 -current_version $(VERSION) \ - -shared -undefined dynamic_lookup + -shared -undefined dynamic_lookup \ -+ -install_name $(INSTALL_LIB)/$(SO_MAIN) ++ -install_name $(INSTALL)/lib/$(SO_MAIN) # When a Mac *.dylib file is moved, this command is required # to change its internal name to match its location in the filesystem: SO_INSTALL_NAME = install_name_tool -id From 5b648efb97091058d39b3a9db547ce5cd35c94c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 6 Dec 2019 10:25:23 +0100 Subject: [PATCH 283/340] clean the doc of Monte-Carlo method --- src/sage/calculus/integration.pyx | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/sage/calculus/integration.pyx b/src/sage/calculus/integration.pyx index da5c3aff464..d0a5983eb60 100644 --- a/src/sage/calculus/integration.pyx +++ b/src/sage/calculus/integration.pyx @@ -398,13 +398,17 @@ cdef double c_monte_carlo_ff(double *x, size_t dim, void *params): ( params).call_c(x, &result) return result -def monte_carlo_integral(func, xl, xu, size_t calls, algorithm='plain', params=None): + +def monte_carlo_integral(func, xl, xu, size_t calls, algorithm='plain', + params=None): """ - Integrate ``func``. + Integrate ``func`` by Monte-Carlo method. + + Integrate ``func`` over the ``dim``-dimensional hypercubic region + defined by the lower and upper limits in the arrays ``xl`` and + ``xu``, each of size ``dim``. - Integrate ``func`` over the dim-dimensional hypercubic region defined by - the lower and upper limits in the arrays xl and xu, each of size dim. - The integration uses a fixed number of function calls calls and obtains + The integration uses a fixed number of function calls and obtains random sampling points using the default gsl's random number generator. ALGORITHM: Uses calls to the GSL (GNU Scientific Library) C library. @@ -412,19 +416,19 @@ def monte_carlo_integral(func, xl, xu, size_t calls, algorithm='plain', params=N INPUT: - - ``func`` -- The function to integrate + - ``func`` -- the function to integrate - ``params`` -- used to pass parameters to your function - ``xl`` -- list of lower limits - ``xu`` -- list of upper limits - - ``calls`` -- Number of functions calls used. + - ``calls`` -- number of functions calls used - ``algorithm`` -- valid choices are: * 'plain' -- The plain Monte Carlo algorithm samples points randomly - from the integration region to estimate the integral and its error. + from the integration region to estimate the integral and its error. * 'miser' -- The MISER algorithm of Press and Farrar is based on - recursive stratified sampling + recursive stratified sampling * 'vegas' -- The VEGAS algorithm of Lepage is based on importance - sampling. + sampling. EXAMPLES:: @@ -497,13 +501,13 @@ def monte_carlo_integral(func, xl, xu, size_t calls, algorithm='plain', params=N Traceback (most recent call last): ... ValueError: The function to be integrated depends on 2 variables (x, y), - and so cannot be integrated in 1 dimensions. Please addmore items in + and so cannot be integrated in 1 dimensions. Please add more items in upper and lower limits sage: monte_carlo_integral(f, [0], [2], 100) Traceback (most recent call last): ... ValueError: The function to be integrated depends on 2 variables ('x', 'y'), - and so cannot be integrated in 1 dimensions. Please addmore items in + and so cannot be integrated in 1 dimensions. Please add more items in upper and lower limits AUTHORS: @@ -574,7 +578,7 @@ def monte_carlo_integral(func, xl, xu, size_t calls, algorithm='plain', params=N elif len(vars) > target_dim: raise ValueError(("The function to be integrated depends on " "{} variables {}, and so cannot be " - "integrated in {} dimensions. Please add" + "integrated in {} dimensions. Please add " "more items in upper and lower limits" ).format(len(vars), tuple(vars), target_dim)) From 5ee018a1b648ab1228d382697b818ddd62bd61dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 5 Dec 2019 14:27:45 +0100 Subject: [PATCH 284/340] trac 28632 introduced Narayana numbers and Eulerian polynomials --- src/sage/combinat/combinat.py | 141 +++++++++++++++++++++++++++++++--- 1 file changed, 130 insertions(+), 11 deletions(-) diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index 7e7411a69f7..ca96c644015 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -13,14 +13,17 @@ - Catalan numbers, :func:`catalan_number` (not to be confused with the Catalan constant) +- Narayana numbers, :func:`narayana_number` + - Euler numbers, :func:`euler_number` (Maxima) +- Eulerian polynomial, :func:`eulerian_polynomial` + - Fibonacci numbers, :func:`fibonacci` (PARI) and :func:`fibonacci_number` (GAP) The PARI version is better. -- Lucas numbers, :func:`lucas_number1`, - :func:`lucas_number2`. +- Lucas numbers, :func:`lucas_number1`, :func:`lucas_number2`. - Stirling numbers, :func:`stirling_number1`, :func:`stirling_number2`. @@ -130,7 +133,7 @@ --------------------- """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 David Joyner , # 2007 Mike Hansen , # 2006 William Stein @@ -139,19 +142,21 @@ # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import absolute_import from six.moves import range from six import iteritems, add_metaclass from sage.interfaces.all import maxima from sage.rings.all import ZZ, QQ, Integer, infinity -from sage.arith.all import bernoulli, binomial, factorial +from sage.arith.all import bernoulli, factorial from sage.rings.polynomial.polynomial_element import Polynomial +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.libs.all import pari from sage.misc.prandom import randint from sage.misc.all import prod +from sage.misc.cachefunc import cached_function from sage.structure.sage_object import SageObject from sage.structure.parent import Parent from sage.misc.lazy_attribute import lazy_attribute @@ -462,7 +467,42 @@ def catalan_number(n): return ZZ.zero() if n == -1: return QQ((-1, 2)) - return binomial(2 * n, n).divide_knowing_divisible_by(n + 1) + return (2 * n).binomial(n).divide_knowing_divisible_by(n + 1) + + +def narayana_number(n, k): + r""" + Return the Narayana number of index ``(n, k)``. + + For every integer `n \geq 1`, the sum of Narayana numbers `\sum_k N_{n,k}` + is the Catalan number `C_n`. + + INPUT: + + - ``n`` -- an integer + + - ``k`` -- an integer between ``0`` and ``n - 1`` + + OUTPUT: + + an integer + + EXAMPLES:: + + sage: from sage.combinat.combinat import narayana_number + sage: [narayana_number(3, i) for i in range(3)] + [1, 3, 1] + sage: sum(narayana_number(7,i) for i in range(7)) == catalan_number(7) + True + + REFERENCES: + + - wikipedia:`Narayana_number` + """ + n = ZZ(n) + if n <= 0: + return ZZ.zero() + return (n.binomial(k + 1) * n.binomial(k)).divide_knowing_divisible_by(n) def euler_number(n, algorithm='flint'): @@ -492,6 +532,11 @@ def euler_number(n, algorithm='flint'): ... ValueError: n (=-1) must be a nonnegative integer + TESTS:: + + sage: euler_number(6, 'maxima') + -61 + REFERENCES: - :wikipedia:`Euler_number` @@ -500,7 +545,7 @@ def euler_number(n, algorithm='flint'): if n < 0: raise ValueError("n (=%s) must be a nonnegative integer" % n) if algorithm == 'maxima': - return ZZ(maxima.eval("euler(%s)" % n)) + return ZZ(maxima.euler(n)) elif algorithm == 'flint': import sage.libs.flint.arith return sage.libs.flint.arith.euler_number(n) @@ -508,6 +553,81 @@ def euler_number(n, algorithm='flint'): raise ValueError("algorithm must be 'flint' or 'maxima'") +@cached_function +def eulerian_number(n, k): + """ + Return the Eulerian number of index ``(n, k)``. + + This is the coefficient of `t^k` in the Eulerian polynomial `A_n(t)`. + + .. SEEALSO:: :func:`eulerian_polynomial` + + EXAMPLES:: + + sage: from sage.combinat.combinat import eulerian_number + sage: [eulerian_number(5,i) for i in range(5)] + [1, 26, 66, 26, 1] + """ + n = ZZ(n) + if k == 0 or k == n - 1: + return ZZ.one() + s = (n - k) * eulerian_number(n - 1, k - 1) + s += (k + 1) * eulerian_number(n - 1, k) + return s + + +@cached_function +def eulerian_polynomial(n, algorithm='derivative'): + """ + Return the Eulerian polynomial of index ``n``. + + This is the generating polynomial counting permutations in the + symmetric group `S_n` according to their number of descents. + + INPUT: + + - ``n`` -- an integer + + - ``algorithm`` -- ``derivative`` (default) or ``coeffs`` + + OUTPUT: + + polynomial in one variable ``t`` + + .. SEEALSO:: :func:`eulerian_number` + + EXAMPLES:: + + sage: from sage.combinat.combinat import eulerian_polynomial + sage: eulerian_polynomial(5) + t^4 + 26*t^3 + 66*t^2 + 26*t + 1 + + TESTS:: + + sage: eulerian_polynomial(7)(1) == factorial(7) + True + + sage: eulerian_polynomial(5, algorithm='coeffs') + t^4 + 26*t^3 + 66*t^2 + 26*t + 1 + + REFERENCES: + + - :wikipedia:`Eulerian_number` + """ + n = ZZ(n) + R = PolynomialRing(ZZ, 't') + if n < 0: + return R.zero() + if n == 1: + return R.one() + t = R.gen() + if algorithm == 'derivative': + A = eulerian_polynomial(n - 1, algorithm=algorithm) + return t * (1 - t) * A.derivative() + (1 + (n - 1) * t) * A + elif algorithm == 'coeffs': + return R([eulerian_number(n, k) for k in range(n)]) + + def fibonacci(n, algorithm="pari"): """ Return the `n`-th Fibonacci number. @@ -2570,7 +2690,7 @@ def number_of_unordered_tuples(S, k, algorithm='naive'): 1 """ if algorithm == 'naive': - return ZZ( len(set(S)) + k - 1 ).binomial(k) # The set is there to avoid duplicates + return ZZ(len(set(S)) + k - 1).binomial(k) # The set is there to avoid duplicates if algorithm == 'gap': k = ZZ(k) from sage.libs.gap.libgap import libgap @@ -2694,7 +2814,6 @@ def bell_polynomial(n, k): - Blair Sutton (2009-01-26) - Thierry Monteil (2015-09-29): the result must always be a polynomial. """ - from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.combinat.partition import Partitions R = PolynomialRing(ZZ, 'x', n-k+1) vars = R.gens() @@ -2880,7 +2999,7 @@ def bernoulli_polynomial(x, n): return x - ZZ(1)/2 k = n.mod(2) - coeffs = [0]*k + sum(([binomial(n, i)*bernoulli(n-i), 0] + coeffs = [0]*k + sum(([n.binomial(i) * bernoulli(n-i), 0] for i in range(k, n+1, 2)), []) coeffs[-3] = -n/2 From ac4fd9d01ddddf11e262cb55042922717727f075 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Wed, 16 Oct 2019 08:56:06 +0200 Subject: [PATCH 285/340] H -> facet_names; V -> Vrep --- .../combinatorial_polyhedron/base.pxd | 24 ++++----- .../combinatorial_polyhedron/base.pyx | 52 +++++++++---------- .../combinatorial_face.pxd | 4 +- .../combinatorial_face.pyx | 24 ++++----- .../face_iterator.pxd | 4 +- .../face_iterator.pyx | 4 +- .../polyhedron_face_lattice.pxd | 4 +- .../polyhedron_face_lattice.pyx | 4 +- 8 files changed, 63 insertions(+), 57 deletions(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd index 0a998c2ca9e..57ff89c2499 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd @@ -9,17 +9,17 @@ from .polyhedron_face_lattice cimport PolyhedronFaceLattice @cython.final cdef class CombinatorialPolyhedron(SageObject): # Do not assume any of those attributes to be initialized, use the corresponding methods instead. - cdef tuple _V # the names of VRep, if they exist - cdef tuple _H # the names of HRep, if they exist - cdef tuple _equalities # stores equalities, given on input (might belong to Hrep) - cdef int _dimension # stores dimension, -2 on init + cdef tuple _Vrep # the names of VRep, if they exist + cdef tuple _facet_names # the names of HRep without equalities, if they exist + cdef tuple _equalities # stores equalities, given on input (might belong to Hrep) + cdef int _dimension # stores dimension, -2 on init cdef unsigned int _n_Hrepresentation # Hrepr might include equalities cdef unsigned int _n_Vrepresentation # Vrepr might include rays/lines - cdef size_t _n_facets # length Hrep without equalities - cdef bint _bounded # ``True`` iff Polyhedron is bounded - cdef ListOfFaces _bitrep_facets # facets in bit representation - cdef ListOfFaces _bitrep_Vrepr # vertices in bit representation - cdef ListOfFaces _far_face # a 'face' containing all none-vertices of Vrepr + cdef size_t _n_facets # length Hrep without equalities + cdef bint _bounded # ``True`` iff Polyhedron is bounded + cdef ListOfFaces _bitrep_facets # facets in bit representation + cdef ListOfFaces _bitrep_Vrepr # vertices in bit representation + cdef ListOfFaces _far_face # a 'face' containing all none-vertices of Vrepr cdef tuple _far_face_tuple cdef tuple _f_vector @@ -38,10 +38,10 @@ cdef class CombinatorialPolyhedron(SageObject): cdef size_t _n_ridges cdef size_t **_face_lattice_incidences # stores incidences in Hasse diagram labeled indices of the faces cdef size_t _n_face_lattice_incidences - cdef PolyhedronFaceLattice _all_faces # class to generate Hasse diagram incidences + cdef PolyhedronFaceLattice _all_faces # class to generate Hasse diagram incidences - cdef tuple V(self) - cdef tuple H(self) + cdef tuple Vrep(self) + cdef tuple facet_names(self) cdef tuple equalities(self) cdef unsigned int n_Vrepresentation(self) cdef unsigned int n_Hrepresentation(self) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index 76d8a981653..b9f81fd5ffd 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -349,10 +349,10 @@ cdef class CombinatorialPolyhedron(SageObject): if Vrepr: # store vertices names - self._V = tuple(Vrepr) - Vinv = {v: i for i,v in enumerate(self._V)} + self._Vrep = tuple(Vrepr) + Vinv = {v: i for i,v in enumerate(self._Vrep)} else: - self._V = None + self._Vrep = None Vinv = None if facets: @@ -367,11 +367,11 @@ cdef class CombinatorialPolyhedron(SageObject): # will be detected. if not facets[i].is_inequality(): test[i] = 0 - self._H = tuple(facets[i] for i in range(len(facets)) if test[i]) + self._facet_names = tuple(facets[i] for i in range(len(facets)) if test[i]) self._equalities = tuple(facets[i] for i in range(len(facets)) if not test[i]) else: - self._H = None + self._facet_names = None if data == [] or data == (): # Handling the empty polyhedron. @@ -419,22 +419,22 @@ cdef class CombinatorialPolyhedron(SageObject): if is_iterator(data): data = tuple(data) - if self._V is None: + if self._Vrep is None: # Get the names of the Vrepr. Vrepr = sorted(set.union(*map(set, data))) n_Vrepresentation = len(Vrepr) if Vrepr != range(len(Vrepr)): - self._V = tuple(Vrepr) - Vinv = {v: i for i,v in enumerate(self._V)} + self._Vrep = tuple(Vrepr) + Vinv = {v: i for i,v in enumerate(self._Vrep)} else: # Assuming the user gave as correct names for the vertices # and labeled them instead by `0,...,n`. - n_Vrepresentation = len(self._V) + n_Vrepresentation = len(self._Vrep) self._n_Vrepresentation = n_Vrepresentation # Relabel the Vrepr to be `0,...,n`. - if self._V is not None: + if self._Vrep is not None: def f(v): return Vinv[v] else: def f(v): return int(v) @@ -568,8 +568,8 @@ cdef class CombinatorialPolyhedron(SageObject): A vertex at (0, 0, 0), A ray in the direction (0, 1, 0)) """ - if self.V() is not None: - return self.V() + if self.Vrep() is not None: + return self.Vrep() else: return tuple(smallInteger(i) for i in range(self.n_Vrepresentation())) @@ -590,8 +590,8 @@ cdef class CombinatorialPolyhedron(SageObject): An inequality (0, 1, 1) x - 3 >= 0, An inequality (0, 0, 1) x - 1 >= 0) """ - if self.H() is not None: - return self.equalities() + self.H() + if self.facet_names() is not None: + return self.equalities() + self.facet_names() else: return tuple(smallInteger(i) for i in range(self.n_Hrepresentation())) @@ -724,8 +724,8 @@ cdef class CombinatorialPolyhedron(SageObject): """ if unlikely(self.dimension() == 0): # Handling the case of a trivial polyhedron of dimension `0`. - if names and self.V(): - return (self.V()[0],) + if names and self.Vrep(): + return (self.Vrep()[0],) else: return (smallInteger(0),) if not self.is_bounded(): @@ -739,8 +739,8 @@ cdef class CombinatorialPolyhedron(SageObject): except StopIteration: # The Polyhedron has no vertex. return () - if names and self.V(): - return tuple(self.V()[i] for i in range(self.n_Vrepresentation()) if not i in self.far_face_tuple()) + if names and self.Vrep(): + return tuple(self.Vrep()[i] for i in range(self.n_Vrepresentation()) if not i in self.far_face_tuple()) else: return tuple(smallInteger(i) for i in range(self.n_Vrepresentation()) if not i in self.far_face_tuple()) @@ -930,8 +930,8 @@ cdef class CombinatorialPolyhedron(SageObject): # with each array containing ``len_edge_list`` of edges. # Mapping the indices of the Vrepr to the names, if requested. - if self.V() is not None and names is True: - def f(size_t i): return self.V()[i] + if self.Vrep() is not None and names is True: + def f(size_t i): return self.Vrep()[i] else: def f(size_t i): return smallInteger(i) @@ -1113,8 +1113,8 @@ cdef class CombinatorialPolyhedron(SageObject): # with each array containing ``len_ridge_list`` of ridges. # Mapping the indices of the Vepr to the names, if requested. - if self.H() is not None and names is True: - def f(size_t i): return self.H()[i] + if self.facet_names() is not None and names is True: + def f(size_t i): return self.facet_names()[i] else: def f(size_t i): return smallInteger(i) @@ -1537,19 +1537,19 @@ cdef class CombinatorialPolyhedron(SageObject): # Let ``_all_faces`` determine Vrepresentation. return self._all_faces.get_face(dim, newindex) - cdef tuple V(self): + cdef tuple Vrep(self): r""" Return the names of the Vrepresentation, if they exist. Else return ``None``. """ - return self._V + return self._Vrep - cdef tuple H(self): + cdef tuple facet_names(self): r""" Return the names Hrepresentatives, which are facets. If not given, return ``None``. """ - return self._H + return self._facet_names cdef tuple equalities(self): r""" diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pxd b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pxd index aee12405708..ef5ea9c117c 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pxd +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pxd @@ -17,9 +17,11 @@ cdef class CombinatorialFace(SageObject): cdef int _dimension # dimension of current face, dual dimension if ``dual`` cdef int _ambient_dimension # dimension of the polyhedron cdef size_t face_length # stores length of the faces in terms of uint64_t - cdef tuple _V, _H, _equalities # some copies from ``CombinatorialPolyhedron`` cdef size_t _hash_index # an index to give different hashes for all faces of a Polyhedron + # some copies from ``CombinatorialPolyhedron`` + cdef tuple _ambient_Vrep, _ambient_facets, _equalities + # Atoms and coatoms are the vertices/facets of the Polyedron. # If ``dual == 0``, then coatoms are facets, atoms vertices and vice versa. cdef ListOfFaces atoms, coatoms diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx index 45b18d87360..6994a5f7195 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx @@ -173,8 +173,8 @@ cdef class CombinatorialFace(SageObject): self._dimension = it.current_dimension self._ambient_dimension = it.dimension self.face_length = it.face_length - self._V = it._V - self._H = it._H + self._ambient_Vrep = it._Vrep + self._ambient_facets = it._facet_names self._equalities = it._equalities self.atoms = it.atoms self.coatoms = it.coatoms @@ -196,8 +196,8 @@ cdef class CombinatorialFace(SageObject): self._dimension = dimension self._ambient_dimension = all_faces.dimension self.face_length = all_faces.face_length - self._V = all_faces._V - self._H = all_faces._H + self._ambient_Vrep = all_faces._Vrep + self._ambient_facets = all_faces._facet_names self._equalities = all_faces._equalities self.atoms = all_faces.atoms self.coatoms = all_faces.coatoms @@ -367,8 +367,8 @@ cdef class CombinatorialFace(SageObject): if self._dual: # if dual, the Vrepresenation corresponds to the coatom-representation length = self.set_coatom_repr() - if names and self._V: - return tuple(self._V[self.coatom_repr[i]] + if names and self._ambient_Vrep: + return tuple(self._ambient_Vrep[self.coatom_repr[i]] for i in range(length)) else: return tuple(smallInteger(self.coatom_repr[i]) @@ -376,8 +376,8 @@ cdef class CombinatorialFace(SageObject): else: # if not dual, the Vrepresenation corresponds to the atom-representation length = self.set_atom_repr() - if names and self._V: - return tuple(self._V[self.atom_repr[i]] + if names and self._ambient_Vrep: + return tuple(self._ambient_Vrep[self.atom_repr[i]] for i in range(length)) else: return tuple(smallInteger(self.atom_repr[i]) @@ -486,8 +486,8 @@ cdef class CombinatorialFace(SageObject): if not self._dual: # if not dual, the facet-represention corresponds to the coatom-representation length = self.set_coatom_repr() # fill self.coatom_repr_face - if names and self._H: - return tuple(self._H[self.coatom_repr[i]] + if names and self._ambient_facets: + return tuple(self._ambient_facets[self.coatom_repr[i]] for i in range(length)) + self._equalities else: return tuple(smallInteger(self.coatom_repr[i]) @@ -495,8 +495,8 @@ cdef class CombinatorialFace(SageObject): else: # if dual, the facet-represention corresponds to the atom-representation length = self.set_atom_repr() # fill self.atom_repr_face - if names and self._H: - return tuple(self._H[self.atom_repr[i]] + if names and self._ambient_facets: + return tuple(self._ambient_facets[self.atom_repr[i]] for i in range(length)) + self._equalities else: return tuple(smallInteger(self.atom_repr[i]) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd index dabb063942e..14e5253c98f 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd @@ -19,7 +19,9 @@ cdef class FaceIterator(SageObject): cdef MemoryAllocator _mem cdef tuple newfaces_lists # tuple to hold the ListOfFaces corresponding to maybe_newfaces cdef size_t face_length # stores length of the faces in terms of uint64_t - cdef tuple _V, _H, _equalities # some copies from ``CombinatorialPolyhedron`` + + # some copies from ``CombinatorialPolyhedron`` + cdef tuple _Vrep, _facet_names, _equalities # Atoms and coatoms are the vertices/facets of the Polyedron. # If ``dual == 0``, then coatoms are facets, atoms vertices and vice versa. diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx index b1e074ec93b..2636111cca6 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx @@ -446,8 +446,8 @@ cdef class FaceIterator(SageObject): self.coatoms = C.bitrep_facets() self.atoms = C.bitrep_Vrepr() self.face_length = self.coatoms.face_length - self._V = C.V() - self._H = C.H() + self._Vrep = C.Vrep() + self._facet_names = C.facet_names() self._equalities = C.equalities() self.atom_repr = self._mem.allocarray(self.coatoms.n_atoms, sizeof(size_t)) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pxd b/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pxd index 12b85491a34..17c84df68e7 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pxd +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pxd @@ -10,12 +10,14 @@ cdef class PolyhedronFaceLattice: cdef int dimension # dimension of Polyhedron cdef readonly bint dual # if True, then List of all faces by dual Polyhedron cdef size_t face_length # stores length of the faces in terms of uint64_t - cdef tuple _V, _H, _equalities # some copies from CombinatorialPolyhedron cdef size_t *f_vector # a copy of the f-vector, is reversed if dual cdef size_t *face_counter # how many faces of each dimension have been initialized cdef size_t *atom_repr # a place where atom-representaion of face will be stored cdef size_t *coatom_repr # a place where coatom-representaion of face will be stored + # some copies from CombinatorialPolyhedron + cdef tuple _Vrep, _facet_names, _equalities + # Atoms and coatoms are the Vrepr/facets of the Polyedron. # If ``dual == 0``, then coatoms are facets, atoms Vrepresentatives and vice versa. cdef ListOfFaces atoms, coatoms diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx index 2cac35e56a2..8256d4a2672 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx @@ -134,8 +134,8 @@ cdef class PolyhedronFaceLattice: self.dual = False cdef FaceIterator face_iter = C._face_iter(self.dual, -2) self.face_length = face_iter.face_length - self._V = C.V() - self._H = C.H() + self._Vrep = C.Vrep() + self._facet_names = C.facet_names() self._equalities = C.equalities() # copy f_vector for later use From 6b12213231dd658db0fe44791e04d250a054699d Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Fri, 6 Dec 2019 14:43:22 +0100 Subject: [PATCH 286/340] check whether polytope is full-dimensional before taking the polar; added a polar version in its affine span --- src/sage/geometry/polyhedron/base.py | 50 +++++++++++++++++++--------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index a6ac1046b74..949e0b5f258 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -5147,14 +5147,8 @@ def barycentric_subdivision(self, subdivision_frac=None): ambient_dim = self.ambient_dim() polytope_dim = self.dimension() - if ambient_dim != polytope_dim: - start_polar = parent.element_class( - parent, [((self - barycenter).polar().vertices()), [], []], None) - polar = parent.element_class( - parent, [((self - barycenter).polar().vertices()), [], []], None) - else: - start_polar = (self - barycenter).polar() - polar = (self - barycenter).polar() + start_polar = (self - barycenter).polar(in_affine_span=True) + polar = (self - barycenter).polar(in_affine_span=True) for i in range(self.dimension() - 1): @@ -5191,10 +5185,7 @@ def barycentric_subdivision(self, subdivision_frac=None): polar = parent.element_class(parent, None, [new_ieqs, new_eqns]) - if ambient_dim != polytope_dim: - return (parent.element_class(parent, [polar.polar().vertices(), [], []], None)) + barycenter - else: - return (polar.polar()) + barycenter + return (polar.polar(in_affine_span=True)) + barycenter @cached_method def face_lattice(self): @@ -5666,7 +5657,7 @@ def vertex_digraph(self, f, increasing=True): dg.add_edge(vi, vj) return dg - def polar(self): + def polar(self, in_affine_span=False): """ Return the polar (dual) polytope. @@ -5674,6 +5665,10 @@ def polar(self): is at the origin, and then the vertices are used as the coefficients in the polar inequalities. + The polytope must be full-dimensional, unless ``in_affine_span`` is ``True``. + If ``in_affine_span`` is ``True``, then the operation will be performed in the + linear/affine span of the polyhedron (after translation). + EXAMPLES:: sage: p = Polyhedron(vertices = [[0,0,1],[0,1,0],[1,0,0],[0,0,0],[1,1,1]], base_ring=QQ) @@ -5688,6 +5683,20 @@ def polar(self): sage: octahedron == cube_dual True + ``in_affine_span`` somewhat ignores equations, performing the polar in the + spanned subspace (after translating barycenter to origin):: + + sage: P = polytopes.simplex(3, base_ring=QQ) + sage: P.polar(in_affine_span=True) + A 3-dimensional polyhedron in QQ^4 defined as the convex hull of 4 vertices + + Embedding the polytope in a higher dimension, commutes with polar in this case:: + + sage: point = Polyhedron([[0]]) + sage: P = polytopes.cube().change_ring(QQ) + sage: (P*point).polar(in_affine_span=True) == P.polar()*point + True + TESTS:: Check that :trac:`25081` is fixed:: @@ -5695,12 +5704,23 @@ def polar(self): sage: C = polytopes.hypercube(4,backend='cdd') sage: C.polar().backend() 'cdd' + + Check that :trac:`28850` is fixed:: + + sage: P = polytopes.simplex(3, base_ring=QQ) + sage: P.polar() + Traceback (most recent call last): + ... + AssertionError: must be full-dimensional """ - assert self.is_compact(), "Not a polytope." + assert self.is_compact(), "not a polytope" + if not in_affine_span: + assert self.dim() == self.ambient_dim(), "must be full-dimensional" + verts = [list(self.center() - v.vector()) for v in self.vertex_generator()] parent = self.parent().base_extend(self.center().parent()) - return parent.element_class(parent, None, [[[1] + list(v) for v in verts], []]) + return parent.element_class(parent, None, [[[1] + list(v) for v in verts], self.equations()]) def is_self_dual(self): r""" From fa68739e619b645501bed7fe34a749fe7762fb47 Mon Sep 17 00:00:00 2001 From: "E. Madison Bray" Date: Mon, 2 Dec 2019 18:57:02 +0100 Subject: [PATCH 287/340] Trac #28829: Patch suitesparse to support installing correctly on Cygwin. This includes: * Installing DLLs under bin/ with a cyg- prefix instead of lib- * Creating and installing import libs (.dll.a files) in lib/ For the time being versioning of import libs is not used, but it is for DLLs. This unfortunately requires a patch bomb since all of SuiteSparse's libraries have their own Makefiles even though they are near copies of each other with minor differences. --- .../pkgs/suitesparse/patches/04-cygwin.patch | 762 ++++++++++++++++++ 1 file changed, 762 insertions(+) create mode 100644 build/pkgs/suitesparse/patches/04-cygwin.patch diff --git a/build/pkgs/suitesparse/patches/04-cygwin.patch b/build/pkgs/suitesparse/patches/04-cygwin.patch new file mode 100644 index 00000000000..803a395e86d --- /dev/null +++ b/build/pkgs/suitesparse/patches/04-cygwin.patch @@ -0,0 +1,762 @@ +Patch to support installing correctly on Cygwin. + +This includes: + +* Installing DLLs under bin/ with a cyg- prefix instead of lib- +* Creating and installing import libs (.dll.a files) in lib/ + +For the time being versioning of import libs is not used, but it is +for DLLs. + +This unfortunately requires a patch bomb since all of SuiteSparse's +libraries have their own Makefiles even though they are near copies +of each other with minor differences. + +See https://trac.sagemath.org/ticket/28829 +diff -ruN a/AMD/Lib/Makefile b/AMD/Lib/Makefile +--- a/AMD/Lib/Makefile 2019-12-02 16:05:04.856283600 +0100 ++++ b/AMD/Lib/Makefile 2019-12-02 18:12:09.753790100 +0100 +@@ -2,7 +2,7 @@ + # AMD Lib/Makefile + #------------------------------------------------------------------------------- + +-LIBRARY = libamd ++LIBRARY = amd + VERSION = 2.4.6 + SO_VERSION = 2 + +@@ -81,19 +81,22 @@ + #------------------------------------------------------------------------------- + + # install AMD +-install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) ++install: $(AR_TARGET) $(INSTALL_SO) + +-$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) ++$(INSTALL_SO): $(OBJ) + @mkdir -p $(INSTALL_LIB) ++ @mkdir -p $(dir $(INSTALL_SO)) + @mkdir -p $(INSTALL_INCLUDE) + @mkdir -p $(INSTALL_DOC) + $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) ++ifneq ($(UNAME),Cygwin) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) ++ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) ++endif + $(CP) ../Include/amd.h $(INSTALL_INCLUDE) + $(CP) ../Doc/AMD_UserGuide.pdf $(INSTALL_DOC) + $(CP) ../README.txt $(INSTALL_DOC)/AMD_README.txt +- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) + chmod 644 $(INSTALL_INCLUDE)/amd.h + chmod 644 $(INSTALL_DOC)/AMD_UserGuide.pdf + chmod 644 $(INSTALL_DOC)/AMD_README.txt +diff -ruN a/BTF/Lib/Makefile b/BTF/Lib/Makefile +--- a/BTF/Lib/Makefile 2019-12-02 16:04:51.542288600 +0100 ++++ b/BTF/Lib/Makefile 2019-12-02 18:12:16.908303300 +0100 +@@ -2,7 +2,7 @@ + # BTF Lib/Makefile + #------------------------------------------------------------------------------- + +-LIBRARY = libbtf ++LIBRARY = btf + VERSION = 1.2.6 + SO_VERSION = 1 + +@@ -66,18 +66,21 @@ + #------------------------------------------------------------------------------- + + # install BTF +-install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) ++install: $(AR_TARGET) $(INSTALL_SO) + +-$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) ++$(INSTALL_SO): $(OBJ) + @mkdir -p $(INSTALL_LIB) ++ @mkdir -p $(dir $(INSTALL_SO)) + @mkdir -p $(INSTALL_INCLUDE) + @mkdir -p $(INSTALL_DOC) + $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) ++ifneq ($(UNAME),Cygwin) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) ++ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) ++endif + $(CP) ../Include/btf.h $(INSTALL_INCLUDE) + $(CP) ../README.txt $(INSTALL_DOC)/BTF_README.txt +- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) + chmod 644 $(INSTALL_INCLUDE)/btf.h + chmod 644 $(INSTALL_DOC)/BTF_README.txt + +diff -ruN a/CAMD/Lib/Makefile b/CAMD/Lib/Makefile +--- a/CAMD/Lib/Makefile 2019-12-02 16:04:50.051276500 +0100 ++++ b/CAMD/Lib/Makefile 2019-12-02 18:12:07.722810200 +0100 +@@ -2,7 +2,7 @@ + # CAMD Lib/Makefile + #------------------------------------------------------------------------------- + +-LIBRARY = libcamd ++LIBRARY = camd + VERSION = 2.4.6 + SO_VERSION = 2 + +@@ -62,19 +62,22 @@ + #------------------------------------------------------------------------------- + + # install CAMD +-install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) ++install: $(AR_TARGET) $(INSTALL_SO) + +-$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) ++$(INSTALL_SO): $(OBJ) + @mkdir -p $(INSTALL_LIB) ++ @mkdir -p $(dir $(INSTALL_SO)) + @mkdir -p $(INSTALL_INCLUDE) + @mkdir -p $(INSTALL_DOC) + $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) ++ifneq ($(UNAME),Cygwin) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) ++ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) ++endif + $(CP) ../Include/camd.h $(INSTALL_INCLUDE) + $(CP) ../Doc/CAMD_UserGuide.pdf $(INSTALL_DOC) + $(CP) ../README.txt $(INSTALL_DOC)/CAMD_README.txt +- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) + chmod 644 $(INSTALL_INCLUDE)/camd.h + chmod 644 $(INSTALL_DOC)/CAMD_UserGuide.pdf + chmod 644 $(INSTALL_DOC)/CAMD_README.txt +diff -ruN a/CCOLAMD/Lib/Makefile b/CCOLAMD/Lib/Makefile +--- a/CCOLAMD/Lib/Makefile 2019-12-02 16:04:49.279277800 +0100 ++++ b/CCOLAMD/Lib/Makefile 2019-12-02 18:12:22.610632700 +0100 +@@ -2,7 +2,7 @@ + # CCOLAMD Lib/Makefile + #------------------------------------------------------------------------------- + +-LIBRARY = libccolamd ++LIBRARY = ccolamd + VERSION = 2.9.6 + SO_VERSION = 2 + +@@ -49,18 +49,21 @@ + - $(RM) -r $(PURGE) + + # install CCOLAMD +-install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) ++install: $(AR_TARGET) $(INSTALL_SO) + +-$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) ++$(INSTALL_SO): $(OBJ) + @mkdir -p $(INSTALL_LIB) ++ @mkdir -p $(dir $(INSTALL_SO)) + @mkdir -p $(INSTALL_INCLUDE) + @mkdir -p $(INSTALL_DOC) + $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) ++ifneq ($(UNAME),Cygwin) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) ++ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) ++endif + $(CP) ../Include/ccolamd.h $(INSTALL_INCLUDE) + $(CP) ../README.txt $(INSTALL_DOC)/CCOLAMD_README.txt +- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) + chmod 644 $(INSTALL_INCLUDE)/ccolamd.h + chmod 644 $(INSTALL_DOC)/CCOLAMD_README.txt + +diff -ruN a/CHOLMOD/Lib/Makefile b/CHOLMOD/Lib/Makefile +--- a/CHOLMOD/Lib/Makefile 2019-12-02 16:04:51.453293800 +0100 ++++ b/CHOLMOD/Lib/Makefile 2019-12-02 18:12:16.627302900 +0100 +@@ -2,7 +2,7 @@ + # CHOLMOD/Lib/Makefile: for compiling the CHOLMOD library + #=============================================================================== + +-LIBRARY = libcholmod ++LIBRARY = cholmod + VERSION = 3.0.13 + SO_VERSION = 3 + +@@ -535,20 +535,23 @@ + #------------------------------------------------------------------------------- + + # install CHOLMOD +-install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) ++install: $(AR_TARGET) $(INSTALL_SO) + +-$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) ++$(INSTALL_SO): $(OBJ) + @mkdir -p $(INSTALL_LIB) ++ @mkdir -p $(dir $(INSTALL_SO)) + @mkdir -p $(INSTALL_INCLUDE) + @mkdir -p $(INSTALL_DOC) + $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) ++ifneq ($(UNAME),Cygwin) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) ++ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) ++endif + $(CP) ../Include/cholmod*.h $(INSTALL_INCLUDE) + $(RM) $(INSTALL_INCLUDE)/cholmod_internal.h +- $(CP) ../Doc/CHOLMOD_UserGuide.pdf $(INSTALL_DOC) + $(CP) ../README.txt $(INSTALL_DOC)/CHOLMOD_README.txt +- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) ++ $(CP) ../Doc/CHOLMOD_UserGuide.pdf $(INSTALL_DOC) + chmod 644 $(INSTALL_INCLUDE)/cholmod*.h + chmod 644 $(INSTALL_DOC)/CHOLMOD_UserGuide.pdf + chmod 644 $(INSTALL_DOC)/CHOLMOD_README.txt +diff -ruN a/COLAMD/Lib/Makefile b/COLAMD/Lib/Makefile +--- a/COLAMD/Lib/Makefile 2019-12-02 16:04:58.545276600 +0100 ++++ b/COLAMD/Lib/Makefile 2019-12-02 18:12:17.545302000 +0100 +@@ -2,7 +2,7 @@ + # COLAMD Lib/Makefile + #------------------------------------------------------------------------------- + +-LIBRARY = libcolamd ++LIBRARY = colamd + VERSION = 2.9.6 + SO_VERSION = 2 + +@@ -49,18 +49,21 @@ + - $(RM) -r $(PURGE) + + # install COLAMD +-install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) ++install: $(AR_TARGET) $(INSTALL_SO) + +-$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) ++$(INSTALL_SO): $(OBJ) + @mkdir -p $(INSTALL_LIB) ++ @mkdir -p $(dir $(INSTALL_SO)) + @mkdir -p $(INSTALL_INCLUDE) + @mkdir -p $(INSTALL_DOC) + $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) ++ifneq ($(UNAME),Cygwin) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) ++ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) ++endif + $(CP) ../Include/colamd.h $(INSTALL_INCLUDE) + $(CP) ../README.txt $(INSTALL_DOC)/COLAMD_README.txt +- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) + chmod 644 $(INSTALL_INCLUDE)/colamd.h + chmod 644 $(INSTALL_DOC)/COLAMD_README.txt + +diff -ruN a/CSparse/Lib/Makefile b/CSparse/Lib/Makefile +--- a/CSparse/Lib/Makefile 2019-12-02 16:04:58.059294300 +0100 ++++ b/CSparse/Lib/Makefile 2019-12-02 18:12:09.158797700 +0100 +@@ -14,7 +14,7 @@ + # install' in this Makefile only installs a static compiled library in + # CSparse/Lib. It does not install it for system-wide usage. + +-LIBRARY = libcsparse ++LIBRARY = csparse + CF = $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -O + + I = -I../Include +diff -ruN a/CXSparse/Lib/Makefile b/CXSparse/Lib/Makefile +--- a/CXSparse/Lib/Makefile 2019-12-02 16:04:49.462296500 +0100 ++++ b/CXSparse/Lib/Makefile 2019-12-02 18:12:23.167631600 +0100 +@@ -2,7 +2,7 @@ + # CXSparse Lib/Makefile + #------------------------------------------------------------------------------- + +-LIBRARY = libcxsparse ++LIBRARY = cxsparse + VERSION = 3.2.0 + SO_VERSION = 3 + +@@ -113,18 +113,21 @@ + - $(RM) -r $(PURGE) + + # install CXSparse +-install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) ++install: $(AR_TARGET) $(INSTALL_SO) + +-$(INSTALL_LIB)/$(SO_TARGET): $(CS) ++$(INSTALL_SO): $(CS) + @mkdir -p $(INSTALL_LIB) ++ @mkdir -p $(dir $(INSTALL_SO)) + @mkdir -p $(INSTALL_INCLUDE) + @mkdir -p $(INSTALL_DOC) + $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) ++ifneq ($(UNAME),Cygwin) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) ++ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) ++endif + $(CP) ../Include/cs.h $(INSTALL_INCLUDE) + $(CP) ../README.txt $(INSTALL_DOC)/CXSPARSE_README.txt +- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) + chmod 644 $(INSTALL_INCLUDE)/cs.h + chmod 644 $(INSTALL_DOC)/CXSPARSE_README.txt + +diff -ruN a/CXSparse_newfiles/Lib/Makefile b/CXSparse_newfiles/Lib/Makefile +--- a/CXSparse_newfiles/Lib/Makefile 2019-12-02 16:05:04.505277300 +0100 ++++ b/CXSparse_newfiles/Lib/Makefile 2019-12-02 18:12:08.029790200 +0100 +@@ -2,7 +2,7 @@ + # CXSparse Lib/Makefile + #------------------------------------------------------------------------------- + +-LIBRARY = libcxsparse ++LIBRARY = cxsparse + VERSION = 3.2.0 + SO_VERSION = 3 + +@@ -113,18 +113,21 @@ + - $(RM) -r $(PURGE) + + # install CXSparse +-install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) ++install: $(AR_TARGET) $(INSTALL_SO) + +-$(INSTALL_LIB)/$(SO_TARGET): $(CS) ++$(INSTALL_SO): $(CS) + @mkdir -p $(INSTALL_LIB) ++ @mkdir -p $(dir $(INSTALL_SO)) + @mkdir -p $(INSTALL_INCLUDE) + @mkdir -p $(INSTALL_DOC) + $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) ++ifneq ($(UNAME),Cygwin) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) ++ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) ++endif + $(CP) ../Include/cs.h $(INSTALL_INCLUDE) + $(CP) ../README.txt $(INSTALL_DOC)/CXSPARSE_README.txt +- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) + chmod 644 $(INSTALL_INCLUDE)/cs.h + chmod 644 $(INSTALL_DOC)/CXSPARSE_README.txt + +diff -ruN a/GPUQREngine/Lib/Makefile b/GPUQREngine/Lib/Makefile +--- a/GPUQREngine/Lib/Makefile 2019-12-02 16:04:50.027276700 +0100 ++++ b/GPUQREngine/Lib/Makefile 2019-12-02 18:12:07.617802700 +0100 +@@ -2,7 +2,7 @@ + # GPUQREngine/Lib/Makefile: for compiling the GPUQREngine library + #------------------------------------------------------------------------------- + +-LIBRARY = libGPUQREngine ++LIBRARY = GPUQREngine + VERSION = 1.0.5 + SO_VERSION = 1 + +@@ -129,17 +129,20 @@ + #------------------------------------------------------------------------------- + + # install GPUQREngine. Note that the include files are not installed. +-install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) ++install: $(AR_TARGET) $(INSTALL_SO) + +-$(INSTALL_LIB)/$(SO_TARGET): $(OBJS) ++$(INSTALL_SO): $(OBJS) + @mkdir -p $(INSTALL_LIB) ++ @mkdir -p $(dir $(INSTALL_SO)) + @mkdir -p $(INSTALL_INCLUDE) + @mkdir -p $(INSTALL_DOC) + $(CXX) $(SO_OPTS) $^ -o $@ $(LDLIBS) ++ifneq ($(UNAME),Cygwin) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) +- $(CP) ../README.txt $(INSTALL_DOC)/GPUQRENGINE_README.txt + chmod 755 $(INSTALL_LIB)/$(SO_TARGET) ++endif ++ $(CP) ../README.txt $(INSTALL_DOC)/GPUQRENGINE_README.txt + chmod 644 $(INSTALL_DOC)/GPUQRENGINE_README.txt + + # uninstall GPUQREngine +diff -ruN a/KLU/Lib/Makefile b/KLU/Lib/Makefile +--- a/KLU/Lib/Makefile 2019-12-02 16:04:51.621283700 +0100 ++++ b/KLU/Lib/Makefile 2019-12-02 18:12:09.148789600 +0100 +@@ -2,7 +2,7 @@ + # KLU Lib/Makefile + #------------------------------------------------------------------------------- + +-LIBRARY = libklu ++LIBRARY = klu + VERSION = 1.3.8 + SO_VERSION = 1 + +@@ -263,19 +263,22 @@ + #------------------------------------------------------------------------------- + + # install KLU +-install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) ++install: $(AR_TARGET) $(INSTALL_SO) + +-$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) ++$(INSTALL_SO): $(OBJ) + @mkdir -p $(INSTALL_LIB) ++ @mkdir -p $(dir $(INSTALL_SO)) + @mkdir -p $(INSTALL_INCLUDE) + @mkdir -p $(INSTALL_DOC) + $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) ++ifneq ($(UNAME),Cygwin) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) ++ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) ++endif + $(CP) ../Include/klu.h $(INSTALL_INCLUDE) + $(CP) ../Doc/KLU_UserGuide.pdf $(INSTALL_DOC) + $(CP) ../README.txt $(INSTALL_DOC)/KLU_README.txt +- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) + chmod 644 $(INSTALL_INCLUDE)/klu.h + chmod 644 $(INSTALL_DOC)/KLU_UserGuide.pdf + chmod 644 $(INSTALL_DOC)/KLU_README.txt +diff -ruN a/LDL/Lib/Makefile b/LDL/Lib/Makefile +--- a/LDL/Lib/Makefile 2019-12-02 16:04:51.803294200 +0100 ++++ b/LDL/Lib/Makefile 2019-12-02 18:12:17.500303700 +0100 +@@ -2,7 +2,7 @@ + # LDL Lib/Makefile + #------------------------------------------------------------------------------- + +-LIBRARY = libldl ++LIBRARY = ldl + VERSION = 2.2.6 + SO_VERSION = 2 + +@@ -46,19 +46,22 @@ + - $(RM) -r $(CLEAN) + + # install LDL +-install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) ++install: $(AR_TARGET) $(INSTALL_SO) + +-$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) ++$(INSTALL_SO): $(OBJ) + @mkdir -p $(INSTALL_LIB) ++ @mkdir -p $(dir $(INSTALL_SO)) + @mkdir -p $(INSTALL_INCLUDE) + @mkdir -p $(INSTALL_DOC) + $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) ++ifneq ($(UNAME),Cygwin) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) ++ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) ++endif + $(CP) ../Include/ldl.h $(INSTALL_INCLUDE) + $(CP) ../Doc/ldl_userguide.pdf $(INSTALL_DOC) + $(CP) ../README.txt $(INSTALL_DOC)/LDL_README.txt +- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) + chmod 644 $(INSTALL_INCLUDE)/ldl.h + chmod 644 $(INSTALL_DOC)/ldl_userguide.pdf + chmod 644 $(INSTALL_DOC)/LDL_README.txt +diff -ruN a/RBio/Lib/Makefile b/RBio/Lib/Makefile +--- a/RBio/Lib/Makefile 2019-12-02 16:05:04.771295500 +0100 ++++ b/RBio/Lib/Makefile 2019-12-02 18:12:09.016789800 +0100 +@@ -2,7 +2,7 @@ + # RBio/Lib/Makefile: for compiling the RBio library + #=============================================================================== + +-LIBRARY = librbio ++LIBRARY = rbio + VERSION = 2.2.6 + SO_VERSION = 2 + +@@ -60,18 +60,21 @@ + #------------------------------------------------------------------------------- + + # install RBio +-install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) ++install: $(AR_TARGET) $(INSTALL_SO) + +-$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) ++$(INSTALL_SO): $(OBJ) + @mkdir -p $(INSTALL_LIB) ++ @mkdir -p $(dir $(INSTALL_SO)) + @mkdir -p $(INSTALL_INCLUDE) + @mkdir -p $(INSTALL_DOC) + $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) ++ifneq ($(UNAME),Cygwin) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) ++ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) ++endif + $(CP) ../Include/RBio.h $(INSTALL_INCLUDE) + $(CP) ../README.txt $(INSTALL_DOC)/RBIO_README.txt +- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) + chmod 644 $(INSTALL_INCLUDE)/RBio.h + chmod 644 $(INSTALL_DOC)/RBIO_README.txt + +diff -ruN a/SPQR/Lib/Makefile b/SPQR/Lib/Makefile +--- a/SPQR/Lib/Makefile 2019-12-02 16:04:50.190277100 +0100 ++++ b/SPQR/Lib/Makefile 2019-12-02 18:12:07.955789500 +0100 +@@ -2,7 +2,7 @@ + # SuiteSparseQR/Lib/Makefile + #=============================================================================== + +-LIBRARY = libspqr ++LIBRARY = spqr + VERSION = 2.0.9 + SO_VERSION = 2 + +@@ -242,22 +242,25 @@ + #------------------------------------------------------------------------------- + + # install SPQR +-install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) ++install: $(AR_TARGET) $(INSTALL_SO) + +-$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) ++$(INSTALL_SO): $(OBJ) + @mkdir -p $(INSTALL_LIB) ++ @mkdir -p $(dir $(INSTALL_SO)) + @mkdir -p $(INSTALL_INCLUDE) + @mkdir -p $(INSTALL_DOC) + $(CXX) $(SO_OPTS) $^ -o $@ $(LDLIBS) ++ifneq ($(UNAME),Cygwin) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) ++ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) ++endif + $(CP) ../Include/SuiteSparseQR.hpp $(INSTALL_INCLUDE) + $(CP) ../Include/SuiteSparseQR_C.h $(INSTALL_INCLUDE) + $(CP) ../Include/SuiteSparseQR_definitions.h $(INSTALL_INCLUDE) + $(CP) ../Include/spqr.hpp $(INSTALL_INCLUDE) + $(CP) ../Doc/spqr_user_guide.pdf $(INSTALL_DOC) + $(CP) ../README.txt $(INSTALL_DOC)/SPQR_README.txt +- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) + chmod 644 $(INSTALL_INCLUDE)/SuiteSparseQR.hpp + chmod 644 $(INSTALL_INCLUDE)/SuiteSparseQR_C.h + chmod 644 $(INSTALL_INCLUDE)/SuiteSparseQR_definitions.h +diff -ruN a/SuiteSparse_config/Makefile b/SuiteSparse_config/Makefile +--- a/SuiteSparse_config/Makefile 2019-12-02 16:05:03.939278100 +0100 ++++ b/SuiteSparse_config/Makefile 2019-12-02 18:12:16.275303600 +0100 +@@ -6,7 +6,7 @@ + export SUITESPARSE + + # version of SuiteSparse_config is also version of SuiteSparse meta-package +-LIBRARY = libsuitesparseconfig ++LIBRARY = suitesparseconfig + VERSION = 5.5.0 + SO_VERSION = 5 + +@@ -44,19 +44,23 @@ + - $(RM) -r $(CLEAN) + + # install SuiteSparse_config +-install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) ++install: $(AR_TARGET) $(INSTALL_SO) + +-$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) ++$(INSTALL_SO): $(OBJ) + @mkdir -p $(INSTALL_LIB) ++# Likely redundant with the above but not on Cygwin ++ @mkdir -p $(dir $(INSTALL_SO)) + @mkdir -p $(INSTALL_INCLUDE) + @mkdir -p $(INSTALL_DOC) + $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) ++ifneq ($(UNAME),Cygwin) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) +- $(CP) SuiteSparse_config.h $(INSTALL_INCLUDE) +- $(CP) README.txt $(INSTALL_DOC)/SUITESPARSECONFIG_README.txt + chmod 755 $(INSTALL_LIB)/$(SO_TARGET) + chmod 755 $(INSTALL_LIB)/$(SO_PLAIN) ++endif ++ $(CP) SuiteSparse_config.h $(INSTALL_INCLUDE) ++ $(CP) README.txt $(INSTALL_DOC)/SUITESPARSECONFIG_README.txt + chmod 644 $(INSTALL_INCLUDE)/SuiteSparse_config.h + chmod 644 $(INSTALL_DOC)/SUITESPARSECONFIG_README.txt + +diff -ruN a/SuiteSparse_config/SuiteSparse_config.mk b/SuiteSparse_config/SuiteSparse_config.mk +--- a/SuiteSparse_config/SuiteSparse_config.mk 2019-12-02 16:05:03.944279100 +0100 ++++ b/SuiteSparse_config/SuiteSparse_config.mk 2019-12-02 18:12:16.277302200 +0100 +@@ -153,6 +153,11 @@ + # It places its shared *.so libraries in SuiteSparse/lib. + # Linux also requires the -lrt library (see below) + LDLIBS ?= -lm ++ # Note: Because suitesparse doesn't really do install staging properly ++ # (it just outputs final build artifacts directly to their install paths) ++ # we must add that path to our linker flags in order to link properly ++ # against built libraries; it might be better to fix the whole build ++ # system though). + LDFLAGS += -L$(INSTALL_LIB) + + # NOTE: Use of the Intel MKL BLAS is strongly recommended. The OpenBLAS can +@@ -340,16 +346,15 @@ + #--------------------------------------------------------------------------- + + # To disable these auto configurations, use 'make UNAME=custom' +- + ifndef UNAME +- ifeq ($(OS),Windows_NT) +- # Cygwin Make on Windows has an $(OS) variable, but not uname. +- # Note that this option is untested. +- UNAME = Windows +- else +- # Linux and Darwin (Mac OSX) have been tested. +- UNAME := $(shell uname) +- endif ++ # Linux and Darwin (Mac OSX) have been tested. ++ UNAME := $(shell uname) ++ endif ++ ++ # On Cygwin we'll typically have UNAME=CYGWIN but just normalize ++ # to "CYGWIN" ++ ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN) ++ UNAME := Cygwin + endif + + #--------------------------------------------------------------------------- +@@ -446,21 +451,23 @@ + + SO_OPTS = $(LDFLAGS) + +-ifeq ($(UNAME),Windows) +- # Cygwin Make on Windows (untested) +- AR_TARGET = $(LIBRARY).lib +- SO_PLAIN = $(LIBRARY).dll +- SO_MAIN = $(LIBRARY).$(SO_VERSION).dll +- SO_TARGET = $(LIBRARY).$(VERSION).dll +- SO_INSTALL_NAME = echo ++ifeq ($(UNAME),Cygwin) ++ # Cygwin Make on Windows ++ AR_TARGET = lib$(LIBRARY).a ++ SO_TARGET = cyg$(LIBRARY)-$(SO_VERSION).dll ++ IMPLIB = lib$(LIBRARY).dll.a ++ SO_OPTS += -shared -Wl,--no-undefined -Wl,--out-implib -Wl,$(INSTALL_LIB)/$(IMPLIB) ++ INSTALL_DLL := $(DESTDIR)$(INSTALL)/bin ++ INSTALL_SO = $(INSTALL_DLL)/$(SO_TARGET) + else + # Mac or Linux/Unix +- AR_TARGET = $(LIBRARY).a ++ AR_TARGET = lib$(LIBRARY).a ++ INSTALL_SO = $(INSTALL_LIB)/$(SO_TARGET) + ifeq ($(UNAME),Darwin) + # Mac +- SO_PLAIN = $(LIBRARY).dylib +- SO_MAIN = $(LIBRARY).$(SO_VERSION).dylib +- SO_TARGET = $(LIBRARY).$(VERSION).dylib ++ SO_PLAIN = lib$(LIBRARY).dylib ++ SO_MAIN = lib$(LIBRARY).$(SO_VERSION).dylib ++ SO_TARGET = lib$(LIBRARY).$(VERSION).dylib + SO_OPTS += -dynamiclib -compatibility_version $(SO_VERSION) \ + -current_version $(VERSION) \ + -shared -undefined dynamic_lookup +@@ -469,9 +476,9 @@ + SO_INSTALL_NAME = install_name_tool -id + else + # Linux and other variants of Unix +- SO_PLAIN = $(LIBRARY).so +- SO_MAIN = $(LIBRARY).so.$(SO_VERSION) +- SO_TARGET = $(LIBRARY).so.$(VERSION) ++ SO_PLAIN = lib$(LIBRARY).so ++ SO_MAIN = lib$(LIBRARY).so.$(SO_VERSION) ++ SO_TARGET = lib$(LIBRARY).so.$(VERSION) + SO_OPTS += -shared -Wl,-soname -Wl,$(SO_MAIN) -Wl,--no-undefined + # Linux/Unix *.so files can be moved without modification: + SO_INSTALL_NAME = echo +diff -ruN a/SuiteSparse_config/xerbla/Makefile b/SuiteSparse_config/xerbla/Makefile +--- a/SuiteSparse_config/xerbla/Makefile 2019-12-02 16:05:03.949290500 +0100 ++++ b/SuiteSparse_config/xerbla/Makefile 2019-12-02 18:12:16.284303200 +0100 +@@ -16,9 +16,9 @@ + all: library + + ifeq ($(USE_FORTRAN),0) +- LIBRARY = libcerbla ++ LIBRARY = cerbla + else +- LIBRARY = libxerbla ++ LIBRARY = xerbla + endif + + include ../SuiteSparse_config.mk +@@ -44,19 +44,22 @@ + - $(RM) xerbla.o + + # install libcerbla / libxerbla +-install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) ++install: $(AR_TARGET) $(INSTALL_SO) + +-$(INSTALL_LIB)/$(SO_TARGET): $(DEPENDS) ++$(INSTALL_SO): $(DEPENDS) + @mkdir -p $(INSTALL_LIB) ++ @mkdir -p $(dir $(INSTALL_SO)) + @mkdir -p $(INSTALL_INCLUDE) + @mkdir -p $(INSTALL_DOC) + $(COMPILE) + $(CC) $(SO_OPTS) xerbla.o -o $@ + - $(RM) xerbla.o ++ifneq ($(UNAME),Cygwin) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) +- $(CP) xerbla.h $(INSTALL_INCLUDE) + chmod 755 $(INSTALL_LIB)/$(SO_TARGET) ++endif ++ $(CP) xerbla.h $(INSTALL_INCLUDE) + chmod 644 $(INSTALL_INCLUDE)/xerbla.h + + # uninstall libcerbla / libxerbla +diff -ruN a/SuiteSparse_GPURuntime/Lib/Makefile b/SuiteSparse_GPURuntime/Lib/Makefile +--- a/SuiteSparse_GPURuntime/Lib/Makefile 2019-12-02 16:04:57.931276800 +0100 ++++ b/SuiteSparse_GPURuntime/Lib/Makefile 2019-12-02 18:12:08.912790400 +0100 +@@ -2,7 +2,7 @@ + # SuiteSparse_GPURuntime/Lib/Makfile + #------------------------------------------------------------------------------- + +-LIBRARY = libSuiteSparse_GPURuntime ++LIBRARY = SuiteSparse_GPURuntime + VERSION = 1.0.5 + SO_VERSION = 1 + +@@ -70,17 +70,20 @@ + #------------------------------------------------------------------------------- + + # install SuiteSparse_GPURuntime (just the library, not the include files) +-install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) ++install: $(AR_TARGET) $(INSTALL_SO) + +-$(INSTALL_LIB)/$(SO_TARGET): $(OBJS) ++$(INSTALL_SO): $(OBJS) + @mkdir -p $(INSTALL_LIB) ++ @mkdir -p $(dir $(INSTALL_SO)) + @mkdir -p $(INSTALL_INCLUDE) + @mkdir -p $(INSTALL_DOC) + $(CXX) $(SO_OPTS) $^ -o $@ $(LDLIBS) ++ifneq ($(UNAME),Cygwin) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) +- $(CP) ../README.txt $(INSTALL_DOC)/GPURUNTIME_README.txt + chmod 755 $(INSTALL_LIB)/$(SO_TARGET) ++endif ++ $(CP) ../README.txt $(INSTALL_DOC)/GPURUNTIME_README.txt + chmod 644 $(INSTALL_DOC)/GPURUNTIME_README.txt + + # uninstall SuiteSparse_GPURuntime +diff -ruN a/UMFPACK/Lib/Makefile b/UMFPACK/Lib/Makefile +--- a/UMFPACK/Lib/Makefile 2019-12-02 16:05:03.957276500 +0100 ++++ b/UMFPACK/Lib/Makefile 2019-12-02 18:12:17.206308800 +0100 +@@ -2,7 +2,7 @@ + # UMFPACK Makefile for compiling on Unix systems + #------------------------------------------------------------------------------- + +-LIBRARY = libumfpack ++LIBRARY = umfpack + VERSION = 5.7.9 + SO_VERSION = 5 + +@@ -288,20 +288,23 @@ + + #------------------------------------------------------------------------------- + # install UMFPACK +-install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) ++install: $(AR_TARGET) $(INSTALL_SO) + +-$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) ++$(INSTALL_SO): $(OBJ) + @mkdir -p $(INSTALL_LIB) ++ @mkdir -p $(dir $(INSTALL_SO)) + @mkdir -p $(INSTALL_INCLUDE) + @mkdir -p $(INSTALL_DOC) + $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) ++ifneq ($(UNAME),Cygwin) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) + ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) ++ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) ++endif + $(CP) ../Include/umfpack*.h $(INSTALL_INCLUDE) + $(CP) ../Doc/UMFPACK_UserGuide.pdf $(INSTALL_DOC) + $(CP) ../Doc/UMFPACK_QuickStart.pdf $(INSTALL_DOC) + $(CP) ../README.txt $(INSTALL_DOC)/UMFPACK_README.txt +- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) + chmod 644 $(INSTALL_INCLUDE)/umfpack*.h + chmod 644 $(INSTALL_DOC)/UMFPACK_UserGuide.pdf + chmod 644 $(INSTALL_DOC)/UMFPACK_QuickStart.pdf From 50bbb7613eefd758e6f33da503a9aa09f08d7efe Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Fri, 6 Dec 2019 16:59:13 +0100 Subject: [PATCH 288/340] polar of polytope over integers respects backend --- src/sage/geometry/polyhedron/base_ZZ.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index 598ae6db1f8..e977d20a092 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -56,7 +56,7 @@ def __dir__(self): r""" TESTS: - Removes the Ehrhart quasipolynomial from the list of methods for the + Removes the Ehrhart quasipolynomial from the list of methods for the lattice polyhedron:: sage: P = polytopes.cube() @@ -491,16 +491,24 @@ def polar(self): sage: p.polar().base_ring() Integer Ring + + TESTS: + + Test that :trac:`28551` is fixed:: + + sage: polytopes.cube(backend='normaliz').polar().backend() # optional - pynormaliz + 'normaliz' """ if not self.has_IP_property(): raise ValueError('The polytope must have the IP property.') vertices = [ ieq.A()/ieq.b() for ieq in self.inequality_generator() ] + if all( all(v_i in ZZ for v_i in v) for v in vertices): - return Polyhedron(vertices=vertices, base_ring=ZZ) + return Polyhedron(vertices=vertices, base_ring=ZZ, backend=self.backend()) else: - return Polyhedron(vertices=vertices, base_ring=QQ) + return Polyhedron(vertices=vertices, base_ring=QQ, backend=self.backend()) @cached_method def is_reflexive(self): From 3c6548e818ad7fd43641c8c04144e1de1e459235 Mon Sep 17 00:00:00 2001 From: Christian Wuthrich Date: Fri, 6 Dec 2019 22:51:28 +0000 Subject: [PATCH 289/340] some doctests improvements --- .../schemes/elliptic_curves/ell_tate_curve.py | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_tate_curve.py b/src/sage/schemes/elliptic_curves/ell_tate_curve.py index 65abddbfd37..920ef9c530c 100644 --- a/src/sage/schemes/elliptic_curves/ell_tate_curve.py +++ b/src/sage/schemes/elliptic_curves/ell_tate_curve.py @@ -11,7 +11,7 @@ the series `s_4(q)` and `s_6(q)` such that the `y^2+x y = x^3 + s_4(q) x+s_6(q)` curve is isomorphic to `E` over `\bar{\QQ}_p` (or over `\QQ_p` if the reduction is *split* multiplicative). -There is `p`-adic analytic map from +There is a `p`-adic analytic map from `\bar{\QQ}^{\times}_p` to this curve with kernel `q^{\ZZ}`. Points of good reduction correspond to points of valuation `0` in `\bar{\QQ}^{\times}_p`. @@ -61,7 +61,7 @@ class TateCurve(SageObject): Tate's `p`-adic uniformisation of an elliptic curve with multiplicative reduction. - .. note:: + .. NOTE:: Some of the methods of this Tate curve only work when the reduction is split multiplicative over `\QQ_p`. @@ -80,9 +80,9 @@ def __init__(self, E, p): r""" INPUT: - - ``E`` - an elliptic curve over the rational numbers + - ``E`` -- an elliptic curve over the rational numbers - - ``p`` - a prime where `E` has multiplicative reduction, + - ``p`` -- a prime where `E` has multiplicative reduction, i.e., such that `j(E)` has negative valuation. EXAMPLES:: @@ -167,7 +167,7 @@ def parameter(self, prec=20): INPUT: - - ``prec`` - the `p`-adic precision, default is 20. + - ``prec`` -- the `p`-adic precision, default is 20. EXAMPLES:: @@ -209,7 +209,7 @@ def curve(self, prec=20): INPUT: - - ``prec`` - the `p`-adic precision, default is 20. + - ``prec`` -- the `p`-adic precision, default is 20. EXAMPLES:: @@ -246,7 +246,7 @@ def _Csquare(self, prec=20): INPUT: - - ``prec`` - the `p`-adic precision, default is 20. + - ``prec`` -- the `p`-adic precision, default is 20. EXAMPLES:: @@ -272,7 +272,7 @@ def E2(self, prec=20): INPUT: - - ``prec`` - the `p`-adic precision, default is 20. + - ``prec`` -- the `p`-adic precision, default is 20. EXAMPLES:: @@ -295,7 +295,7 @@ def E2(self, prec=20): def is_split(self): r""" - Returns True if the given elliptic curve has split multiplicative reduction. + Return True if the given elliptic curve has split multiplicative reduction. EXAMPLES:: @@ -316,9 +316,9 @@ def parametrisation_onto_tate_curve(self, u, prec=None): INPUT: - - ``u`` - a non-zero `p`-adic number. + - ``u`` -- a non-zero `p`-adic number. - - ``prec`` - the `p`-adic precision, default is the relative precision of ``u`` + - ``prec`` -- the `p`-adic precision, default is the relative precision of ``u`` otherwise 20. @@ -370,14 +370,13 @@ def L_invariant(self, prec=20): Returns the *mysterious* `\mathcal{L}`-invariant associated to an elliptic curve with split multiplicative reduction. - One - instance where this constant appears is in the exceptional + One instance where this constant appears is in the exceptional case of the `p`-adic Birch and Swinnerton-Dyer conjecture as formulated in [MTT1986]_. See [Col2004]_ for a detailed discussion. INPUT: - - ``prec`` - the `p`-adic precision, default is 20. + - ``prec`` -- the `p`-adic precision, default is 20. EXAMPLES:: @@ -408,7 +407,7 @@ def _isomorphism(self, prec=20): INPUT: - - ``prec`` - the `p`-adic precision, default is 20. + - ``prec`` -- the `p`-adic precision, default is 20. EXAMPLES:: @@ -445,7 +444,7 @@ def _inverse_isomorphism(self, prec=20): INPUT: - - ``prec`` - the `p`-adic precision, default is 20. + - ``prec`` -- the `p`-adic precision, default is 20. EXAMPLES:: @@ -468,9 +467,9 @@ def lift(self, P, prec=20): INPUT: - - ``P`` - a point on the elliptic curve. + - ``P`` -- a point on the elliptic curve. - - ``prec`` - the `p`-adic precision, default is 20. + - ``prec`` -- the `p`-adic precision, default is 20. EXAMPLES:: @@ -527,9 +526,9 @@ def parametrisation_onto_original_curve(self, u, prec=None): INPUT: - - ``u`` - a non-zero `p`-adic number. + - ``u`` -- a non-zero `p`-adic number. - - ``prec`` - the `p`-adic precision, default is the relative precision of ``u`` + - ``prec`` -- the `p`-adic precision, default is the relative precision of ``u`` otherwise 20. EXAMPLES:: @@ -583,7 +582,7 @@ def padic_height(self, prec=20): INPUT: - - ``prec`` - the `p`-adic precision, default is 20. + - ``prec`` -- the `p`-adic precision, default is 20. OUTPUT: From 456f57e84f6ea592b3dcc123c10fe8859e6e8561 Mon Sep 17 00:00:00 2001 From: Christian Wuthrich Date: Fri, 6 Dec 2019 23:57:12 +0000 Subject: [PATCH 290/340] another small doc string improvement --- src/sage/schemes/elliptic_curves/ell_tate_curve.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_tate_curve.py b/src/sage/schemes/elliptic_curves/ell_tate_curve.py index 920ef9c530c..533078f0808 100644 --- a/src/sage/schemes/elliptic_curves/ell_tate_curve.py +++ b/src/sage/schemes/elliptic_curves/ell_tate_curve.py @@ -367,7 +367,7 @@ def parametrisation_onto_tate_curve(self, u, prec=None): def L_invariant(self, prec=20): r""" - Returns the *mysterious* `\mathcal{L}`-invariant associated + Return the *mysterious* `\mathcal{L}`-invariant associated to an elliptic curve with split multiplicative reduction. One instance where this constant appears is in the exceptional @@ -632,7 +632,8 @@ def _height(P, check=True): def padic_regulator(self, prec=20): r""" - Compute the canonical `p`-adic regulator on the extended Mordell-Weil group as in [MTT1986]_ + Compute the canonical `p`-adic regulator on the extended + Mordell-Weil group as in [MTT1986]_ (with the correction of [Wer1998]_ and sign convention in [SW2013]_.) The `p`-adic Birch and Swinnerton-Dyer conjecture predicts From cd01eadda35829610e2287bc296c788af2868a34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 7 Dec 2019 11:38:07 +0100 Subject: [PATCH 291/340] trac 28632 alternative algo for eulerian numbers --- src/sage/combinat/combinat.py | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index ca96c644015..dc4073b5d97 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -554,12 +554,24 @@ def euler_number(n, algorithm='flint'): @cached_function -def eulerian_number(n, k): +def eulerian_number(n, k, algorithm='recursive'): """ Return the Eulerian number of index ``(n, k)``. This is the coefficient of `t^k` in the Eulerian polynomial `A_n(t)`. + INPUT: + + - ``n`` -- integer + + - ``k`` -- integer between ``0`` and ``n - 1`` + + - ``algorithm`` -- ``"recursive"`` (default) or ``"formula"`` + + OUTPUT: + + an integer + .. SEEALSO:: :func:`eulerian_polynomial` EXAMPLES:: @@ -567,13 +579,21 @@ def eulerian_number(n, k): sage: from sage.combinat.combinat import eulerian_number sage: [eulerian_number(5,i) for i in range(5)] [1, 26, 66, 26, 1] + + TESTS:: + + sage: [eulerian_number(5,i,"formula") for i in range(5)] + [1, 26, 66, 26, 1] """ n = ZZ(n) if k == 0 or k == n - 1: return ZZ.one() - s = (n - k) * eulerian_number(n - 1, k - 1) - s += (k + 1) * eulerian_number(n - 1, k) - return s + if algorithm == "recursive": + s = (n - k) * eulerian_number(n - 1, k - 1, algorithm=algorithm) + s += (k + 1) * eulerian_number(n - 1, k, algorithm=algorithm) + return s + return sum((-1)**m * (n + 1).binomial(m) * (k + 1 - m)**n + for m in range(k + 1)) @cached_function @@ -588,7 +608,7 @@ def eulerian_polynomial(n, algorithm='derivative'): - ``n`` -- an integer - - ``algorithm`` -- ``derivative`` (default) or ``coeffs`` + - ``algorithm`` -- ``"derivative"`` (default) or ``"coeffs"`` OUTPUT: From 2b5583eb59741e194bb06cdf84301605f6111276 Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Fri, 29 Nov 2019 07:22:44 +0100 Subject: [PATCH 292/340] 28819: avoid running external software during normal test runs --- src/sage/doctest/external.py | 37 ++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/sage/doctest/external.py b/src/sage/doctest/external.py index 9cbc42b1788..e19c9891b9c 100644 --- a/src/sage/doctest/external.py +++ b/src/sage/doctest/external.py @@ -5,6 +5,11 @@ of each software is tested only when necessary. This is mainly used for the doctests which require certain external software installed on the system. +Even though the functions in this module should also work when an external +software is not present, most doctests in this module are only tested if +testing of external software is explicitly enabled in order to avoid invoking +external software otherwise. See :trac:`28819` for details. + AUTHORS: - Kwankyu Lee (2016-03-09) -- initial version, based on code by Robert Bradshaw and Nathann Cohen @@ -36,7 +41,7 @@ def has_internet(): EXAMPLES:: sage: from sage.doctest.external import has_internet - sage: has_internet() # optional -- internet + sage: has_internet() # random, optional -- internet True """ from six.moves import urllib @@ -55,7 +60,7 @@ def has_latex(): EXAMPLES:: sage: from sage.doctest.external import has_latex - sage: has_latex() # random + sage: has_latex() # random, optional - latex True """ from sage.misc.latex import _run_latex_, _latex_file_ @@ -77,7 +82,7 @@ def has_magma(): EXAMPLES:: sage: from sage.doctest.external import has_magma - sage: has_magma() # random + sage: has_magma() # random, optional - magma True """ from sage.interfaces.magma import magma @@ -94,7 +99,7 @@ def has_matlab(): EXAMPLES:: sage: from sage.doctest.external import has_matlab - sage: has_matlab() # random + sage: has_matlab() # random, optional - matlab True """ from sage.interfaces.matlab import matlab @@ -111,7 +116,7 @@ def has_mathematica(): EXAMPLES:: sage: from sage.doctest.external import has_mathematica - sage: has_mathematica() # random + sage: has_mathematica() # random, optional - mathematica True """ from sage.interfaces.mathematica import mathematica @@ -128,7 +133,7 @@ def has_maple(): EXAMPLES:: sage: from sage.doctest.external import has_maple - sage: has_maple() # random + sage: has_maple() # random, optional - maple True """ from sage.interfaces.maple import maple @@ -145,7 +150,7 @@ def has_macaulay2(): EXAMPLES:: sage: from sage.doctest.external import has_macaulay2 - sage: has_macaulay2() # random + sage: has_macaulay2() # random, optional - macaulay2 True """ from sage.interfaces.macaulay2 import macaulay2 @@ -162,7 +167,7 @@ def has_octave(): EXAMPLES:: sage: from sage.doctest.external import has_octave - sage: has_octave() # random + sage: has_octave() # random, optional - octave True """ from sage.interfaces.octave import octave @@ -192,7 +197,7 @@ def has_scilab(): EXAMPLES:: sage: from sage.doctest.external import has_scilab - sage: has_scilab() # random + sage: has_scilab() # random, optional - scilab True """ from sage.interfaces.scilab import scilab @@ -209,7 +214,7 @@ def has_cplex(): EXAMPLES:: sage: from sage.doctest.external import has_cplex - sage: has_cplex() # random + sage: has_cplex() # random, optional - CPLEX True """ from sage.numerical.mip import MixedIntegerLinearProgram @@ -226,7 +231,7 @@ def has_gurobi(): EXAMPLES:: sage: from sage.doctest.external import has_gurobi - sage: has_gurobi() # random + sage: has_gurobi() # random, optional - Gurobi True """ from sage.numerical.mip import MixedIntegerLinearProgram @@ -299,7 +304,7 @@ def _lookup(software): EXAMPLES:: - sage: sage.doctest.external._lookup('internet') # random + sage: sage.doctest.external._lookup('internet') # random, optional - internet True """ if software in external_software: @@ -332,9 +337,9 @@ class AvailableSoftware(object): 'octave', 'pandoc', 'scilab'] - sage: 'internet' in available_software # random + sage: 'internet' in available_software # random, optional - internet True - sage: available_software.issuperset(set(['internet','latex'])) # random + sage: available_software.issuperset(set(['internet','latex'])) # random, optional - internet latex True """ def __init__(self): @@ -360,7 +365,7 @@ def __contains__(self, item): EXAMPLES:: sage: from sage.doctest.external import available_software - sage: 'internet' in available_software # random + sage: 'internet' in available_software # random, optional - internet True """ try: @@ -386,7 +391,7 @@ def issuperset(self, other): EXAMPLES:: sage: from sage.doctest.external import available_software - sage: available_software.issuperset(set(['internet','latex','magma'])) # random + sage: available_software.issuperset(set(['internet','latex','magma'])) # random, optional - internet latex magma True """ for item in other: From a0d4b161927b4de45374b6508f6cf5d2e019cb6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 8 Dec 2019 12:57:24 +0100 Subject: [PATCH 293/340] trac 28632 better cache, change examples for Eulerian numbers --- src/sage/combinat/combinat.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index dc4073b5d97..46f7f21c052 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -553,7 +553,7 @@ def euler_number(n, algorithm='flint'): raise ValueError("algorithm must be 'flint' or 'maxima'") -@cached_function +@cached_function(key=lambda n, k, a: (n, k)) def eulerian_number(n, k, algorithm='recursive'): """ Return the Eulerian number of index ``(n, k)``. @@ -582,8 +582,8 @@ def eulerian_number(n, k, algorithm='recursive'): TESTS:: - sage: [eulerian_number(5,i,"formula") for i in range(5)] - [1, 26, 66, 26, 1] + sage: [eulerian_number(6,i,"formula") for i in range(6)] + [1, 57, 302, 302, 57, 1] """ n = ZZ(n) if k == 0 or k == n - 1: @@ -596,7 +596,7 @@ def eulerian_number(n, k, algorithm='recursive'): for m in range(k + 1)) -@cached_function +@cached_function(key=lambda n, a: n) def eulerian_polynomial(n, algorithm='derivative'): """ Return the Eulerian polynomial of index ``n``. @@ -627,8 +627,8 @@ def eulerian_polynomial(n, algorithm='derivative'): sage: eulerian_polynomial(7)(1) == factorial(7) True - sage: eulerian_polynomial(5, algorithm='coeffs') - t^4 + 26*t^3 + 66*t^2 + 26*t + 1 + sage: eulerian_polynomial(6, algorithm='coeffs') + t^5 + 57*t^4 + 302*t^3 + 302*t^2 + 57*t + 1 REFERENCES: @@ -645,7 +645,7 @@ def eulerian_polynomial(n, algorithm='derivative'): A = eulerian_polynomial(n - 1, algorithm=algorithm) return t * (1 - t) * A.derivative() + (1 + (n - 1) * t) * A elif algorithm == 'coeffs': - return R([eulerian_number(n, k) for k in range(n)]) + return R([eulerian_number(n, k, "formula") for k in range(n)]) def fibonacci(n, algorithm="pari"): From de418417203a71142c327f99f5e98fdfa1f9dd7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 8 Dec 2019 13:02:40 +0100 Subject: [PATCH 294/340] trac 28632 better doctest for Catalan --- src/sage/combinat/combinat.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index 46f7f21c052..31242dbacbb 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -449,8 +449,9 @@ def catalan_number(n): sage: [catalan_number(i) for i in range(7)] [1, 1, 2, 5, 14, 42, 132] - sage: taylor((-1/2)*sqrt(1 - 4*x^2), x, 0, 15) - 132*x^14 + 42*x^12 + 14*x^10 + 5*x^8 + 2*x^6 + x^4 + x^2 - 1/2 + sage: x = (QQ[['x']].0).O(8) + sage: (-1/2)*sqrt(1 - 4*x) + -1/2 + x + x^2 + 2*x^3 + 5*x^4 + 14*x^5 + 42*x^6 + 132*x^7 + O(x^8) sage: [catalan_number(i) for i in range(-7,7)] [0, 0, 0, 0, 0, 0, -1/2, 1, 1, 2, 5, 14, 42, 132] sage: [catalan_number(n).mod(2) for n in range(16)] From 87c3057957495ee3ff135e88f792151b8c89cea9 Mon Sep 17 00:00:00 2001 From: Release Manager Date: Sun, 8 Dec 2019 22:22:04 +0100 Subject: [PATCH 295/340] Updated SageMath version to 9.0.beta9 --- VERSION.txt | 2 +- build/pkgs/configure/checksums.ini | 6 +++--- build/pkgs/configure/package-version.txt | 2 +- src/bin/sage-version.sh | 6 +++--- src/sage/version.py | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index 9d9a6dbdb67..615e8ce6e5c 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 9.0.beta8, Release Date: 2019-12-01 +SageMath version 9.0.beta9, Release Date: 2019-12-08 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 0ede27c8a05..5b8c3b855a7 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=a2caaf716e5fc337d3e6cbe183b4053044a787e7 -md5=53beeb0688c649dceb5c25581b8db20b -cksum=1086485538 +sha1=01328191e9d2fd853525a20a951ae84b15ebab13 +md5=e69a2028835f1d7d2b685bab4f833b64 +cksum=1396398076 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 12817cdd87e..a55ce1adebf 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -7b3f429848d4d67dfb826d57838416907bd3100d +abea10f4aefd6b14aa0598f16dddcca06be0c41b diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 8ac3783e8c5..caf812d3923 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -1,5 +1,5 @@ # Sage version information for shell scripts # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='9.0.beta8' -SAGE_RELEASE_DATE='2019-12-01' -SAGE_VERSION_BANNER='SageMath version 9.0.beta8, Release Date: 2019-12-01' +SAGE_VERSION='9.0.beta9' +SAGE_RELEASE_DATE='2019-12-08' +SAGE_VERSION_BANNER='SageMath version 9.0.beta9, Release Date: 2019-12-08' diff --git a/src/sage/version.py b/src/sage/version.py index e78f9f37b84..217bcfd0b05 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 = '9.0.beta8' -date = '2019-12-01' -banner = 'SageMath version 9.0.beta8, Release Date: 2019-12-01' +version = '9.0.beta9' +date = '2019-12-08' +banner = 'SageMath version 9.0.beta9, Release Date: 2019-12-08' From 7d6f0aa1714620de4b1c45c27e46e71d316f75bb Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Tue, 6 Aug 2019 17:09:09 -0400 Subject: [PATCH 296/340] Trac #28329: suppress warnings from failed swap statistics collection. On Linux, the swap_memory() function in psutil tries to collect swap statistics from the /proc/vmstat file. It looks for two lines named "pswpin" and "pswpout", and throws a warning if they aren't found. Indeed, the presence of those lines is controlled by the kernel CONFIG_VM_EVENT_COUNTERS option, so they may not exist. The resulting warning is superfluous because we don't use those particular statistics for anything in SageMath. But it's rather ugly, and is displayed to the user every time SageMath is started. And what's worse, the additional output from commands like "sage -t" causes some doctests to fail. This commit adds a global "ignore" filter for this warning in sage/all.py. The obvious approach -- to ignore the warning locally in a catch_warnings() context -- doesn't work because that context manager is not thread-safe (other tests begin to fail if we try). --- src/sage/all.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/sage/all.py b/src/sage/all.py index 1e36169b1b2..a431d6bda46 100644 --- a/src/sage/all.py +++ b/src/sage/all.py @@ -81,6 +81,15 @@ from functools import reduce # in order to keep reduce in python3 import sage.misc.lazy_import + +# The psutil swap_memory() function tries to collect some statistics +# that may not be available and that we don't need. Hide the warnings +# that are emitted if the stats aren't available (Trac #28329). That +# function is called in two places, so let's install this filter +# before the first one is imported from sage.misc.all below. +import warnings +warnings.filterwarnings('ignore', category=RuntimeWarning, + message=r"'sin' and 'sout' swap memory stats couldn't be determined") from sage.misc.all import * # takes a while from sage.typeset.all import * from sage.repl.all import * @@ -301,7 +310,6 @@ def _write_started_file(): O.close() -import warnings try: warnings.filters.remove(('ignore', None, DeprecationWarning, None, 0)) except ValueError: From 717ff0fb6cb79c2c74fd294633f838400018c9b2 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 9 Dec 2019 12:49:05 +1000 Subject: [PATCH 297/340] Adding Eulerian numbers to the documentation. --- src/sage/combinat/combinat.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index 31242dbacbb..d5532574e9f 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -17,6 +17,8 @@ - Euler numbers, :func:`euler_number` (Maxima) +- Eulerian numbers, :func:`eulerian_number` + - Eulerian polynomial, :func:`eulerian_polynomial` - Fibonacci numbers, :func:`fibonacci` (PARI) and From 20e5444714dc867c4a3b5080cf2c89bbdba0bc22 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Mon, 9 Dec 2019 11:51:19 +0100 Subject: [PATCH 298/340] convert between bytes and strings --- src/sage/interfaces/frobby.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/sage/interfaces/frobby.py b/src/sage/interfaces/frobby.py index 2cb59b9491a..bdbbd0f3cc3 100644 --- a/src/sage/interfaces/frobby.py +++ b/src/sage/interfaces/frobby.py @@ -78,7 +78,13 @@ def __call__(self, action, input=None, options=[], verbose=False): print("Frobby input:\n", input) process = Popen(command, stdin = PIPE, stdout = PIPE, stderr = PIPE) - output, err = process.communicate(input = input) + if input: + frinput = bytes(input,'ascii') + else: + frinput = None + output, err = process.communicate(input = frinput) + output = output.decode('ascii') + err = err.decode('ascii') if verbose: print("Frobby output:\n", output) From a863098cd8208c9926cd5b3444902f7e20bf17c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 9 Dec 2019 14:00:31 +0100 Subject: [PATCH 299/340] some enhanced tests in schemes folder (about len) --- src/sage/schemes/curves/affine_curve.py | 8 +++--- src/sage/schemes/curves/projective_curve.py | 4 +-- src/sage/schemes/elliptic_curves/BSD.py | 5 ++-- src/sage/schemes/elliptic_curves/ell_field.py | 6 ++--- src/sage/schemes/elliptic_curves/ell_point.py | 2 +- .../elliptic_curves/ell_rational_field.py | 8 +++--- .../schemes/elliptic_curves/isogeny_class.py | 2 +- .../elliptic_curves/isogeny_small_degree.py | 2 +- .../schemes/elliptic_curves/kodaira_symbol.py | 8 +++--- .../schemes/elliptic_curves/padic_lseries.py | 4 +-- .../schemes/elliptic_curves/saturation.py | 8 +++--- .../schemes/plane_conics/con_finite_field.py | 25 ++++++++----------- src/sage/schemes/toric/divisor.py | 8 +++--- src/sage/schemes/toric/variety.py | 4 +-- src/sage/schemes/toric/weierstrass.py | 6 ++--- 15 files changed, 49 insertions(+), 51 deletions(-) diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index ce577ba84e2..f6fc40f11e8 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -796,7 +796,7 @@ def extension(self): # map from the patch to the original curve, and the set of singular points # of the patch res = [[C, [placeholder], placeholder, C.singular_points()]] - if len(res[0][3]) == 0: + if not res[0][3]: if C.is_smooth(): raise TypeError("this curve is already nonsingular") else: @@ -808,7 +808,7 @@ def extension(self): while not_resolved: [BC, t_maps, pi, pts] = [res[t][0], res[t][1], res[t][2], res[t][3]] # check if there are any singular points in this patch - if len(pts) == 0: + if not pts: t = t + 1 if t == len(res): not_resolved = False @@ -845,7 +845,7 @@ def extension(self): if tmp_curve.is_singular(tmp_pt): n_pts.append(tmp_pt) # avoid needlessly extending the base field - if len(n_pts) > 0: + if n_pts: # coerce everything to the new base field BC = BC.change_ring(emb) t_maps = [t_maps[j].change_ring(emb) for j in range(len(t_maps))] @@ -1064,7 +1064,7 @@ def local_coordinates(self, pt, n): for x in e: for y in vars0: if str(y) in x: - if len(x.replace(str(y),"")) != 0: + if x.replace(str(y), ""): i = x.find("-") if i>0: vals.append([eval(x[1:i]),x[:i],F(eval(x[i+1:]))]) diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index b5bd3c8c3ea..5393b58172c 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -678,7 +678,7 @@ def local_coordinates(self, pt, n): for x in e: for y in vars0: if str(y) in x: - if len(x.replace(str(y),"")): + if x.replace(str(y), ""): i = x.find("-") if i>0: vals.append([eval(x[1:i]),x[:i],F(eval(x[i+1:]))]) @@ -1380,7 +1380,7 @@ def extension(self): pts.pop(i) except TypeError: pts.pop(i) - if len(pts) > 0: + if pts: temp_exc = C.excellent_position(pts[0]) temp_qua = temp_exc.codomain().quadratic_transform() C = temp_qua.codomain() diff --git a/src/sage/schemes/elliptic_curves/BSD.py b/src/sage/schemes/elliptic_curves/BSD.py index a1d867367f0..7bb2545d007 100644 --- a/src/sage/schemes/elliptic_curves/BSD.py +++ b/src/sage/schemes/elliptic_curves/BSD.py @@ -598,7 +598,8 @@ def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, if verbosity > 0: s = str(BSD.primes)[1:-1] if 2 not in BSD.primes: - if len(s) == 0: s = '2' + if not s: + s = '2' else: s = '2, '+s print('True for p not in {' + s + '} by Kolyvagin.') BSD.proof['finite'] = copy(BSD.primes) @@ -899,7 +900,7 @@ def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, # print some extra information if verbosity > 1: - if len(BSD.primes) > 0: + if BSD.primes: print('Remaining primes:') for p in BSD.primes: s = 'p = ' + str(p) + ': ' diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index 2d441957d33..e4f705e4dc3 100644 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -440,7 +440,7 @@ def is_quadratic_twist(self, other): um = c6E/c6F x=rings.polygen(K) ulist=(x**3-um).roots(multiplicities=False) - if len(ulist)==0: + if not ulist: D = zero else: D = ulist[0] @@ -448,7 +448,7 @@ def is_quadratic_twist(self, other): um=c4E/c4F x=rings.polygen(K) ulist=(x**2-um).roots(multiplicities=False) - if len(ulist)==0: + if not ulist: D = zero else: D = ulist[0] @@ -705,7 +705,7 @@ def descend_to(self, K, f=None): return [] elif f is None: embeddings = K.embeddings(L) - if len(embeddings) == 0: + if not embeddings: raise TypeError("Input must be a subfield of the base field of the curve.") for g in embeddings: try: diff --git a/src/sage/schemes/elliptic_curves/ell_point.py b/src/sage/schemes/elliptic_curves/ell_point.py index da3fc60a761..9a8648260ef 100644 --- a/src/sage/schemes/elliptic_curves/ell_point.py +++ b/src/sage/schemes/elliptic_curves/ell_point.py @@ -3180,7 +3180,7 @@ def elliptic_logarithm(self, embedding=None, precision=100, if emb is None: emb = K.embeddings(RealField(precision)) - if len(emb) > 0: + if emb: emb = emb[0] else: emb = K.embeddings(ComplexField(precision))[0] diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index d8a6a5ec580..3f1834df0b5 100644 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -2298,7 +2298,7 @@ def _compute_gens(self, proof, misc.verbose("Trying direct search up to height %s"%h) G = self.point_search(h, verbose) G = [P for P in G if P.order() == oo] - if len(G) > 0: + if G: misc.verbose("Direct search succeeded.") G, _, _ = self.saturation(G, verbose=verbose) misc.verbose("Computed saturation.") @@ -2566,8 +2566,8 @@ def saturation(self, points, verbose=False, max_prime=0, odd_primes_only=False): """ if not isinstance(points, list): - raise TypeError("points (=%s) must be a list."%points) - if len(points) == 0: + raise TypeError("points (=%s) must be a list." % points) + if not points: return [], None, R(1) v = [] @@ -6962,7 +6962,7 @@ def elliptic_curve_congruence_graph(curves): n = a_E[l] - a_F[l] if n != 0: p_edges = [p for p in p_edges if p.divides(n)] - if len(p_edges): + if p_edges: G.add_edge(E.cremona_label(), F.cremona_label(), p_edges) return G diff --git a/src/sage/schemes/elliptic_curves/isogeny_class.py b/src/sage/schemes/elliptic_curves/isogeny_class.py index d09a011f394..6742a4635d8 100644 --- a/src/sage/schemes/elliptic_curves/isogeny_class.py +++ b/src/sage/schemes/elliptic_curves/isogeny_class.py @@ -1068,7 +1068,7 @@ def _compute(self): raise RuntimeError("unable to find %s in the database" % self.E) db = sage.databases.cremona.CremonaDatabase() curves = db.isogeny_class(label) - if len(curves) == 0: + if not curves: raise RuntimeError("unable to find %s in the database" % self.E) # All curves will have the same conductor and isogeny class, # and there are most 8 of them, so lexicographic sorting is okay. diff --git a/src/sage/schemes/elliptic_curves/isogeny_small_degree.py b/src/sage/schemes/elliptic_curves/isogeny_small_degree.py index 4a61dfdbbf5..7178da3685a 100644 --- a/src/sage/schemes/elliptic_curves/isogeny_small_degree.py +++ b/src/sage/schemes/elliptic_curves/isogeny_small_degree.py @@ -1726,7 +1726,7 @@ def isogenies_prime_degree_genus_plus_0(E, l=None, minimal_models=True): S += [[u0,v0] for v0 in (X**2-f(u0)).roots(multiplicities=False)] else: S += [[u0,(2*j-a(u0))/b(u0)]] - if len(S) == 0: + if not S: return [] S.sort() diff --git a/src/sage/schemes/elliptic_curves/kodaira_symbol.py b/src/sage/schemes/elliptic_curves/kodaira_symbol.py index e968d21a7d0..b33595b5dda 100644 --- a/src/sage/schemes/elliptic_curves/kodaira_symbol.py +++ b/src/sage/schemes/elliptic_curves/kodaira_symbol.py @@ -44,7 +44,7 @@ """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 David Roe # William Stein # @@ -57,8 +57,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.sage_object import SageObject from sage.structure.richcmp import richcmp_method, richcmp @@ -152,7 +152,7 @@ def __init__(self, symbol): self._starred = (n < 0) self._pari = n return - elif len(symbol) == 0: + elif not symbol: raise TypeError("symbol must be a nonempty string") if symbol[0] == "I": symbol = symbol[1:] diff --git a/src/sage/schemes/elliptic_curves/padic_lseries.py b/src/sage/schemes/elliptic_curves/padic_lseries.py index adefa408f6f..248539914b5 100644 --- a/src/sage/schemes/elliptic_curves/padic_lseries.py +++ b/src/sage/schemes/elliptic_curves/padic_lseries.py @@ -948,7 +948,7 @@ def series(self, n=2, quadratic_twist=+1, prec=5, eta=0): R = PowerSeriesRing(K,'T',res_series_prec) L = R(L,res_series_prec) aj = L.list() - if len(aj) > 0: + if aj: aj = [aj[0].add_bigoh(padic_prec-2)] + \ [aj[j].add_bigoh(bounds[j]) for j in range(1,len(aj))] L = R(aj,res_series_prec ) @@ -1214,7 +1214,7 @@ def series(self, n=3, quadratic_twist=+1, prec=5, eta=0): # the coefficients are now treated as alpha-adic numbers (trac 20254) L = R(L,prec) aj = L.list() - if len(aj) > 0: + if aj: bj = [aj[0].add_bigoh(2*(padic_prec-2))] j = 1 while j < len(aj): diff --git a/src/sage/schemes/elliptic_curves/saturation.py b/src/sage/schemes/elliptic_curves/saturation.py index 6d6459079d4..72c1dbf7f42 100644 --- a/src/sage/schemes/elliptic_curves/saturation.py +++ b/src/sage/schemes/elliptic_curves/saturation.py @@ -308,8 +308,8 @@ def a(pt,g): for Q in K.primes_above(q, degree=1): if not E.is_local_integral_model(Q) or Edisc.valuation(Q)!=0: continue - vecs = projections(Q,p) - if len(vecs) == 0: + vecs = projections(Q, p) + if not vecs: continue for v in vecs: A = matrix(A.rows()+[v]) @@ -421,8 +421,8 @@ def full_p_saturation(Plist, p, lin_combs = dict(), verbose=False): 1) """ - if len(Plist) == 0: - return Plist, ZZ(0) + if not Plist: + return Plist, ZZ.zero() exponent = ZZ(0) diff --git a/src/sage/schemes/plane_conics/con_finite_field.py b/src/sage/schemes/plane_conics/con_finite_field.py index 39f118fc667..de09ed5c057 100644 --- a/src/sage/schemes/plane_conics/con_finite_field.py +++ b/src/sage/schemes/plane_conics/con_finite_field.py @@ -7,7 +7,7 @@ """ from __future__ import absolute_import -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009/2010 Marco Streng # # Distributed under the terms of the GNU General Public License (GPL) @@ -19,16 +19,18 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.rings.all import PolynomialRing from sage.schemes.curves.projective_curve import ProjectivePlaneCurve_finite_field from .con_field import ProjectiveConic_field + class ProjectiveConic_finite_field(ProjectiveConic_field, ProjectivePlaneCurve_finite_field): r""" Create a projective plane conic curve over a finite field. + See ``Conic`` for full documentation. EXAMPLES:: @@ -54,7 +56,6 @@ def __init__(self, A, f): """ ProjectiveConic_field.__init__(self, A, f) - def count_points(self, n): r""" If the base field `B` of `self` is finite of order `q`, @@ -70,10 +71,9 @@ def count_points(self, n): """ F = self.base_ring() q = F.cardinality() - return [q**i+1 for i in range(1, n+1)] - + return [q**i + 1 for i in range(1, n + 1)] - def has_rational_point(self, point = False, read_cache = True, \ + def has_rational_point(self, point = False, read_cache = True, algorithm = 'default'): r""" Always returns ``True`` because self has a point defined over @@ -135,10 +135,7 @@ def has_rational_point(self, point = False, read_cache = True, \ return True, pt while True: x = B.random_element() - Y = PolynomialRing(B,'Y').gen() - r = self.defining_polynomial()([x,Y,1]).roots() - if len(r) > 0: - return True, self.point([x,r[0][0],B(1)]) - - - + Y = PolynomialRing(B, 'Y').gen() + r = self.defining_polynomial()([x, Y, 1]).roots() + if r: + return True, self.point([x, r[0][0], B(1)]) diff --git a/src/sage/schemes/toric/divisor.py b/src/sage/schemes/toric/divisor.py index 5ef1081f94b..daf8c3b9f3b 100644 --- a/src/sage/schemes/toric/divisor.py +++ b/src/sage/schemes/toric/divisor.py @@ -156,15 +156,15 @@ """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Volker Braun # Copyright (C) 2012 Andrey Novoseltsev # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from six.moves import zip from sage.combinat.combination import Combinations @@ -1528,7 +1528,7 @@ def Kodaira_map(self, names='z'): x^2*u*z*w^2 : y*v^2*z^2*w : x*v*z^2*w^2) """ sections = self.sections_monomials() - if len(sections) == 0: + if not sections: raise ValueError('The Kodaira map is not defined for divisors without sections.') src = self.parent().scheme() from sage.schemes.projective.projective_space import ProjectiveSpace diff --git a/src/sage/schemes/toric/variety.py b/src/sage/schemes/toric/variety.py index 60c95f9a332..e1d964200d1 100644 --- a/src/sage/schemes/toric/variety.py +++ b/src/sage/schemes/toric/variety.py @@ -3498,10 +3498,10 @@ def part_of_degree(self, d): Q = self.parent() # We iterate over monomials of self.lift() p = [x for x in self.lift() if x[1].total_degree() == d] - if len(p)==0: + if not p: return Q.zero() else: - return Q(sum(x[0]*x[1] for x in p)) + return Q.sum(x[0] * x[1] for x in p) def exp(self): r""" diff --git a/src/sage/schemes/toric/weierstrass.py b/src/sage/schemes/toric/weierstrass.py index 9e913cc1e72..788dc3d1ae2 100644 --- a/src/sage/schemes/toric/weierstrass.py +++ b/src/sage/schemes/toric/weierstrass.py @@ -134,7 +134,7 @@ # # Distributed under the terms of the GNU General Public License (GPL) # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ######################################################################## from __future__ import print_function @@ -606,9 +606,9 @@ def index(monomial): i = index(m) coeffs[i] = c*m + coeffs.pop(i, R.zero()) result = tuple(coeffs.pop(index(m), R.zero()) // m for m in monomials) - if len(coeffs) != 0: + if coeffs: raise ValueError('The polynomial contains more monomials than ' - 'given: '+str(coeffs)) + 'given: ' + str(coeffs)) return result From 8035353f21fd01af81d90e6fa7e229ed81245ccc Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Mon, 9 Dec 2019 15:36:13 +0100 Subject: [PATCH 300/340] Use str_to_bytes and bytes_to_str --- src/sage/interfaces/frobby.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sage/interfaces/frobby.py b/src/sage/interfaces/frobby.py index 961d89ad725..e10da8a0123 100644 --- a/src/sage/interfaces/frobby.py +++ b/src/sage/interfaces/frobby.py @@ -26,6 +26,8 @@ from subprocess import Popen, PIPE from sage.misc.misc_c import prod +from sage.cpython.string import bytes_to_str, str_to_bytes + class Frobby: def __call__(self, action, input=None, options=[], verbose=False): @@ -79,12 +81,12 @@ def __call__(self, action, input=None, options=[], verbose=False): process = Popen(command, stdin = PIPE, stdout = PIPE, stderr = PIPE) if input: - frinput = bytes(input,'ascii') + frinput = str_to_bytes(input) else: frinput = None output, err = process.communicate(input = frinput) - output = output.decode('ascii') - err = err.decode('ascii') + output = bytes_to_str(output) + err = bytes_to_str(err) if verbose: print("Frobby output:\n", output) From 0b4843dac553a5918e047ecc98dd4e5643848f69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 9 Dec 2019 18:04:51 +0100 Subject: [PATCH 301/340] some trivial changes for spaces around = in combinat --- .../cluster_algebra_quiver/cluster_seed.py | 6 +++--- .../combinat/crystals/highest_weight_crystals.py | 2 +- src/sage/combinat/designs/database.py | 10 +++++----- .../designs/orthogonal_arrays_build_recursive.py | 6 +++--- src/sage/combinat/designs/resolvable_bibd.py | 3 ++- .../designs/steiner_quadruple_systems.py | 2 +- .../combinat/designs/subhypergraph_search.pyx | 3 ++- src/sage/combinat/free_module.py | 4 ++-- src/sage/combinat/k_tableau.py | 6 +++--- .../multiset_partition_into_sets_ordered.py | 2 +- .../combinat/non_decreasing_parking_function.py | 2 +- src/sage/combinat/ordered_tree.py | 2 +- src/sage/combinat/parallelogram_polyomino.py | 2 +- src/sage/combinat/permutation.py | 8 ++++---- src/sage/combinat/posets/hasse_diagram.py | 4 ++-- src/sage/combinat/root_system/branching_rules.py | 6 +++--- .../root_system/hecke_algebra_representation.py | 2 +- .../non_symmetric_macdonald_polynomials.py | 8 ++++---- .../root_system/root_lattice_realizations.py | 2 +- src/sage/combinat/sf/k_dual.py | 4 ++-- src/sage/combinat/sf/llt.py | 4 ++-- src/sage/combinat/sf/new_kschur.py | 16 ++++++++-------- src/sage/combinat/sf/sf.py | 6 +++--- src/sage/combinat/tableau.py | 12 ++++++------ src/sage/combinat/vector_partition.py | 13 +++++++------ src/sage/combinat/words/word_generators.py | 6 +++--- 26 files changed, 72 insertions(+), 69 deletions(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index d5c469050a0..79f582b0f6f 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -973,7 +973,7 @@ def _repr_(self): name += ' with %s frozen variables'%self._m return name - def plot(self, circular=False, mark=None, save_pos=False, force_c =False, with_greens=False, add_labels = False): + def plot(self, circular=False, mark=None, save_pos=False, force_c=False, with_greens=False, add_labels=False): r""" Returns the plot of the quiver of ``self``. @@ -1011,7 +1011,7 @@ def plot(self, circular=False, mark=None, save_pos=False, force_c =False, with_g return quiver.plot(circular=circular, mark=mark, save_pos=save_pos, greens=greens) - def show(self, fig_size=1, circular=False, mark=None, save_pos=False, force_c = False, with_greens= False, add_labels = False): + def show(self, fig_size=1, circular=False, mark=None, save_pos=False, force_c=False, with_greens=False, add_labels=False): r""" Shows the plot of the quiver of ``self``. @@ -2866,7 +2866,7 @@ def mutation_analysis(self, options=['all'], filter=None): if 'red_vertices_diff' in options or ('all' in options and self._use_c_vec): initial_red_vertices = self.red_vertices() if 'urban_renewals_diff' in options or 'all' in options: - initial_urban_renewals= self.urban_renewals() + initial_urban_renewals = self.urban_renewals() if 'sources_diff' in options or 'all' in options: initial_sources = self.quiver().sources() if 'sinks_diff' in options or 'all' in options: diff --git a/src/sage/combinat/crystals/highest_weight_crystals.py b/src/sage/combinat/crystals/highest_weight_crystals.py index b6c74823063..283f92ef1d5 100644 --- a/src/sage/combinat/crystals/highest_weight_crystals.py +++ b/src/sage/combinat/crystals/highest_weight_crystals.py @@ -261,7 +261,7 @@ def _repr_(self): EXAMPLES:: sage: C = CartanType(['E',6]) - sage: La =C.root_system().weight_lattice().fundamental_weights() + sage: La = C.root_system().weight_lattice().fundamental_weights() sage: crystals.HighestWeight(2*La[2]) Finite dimensional highest weight crystal of type ['E', 6] and highest weight 2*Lambda[2] """ diff --git a/src/sage/combinat/designs/database.py b/src/sage/combinat/designs/database.py index a0dd1391084..91e2f54fc70 100644 --- a/src/sage/combinat/designs/database.py +++ b/src/sage/combinat/designs/database.py @@ -424,7 +424,7 @@ def OA_7_66(): # base block of a (73,9,1) BIBD B = [0, 19, 26, 14, 63, 15, 32, 35, 65] # The corresponding BIBD - BIBD= [[(x+i)%73 for x in B] for i in range(73)] + BIBD = [[(x+i)%73 for x in B] for i in range(73)] # the first 7 elements of an oval # # (this is the only difference with the OA(7,68) construction) @@ -464,7 +464,7 @@ def OA_7_68(): # base block of a (73,9,1) BIBD B = [0, 19, 26, 14, 63, 15, 32, 35, 65] # The corresponding BIBD - BIBD= [[(x+i)%73 for x in B] for i in range(73)] + BIBD = [[(x+i)%73 for x in B] for i in range(73)] # the first 5 elements of an oval # # (this is the only difference with the OA(7,66) construction) @@ -503,7 +503,7 @@ def OA_8_69(): # base block of a (73,9,1) BIBD B = [1,2,4,8,16,32,37,55,64] # The corresponding BIBD - BIBD= [[(x+i)%73 for x in B] for i in range(73)] + BIBD = [[(x+i)%73 for x in B] for i in range(73)] oval = [72,71,69,65] # PBD minus the oval PBD = [[x for x in B if x not in oval] for B in BIBD] @@ -577,7 +577,7 @@ def OA_7_74(): # base block of a (91,10,1) BIBD B = [0,1,3,9,27,81,61,49,56,77] # The corresponding BIBD - BIBD= [[(x+i)%91 for x in B] for i in range(91)] + BIBD = [[(x+i)%91 for x in B] for i in range(91)] # an oval oval = [(-x)%91 for x in B][-7:] # PBD minus the oval+B @@ -616,7 +616,7 @@ def OA_8_76(): # base block of a (91,10,1) BIBD B = [0,1,3,9,27,81,61,49,56,77] # The corresponding BIBD - BIBD= [[(x+i)%91 for x in B] for i in range(91)] + BIBD = [[(x+i)%91 for x in B] for i in range(91)] oval = [2,4,5,12,24] to_remove = oval + B # PBD minus the oval diff --git a/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py b/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py index b6c16ceb5e6..b1a6aa41310 100644 --- a/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py +++ b/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py @@ -709,9 +709,9 @@ def thwart_lemma_3_5(k,n,m,a,b,c,d=0,complement=False,explain_construction=False OA = [list(B[3:]+B[:3]) for B in OA] # Set of values in the axb square - third_complement= set([B[-1] for B in OA if B[-3] < a and B[-2] < b]) + third_complement = set(B[-1] for B in OA if B[-3] < a and B[-2] < b) - assert n-len(third_complement) >= c + assert n - len(third_complement) >= c # The keepers first_set = list(range(a)) @@ -1164,7 +1164,7 @@ def _reorder_matrix(matrix): sage: all(set(M2[i][0] for i in range(N)) == set(range(N)) for i in range(k)) True - sage: M =[list(range(10))]*10 + sage: M = [list(range(10))] * 10 sage: N = k = 10 sage: M2 = _reorder_matrix(M) sage: all(set(M2[i][0] for i in range(N)) == set(range(N)) for i in range(k)) diff --git a/src/sage/combinat/designs/resolvable_bibd.py b/src/sage/combinat/designs/resolvable_bibd.py index 283e39e091c..1f6b07de1f2 100644 --- a/src/sage/combinat/designs/resolvable_bibd.py +++ b/src/sage/combinat/designs/resolvable_bibd.py @@ -348,12 +348,13 @@ def kirkman_triple_system(v,existence=False): k=3, lambd=1, check=True, - copy =False) + copy=False) KTS._classes = classes assert KTS.is_resolvable() return KTS + def v_4_1_rbibd(v,existence=False): r""" Return a `(v,4,1)`-RBIBD. diff --git a/src/sage/combinat/designs/steiner_quadruple_systems.py b/src/sage/combinat/designs/steiner_quadruple_systems.py index 083d0ccfba0..4a7092da2d6 100644 --- a/src/sage/combinat/designs/steiner_quadruple_systems.py +++ b/src/sage/combinat/designs/steiner_quadruple_systems.py @@ -257,7 +257,7 @@ def three_n_minus_four(B): for a in range(2): for aa in range(n-2): for aaa in range(n-2): - aaaa= -(a+aa+aaa)%(n-2) + aaaa = -(a+aa+aaa) % (n-2) Y.append([r(0,aa),r(1,aaa), r(2,aaaa),3*(n-2)+a]) # Line 4. diff --git a/src/sage/combinat/designs/subhypergraph_search.pyx b/src/sage/combinat/designs/subhypergraph_search.pyx index d4ca69ea066..bf06793e43f 100644 --- a/src/sage/combinat/designs/subhypergraph_search.pyx +++ b/src/sage/combinat/designs/subhypergraph_search.pyx @@ -244,7 +244,8 @@ cdef induced_hypergraph(hypergraph * h, int n, hypergraph * tmp): num_sets += 1 tmp.m = num_sets tmp.n = n - tmp.limbs =1 + tmp.limbs = 1 + cdef void trace_hypergraph64(hypergraph * h, int n, hypergraph * tmp): r""" diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index 51be7921346..77ca49304af 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -1330,13 +1330,13 @@ def _repr_(self): sage: T = tensor([F, G]) sage: T # indirect doctest F # G - sage: T.print_options(tensor_symbol= ' @ ') # note the spaces + sage: T.print_options(tensor_symbol=' @ ') # note the spaces sage: T # indirect doctest F @ G To avoid a side\--effect on another doctest, we revert the change:: - sage: T.print_options(tensor_symbol= ' # ') + sage: T.print_options(tensor_symbol=' # ') """ from sage.categories.tensor import tensor if hasattr(self, "_print_options"): diff --git a/src/sage/combinat/k_tableau.py b/src/sage/combinat/k_tableau.py index 39dee9914b0..8770fb9c464 100644 --- a/src/sage/combinat/k_tableau.py +++ b/src/sage/combinat/k_tableau.py @@ -2571,10 +2571,10 @@ def _is_valid_standard( self ): True """ Tshapes = intermediate_shapes(self.to_unmarked_standard_list()) - if not all( Partition(la).is_core(self.k+1) for la in Tshapes): + if not all(Partition(la).is_core(self.k + 1) for la in Tshapes): return False - Tsizes =[Core(lam, self.k+1).length() for lam in Tshapes] - return all(Tsizes[i]==Tsizes[i+1]-1 for i in range(len(Tsizes)-1)) + Tsizes = [Core(lam, self.k + 1).length() for lam in Tshapes] + return all(Tsizes[i] == Tsizes[i+1]-1 for i in range(len(Tsizes)-1)) def is_column_strict_with_weight( self, mu ): """ diff --git a/src/sage/combinat/multiset_partition_into_sets_ordered.py b/src/sage/combinat/multiset_partition_into_sets_ordered.py index b8dc15efab5..792e884c62b 100755 --- a/src/sage/combinat/multiset_partition_into_sets_ordered.py +++ b/src/sage/combinat/multiset_partition_into_sets_ordered.py @@ -2763,7 +2763,7 @@ def _base_iterator(constraints): min_ord = max_ord = constraints["order"] max_k = min(max_k, max_ord) if min_ord: - min_k =max(1, min_k, min_ord // len(A)) + min_k = max(1, min_k, min_ord // len(A)) if infinity not in (max_k, max_ord): return chain(*(_iterator_order(A, ord, range(min_k, max_k+1)) \ for ord in range(min_ord, max_ord+1))) diff --git a/src/sage/combinat/non_decreasing_parking_function.py b/src/sage/combinat/non_decreasing_parking_function.py index 1607749c172..d89b40d527a 100644 --- a/src/sage/combinat/non_decreasing_parking_function.py +++ b/src/sage/combinat/non_decreasing_parking_function.py @@ -371,7 +371,7 @@ def __init__(self): """ TESTS:: - sage: PF= NonDecreasingParkingFunctions() + sage: PF = NonDecreasingParkingFunctions() sage: PF == loads(dumps(PF)) True """ diff --git a/src/sage/combinat/ordered_tree.py b/src/sage/combinat/ordered_tree.py index afab4de22eb..95873af80dc 100644 --- a/src/sage/combinat/ordered_tree.py +++ b/src/sage/combinat/ordered_tree.py @@ -451,7 +451,7 @@ def H(path): lower_path.append(0) lower_path += [1] * (self.node_number() - len(lower_path)) - upper_path =[] + upper_path = [] for i in range(1, len(upper_nodes)): upper_path.append(1) upper_path += [0] * (H(upper_nodes[i]) - H(upper_nodes[i - 1])) diff --git a/src/sage/combinat/parallelogram_polyomino.py b/src/sage/combinat/parallelogram_polyomino.py index 47d23799100..24a0d00081c 100644 --- a/src/sage/combinat/parallelogram_polyomino.py +++ b/src/sage/combinat/parallelogram_polyomino.py @@ -2660,7 +2660,7 @@ def _to_tikz_bounce(self, directions=[0, 1]): sage: pp.to_tikz() == pp._to_tikz_bounce() False sage: pp.set_options(drawing_components=dict( - ....: diagram= False, bounce_0=True) + ....: diagram=False, bounce_0=True) ....: ) sage: pp.to_tikz() == pp._to_tikz_bounce([0]) True diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py index 85c57c4f8b6..64b08f01ba1 100644 --- a/src/sage/combinat/permutation.py +++ b/src/sage/combinat/permutation.py @@ -4253,11 +4253,11 @@ def simion_schmidt(self, avoid=[1,2,3]): EXAMPLES:: - sage: P=Permutations(6) - sage: p=P([4,5,1,6,3,2]) - sage: pl= [ [1,2,3], [1,3,2], [3,1,2], [3,2,1] ] + sage: P = Permutations(6) + sage: p = P([4,5,1,6,3,2]) + sage: pl = [ [1,2,3], [1,3,2], [3,1,2], [3,2,1] ] sage: for q in pl: - ....: s=p.simion_schmidt(q) + ....: s = p.simion_schmidt(q) ....: print("{} {}".format(s, s.has_pattern(q))) [4, 6, 1, 5, 3, 2] False [4, 2, 1, 3, 5, 6] False diff --git a/src/sage/combinat/posets/hasse_diagram.py b/src/sage/combinat/posets/hasse_diagram.py index 90ebb6dafdd..334a1a0985d 100644 --- a/src/sage/combinat/posets/hasse_diagram.py +++ b/src/sage/combinat/posets/hasse_diagram.py @@ -2615,8 +2615,8 @@ def neutral_elements(self): EXAMPLES:: sage: from sage.combinat.posets.hasse_diagram import HasseDiagram - sage: H= HasseDiagram({0: [1, 2], 1: [4], 2: [3], 3: [4, 5], - ....: 4: [6], 5:[6]}) + sage: H = HasseDiagram({0: [1, 2], 1: [4], 2: [3], 3: [4, 5], + ....: 4: [6], 5:[6]}) sage: sorted(H.neutral_elements()) [0, 4, 6] diff --git a/src/sage/combinat/root_system/branching_rules.py b/src/sage/combinat/root_system/branching_rules.py index 24a610611c8..1bc814bff6e 100644 --- a/src/sage/combinat/root_system/branching_rules.py +++ b/src/sage/combinat/root_system/branching_rules.py @@ -451,8 +451,8 @@ def branch_weyl_character(chi, R, S, rule="default"): B4(0,0,0,0) + B4(1/2,1/2,1/2,1/2) + B4(1,0,0,0)] sage: E6 = WeylCharacterRing("E6", style="coroots") - sage: A2xA2xA2=WeylCharacterRing("A2xA2xA2",style="coroots") - sage: A5xA1=WeylCharacterRing("A5xA1",style="coroots") + sage: A2xA2xA2 = WeylCharacterRing("A2xA2xA2",style="coroots") + sage: A5xA1 = WeylCharacterRing("A5xA1",style="coroots") sage: G2 = WeylCharacterRing("G2", style="coroots") sage: A1xA1 = WeylCharacterRing("A1xA1", style="coroots") sage: F4 = WeylCharacterRing("F4",style="coroots") @@ -470,7 +470,7 @@ def branch_weyl_character(chi, R, S, rule="default"): sage: D6xA1 = WeylCharacterRing("D6xA1",style="coroots") sage: E7(1,0,0,0,0,0,0).branch(D6xA1,rule="extended") D6xA1(0,0,0,0,1,0,1) + D6xA1(0,1,0,0,0,0,0) + D6xA1(0,0,0,0,0,0,2) - sage: A5xA2 =WeylCharacterRing("A5xA2",style="coroots") + sage: A5xA2 = WeylCharacterRing("A5xA2",style="coroots") sage: E7(1,0,0,0,0,0,0).branch(A5xA2,rule="extended") A5xA2(0,0,0,1,0,1,0) + A5xA2(0,1,0,0,0,0,1) + A5xA2(1,0,0,0,1,0,0) + A5xA2(0,0,0,0,0,1,1) sage: E8 = WeylCharacterRing("E8",style="coroots") diff --git a/src/sage/combinat/root_system/hecke_algebra_representation.py b/src/sage/combinat/root_system/hecke_algebra_representation.py index 6498afbeaa5..7c4f64a6a5e 100644 --- a/src/sage/combinat/root_system/hecke_algebra_representation.py +++ b/src/sage/combinat/root_system/hecke_algebra_representation.py @@ -626,7 +626,7 @@ def Y_lambdacheck(self, lambdacheck): # and Macdonald polynomials) if self._side == "left": word = tuple([x for x in reversed(word)]) - signs= tuple([x for x in reversed(signs)]) + signs = tuple([x for x in reversed(signs)]) # The power of q implements the fact that Y^\deltacheck = 1/q. # The classical simple coroots have no \deltacheck term. # alpha[0] has a \deltacheck with coefficient one diff --git a/src/sage/combinat/root_system/non_symmetric_macdonald_polynomials.py b/src/sage/combinat/root_system/non_symmetric_macdonald_polynomials.py index 3ae5effddbd..3205a0935f0 100644 --- a/src/sage/combinat/root_system/non_symmetric_macdonald_polynomials.py +++ b/src/sage/combinat/root_system/non_symmetric_macdonald_polynomials.py @@ -15,13 +15,13 @@ Special thanks go to Bogdan Ion and Mark Shimozono for their patient explanations and hand computations to check the code. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013 Nicolas M. Thiery # Anne Schilling # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute from sage.rings.integer_ring import ZZ @@ -1802,7 +1802,7 @@ def symmetric_macdonald_polynomial(self, mu): sage: P = SymmetricFunctions(K).macdonald().P() sage: g = P[2,1].expand(3); g x0^2*x1 + x0*x1^2 + x0^2*x2 + ((-2*q*t^2 + q*t - t^2 + q - t + 2)/(-q*t^2 + 1))*x0*x1*x2 + x1^2*x2 + x0*x2^2 + x1*x2^2 - sage: fe =f.expand(g.parent().gens()); fe + sage: fe = f.expand(g.parent().gens()); fe x0^2*x1 + x0*x1^2 + x0^2*x2 + ((2*q*v^4 + v^4 - q*v^2 + v^2 - q - 2)/(q*v^4 - 1))*x0*x1*x2 + x1^2*x2 + x0*x2^2 + x1*x2^2 sage: g.map_coefficients(lambda x: x.subs(t=v*v)) == fe True diff --git a/src/sage/combinat/root_system/root_lattice_realizations.py b/src/sage/combinat/root_system/root_lattice_realizations.py index 24e9c4c647f..7f9594fde58 100644 --- a/src/sage/combinat/root_system/root_lattice_realizations.py +++ b/src/sage/combinat/root_system/root_lattice_realizations.py @@ -2847,7 +2847,7 @@ def plot_bounding_box(self, **options): plot_options = self.plot_parse_options(**options) return plot_options.bounding_box.plot(color="gray", alpha=0.5, wireframe=False) - def plot_alcove_walk(self, word, start=None, foldings=None, color ="orange", **options): + def plot_alcove_walk(self, word, start=None, foldings=None, color="orange", **options): r""" Plot an alcove walk. diff --git a/src/sage/combinat/sf/k_dual.py b/src/sage/combinat/sf/k_dual.py index b88de0b326a..160eeadfbcc 100644 --- a/src/sage/combinat/sf/k_dual.py +++ b/src/sage/combinat/sf/k_dual.py @@ -903,8 +903,8 @@ def __init__(self, kBoundedRing, prefix): """ CombinatorialFreeModule.__init__(self, kBoundedRing.base_ring(), kBoundedRing.indices(), - category= KBoundedQuotientBases(kBoundedRing), - prefix='%s%d'%(prefix, kBoundedRing.k)) + category=KBoundedQuotientBases(kBoundedRing), + prefix='%s%d' % (prefix, kBoundedRing.k)) self._kBoundedRing = kBoundedRing self.k = kBoundedRing.k diff --git a/src/sage/combinat/sf/llt.py b/src/sage/combinat/sf/llt.py index 7ec00a47cc9..898df50a221 100644 --- a/src/sage/combinat/sf/llt.py +++ b/src/sage/combinat/sf/llt.py @@ -639,7 +639,7 @@ def __init__(self, llt): self._self_to_m_cache = hsp_to_m_cache[level] self._m_to_self_cache = m_to_hsp_cache[level] - LLT_generic.__init__(self, llt, prefix="HSp%s"%level) + LLT_generic.__init__(self, llt, prefix="HSp%s" % level) def _to_m(self, part): @@ -708,7 +708,7 @@ def __init__(self, llt): m_to_hcosp_cache[level] = {} self._self_to_m_cache = hcosp_to_m_cache[level] self._m_to_self_cache = m_to_hcosp_cache[level] - LLT_generic.__init__(self, llt, prefix= "HCosp%s"%level) + LLT_generic.__init__(self, llt, prefix="HCosp%s" % level) def _to_m(self, part): r""" diff --git a/src/sage/combinat/sf/new_kschur.py b/src/sage/combinat/sf/new_kschur.py index 5fcae35fedd..61f9a5db317 100644 --- a/src/sage/combinat/sf/new_kschur.py +++ b/src/sage/combinat/sf/new_kschur.py @@ -980,8 +980,8 @@ def __init__(self, kBoundedRing): """ CombinatorialFreeModule.__init__(self, kBoundedRing.base_ring(), kBoundedRing.indices(), - category= KBoundedSubspaceBases(kBoundedRing, kBoundedRing.t), - prefix='ks%d'%kBoundedRing.k) + category=KBoundedSubspaceBases(kBoundedRing, kBoundedRing.t), + prefix='ks%d' % kBoundedRing.k) self._kBoundedRing = kBoundedRing @@ -1236,8 +1236,8 @@ def __init__(self, kBoundedRing): """ CombinatorialFreeModule.__init__(self, kBoundedRing.base_ring(), kBoundedRing.indices(), - category= KBoundedSubspaceBases(kBoundedRing, kBoundedRing.t), - prefix='ksp%d'%kBoundedRing.k) + category=KBoundedSubspaceBases(kBoundedRing, kBoundedRing.t), + prefix='ksp%d' % kBoundedRing.k) self._kBoundedRing = kBoundedRing @@ -1350,8 +1350,8 @@ def __init__(self, kBoundedRing): """ CombinatorialFreeModule.__init__(self, kBoundedRing.base_ring(), kBoundedRing.indices(), - category= KBoundedSubspaceBases(kBoundedRing, kBoundedRing.t), - prefix='h%d'%kBoundedRing.k) + category=KBoundedSubspaceBases(kBoundedRing, kBoundedRing.t), + prefix='h%d' % kBoundedRing.k) self._kBoundedRing = kBoundedRing @@ -1425,8 +1425,8 @@ def __init__(self, kBoundedRing): """ CombinatorialFreeModule.__init__(self, kBoundedRing.base_ring(), kBoundedRing.indices(), - category= KBoundedSubspaceBases(kBoundedRing, kBoundedRing.base_ring().one()), - prefix='Kks%d'%kBoundedRing.k) + category=KBoundedSubspaceBases(kBoundedRing, kBoundedRing.base_ring().one()), + prefix='Kks%d' % kBoundedRing.k) self._kBoundedRing = kBoundedRing diff --git a/src/sage/combinat/sf/sf.py b/src/sage/combinat/sf/sf.py index 97f0bff0742..cd61a8eabab 100644 --- a/src/sage/combinat/sf/sf.py +++ b/src/sage/combinat/sf/sf.py @@ -1486,7 +1486,7 @@ def kBoundedSubspace(self, k, t='t'): from sage.combinat.sf.new_kschur import KBoundedSubspace return KBoundedSubspace(self, k, t=t) - def kschur(self, k, t ='t'): + def kschur(self, k, t='t'): r""" Returns the `k`-Schur functions. @@ -1506,9 +1506,9 @@ def kschur(self, k, t ='t'): """ return self.kBoundedSubspace(k, t=t).kschur() - def ksplit(self, k, t ='t'): + def ksplit(self, k, t='t'): r""" - Returns the `k`-split basis of the `k`-bounded subspace. + Return the `k`-split basis of the `k`-bounded subspace. EXAMPLES:: diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index 08ffe502703..4c253926fe6 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -74,7 +74,7 @@ - Add a class for tableaux of a given shape (eg Tableaux_shape) """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 Mike Hansen , # 2011 Jason Bandlow # @@ -82,8 +82,8 @@ # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import print_function, absolute_import from six.moves import range, zip, map from six import add_metaclass, text_type @@ -1506,7 +1506,7 @@ def bender_knuth_involution(self, k, rows=None, check=True): sk = SkewTableau(self).bender_knuth_involution(k, rows, False) return SemistandardTableaux()(list(sk)) - @combinatorial_map(name ='reading word permutation') + @combinatorial_map(name='reading word permutation') def reading_word_permutation(self): """ Return the permutation obtained by reading the entries of the @@ -8015,8 +8015,8 @@ def __iter__(self): #Convert the tableau vector back to the regular tableau #format - row_count= [0]*len(pi) - tableau = [[None]*n for n in pi] + row_count = [0] * len(pi) + tableau = [[None] * n for n in pi] for i in range(size): tableau[tableau_vector[i]][row_count[tableau_vector[i]]] = i+1 diff --git a/src/sage/combinat/vector_partition.py b/src/sage/combinat/vector_partition.py index a9d329772e6..59cd9b542bc 100644 --- a/src/sage/combinat/vector_partition.py +++ b/src/sage/combinat/vector_partition.py @@ -83,19 +83,20 @@ def IntegerVectorsIterator(vect, min = None): sage: list(IntegerVectorsIterator([1, 1], min = [1, 0])) [[1, 0], [1, 1]] """ - if len(vect) == 0: + if not vect: yield [] else: if min is None: - min = [0]*len(vect) + min = [0] * len(vect) if vect < min: return else: - for vec in IntegerVectorsIterator(vect[1:], min =min[1:]): - yield [min[0]]+vec - for j in range(min[0]+1,vect[0]+1): + for vec in IntegerVectorsIterator(vect[1:], min=min[1:]): + yield [min[0]] + vec + for j in range(min[0] + 1, vect[0] + 1): for vec in IntegerVectorsIterator(vect[1:]): - yield [j]+vec + yield [j] + vec + class VectorPartition(CombinatorialElement): r""" diff --git a/src/sage/combinat/words/word_generators.py b/src/sage/combinat/words/word_generators.py index 7af41ef2305..9e16021c9f1 100644 --- a/src/sage/combinat/words/word_generators.py +++ b/src/sage/combinat/words/word_generators.py @@ -1892,7 +1892,7 @@ def s_adic(self, sequence, letters, morphisms=None): elif hasattr(morphisms, '__call__'): seq = (morphisms(i) for i in sequence) else: - raise TypeError("morphisms (=%s) must be None, callable or provide a __getitem__ method."%morphisms) + raise TypeError("morphisms (=%s) must be None, callable or provide a __getitem__ method." % morphisms) from sage.combinat.words.word import FiniteWord_class if isinstance(sequence,(tuple,list,str,FiniteWord_class)) \ @@ -1901,12 +1901,12 @@ def s_adic(self, sequence, letters, morphisms=None): return prod(seq)(letters) from itertools import tee - seq_it,seq= tee(seq) + seq_it, seq = tee(seq) m = next(seq_it) W = m.codomain() kwds = {} - kwds['data'] = self._s_adic_iterator(seq,letters) + kwds['data'] = self._s_adic_iterator(seq, letters) kwds['datatype'] = 'iter' kwds['caching'] = True #kwds['check'] = False From 1da26c0a63f73ce9002c4f5f0d8e2430248a5988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 9 Dec 2019 18:29:17 +0100 Subject: [PATCH 302/340] changin some Returns to Return --- src/sage/data_structures/bitset.pxi | 2 +- src/sage/databases/findstat.py | 4 +- src/sage/databases/oeis.py | 26 ++++---- src/sage/databases/sloane.py | 2 +- src/sage/databases/sql_db.py | 60 ++++++++++--------- src/sage/databases/symbolic_data.py | 2 +- src/sage/doctest/forker.py | 2 +- .../endPN_minimal_model.py | 6 +- src/sage/ext/fast_callable.pyx | 22 +++---- 9 files changed, 67 insertions(+), 59 deletions(-) diff --git a/src/sage/data_structures/bitset.pxi b/src/sage/data_structures/bitset.pxi index d725556bef5..4b9ddbca063 100644 --- a/src/sage/data_structures/bitset.pxi +++ b/src/sage/data_structures/bitset.pxi @@ -226,7 +226,7 @@ cdef inline bint bitset_eq(bitset_t a, bitset_t b): cdef inline int bitset_cmp(bitset_t a, bitset_t b): """ - Compare bitsets a and b. Returns 0 if the two sets are + Compare bitsets a and b. Return 0 if the two sets are identical, and consistently return -1 or 1 for two sets that are not equal. diff --git a/src/sage/databases/findstat.py b/src/sage/databases/findstat.py index cb5f9711ac8..a2c596085f6 100644 --- a/src/sage/databases/findstat.py +++ b/src/sage/databases/findstat.py @@ -2051,7 +2051,7 @@ def _richcmp_(self, other, op): def __hash__(self): """ - Returns a hash value for the collection. + Return a hash value for the collection. EXAMPLES:: @@ -2822,7 +2822,7 @@ def _richcmp_(self, other, op): def __hash__(self): """ - Returns a hash value for the map. + Return a hash value for the map. EXAMPLES:: diff --git a/src/sage/databases/oeis.py b/src/sage/databases/oeis.py index 1f46e4d2e52..74dcfc545b6 100644 --- a/src/sage/databases/oeis.py +++ b/src/sage/databases/oeis.py @@ -681,7 +681,7 @@ def __classcall__(cls, ident): def __init__(self, ident): r""" - Initializes an OEIS sequence. + Initialize an OEIS sequence. There is no fetching of additional information about the sequence at this point, only the A-number is required to construct a sequence. @@ -873,7 +873,7 @@ def name(self): def old_IDs(self): r""" - Returns the IDs of the sequence ``self`` corresponding to ancestors of OEIS. + Return the IDs of the sequence ``self`` corresponding to ancestors of OEIS. OUTPUT: @@ -935,7 +935,7 @@ def offsets(self): def author(self): r""" - Returns the author of the sequence in the encyclopedia. + Return the author of the sequence in the encyclopedia. OUTPUT: @@ -1095,7 +1095,7 @@ def natural_object(self): def is_dead(self, warn_only=False): r""" - Tells whether the sequence is dead (i.e. eroneous). + Tell whether the sequence is dead (i.e. erroneous). INPUT: @@ -1142,7 +1142,7 @@ def is_dead(self, warn_only=False): def is_finite(self): r""" - Tells whether the sequence is finite. + Tell whether the sequence is finite. Currently, OEIS only provides a keyword when the sequence is known to be finite. So, when this keyword is not there, we do not know whether @@ -1150,8 +1150,8 @@ def is_finite(self): OUTPUT: - - Returns ``True`` when the sequence is known to be finite. - - Returns ``Unknown`` otherwise. + - ``True`` when the sequence is known to be finite. + - ``Unknown`` otherwise. .. TODO:: @@ -1191,7 +1191,7 @@ def is_finite(self): def is_full(self): r""" - Tells whether the sequence ``self`` is full, that is, if all its + Tell whether the sequence ``self`` is full, that is, if all its elements are listed in ``self.first_terms()``. Currently, OEIS only provides a keyword when the sequence is known to @@ -1200,8 +1200,8 @@ def is_full(self): OUTPUT: - - Returns ``True`` when the sequence is known to be full. - - Returns ``Unknown`` otherwise. + - ``True`` when the sequence is known to be full. + - ``Unknown`` otherwise. EXAMPLES:: @@ -1277,7 +1277,7 @@ def first_terms(self, number=None): def _repr_(self): r""" - Prints the sequence number and a short summary of this sequence. + Print the sequence number and a short summary of this sequence. OUTPUT: @@ -1397,7 +1397,7 @@ def __getitem__(self, i): def __iter__(self): r""" - Iterates over the first terms of ``self``, and raises an error if + Iterate over the first terms of ``self``, and raises an error if those first terms are exhausted and the real associated sequence still have terms to produce. @@ -1834,7 +1834,7 @@ def show(self): def programs(self, language='other'): r""" - Returns programs implementing the sequence ``self`` in the given ``language``. + Return programs implementing the sequence ``self`` in the given ``language``. INPUT: diff --git a/src/sage/databases/sloane.py b/src/sage/databases/sloane.py index 99aba267417..6235e51ca72 100644 --- a/src/sage/databases/sloane.py +++ b/src/sage/databases/sloane.py @@ -118,7 +118,7 @@ def __repr__(self): def __iter__(self): """ - Returns an iterator through the encyclopedia. Elements are of the + Return an iterator through the encyclopedia. Elements are of the form [number, sequence]. """ for i in self.__data__: diff --git a/src/sage/databases/sql_db.py b/src/sage/databases/sql_db.py index c308d3ac686..71e811e8611 100644 --- a/src/sage/databases/sql_db.py +++ b/src/sage/databases/sql_db.py @@ -100,9 +100,12 @@ def regexp(expr, item): """ Function to define regular expressions in pysqlite. - Returns ``True`` if parameter ``item`` matches the regular expression - parameter ``expr``. - Returns ``False`` otherwise (i.e.: no match). + + OUTPUT: + + - ``True`` if parameter ``item`` matches the regular expression + parameter ``expr`` + - ``False`` otherwise (i.e.: no match) REFERENCES: @@ -121,6 +124,7 @@ def regexp(expr, item): r = re.compile(expr) return r.match(item) is not None + def verify_type(type): """ Verify that the specified ``type`` is one of the allowed strings. @@ -143,6 +147,7 @@ def verify_type(type): raise TypeError('%s is not a legal type.'%type) return True + def verify_column(col_dict): """ Verify that ``col_dict`` is in proper format, and return a dict with @@ -176,7 +181,7 @@ def verify_column(col_dict): def verify_operator(operator): """ - Checks that ``operator`` is one of the allowed strings. + Check that ``operator`` is one of the allowed strings. Legal operators include the following strings: - '=' @@ -210,9 +215,10 @@ def verify_operator(operator): raise TypeError('%s is not a legal operator.'%operator) return True + def construct_skeleton(database): """ - Constructs a database skeleton from the sql data. The skeleton data + Construct a database skeleton from the sql data. The skeleton data structure is a triple indexed dictionary of the following format:: | - skeleton -- a triple-indexed dictionary @@ -271,7 +277,7 @@ def construct_skeleton(database): p = 0 def _create_print_table(cur, col_titles, **kwds): """ - Creates a nice printable table from the cursor given with the given + Create a nice printable table from the cursor given with the given column titles. KEYWORDS: @@ -513,7 +519,7 @@ def __init__(self, database, *args, **kwds): def __repr__(self): """ - Overrides the print output to display useful info regarding the + Override the print output to display useful info regarding the query. EXAMPLES:: @@ -540,7 +546,7 @@ def __repr__(self): def get_query_string(self): """ - Returns a copy of the query string. + Return a copy of the query string. EXAMPLES:: @@ -559,7 +565,7 @@ def get_query_string(self): def __iter__(self): """ - Returns an iterator over the results of the query. + Return an iterator over the results of the query. EXAMPLES:: @@ -584,7 +590,7 @@ def __iter__(self): def query_results(self): """ - Runs the query by executing the ``__query_string__``. Returns the + Run the query by executing the ``__query_string__``. Return the results of the query in a list. EXAMPLES:: @@ -605,7 +611,7 @@ def query_results(self): def show(self, **kwds): """ - Displays the result of the query in table format. + Display the result of the query in table format. KEYWORDS: @@ -676,7 +682,7 @@ def show(self, **kwds): def __copy__(self): """ - Returns a copy of itself. + Return a copy of itself. EXAMPLES:: @@ -696,7 +702,7 @@ def __copy__(self): def intersect(self, other, join_table=None, join_dict=None, \ in_place=False): """ - Returns a new ``SQLQuery`` that is the intersection of ``self`` and + Return a new ``SQLQuery`` that is the intersection of ``self`` and ``other``. ``join_table`` and ``join_dict`` can be ``None`` iff the two queries only search one table in the database. All display columns will be concatenated in order: self display cols + other display cols. @@ -826,7 +832,7 @@ def _merge_queries(self, other, ret, join_table, join_dict, operator): def union(self, other, join_table=None, join_dict=None, in_place=False): """ - Returns a new ``SQLQuery`` that is the union of self and other. + Return a new ``SQLQuery`` that is the union of self and other. ``join_table`` and ``join_dict`` can be ``None`` iff the two queries only search one table in the database. All display columns will be concatenated in order: self display cols + other display cols. @@ -1088,7 +1094,7 @@ def __init__(self, filename=None, read_only=None, skeleton=None): def __repr__(self): """ - Overrides the print output to display useful info regarding the + Override the print output to display useful info regarding the database. EXAMPLES:: @@ -1114,7 +1120,7 @@ def __repr__(self): def __copy__(self): """ - Returns an instance of ``SQLDatabase`` that points to a copy database, + Return an instance of ``SQLDatabase`` that points to a copy database, and allows modification. EXAMPLES:: @@ -1197,7 +1203,7 @@ def save(self, filename): def get_skeleton(self, check=False): """ - Returns a dictionary representing the hierarchical structure of the + Return a dictionary representing the hierarchical structure of the database, in the following format:: | - skeleton -- a triple-indexed dictionary @@ -1244,7 +1250,7 @@ def get_skeleton(self, check=False): def query(self, *args, **kwds): """ - Creates a ``SQLQuery`` on this database. For full class details, + Create a ``SQLQuery`` on this database. For full class details, type ``SQLQuery?`` and press shift+enter. EXAMPLES:: @@ -1292,7 +1298,7 @@ def show(self, table_name, **kwds): def get_cursor(self, ignore_warning=None): """ - Returns a pysqlite cursor for the database connection. + Return a pysqlite cursor for the database connection. A cursor is an input from which you can execute sqlite commands on the database. @@ -1322,7 +1328,7 @@ def get_cursor(self, ignore_warning=None): def get_connection(self, ignore_warning=None): """ - Returns a pysqlite connection to the database. + Return a pysqlite connection to the database. You most likely want ``get_cursor()`` instead, which is used for executing sqlite commands on the database. @@ -1367,7 +1373,7 @@ def get_connection(self, ignore_warning=None): def create_table(self, table_name, table_skeleton): """ - Creates a new table in the database. + Create a new table in the database. To create a table, a column structure must be specified. The form for this is a Python dict, for example:: @@ -1530,7 +1536,7 @@ def add_column(self, table_name, col_name, col_dict, default='NULL'): def _rebuild_table(self, table_name, col_name=None, default=''): """ - Rebuilds the table ``table_name`` adding column ``col_name`` if not + Rebuild the table ``table_name`` adding column ``col_name`` if not ``None``. If a new column is added, each rows' value is set to ``default``. @@ -1688,7 +1694,7 @@ def drop_column(self, table_name, col_name): def rename_table(self, table_name, new_name): """ - Renames the table ``table_name`` to ``new_name``. + Rename the table ``table_name`` to ``new_name``. EXAMPLES:: @@ -1753,7 +1759,7 @@ def drop_table(self, table_name): def drop_data_from_table(self, table_name): """ - Removes all rows from ``table_name``. + Remove all rows from ``table_name``. EXAMPLES:: @@ -2049,7 +2055,7 @@ def add_row(self, table_name, values, entry_order=None): def delete_rows(self, query): """ - Uses a ``SQLQuery`` instance to modify (delete rows from) the + Use a ``SQLQuery`` instance to modify (delete rows from) the database. ``SQLQuery`` must have no join statements. (As of now, you can only @@ -2148,7 +2154,7 @@ def add_rows(self, table_name, rows, entry_order=None): def vacuum(self): """ - Cleans the extra hard disk space used up by a database that has + Clean the extra hard disk space used up by a database that has recently shrunk. EXAMPLES:: @@ -2166,7 +2172,7 @@ def vacuum(self): def commit(self): """ - Commits changes to file. + Commit changes to file. EXAMPLES:: diff --git a/src/sage/databases/symbolic_data.py b/src/sage/databases/symbolic_data.py index 426bdb5a2b1..5a763b91deb 100644 --- a/src/sage/databases/symbolic_data.py +++ b/src/sage/databases/symbolic_data.py @@ -84,7 +84,7 @@ def __init__(self): def get_ideal(self, name, base_ring=QQ, term_order="degrevlex"): """ - Returns the ideal given by 'name' over the base ring given by + Return the ideal given by 'name' over the base ring given by 'base_ring' in a polynomial ring with the term order given by 'term_order'. diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py index 7656a69ce09..c91a49c06be 100644 --- a/src/sage/doctest/forker.py +++ b/src/sage/doctest/forker.py @@ -2300,7 +2300,7 @@ def save_result_output(self): def kill(self): """ - Kill this worker. Returns ``True`` if the signal(s) are sent + Kill this worker. Return ``True`` if the signal(s) are sent successfully or ``False`` if the worker process no longer exists. This method is only called if there is something wrong with the diff --git a/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py b/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py index 1d28b94631c..38b28a7219a 100644 --- a/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +++ b/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py @@ -77,12 +77,12 @@ def bCheck(c, v, p, b): return (bval).ceil() -def scale(c,v,p): +def scale(c, v, p): r""" Create scaled integer polynomial with respect to prime ``p``. Given an integral polynomial ``c``, we can write `c = p^i*c'`, where ``p`` does not - divide ``c``. Returns ``c'`` and `v - i` where `i` is the smallest valuation of the + divide ``c``. Return ``c'`` and `v - i` where `i` is the smallest valuation of the coefficients of `c`. INPUT: @@ -116,7 +116,7 @@ def scale(c,v,p): flag = False else: flag = True - return [flag,c,v] + return [flag, c, v] def blift(LF, Li, p, k, S=None, all_orbits=False): diff --git a/src/sage/ext/fast_callable.pyx b/src/sage/ext/fast_callable.pyx index 7c37796afbf..94e2928525b 100644 --- a/src/sage/ext/fast_callable.pyx +++ b/src/sage/ext/fast_callable.pyx @@ -314,7 +314,7 @@ def fast_callable(x, domain=None, vars=None, _autocompute_vars_for_backward_compatibility_with_deprecated_fast_float_functionality=False, expect_one_var=False): r""" - Given an expression x, compiles it into a form that can be quickly + Given an expression x, compile it into a form that can be quickly evaluated, given values for the variables in x. Currently, x can be an expression object, an element of SR, or a @@ -538,7 +538,7 @@ def fast_callable(x, domain=None, vars=None, def function_name(fn): r""" - Given a function, returns a string giving a name for the function. + Given a function, return a string giving a name for the function. For functions we recognize, we use our standard opcode name for the function (so operator.add becomes 'add', and sage.all.sin becomes 'sin'). @@ -700,7 +700,7 @@ cdef class ExpressionTreeBuilder: def var(self, v): r""" - Turn the argument into an ExpressionVariable. Looks it up in + Turn the argument into an ExpressionVariable. Look it up in the list of variables. (Variables are matched by name.) EXAMPLES:: @@ -752,6 +752,7 @@ cdef class ExpressionTreeBuilder: def call(self, fn, *args): r""" Construct a call node, given a function and a list of arguments. + The arguments will be converted to Expressions using ExpressionTreeBuilder.__call__. @@ -818,7 +819,7 @@ cdef op_inv = operator.inv cdef class Expression: r""" - Represents an expression for fast_callable. + Represent an expression for fast_callable. Supports the standard Python arithmetic operators; if arithmetic is attempted between an Expression and a non-Expression, the @@ -863,7 +864,7 @@ cdef class Expression: def _get_etb(self): r""" - Returns the ExpressionTreeBuilder used to build a given expression. + Return the ExpressionTreeBuilder used to build a given expression. EXAMPLES:: @@ -1543,7 +1544,7 @@ cdef class ExpressionChoice(Expression): cpdef _expression_binop_helper(s, o, op): r""" - Makes an Expression for (s op o). Either s or o (or both) must already + Make an Expression for (s op o). Either s or o (or both) must already be an expression. EXAMPLES:: @@ -1623,7 +1624,7 @@ class IntegerPowerFunction(object): def __init__(self, n): r""" - Initializes an IntegerPowerFunction. + Initialize an IntegerPowerFunction. EXAMPLES:: @@ -2187,7 +2188,7 @@ cdef class InstructionStream: def get_metadata(self): r""" - Returns the interpreter metadata being used by the current + Return the interpreter metadata being used by the current InstructionStream. The code generator sometimes uses this to decide which code @@ -2206,7 +2207,7 @@ cdef class InstructionStream: def current_op_list(self): r""" - Returns the list of instructions that have been added to this + Return the list of instructions that have been added to this InstructionStream so far. It's OK to call this, then add more instructions. @@ -2306,9 +2307,10 @@ cdef class InterpreterMetadata(object): self.by_opcode = by_opcode self.ipow_range = ipow_range + class CompilerInstrSpec(object): r""" - Describes a single instruction to the fast_callable code generator. + Describe a single instruction to the fast_callable code generator. An instruction has a number of stack inputs, a number of stack outputs, and a parameter list describing extra arguments that From b26588bb312709fc046af77a969c4d570c802a48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Tue, 10 Dec 2019 08:58:07 +0100 Subject: [PATCH 303/340] 28863: adding tolerance to doctest result --- src/doc/en/thematic_tutorials/linear_programming.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/en/thematic_tutorials/linear_programming.rst b/src/doc/en/thematic_tutorials/linear_programming.rst index 98cd54a0406..84664b14291 100644 --- a/src/doc/en/thematic_tutorials/linear_programming.rst +++ b/src/doc/en/thematic_tutorials/linear_programming.rst @@ -284,7 +284,7 @@ Should we take a flashlight? :: - sage: taken["flashlight"] + sage: taken["flashlight"] # abs tol 1e-6 1.0 Wise advice. Based on purely random considerations. From 04f106a68212e8c5f0e87bf907d196561d974ab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 10 Dec 2019 19:11:14 +0100 Subject: [PATCH 304/340] trac 28861 fix one raises to raise --- src/sage/databases/oeis.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/databases/oeis.py b/src/sage/databases/oeis.py index 74dcfc545b6..c7293068279 100644 --- a/src/sage/databases/oeis.py +++ b/src/sage/databases/oeis.py @@ -149,14 +149,14 @@ ------------------- """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Thierry Monteil # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ -#***************************************************************************** +# **************************************************************************** from __future__ import print_function from six.moves.urllib.request import urlopen from six.moves.urllib.parse import urlencode @@ -1397,7 +1397,7 @@ def __getitem__(self, i): def __iter__(self): r""" - Iterate over the first terms of ``self``, and raises an error if + Iterate over the first terms of ``self``, and raise an error if those first terms are exhausted and the real associated sequence still have terms to produce. From 4ee9802afe3ef9e893e95756c980163146dd83fa Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Wed, 11 Dec 2019 07:43:59 +0100 Subject: [PATCH 305/340] alignment in docs; AssertionError -> ValueError --- src/sage/geometry/polyhedron/base.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 949e0b5f258..69c38d55719 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -5705,18 +5705,18 @@ def polar(self, in_affine_span=False): sage: C.polar().backend() 'cdd' - Check that :trac:`28850` is fixed:: + Check that :trac:`28850` is fixed:: sage: P = polytopes.simplex(3, base_ring=QQ) sage: P.polar() Traceback (most recent call last): ... - AssertionError: must be full-dimensional + ValueError: must be full-dimensional """ - assert self.is_compact(), "not a polytope" - if not in_affine_span: - assert self.dim() == self.ambient_dim(), "must be full-dimensional" - + if not self.is_compact(): + raise ValueError("not a polytope") + if not in_affine_span and not self.dim() == self.ambient_dim(): + raise ValueError("must be full-dimensional") verts = [list(self.center() - v.vector()) for v in self.vertex_generator()] parent = self.parent().base_extend(self.center().parent()) From f3c0bfbba740e2c001aa0ad15a47e956c8181c0d Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Wed, 11 Dec 2019 13:56:16 +0100 Subject: [PATCH 306/340] fix empty input for Polyhedron class --- src/sage/geometry/polyhedron/base.py | 5 ++- src/sage/geometry/polyhedron/constructor.py | 42 ++++++++++++++++--- .../double_description_inhomogeneous.py | 25 +++++++---- 3 files changed, 58 insertions(+), 14 deletions(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index a6ac1046b74..c20901e0dc4 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -118,7 +118,10 @@ def __init__(self, parent, Vrep, Hrep, **kwds): Element.__init__(self, parent=parent) if Vrep is not None: vertices, rays, lines = Vrep - self._init_from_Vrepresentation(vertices, rays, lines, **kwds) + if vertices or rays or lines: + self._init_from_Vrepresentation(vertices, rays, lines, **kwds) + else: + self._init_empty_polyhedron() elif Hrep is not None: ieqs, eqns = Hrep self._init_from_Hrepresentation(ieqs, eqns, **kwds) diff --git a/src/sage/geometry/polyhedron/constructor.py b/src/sage/geometry/polyhedron/constructor.py index 3f86c771303..bdcdfaa7e71 100644 --- a/src/sage/geometry/polyhedron/constructor.py +++ b/src/sage/geometry/polyhedron/constructor.py @@ -313,7 +313,7 @@ def Polyhedron(vertices=None, rays=None, lines=None, INPUT: - - ``vertices`` -- list of point. Each point can be specified as + - ``vertices`` -- list of points. Each point can be specified as any iterable container of ``base_ring`` elements. If ``rays`` or ``lines`` are specified but no ``vertices``, the origin is taken to be the single vertex. @@ -529,10 +529,31 @@ def Polyhedron(vertices=None, rays=None, lines=None, ... ValueError: no default backend for computations with Real Field with 53 bits of precision + Check that :trac:`17339` is fixed:: + + sage: P = Polyhedron(ambient_dim=0, ieqs=[], eqns=[[1]], base_ring=QQ); P + The empty polyhedron in QQ^0 + sage: P = Polyhedron(ambient_dim=0, ieqs=[], eqns=[], base_ring=QQ); P + A 0-dimensional polyhedron in QQ^0 defined as the convex hull of 1 vertex + sage: P.Vrepresentation() + (A vertex at (),) + sage: P = Polyhedron(ambient_dim=2, ieqs=[], eqns=[], base_ring=QQ); P + A 2-dimensional polyhedron in QQ^2 defined as the convex hull + of 1 vertex and 2 lines + sage: P = Polyhedron(ambient_dim=0, ieqs=[], eqns=[[1]], base_ring=QQ, backend="cdd"); P + The empty polyhedron in QQ^0 + sage: P = Polyhedron(ambient_dim=0, ieqs=[], eqns=[[1]], base_ring=QQ, backend="ppl"); P + The empty polyhedron in QQ^0 + sage: P = Polyhedron(ambient_dim=0, ieqs=[], eqns=[[1]], base_ring=QQ, backend="field"); P + The empty polyhedron in QQ^0 + .. SEEALSO:: :mod:`Library of polytopes ` """ + got_Vrep = not ((vertices is None) and (rays is None) and (lines is None)) + got_Hrep = not ((ieqs is None) and (eqns is None)) + # Clean up the arguments vertices = _make_listlist(vertices) rays = _make_listlist(rays) @@ -540,15 +561,24 @@ def Polyhedron(vertices=None, rays=None, lines=None, ieqs = _make_listlist(ieqs) eqns = _make_listlist(eqns) - got_Vrep = (len(vertices + rays + lines) > 0) - got_Hrep = (len(ieqs + eqns) > 0) - if got_Vrep and got_Hrep: raise ValueError('cannot specify both H- and V-representation.') elif got_Vrep: deduced_ambient_dim = _common_length_of(vertices, rays, lines)[1] + if deduced_ambient_dim is None: + if ambient_dim is not None: + deduced_ambient_dim = ambient_dim + else: + deduced_ambient_dim = 0 elif got_Hrep: - deduced_ambient_dim = _common_length_of(ieqs, eqns)[1] - 1 + deduced_ambient_dim = _common_length_of(ieqs, eqns)[1] + if deduced_ambient_dim is None: + if ambient_dim is not None: + deduced_ambient_dim = ambient_dim + else: + deduced_ambient_dim = 0 + else: + deduced_ambient_dim -= 1 else: if ambient_dim is None: deduced_ambient_dim = 0 @@ -609,7 +639,7 @@ def Polyhedron(vertices=None, rays=None, lines=None, raise ValueError("the only allowed inexact ring is 'RDF' with backend 'cdd'") # Add the origin if necessary - if got_Vrep and len(vertices) == 0: + if got_Vrep and len(vertices) == 0 and len(rays + lines) > 0: vertices = [[0] * ambient_dim] # Specific backends can override the base_ring diff --git a/src/sage/geometry/polyhedron/double_description_inhomogeneous.py b/src/sage/geometry/polyhedron/double_description_inhomogeneous.py index 96a87a54114..91e358009f5 100644 --- a/src/sage/geometry/polyhedron/double_description_inhomogeneous.py +++ b/src/sage/geometry/polyhedron/double_description_inhomogeneous.py @@ -196,12 +196,16 @@ def __init__(self, base_ring, dim, inequalities, equations): [0||0 1] sage: Hrep2Vrep(QQ, 2, [(-1,0,0)], []) # empty [] - sage: Hrep2Vrep(QQ, 2, [], []) # empty - [] + sage: Hrep2Vrep(QQ, 2, [], []) # universe + [0||1 0] + [0||0 1] """ super(Hrep2Vrep, self).__init__(base_ring, dim) inequalities = [list(x) for x in inequalities] equations = [list(x) for x in equations] + if not inequalities and not equations: + # Adding a trivial inequality, so that the ambient dimension is passed to the algorithm. + inequalities = [[self.base_ring.one()] + [self.base_ring.zero()] * self.dim] A = self._init_Vrep(inequalities, equations) DD = Algorithm(A).run() self._extract_Vrep(DD) @@ -442,9 +446,17 @@ def __init__(self, base_ring, dim, vertices, rays, lines): super(Vrep2Hrep, self).__init__(base_ring, dim) if rays or lines: assert len(vertices) > 0 - A = self._init_Vrep(vertices, rays, lines) - DD = Algorithm(A).run() - self._extract_Hrep(DD) + if not vertices and not rays and not lines: + # The algorithm does not work, as the ambient dimension cannot be passed. + # Manually setting a single equality in this case. + one = self.base_ring.one() + zero = self.base_ring.zero() + self.equations = [[one] + [zero]*self.dim] + self.inequalities = [] + else: + A = self._init_Vrep(vertices, rays, lines) + DD = Algorithm(A).run() + self._extract_Hrep(DD) if VERIFY_RESULT: self.verify(vertices, rays, lines) @@ -553,8 +565,7 @@ def verify(self, vertices, rays, lines): return P = Polyhedron(vertices=vertices, rays=rays, lines=lines, base_ring=QQ, ambient_dim=self.dim) - trivial = [self.base_ring.one()] + [self.base_ring.zero()] * self.dim # always true equation - Q = Polyhedron(ieqs=self.inequalities + [trivial], eqns=self.equations, + Q = Polyhedron(ieqs=self.inequalities, eqns=self.equations, base_ring=QQ, ambient_dim=self.dim) if not P == Q: print('incorrect!', P, Q) From c5bf04100b1b1bbd32e7c85e0096f69934948811 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Wed, 11 Dec 2019 15:56:11 +0100 Subject: [PATCH 307/340] added a doctest, some simplification --- src/sage/geometry/polyhedron/constructor.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/sage/geometry/polyhedron/constructor.py b/src/sage/geometry/polyhedron/constructor.py index bdcdfaa7e71..dc3f9506463 100644 --- a/src/sage/geometry/polyhedron/constructor.py +++ b/src/sage/geometry/polyhedron/constructor.py @@ -531,22 +531,28 @@ def Polyhedron(vertices=None, rays=None, lines=None, Check that :trac:`17339` is fixed:: - sage: P = Polyhedron(ambient_dim=0, ieqs=[], eqns=[[1]], base_ring=QQ); P + sage: Polyhedron(ambient_dim=0, ieqs=[], eqns=[[1]], base_ring=QQ) The empty polyhedron in QQ^0 sage: P = Polyhedron(ambient_dim=0, ieqs=[], eqns=[], base_ring=QQ); P A 0-dimensional polyhedron in QQ^0 defined as the convex hull of 1 vertex sage: P.Vrepresentation() (A vertex at (),) - sage: P = Polyhedron(ambient_dim=2, ieqs=[], eqns=[], base_ring=QQ); P + sage: Polyhedron(ambient_dim=2, ieqs=[], eqns=[], base_ring=QQ) A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 lines - sage: P = Polyhedron(ambient_dim=0, ieqs=[], eqns=[[1]], base_ring=QQ, backend="cdd"); P + sage: Polyhedron(ambient_dim=2, ieqs=[], eqns=[], base_ring=QQ, backend='field') + A 2-dimensional polyhedron in QQ^2 defined as the convex hull + of 1 vertex and 2 lines + sage: Polyhedron(ambient_dim=0, ieqs=[], eqns=[[1]], base_ring=QQ, backend="cdd") The empty polyhedron in QQ^0 - sage: P = Polyhedron(ambient_dim=0, ieqs=[], eqns=[[1]], base_ring=QQ, backend="ppl"); P + sage: Polyhedron(ambient_dim=0, ieqs=[], eqns=[[1]], base_ring=QQ, backend="ppl") The empty polyhedron in QQ^0 - sage: P = Polyhedron(ambient_dim=0, ieqs=[], eqns=[[1]], base_ring=QQ, backend="field"); P + sage: Polyhedron(ambient_dim=0, ieqs=[], eqns=[[1]], base_ring=QQ, backend="field") The empty polyhedron in QQ^0 + sage: Polyhedron(ambient_dim=2, vertices=[], rays=[], lines=[], base_ring=QQ) + The empty polyhedron in QQ^2 + .. SEEALSO:: :mod:`Library of polytopes ` From 7eb3cd1d9f73b7b49e653545e56002cd75d3e0e3 Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Wed, 11 Dec 2019 07:42:52 -0800 Subject: [PATCH 308/340] Add doctests re 28789 --- .../hyperelliptic_finite_field.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py index 4adb31dcec1..0f3517ee391 100644 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py @@ -471,6 +471,15 @@ def frobenius_polynomial_pari(self): sage: H.frobenius_polynomial_pari() x^4 + 2*x^3 - 58*x^2 + 202*x + 10201 + TESTS: + + Check that :trac:`28789` is fixed:: + + sage: P. = PolynomialRing(GF(3)) + sage: u = x^10 + x^9 + x^8 + x + sage: C = HyperellipticCurve(u) + sage: C.frobenius_polynomial_pari() + x^8 + 2*x^7 + 6*x^6 + 9*x^5 + 18*x^4 + 27*x^3 + 54*x^2 + 54*x + 81 """ f, h = self.hyperelliptic_polynomials() return ZZ['x'](pari([f, h]).hyperellcharpoly()) @@ -541,6 +550,16 @@ def frobenius_polynomial(self): sage: H = HyperellipticCurve(t^5 + z*t + z**3, t) sage: H.frobenius_polynomial() x^4 - x^3 + 16*x^2 - 32*x + 1024 + + TESTS: + + Check that :trac:`28789` is fixed:: + + sage: P. = PolynomialRing(GF(3)) + sage: u = x^10 + x^9 + x^8 + x + sage: C = HyperellipticCurve(u) + sage: C.frobenius_polynomial() + x^8 + 2*x^7 + 6*x^6 + 9*x^5 + 18*x^4 + 27*x^3 + 54*x^2 + 54*x + 81 """ K = self.base_ring() e = K.degree() From 6a15a44b8702bcd05d441f794493be350ce461f4 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Wed, 11 Dec 2019 20:43:44 +0100 Subject: [PATCH 309/340] raised error instead of crashing for a bug in normaliz --- src/sage/geometry/polyhedron/backend_normaliz.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index a9c2a6fd7ca..681222bf9a3 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -1240,7 +1240,19 @@ def _volume_normaliz(self, measure='euclidean'): sage: cube._volume_normaliz(measure='induced_lattice') # optional - pynormaliz 6 + TESTS: + + Check that :trac:`28872` is fixed an sage doesn't crash:: + + sage: P = polytopes.dodecahedron(backend='normaliz') # optional - pynormaliz + sage: P.volume(measure='induced_lattice') # optional - pynormaliz + Traceback (most recent call last): + ... + NotImplementedError: pynormaliz can only handle euclidean measure for algebraic polyhedra """ + if measure != 'euclidean' and not self._normaliz_field in (ZZ, QQ): + raise NotImplementedError("pynormaliz can only handle euclidean measure for algebraic polyhedra") + cone = self._normaliz_cone assert cone if measure == 'euclidean': From 516a62270a54e6d15f32e87241cf953a4f5daf75 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Wed, 11 Dec 2019 22:44:53 +0100 Subject: [PATCH 310/340] actually fixing our error --- src/sage/geometry/polyhedron/backend_normaliz.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index 681222bf9a3..2bf6fda4946 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -1242,23 +1242,21 @@ def _volume_normaliz(self, measure='euclidean'): TESTS: - Check that :trac:`28872` is fixed an sage doesn't crash:: + Check that :trac:`28872` is fixed:: sage: P = polytopes.dodecahedron(backend='normaliz') # optional - pynormaliz sage: P.volume(measure='induced_lattice') # optional - pynormaliz - Traceback (most recent call last): - ... - NotImplementedError: pynormaliz can only handle euclidean measure for algebraic polyhedra + -1056*sqrt5 + 2400 """ - if measure != 'euclidean' and not self._normaliz_field in (ZZ, QQ): - raise NotImplementedError("pynormaliz can only handle euclidean measure for algebraic polyhedra") - cone = self._normaliz_cone assert cone if measure == 'euclidean': return self._nmz_result(cone, 'EuclideanVolume') elif measure == 'induced_lattice': - return self._nmz_result(cone, 'Volume') + if self._normaliz_field in (ZZ, QQ): + return self._nmz_result(cone, 'Volume') + else: + return self._nmz_result(cone, 'RenfVolume') def _triangulate_normaliz(self): r""" From b8b70e8a09b40b61092ebd6e972748731de11538 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Thu, 12 Dec 2019 13:55:14 +0100 Subject: [PATCH 311/340] more meaningful errors for immutable graphs --- .../graphs/base/static_sparse_backend.pyx | 96 ++++++++++++++++--- src/sage/graphs/digraph.py | 2 +- 2 files changed, 86 insertions(+), 12 deletions(-) diff --git a/src/sage/graphs/base/static_sparse_backend.pyx b/src/sage/graphs/base/static_sparse_backend.pyx index 78cefa54730..3f91dc21b8d 100644 --- a/src/sage/graphs/base/static_sparse_backend.pyx +++ b/src/sage/graphs/base/static_sparse_backend.pyx @@ -172,10 +172,10 @@ cdef class StaticSparseCGraph(CGraph): return 0 <= v and v < self.g.n cdef int add_vertex_unsafe(self, int v) except -1: - raise ValueError("thou shalt not add a vertex to an immutable graph") + raise ValueError("graph is immutable; please change a copy instead (use function copy())") cdef int del_vertex_unsafe(self, int v) except -1: - raise ValueError("thou shalt not remove a vertex from an immutable graph") + raise ValueError("graph is immutable; please change a copy instead (use function copy())") def add_vertex(self, int k): r""" @@ -188,7 +188,7 @@ cdef class StaticSparseCGraph(CGraph): sage: g.add_vertex(45) Traceback (most recent call last): ... - ValueError: thou shalt not add a vertex to an immutable graph + ValueError: graph is immutable; please change a copy instead (use function copy()) """ self.add_vertex_unsafe(k) @@ -203,7 +203,7 @@ cdef class StaticSparseCGraph(CGraph): sage: g.del_vertex(45) Traceback (most recent call last): ... - ValueError: thou shalt not remove a vertex from an immutable graph + ValueError: graph is immutable; please change a copy instead (use function copy()) """ self.del_vertex_unsafe(k) @@ -500,6 +500,81 @@ cdef class StaticSparseBackend(CGraphBackend): """ return v in self._vertex_to_int + def add_edge(self, u, v, l, directed): + r""" + Set edge label. No way. + + TESTS:: + + sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend + sage: g = StaticSparseBackend(graphs.PetersenGraph()) + sage: g.add_edge(1,2,3,True) + Traceback (most recent call last): + ... + ValueError: graph is immutable; please change a copy instead (use function copy()) + """ + raise ValueError("graph is immutable; please change a copy instead (use function copy())") + + def add_edges(self, edges, directed): + r""" + Set edge label. No way. + + TESTS:: + + sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend + sage: g = StaticSparseBackend(graphs.PetersenGraph()) + sage: g.add_edges([[1, 2]], True) + Traceback (most recent call last): + ... + ValueError: graph is immutable; please change a copy instead (use function copy()) + """ + raise ValueError("graph is immutable; please change a copy instead (use function copy())") + + def add_vertices(self, vertices): + r""" + Set edge label. No way. + + TESTS:: + + sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend + sage: g = StaticSparseBackend(graphs.PetersenGraph()) + sage: g.add_vertices([1, 2]) + Traceback (most recent call last): + ... + ValueError: graph is immutable; please change a copy instead (use function copy()) + """ + raise ValueError("graph is immutable; please change a copy instead (use function copy())") + + def del_edge(self, u, v, l, directed): + r""" + Set edge label. No way. + + TESTS:: + + sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend + sage: g = StaticSparseBackend(graphs.PetersenGraph()) + sage: g.set_edge_label(1,2,3,True) + Traceback (most recent call last): + ... + ValueError: graph is immutable; please change a copy instead (use function copy()) + """ + raise ValueError("graph is immutable; please change a copy instead (use function copy())") + + def set_edge_label(self, u, v, l, directed): + r""" + Set edge label. No way. + + TESTS:: + + sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend + sage: g = StaticSparseBackend(graphs.PetersenGraph()) + sage: g.set_edge_label(1,2,3,True) + Traceback (most recent call last): + ... + ValueError: graph is immutable; please change a copy instead (use function copy()) + """ + raise ValueError("graph is immutable; please change a copy instead (use function copy())") + def relabel(self, perm, directed): r""" Relabel the graphs' vertices. No way. @@ -511,10 +586,9 @@ cdef class StaticSparseBackend(CGraphBackend): sage: g.relabel([],True) Traceback (most recent call last): ... - ValueError: thou shalt not relabel an immutable graph - + ValueError: graph is immutable; please change a copy instead (use function copy()) """ - raise ValueError("thou shalt not relabel an immutable graph") + raise ValueError("graph is immutable; please change a copy instead (use function copy())") def get_edge_label(self, object u, object v): """ @@ -1138,11 +1212,11 @@ cdef class StaticSparseBackend(CGraphBackend): sage: g.add_vertex(1) Traceback (most recent call last): ... - ValueError: thou shalt not add a vertex to an immutable graph + ValueError: graph is immutable; please change a copy instead (use function copy()) sage: g.add_vertices([1,2,3]) Traceback (most recent call last): ... - ValueError: thou shalt not add a vertex to an immutable graph + ValueError: graph is immutable; please change a copy instead (use function copy()) """ ( self._cg).add_vertex(v) @@ -1156,11 +1230,11 @@ cdef class StaticSparseBackend(CGraphBackend): sage: g.delete_vertex(1) Traceback (most recent call last): ... - ValueError: thou shalt not remove a vertex from an immutable graph + ValueError: graph is immutable; please change a copy instead (use function copy()) sage: g.delete_vertices([1,2,3]) Traceback (most recent call last): ... - ValueError: thou shalt not remove a vertex from an immutable graph + ValueError: graph is immutable; please change a copy instead (use function copy()) """ ( self._cg).del_vertex(v) diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index 3f13b3324f3..aa05b34f019 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -581,7 +581,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, sage: g.add_edge("Hey", "Heyyyyyyy") Traceback (most recent call last): ... - NotImplementedError + ValueError: graph is immutable; please change a copy instead (use function copy()) sage: {g:1}[g] 1 sage: copy(g) is g # copy is mutable again From 968d9e8188bf4e1a50e2a9ce334c01ce4a6e2c80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 12 Dec 2019 15:25:00 +0100 Subject: [PATCH 312/340] use https in setup.py --- src/setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/setup.py b/src/setup.py index 18f97639943..6c315214278 100755 --- a/src/setup.py +++ b/src/setup.py @@ -858,8 +858,8 @@ def clean_stale_files(self): description = 'Sage: Open Source Mathematics Software', license = 'GNU Public License (GPL)', author = 'William Stein et al.', - author_email= 'http://groups.google.com/group/sage-support', - url = 'http://www.sagemath.org', + author_email= 'https://groups.google.com/group/sage-support', + url = 'https://www.sagemath.org', packages = python_packages, package_data = { 'sage.libs.gap': ['sage.gaprc'], From 22cd92df735983b8d54fa7998f33d7c42f016226 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 12 Dec 2019 15:57:04 +0100 Subject: [PATCH 313/340] fix one internet doctest --- src/sage/repl/attach.py | 2 +- src/sage/repl/load.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/repl/attach.py b/src/sage/repl/attach.py index 5e60d2461d9..515740dbb80 100644 --- a/src/sage/repl/attach.py +++ b/src/sage/repl/attach.py @@ -6,7 +6,7 @@ sage: attach('http://wstein.org/loadtest.py') Traceback (most recent call last): ... - NotImplementedError: you can't attach a URL + NotImplementedError: you cannot attach a URL Check that no file clutter is produced:: diff --git a/src/sage/repl/load.py b/src/sage/repl/load.py index 58e54a0b8a9..73b85444de1 100644 --- a/src/sage/repl/load.py +++ b/src/sage/repl/load.py @@ -154,7 +154,7 @@ def load(filename, globals, attach=False): We can load files using secure http (https):: - sage: sage.repl.load.load('https://github.com/jasongrout/minimum_rank/raw/minimum_rank_1_0_0/minrank.py', globals()) # optional - internet + sage: sage.repl.load.load('https://raw.githubusercontent.com/sagemath/sage-patchbot/2.8.4/sage_patchbot/util.py', globals()) # optional - internet We attach a file:: @@ -166,12 +166,12 @@ def load(filename, globals, attach=False): sage: t in attached_files() True - You can't attach remote URLs (yet):: + You cannot attach remote URLs (yet):: sage: sage.repl.load.load('http://www.sagemath.org/files/loadtest.py', globals(), attach=True) # optional - internet Traceback (most recent call last): ... - NotImplementedError: you can't attach a URL + NotImplementedError: you cannot attach a URL The default search path for loading and attaching files is the current working directory, i.e., ``'.'``. But you can modify the @@ -230,7 +230,7 @@ def load(filename, globals, attach=False): # But see https://en.wikipedia.org/wiki/HTTP_ETag for how # we will do this. # http://www.diveintopython.net/http_web_services/etags.html - raise NotImplementedError("you can't attach a URL") + raise NotImplementedError("you cannot attach a URL") from sage.misc.remote_file import get_remote_file filename = get_remote_file(filename, verbose=False) From 2cb50f47c3eae07de205ed7e4f6b428ea1505e0c Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Thu, 12 Dec 2019 16:25:59 +0100 Subject: [PATCH 314/340] affine hull preservers backend if orthogonal or orthonormal --- src/sage/geometry/polyhedron/base.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index a6ac1046b74..86f381eb995 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -8241,9 +8241,9 @@ def affine_hull(self, as_affine_map=False, orthogonal=False, orthonormal=False, Domain: Vector space of dimension 3 over Rational Field Codomain: Vector space of dimension 3 over Rational Field, (0, 0, 0)) - TESTS:: + TESTS: - Check that :trac:`23355` is fixed:: + Check that :trac:`23355` is fixed:: sage: P = Polyhedron([[7]]); P A 0-dimensional polyhedron in ZZ^1 defined as the convex hull of 1 vertex @@ -8254,7 +8254,7 @@ def affine_hull(self, as_affine_map=False, orthogonal=False, orthonormal=False, sage: P.affine_hull(orthogonal='True') A 0-dimensional polyhedron in QQ^0 defined as the convex hull of 1 vertex - Check that :trac:`24047` is fixed:: + Check that :trac:`24047` is fixed:: sage: P1 = Polyhedron(vertices=([[-1, 1], [0, -1], [0, 0], [-1, -1]])) sage: P2 = Polyhedron(vertices=[[1, 1], [1, -1], [0, -1], [0, 0]]) @@ -8264,10 +8264,14 @@ def affine_hull(self, as_affine_map=False, orthogonal=False, orthonormal=False, sage: Polyhedron([(2,3,4)]).affine_hull() A 0-dimensional polyhedron in ZZ^0 defined as the convex hull of 1 vertex - Check that backend is preserved:: + Check that backend is preserved:: sage: polytopes.simplex(backend='field').affine_hull().backend() 'field' + + sage: P = Polyhedron(vertices=[[0,0], [1,0]], backend='field') + sage: P.affine_hull(orthogonal=True, orthonormal=True, extend=True).backend() + 'field' """ # handle trivial full-dimensional case if self.ambient_dim() == self.dim(): @@ -8299,7 +8303,9 @@ def affine_hull(self, as_affine_map=False, orthogonal=False, orthonormal=False, A = M.gram_schmidt(orthonormal=orthonormal)[0] if as_affine_map: return linear_transformation(A, side='right'), -A*vector(A.base_ring(), self.vertices()[0]) - return Polyhedron([A*vector(A.base_ring(), w) for w in Q.vertices()], base_ring=A.base_ring()) + parent = self.parent().change_ring(A.base_ring(), ambient_dim=self.dim()) + new_vertices = [A*vector(A.base_ring(), w) for w in Q.vertices()] + return parent.element_class(parent, [new_vertices, [], []], None) # translate one vertex to the origin v0 = self.vertices()[0].vector() From c9ce0a6feba6b06fc224c8b2712ee44202a237bd Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Thu, 12 Dec 2019 16:20:41 -0800 Subject: [PATCH 315/340] Add missing doctests to monsky_washnitzer.py, coverage to 100% --- .../hyperelliptic_curves/monsky_washnitzer.py | 178 +++++++++++++++--- 1 file changed, 150 insertions(+), 28 deletions(-) diff --git a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py index 13363c1170a..5c84d4068e1 100644 --- a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +++ b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py @@ -630,13 +630,11 @@ def transpose_list(input): """ INPUT: - - ``input`` -- a list of lists, each list of the same - length + - ``input`` -- a list of lists, each list of the same length OUTPUT: - - ``output`` -- a list of lists such that output[i][j] - = input[j][i] + - ``output`` -- a list of lists such that output[i][j] = input[j][i] EXAMPLES:: @@ -1954,6 +1952,16 @@ def change_ring(self, R): return SpecialHyperellipticQuotientRing(self._Q, R, is_LaurentSeriesRing(self._series_ring)) def __call__(self, val, offset=0, check=True): + """ + Evaluate ``self`` at given arguments + + EXAMPLES:: + sage: R. = QQ['x'] + sage: E = HyperellipticCurve(x^5-3*x+1) + sage: x,y = E.monsky_washnitzer_gens() + sage: x.parent()(x^6) + -(1-y^2)*x + 3*x^2 + """ if isinstance(val, SpecialHyperellipticQuotientElement) and val.parent() is self: if offset == 0: return val @@ -2033,6 +2041,8 @@ def monomial(self, i, j, b=None): def monomial_diff_coeffs(self, i, j): r""" + Compute coefficients of the basis representation of `d(x^iy^j)`. + The key here is that the formula for `d(x^iy^j)` is messy in terms of `i`, but varies nicely with `j`. @@ -2044,6 +2054,14 @@ def monomial_diff_coeffs(self, i, j): Where `A,B` have degree at most `n-1` for each `i`. Pre-compute `A_i, B_i` for each `i` the "hard" way, and the rest are easy. + + EXAMPLES:: + + sage: R. = QQ['x'] + sage: E = HyperellipticCurve(x^5-3*x+1) + sage: x,y = E.monsky_washnitzer_gens() + sage: x.parent().monomial_diff_coeffs(2,3) + ((0, -15, 36, 0, 0), (0, 19, 0, 0, 0)) """ try: return self._monomial_diff_coeffs[i, j] @@ -2066,6 +2084,23 @@ def monomial_diff_coeffs(self, i, j): return coeffs def monomial_diff_coeffs_matrices(self): + """ + Compute tables of coefficients of the basis representation of `d(x^iy^j)` for small `i`, `j`. + + EXAMPLES:: + + sage: R. = QQ['x'] + sage: E = HyperellipticCurve(x^5-3*x+1) + sage: x,y = E.monsky_washnitzer_gens() + sage: x.parent().monomial_diff_coeffs_matrices() + ( + [0 5 0 0 0] [0 2 0 0 0] + [0 0 5 0 0] [0 0 4 0 0] + [0 0 0 5 0] [0 0 0 6 0] + [0 0 0 0 5] [0 0 0 0 8] + [0 0 0 0 0], [0 0 0 0 0] + ) + """ self.monomial_diff_coeffs(0, 0) # precompute stuff R = self.base_ring() mat_1 = matrix(R, self._n, self._n) @@ -2076,6 +2111,21 @@ def monomial_diff_coeffs_matrices(self): return mat_1.transpose(), mat_2.transpose() def _precompute_monomial_diffs(self): + """ + Precompute coefficients of the basis representation of `d(x^iy^j)` for small `i`, `j`. + + EXAMPLES:: + + sage: R. = QQ['x'] + sage: E = HyperellipticCurve(x^5-3*x+1) + sage: x,y = E.monsky_washnitzer_gens() + sage: x.parent()._precompute_monomial_diffs() + [((-3, 0, 0, 0, 5), (0, 0, 0, 0, 0), (0, 0, 0, 0, 0)), + ((-5, 12, 0, 0, 0), (5, 0, 0, 0, 0), (2, 0, 0, 0, 0)), + ((0, -5, 12, 0, 0), (0, 5, 0, 0, 0), (0, 4, 0, 0, 0)), + ((0, 0, -5, 12, 0), (0, 0, 5, 0, 0), (0, 0, 6, 0, 0)), + ((0, 0, 0, -5, 12), (0, 0, 0, 5, 0), (0, 0, 0, 8, 0))] + """ x, y = self.gens() R = self.base_ring() V = FreeModule(R, self.degree()) @@ -2130,9 +2180,29 @@ def degree(self): return self._n def prime(self): + """ + Return the stored prime number `p`. + + EXAMPLES:: + sage: R. = QQ['x'] + sage: E = HyperellipticCurve(x^5-3*x+1) + sage: x,y = E.monsky_washnitzer_gens() + sage: x.parent().prime() is None + True + """ return self._p def monsky_washnitzer(self): + """ + Return the stored Monsky-Washnitzer differential ring. + + EXAMPLES:: + sage: R. = QQ['x'] + sage: E = HyperellipticCurve(x^5-3*x+1) + sage: x,y = E.monsky_washnitzer_gens() + sage: type(x.parent().monsky_washnitzer()) + + """ return self._monsky_washnitzer def is_field(self, proof=True): @@ -2202,7 +2272,7 @@ def _richcmp_(self, other, op): def change_ring(self, R): """ - Return the same element after changing the base ring to R. + Return the same element after changing the base ring to `R`. EXAMPLES:: @@ -2237,7 +2307,7 @@ def __call__(self, *x): def __invert__(self): """ - Return the inverse of the element + Return the inverse of ``self``. The general element in our ring is not invertible, but `y` may be. We do not want to pass to the fraction field. @@ -2296,7 +2366,7 @@ def __eq__(self, other): def _add_(self, other): """ - Return the sum of two elements + Return the sum of two elements. EXAMPLES:: @@ -2310,7 +2380,7 @@ def _add_(self, other): def _sub_(self, other): """ - Return the difference of two elements + Return the difference of two elements. EXAMPLES:: @@ -2324,7 +2394,7 @@ def _sub_(self, other): def _mul_(self, other): """ - Return the product of two elements + Return the product of two elements. EXAMPLES:: @@ -2353,18 +2423,62 @@ def _mul_(self, other): return SpecialHyperellipticQuotientElement(parent, v[0:n]) def _rmul_(self, c): + """ + Return the product of ``self`` with `c` on the left. + + EXAMPLES:: + + sage: R. = QQ['x'] + sage: E = HyperellipticCurve(x^5-3*x+1) + sage: x,y = E.monsky_washnitzer_gens() + sage: x._rmul_(y) + y*1*x + """ coeffs = self._f.list(copy=False) return self.parent()([c*a for a in coeffs], check=False) def _lmul_(self, c): + """ + Return the product of ``self`` with `c` on the right. + + EXAMPLES:: + + sage: R. = QQ['x'] + sage: E = HyperellipticCurve(x^5-3*x+1) + sage: x,y = E.monsky_washnitzer_gens() + sage: x._lmul_(y) + y*1*x + """ coeffs = self._f.list(copy=False) return self.parent()([a*c for a in coeffs], check=False) def __lshift__(self, k): + """ + Return the left shift of ``self`` by `k`. + + EXAMPLES:: + + sage: R. = QQ['x'] + sage: E = HyperellipticCurve(x^5-3*x+1) + sage: x,y = E.monsky_washnitzer_gens() + sage: x.__lshift__(3) + y^3*x + """ coeffs = self._f.list(copy=False) return self.parent()([a << k for a in coeffs], check=False) def __rshift__(self, k): + """ + Return the right shift of ``self`` by `k`. + + EXAMPLES:: + + sage: R. = QQ['x'] + sage: E = HyperellipticCurve(x^5-3*x+1) + sage: x,y = E.monsky_washnitzer_gens() + sage: y.__rshift__(3) + (y^-2)*1 + """ coeffs = self._f.list(copy=False) return self.parent()([a >> k for a in coeffs], check=False) @@ -2417,7 +2531,7 @@ def _latex_(self): def diff(self): """ - Return the differential of ``self`` + Return the differential of ``self``. EXAMPLES:: @@ -2448,7 +2562,7 @@ def diff(self): def extract_pow_y(self, k): r""" - Return the coefficients of `y^k` in ``self`` as a list + Return the coefficients of `y^k` in ``self`` as a list. EXAMPLES:: @@ -2465,7 +2579,7 @@ def extract_pow_y(self, k): def min_pow_y(self): """ - Return the minimal degree of ``self`` w.r.t. y + Return the minimal degree of ``self`` w.r.t. `y`. EXAMPLES:: @@ -2481,7 +2595,7 @@ def min_pow_y(self): def max_pow_y(self): """ - Return the maximal degree of ``self`` w.r.t. y + Return the maximal degree of ``self`` w.r.t. `y`. EXAMPLES:: @@ -2609,7 +2723,7 @@ def __init__(self, base_ring): def invariant_differential(self): """ - Returns `dx/2y` as an element of self. + Returns `dx/2y` as an element of ``self``. EXAMPLES:: @@ -2622,11 +2736,20 @@ def invariant_differential(self): return self(1) def __call__(self, val, offset=0): + """ + Evaluate ``self`` at given arguments. + + sage: R. = QQ['x'] + sage: C = HyperellipticCurve(x^5-4*x+4) + sage: MW = C.invariant_differential().parent() + sage: MW(3) + 3*1 dx/2y + """ return MonskyWashnitzerDifferential(self, val, offset) def base_extend(self, R): """ - Return a new differential ring which is self base-extended to `R` + Return a new differential ring which is ``self`` base-extended to `R`. INPUT: @@ -2659,7 +2782,7 @@ def change_ring(self, R): OUTPUT: - Self, with the coefficient ring changed to `R`. + ``self`` with the coefficient ring changed to `R`. EXAMPLES:: @@ -2676,7 +2799,7 @@ def change_ring(self, R): def degree(self): """ Returns the degree of `Q(x)`, where the model of the underlying - hyperelliptic curve of self is given by `y^2 = Q(x)`. + hyperelliptic curve of ``self`` is given by `y^2 = Q(x)`. EXAMPLES:: @@ -2692,7 +2815,7 @@ def degree(self): def dimension(self): """ - Returns the dimension of self. + Returns the dimension of ``self``. EXAMPLES:: @@ -2840,7 +2963,7 @@ def frob_invariant_differential(self, prec, p): def frob_basis_elements(self, prec, p): r""" - Return the action of a `p`-power lift of Frobenius on the basis + Return the action of a `p`-power lift of Frobenius on the basis. .. MATH:: @@ -2869,8 +2992,7 @@ def frob_basis_elements(self, prec, p): def helper_matrix(self): """ We use this to solve for the linear combination of - `x^i y^j` needed to clear all terms with - `y^{j-1}`. + `x^i y^j` needed to clear all terms with `y^{j-1}`. EXAMPLES:: @@ -2964,7 +3086,7 @@ def _add_(left, right): def _sub_(left, right): """ - Returns the difference of left and right, both elements of the + Returns the difference of ``left`` and ``right``, both elements of the Monsky-Washnitzer ring of differentials. EXAMPLES:: @@ -2985,7 +3107,7 @@ def _sub_(left, right): def __neg__(self): """ - Returns the additive inverse of self. + Returns the additive inverse of ``self``. EXAMPLES:: @@ -3100,7 +3222,7 @@ def _repr_(self): def _latex_(self): """ - Returns the latex representation of self. + Returns the latex representation of ``self``. EXAMPLES:: @@ -3120,7 +3242,7 @@ def _latex_(self): def extract_pow_y(self, k): """ - Returns the power of `y` in `A` where self is `A dx/2y`. + Returns the power of `y` in `A` where ``self`` is `A dx/2y`. EXAMPLES:: @@ -3137,7 +3259,7 @@ def extract_pow_y(self, k): def min_pow_y(self): """ - Returns the minimum power of `y` in `A` where self is `A dx/2y`. + Returns the minimum power of `y` in `A` where ``self`` is `A dx/2y`. EXAMPLES:: @@ -3155,7 +3277,7 @@ def min_pow_y(self): def max_pow_y(self): """ - Returns the maximum power of `y` in `A` where self is `A dx/2y`. + Returns the maximum power of `y` in `A` where ``self`` is `A dx/2y`. EXAMPLES:: @@ -3519,7 +3641,7 @@ def coeffs(self, R=None): OUTPUT: - The raw coefficients of $A$ where self is $A dx/2y$. + The raw coefficients of $A$ where ``self`` is $A dx/2y$. EXAMPLES:: From 389fb277f927bcee3cb296dfbbde2f27560a6a27 Mon Sep 17 00:00:00 2001 From: Emmanuel Charpentier Date: Fri, 13 Dec 2019 13:43:48 +0100 Subject: [PATCH 316/340] Drop R 3.6.2 tarball in place, update checksums. --- build/pkgs/r/checksums.ini | 6 +++--- build/pkgs/r/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/r/checksums.ini b/build/pkgs/r/checksums.ini index b90642c2b66..b97750a51de 100644 --- a/build/pkgs/r/checksums.ini +++ b/build/pkgs/r/checksums.ini @@ -1,4 +1,4 @@ tarball=R-VERSION.tar.gz -sha1=0041c025561b5622e3dc88cdedf82334620cd3c2 -md5=f5003472d58a3d3765a1c537fdae71d5 -cksum=1435085955 +sha1=8eda2af51d63877fcc6674274b6801af605173c5 +md5=90d23d138cee26d275da14b58296e521 +cksum=1222866983 diff --git a/build/pkgs/r/package-version.txt b/build/pkgs/r/package-version.txt index 9575d51bad2..b72762837ea 100644 --- a/build/pkgs/r/package-version.txt +++ b/build/pkgs/r/package-version.txt @@ -1 +1 @@ -3.6.1 +3.6.2 From c3b9fb17f8b526fc9cce5aa19f4fea59da2e18cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 13 Dec 2019 17:56:58 +0100 Subject: [PATCH 317/340] more doc tuning for Monsky-W --- .../hyperelliptic_curves/monsky_washnitzer.py | 105 ++++++++++-------- 1 file changed, 57 insertions(+), 48 deletions(-) diff --git a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py index 5c84d4068e1..bf0ab746450 100644 --- a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +++ b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py @@ -145,7 +145,7 @@ class SpecialCubicQuotientRing(CommutativeAlgebra): .. TODO:: write an example checking multiplication of these polynomials - against Sage's ordinary quotient ring arithmetic. I can't seem + against Sage's ordinary quotient ring arithmetic. I cannot seem to get the quotient ring stuff happening right now... """ def __init__(self, Q, laurent_series=False): @@ -254,10 +254,10 @@ def gens(self): Return a list [x, T] where x and T are the generators of the ring (as element *of this ring*). - .. note:: + .. NOTE:: - I have no idea if this is compatible with the usual Sage - 'gens' interface. + I have no idea if this is compatible with the usual Sage + 'gens' interface. EXAMPLES:: @@ -280,7 +280,7 @@ def gens(self): def create_element(self, p0, p1, p2, check=True): """ - Creates the element `p_0 + p_1*x + p_2*x^2`, where the `p_i` + Create the element `p_0 + p_1*x + p_2*x^2`, where the `p_i` are polynomials in `T`. INPUT: @@ -334,7 +334,7 @@ class SpecialCubicQuotientRingElement(CommutativeAlgebraElement): """ def __init__(self, parent, p0, p1, p2, check=True): """ - Constructs the element `p_0 + p_1*x + p_2*x^2`, where + Construct the element `p_0 + p_1*x + p_2*x^2`, where the `p_i` are polynomials in `T`. INPUT: @@ -370,10 +370,11 @@ def __init__(self, parent, p0, p1, p2, check=True): def coeffs(self): """ - Returns list of three lists of coefficients, corresponding to the - `x^0`, `x^1`, `x^2` coefficients. The lists - are zero padded to the same length. The list entries belong to the - base ring. + Return list of three lists of coefficients, corresponding to the + `x^0`, `x^1`, `x^2` coefficients. + + The lists are zero padded to the same length. The list entries + belong to the base ring. EXAMPLES:: @@ -485,7 +486,7 @@ def _sub_(self, other): def shift(self, n): """ - Returns this element multiplied by `T^n`. + Return this element multiplied by `T^n`. EXAMPLES:: @@ -507,7 +508,7 @@ def shift(self, n): def scalar_multiply(self, scalar): """ - Multiplies this element by a scalar, i.e. just multiply each + Multiply this element by a scalar, i.e. just multiply each coefficient of `x^j` by the scalar. INPUT: @@ -537,6 +538,8 @@ def scalar_multiply(self, scalar): def square(self): """ + Return the square of the element. + EXAMPLES:: sage: B. = PolynomialRing(Integers(125)) @@ -657,7 +660,7 @@ def transpose_list(input): def helper_matrix(Q): """ - Computes the (constant) matrix used to calculate the linear + Compute the (constant) matrix used to calculate the linear combinations of the `d(x^i y^j)` needed to eliminate the negative powers of `y` in the cohomology (i.e. in reduce_negative()). @@ -694,7 +697,7 @@ def helper_matrix(Q): def lift(x): r""" - Tries to call x.lift(), presumably from the `p`-adics to ZZ. + Try to call x.lift(), presumably from the `p`-adics to ZZ. If this fails, it assumes the input is a power series, and tries to lift it to a power series over QQ. @@ -725,7 +728,7 @@ def lift(x): def reduce_negative(Q, p, coeffs, offset, exact_form=None): """ - Applies cohomology relations to incorporate negative powers of + Apply cohomology relations to incorporate negative powers of `y` into the `y^0` term. INPUT: @@ -828,7 +831,7 @@ def reduce_negative(Q, p, coeffs, offset, exact_form=None): def reduce_positive(Q, p, coeffs, offset, exact_form=None): """ - Applies cohomology relations to incorporate positive powers of + Apply cohomology relations to incorporate positive powers of `y` into the `y^0` term. INPUT: @@ -920,7 +923,7 @@ def reduce_positive(Q, p, coeffs, offset, exact_form=None): def reduce_zero(Q, coeffs, offset, exact_form=None): """ - Applies cohomology relation to incorporate `x^2 y^0` term + Apply cohomology relation to incorporate `x^2 y^0` term into `x^0 y^0` and `x^1 y^0` terms. INPUT: @@ -970,7 +973,7 @@ def reduce_zero(Q, coeffs, offset, exact_form=None): def reduce_all(Q, p, coeffs, offset, compute_exact_form=False): """ - Applies cohomology relations to reduce all terms to a linear + Apply cohomology relations to reduce all terms to a linear combination of `dx/y` and `x dx/y`. INPUT: @@ -991,10 +994,10 @@ def reduce_all(Q, p, coeffs, offset, compute_exact_form=False): cohomologous to (A + Bx) dx/y. - .. note:: + .. NOTE:: - The algorithm operates in-place, so the data in coeffs is - destroyed. + The algorithm operates in-place, so the data in coeffs is + destroyed. EXAMPLES:: @@ -1032,7 +1035,7 @@ def reduce_all(Q, p, coeffs, offset, compute_exact_form=False): def frobenius_expansion_by_newton(Q, p, M): r""" - Computes the action of Frobenius on `dx/y` and on + Compute the action of Frobenius on `dx/y` and on `x dx/y`, using Newton's method (as suggested in Kedlaya's paper [Ked2001]_). @@ -1209,7 +1212,7 @@ def frobenius_expansion_by_newton(Q, p, M): def frobenius_expansion_by_series(Q, p, M): r""" - Computes the action of Frobenius on `dx/y` and on `x dx/y`, using a + Compute the action of Frobenius on `dx/y` and on `x dx/y`, using a series expansion. (This function computes the same thing as @@ -1731,9 +1734,10 @@ def matrix_of_frobenius(Q, p, M, trace=None, compute_exact_forms=False): # # **************************************************************************** + def matrix_of_frobenius_hyperelliptic(Q, p=None, prec=None, M=None): r""" - Computes the matrix of Frobenius on Monsky-Washnitzer cohomology, + Compute the matrix of Frobenius on Monsky-Washnitzer cohomology, with respect to the basis `(dx/2y, x dx/2y, ...x^{d-2} dx/2y)`, where `d` is the degree of `Q`. @@ -1903,7 +1907,7 @@ def __init__(self, Q, R=None, invert_y=True): def _repr_(self): """ - String representation + String representation. EXAMPLES:: @@ -1939,7 +1943,7 @@ def base_extend(self, R): def change_ring(self, R): """ - Return the analog of ``self`` over the ring ``R`` + Return the analog of ``self`` over the ring ``R``. EXAMPLES:: @@ -1953,9 +1957,10 @@ def change_ring(self, R): def __call__(self, val, offset=0, check=True): """ - Evaluate ``self`` at given arguments + Evaluate ``self`` at given arguments. EXAMPLES:: + sage: R. = QQ['x'] sage: E = HyperellipticCurve(x^5-3*x+1) sage: x,y = E.monsky_washnitzer_gens() @@ -2015,7 +2020,7 @@ def y(self): def monomial(self, i, j, b=None): """ - Returns `b y^j x^i`, computed quickly. + Return `b y^j x^i`, computed quickly. EXAMPLES:: @@ -2184,6 +2189,7 @@ def prime(self): Return the stored prime number `p`. EXAMPLES:: + sage: R. = QQ['x'] sage: E = HyperellipticCurve(x^5-3*x+1) sage: x,y = E.monsky_washnitzer_gens() @@ -2197,6 +2203,7 @@ def monsky_washnitzer(self): Return the stored Monsky-Washnitzer differential ring. EXAMPLES:: + sage: R. = QQ['x'] sage: E = HyperellipticCurve(x^5-3*x+1) sage: x,y = E.monsky_washnitzer_gens() @@ -2207,7 +2214,7 @@ def monsky_washnitzer(self): def is_field(self, proof=True): """ - Return False as ``self`` is not a field. + Return ``False`` as ``self`` is not a field. EXAMPLES:: @@ -2227,7 +2234,7 @@ class SpecialHyperellipticQuotientElement(CommutativeAlgebraElement): def __init__(self, parent, val=0, offset=0, check=True): """ - Elements in the Hyperelliptic quotient ring + Elements in the Hyperelliptic quotient ring. EXAMPLES:: @@ -2611,7 +2618,7 @@ def max_pow_y(self): def coeffs(self, R=None): """ - Returns the raw coefficients of this element. + Return the raw coefficients of this element. INPUT: @@ -2723,7 +2730,7 @@ def __init__(self, base_ring): def invariant_differential(self): """ - Returns `dx/2y` as an element of ``self``. + Return `dx/2y` as an element of ``self``. EXAMPLES:: @@ -2739,6 +2746,8 @@ def __call__(self, val, offset=0): """ Evaluate ``self`` at given arguments. + EXAMPLES:: + sage: R. = QQ['x'] sage: C = HyperellipticCurve(x^5-4*x+4) sage: MW = C.invariant_differential().parent() @@ -2773,7 +2782,7 @@ def base_extend(self, R): def change_ring(self, R): """ - Returns a new differential ring which is self with the coefficient + Return a new differential ring which is self with the coefficient ring changed to `R`. INPUT: @@ -2798,7 +2807,7 @@ def change_ring(self, R): def degree(self): """ - Returns the degree of `Q(x)`, where the model of the underlying + Return the degree of `Q(x)`, where the model of the underlying hyperelliptic curve of ``self`` is given by `y^2 = Q(x)`. EXAMPLES:: @@ -2815,7 +2824,7 @@ def degree(self): def dimension(self): """ - Returns the dimension of ``self``. + Return the dimension of ``self``. EXAMPLES:: @@ -2831,7 +2840,7 @@ def dimension(self): def Q(self): """ - Returns `Q(x)` where the model of the underlying hyperelliptic curve + Return `Q(x)` where the model of the underlying hyperelliptic curve of self is given by `y^2 = Q(x)`. EXAMPLES:: @@ -2847,7 +2856,7 @@ def Q(self): @cached_method def x_to_p(self, p): """ - Returns and caches `x^p`, reduced via the relations coming from the + Return and cache `x^p`, reduced via the relations coming from the defining polynomial of the hyperelliptic curve. EXAMPLES:: @@ -2867,7 +2876,7 @@ def x_to_p(self, p): @cached_method def frob_Q(self, p): r""" - Returns and caches `Q(x^p)`, which is used in computing the image of + Return and cache `Q(x^p)`, which is used in computing the image of `y` under a `p`-power lift of Frobenius to `A^{\dagger}`. EXAMPLES:: @@ -3065,7 +3074,7 @@ def __init__(self, parent, val=0, offset=0): def _add_(left, right): """ - Returns the sum of left and right, both elements of the + Return the sum of left and right, both elements of the Monsky-Washnitzer ring of differentials. EXAMPLES:: @@ -3086,7 +3095,7 @@ def _add_(left, right): def _sub_(left, right): """ - Returns the difference of ``left`` and ``right``, both elements of the + Return the difference of ``left`` and ``right``, both elements of the Monsky-Washnitzer ring of differentials. EXAMPLES:: @@ -3107,7 +3116,7 @@ def _sub_(left, right): def __neg__(self): """ - Returns the additive inverse of ``self``. + Return the additive inverse of ``self``. EXAMPLES:: @@ -3124,7 +3133,7 @@ def __neg__(self): def _lmul_(self, a): """ - Returns `self * a`. + Return `self * a`. EXAMPLES:: @@ -3145,7 +3154,7 @@ def _lmul_(self, a): def _rmul_(self, a): """ - Returns `a * self`. + Return `a * self`. EXAMPLES:: @@ -3166,7 +3175,7 @@ def _rmul_(self, a): def coeff(self): r""" - Returns `A`, where this element is `A dx/2y`. + Return `A`, where this element is `A dx/2y`. EXAMPLES:: @@ -3222,7 +3231,7 @@ def _repr_(self): def _latex_(self): """ - Returns the latex representation of ``self``. + Return the latex representation of ``self``. EXAMPLES:: @@ -3242,7 +3251,7 @@ def _latex_(self): def extract_pow_y(self, k): """ - Returns the power of `y` in `A` where ``self`` is `A dx/2y`. + Return the power of `y` in `A` where ``self`` is `A dx/2y`. EXAMPLES:: @@ -3259,7 +3268,7 @@ def extract_pow_y(self, k): def min_pow_y(self): """ - Returns the minimum power of `y` in `A` where ``self`` is `A dx/2y`. + Return the minimum power of `y` in `A` where ``self`` is `A dx/2y`. EXAMPLES:: @@ -3277,7 +3286,7 @@ def min_pow_y(self): def max_pow_y(self): """ - Returns the maximum power of `y` in `A` where ``self`` is `A dx/2y`. + Return the maximum power of `y` in `A` where ``self`` is `A dx/2y`. EXAMPLES:: From 3631eea64aad0ade4ca0d733bbcbfb8b170fb3e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 13 Dec 2019 21:37:57 +0100 Subject: [PATCH 318/340] refreshing the shuffle algebra file --- src/sage/algebras/shuffle_algebra.py | 97 ++++++++++++++-------------- 1 file changed, 47 insertions(+), 50 deletions(-) diff --git a/src/sage/algebras/shuffle_algebra.py b/src/sage/algebras/shuffle_algebra.py index d6f94c58c47..ee876858bb2 100644 --- a/src/sage/algebras/shuffle_algebra.py +++ b/src/sage/algebras/shuffle_algebra.py @@ -8,14 +8,13 @@ - Matthieu Deneufchatel (2013-07): Implemented dual PBW basis """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013 Frédéric Chapoton # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** -import six from sage.categories.rings import Rings from sage.categories.algebras_with_basis import AlgebrasWithBasis from sage.categories.commutative_algebras import CommutativeAlgebras @@ -51,9 +50,9 @@ class ShuffleAlgebra(CombinatorialFreeModule): INPUT: - - ``R`` -- ring + - ``R`` -- ring - - ``names`` -- generator names (string or an alphabet) + - ``names`` -- generator names (string or an alphabet) EXAMPLES:: @@ -107,6 +106,15 @@ class ShuffleAlgebra(CombinatorialFreeModule): B[word: bbca] + B[word: bcab] + B[word: bcba] + B[word: cabb] + B[word: cbab] + B[word: cbba] sage: 1 - B[Word('bb')] * B[Word('ca')] / 2 B[word: ] - 1/2*B[word: bbca] - 1/2*B[word: bcab] - 1/2*B[word: bcba] - 1/2*B[word: cabb] - 1/2*B[word: cbab] - 1/2*B[word: cbba] + + TESTS:: + + sage: R = ShuffleAlgebra(QQ,'x') + sage: R.is_commutative() + True + sage: R = ShuffleAlgebra(QQ,'xy') + sage: R.is_commutative() + True """ @staticmethod def __classcall_private__(cls, R, names): @@ -145,8 +153,10 @@ def __init__(self, R, names): self._alphabet = names self.__ngens = self._alphabet.cardinality() CombinatorialFreeModule.__init__(self, R, Words(names, infinite=False), - latex_prefix="", - category=(AlgebrasWithBasis(R), CommutativeAlgebras(R), CoalgebrasWithBasis(R))) + latex_prefix="", + category=(AlgebrasWithBasis(R), + CommutativeAlgebras(R), + CoalgebrasWithBasis(R))) def variable_names(self): r""" @@ -160,21 +170,6 @@ def variable_names(self): """ return self._alphabet - def is_commutative(self): - r""" - Return ``True`` as the shuffle algebra is commutative. - - EXAMPLES:: - - sage: R = ShuffleAlgebra(QQ,'x') - sage: R.is_commutative() - True - sage: R = ShuffleAlgebra(QQ,'xy') - sage: R.is_commutative() - True - """ - return True - def _repr_(self): r""" Text representation of this shuffle algebra. @@ -191,8 +186,8 @@ def _repr_(self): if self.__ngens == 1: gen = "one generator" else: - gen = "%s generators" %self.__ngens - return "Shuffle Algebra on "+ gen +" %s over %s"%( + gen = "%s generators" % self.__ngens + return "Shuffle Algebra on " + gen + " %s over %s" % ( self._alphabet.list(), self.base_ring()) @cached_method @@ -233,9 +228,9 @@ def product_on_basis(self, w1, w2): """ return sum(self.basis()[u] for u in w1.shuffle(w2)) - def gen(self,i): + def gen(self, i): r""" - The ``i``-th generator of the algebra. + Return the ``i``-th generator of the algebra. INPUT: @@ -254,7 +249,7 @@ def gen(self,i): """ n = self.__ngens if i < 0 or not i < n: - raise IndexError("argument i (= %s) must be between 0 and %s"%(i, n-1)) + raise IndexError("argument i (= %s) must be between 0 and %s" % (i, n - 1)) return self.algebra_generators()[i] def coproduct_on_basis(self, w): @@ -278,18 +273,18 @@ def coproduct_on_basis(self, w): sage: F.coproduct_on_basis(Word()) B[word: ] # B[word: ] """ - if len(w) == 0: + if not w: return self.tensor_square().monomial((self.one_basis(), self.one_basis())) + TS = self.tensor_square() if len(w) == 1: - return self.tensor_square().sum_of_terms([ - ((w, self.one_basis()), 1), - ((self.one_basis(), w), 1) ], distinct=True) + return TS.sum_of_terms([((w, self.one_basis()), 1), + ((self.one_basis(), w), 1)], distinct=True) result = self.coproduct_on_basis(Word([w[0]])) for i in w[1:]: - result = self.tensor_square().sum_of_terms([ - ((Word(v1) * Word(u1), Word(v2) * Word(u2)), - coeff1 * coeff2) + result = TS.sum_of_terms([((Word(v1) * Word(u1), + Word(v2) * Word(u2)), + coeff1 * coeff2) for ((u1, u2), coeff1) in self.coproduct_on_basis(Word([i])) for ((v1, v2), coeff2) in result]) return result @@ -315,9 +310,9 @@ def coproduct(self, S): B[word: ] # B[word: ] """ return sum([c * self.coproduct_on_basis(i) - for i,c in S.monomial_coefficients().items()]) + for i, c in S.monomial_coefficients().items()]) - def counit(self,S): + def counit(self, S): """ Return the counit of ``S``. @@ -348,10 +343,10 @@ def algebra_generators(self): Family (B[word: x1], B[word: x2]) """ Words = self.basis().keys() - return Family( [self.monomial(Words([a])) for a in self._alphabet] ) + return Family([self.monomial(Words([a])) for a in self._alphabet]) # FIXME: use this once the keys argument of FiniteFamily will be honoured # for the specifying the order of the elements in the family - #return Family(self._alphabet, lambda a: self.term(self.basis().keys()(a))) + # return Family(self._alphabet, lambda a: self.term(self.basis().keys()(a))) gens = algebra_generators @@ -385,14 +380,14 @@ def _element_constructor_(self, x): if isinstance(P, DualPBWBasis): return self(P.expansion(x)) # ok, not a shuffle algebra element (or should not be viewed as one). - if isinstance(x, six.string_types): + if isinstance(x, str): from sage.misc.sage_eval import sage_eval - return sage_eval(x,locals=self.gens_dict()) + return sage_eval(x, locals=self.gens_dict()) R = self.base_ring() # coercion via base ring x = R(x) if x == 0: - return self.element_class(self,{}) + return self.element_class(self, {}) else: return self.from_base_ring_from_one_basis(x) @@ -536,14 +531,15 @@ def to_dual_pbw_element(self, w): support = [W(i[0]) for i in list(w)] min_elt = W(support[0]) if len(support) > 1: - for word in support[1:len(support)-1]: + for word in support[1:len(support) - 1]: if min_elt.lex_less(word): min_elt = W(word) coeff = list(w)[support.index(min_elt)][1] l[min_elt] = l.get(min_elt, 0) + coeff w = w - coeff * D.expansion_on_basis(W(min_elt)) - return D.sum_of_terms([(m, c) for m,c in l.items() if c != 0]) + return D.sum_of_terms((m, c) for m, c in l.items() if c != 0) + class DualPBWBasis(CombinatorialFreeModule): r""" @@ -627,7 +623,9 @@ def __init__(self, R, names): self._alphabet = names self._alg = ShuffleAlgebra(R, names) CombinatorialFreeModule.__init__(self, R, Words(names), prefix='S', - category=(AlgebrasWithBasis(R), CommutativeAlgebras(R), CoalgebrasWithBasis(R))) + category=(AlgebrasWithBasis(R), + CommutativeAlgebras(R), + CoalgebrasWithBasis(R))) def _repr_(self): """ @@ -816,16 +814,16 @@ def expansion_on_basis(self, w): 2*B[word: aabb] + B[word: abab] """ from sage.functions.other import factorial - if len(w) == 0: + if not w: return self._alg.one() if len(w) == 1: - return self._alg.monomial(w) - + return self._alg.monomial(w) if w.is_lyndon(): W = self.basis().keys() letter = W(w[0]) expansion = self.expansion_on_basis(W(w[1:])) - return self._alg.sum_of_terms([(letter * i, c) for i,c in expansion]) + return self._alg.sum_of_terms((letter * i, c) + for i, c in expansion) lf = w.lyndon_factorization() powers = {} @@ -851,4 +849,3 @@ def expand(self): B[word: ab] + 2*B[word: abb] + B[word: bab] """ return self.parent().expansion(self) - From 7056cc149c62882b2dab1f27948f66ba05a4d251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 14 Dec 2019 10:01:25 +0100 Subject: [PATCH 319/340] more work on shuffle Hopf algebra --- src/sage/algebras/shuffle_algebra.py | 91 +++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 10 deletions(-) diff --git a/src/sage/algebras/shuffle_algebra.py b/src/sage/algebras/shuffle_algebra.py index ee876858bb2..87bb30e1af9 100644 --- a/src/sage/algebras/shuffle_algebra.py +++ b/src/sage/algebras/shuffle_algebra.py @@ -16,9 +16,7 @@ # **************************************************************************** from sage.categories.rings import Rings -from sage.categories.algebras_with_basis import AlgebrasWithBasis -from sage.categories.commutative_algebras import CommutativeAlgebras -from sage.categories.coalgebras_with_basis import CoalgebrasWithBasis +from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.words.alphabet import Alphabet from sage.combinat.words.words import Words @@ -154,9 +152,7 @@ def __init__(self, R, names): self.__ngens = self._alphabet.cardinality() CombinatorialFreeModule.__init__(self, R, Words(names, infinite=False), latex_prefix="", - category=(AlgebrasWithBasis(R), - CommutativeAlgebras(R), - CoalgebrasWithBasis(R))) + category=HopfAlgebrasWithBasis(R).Commutative()) def variable_names(self): r""" @@ -228,6 +224,20 @@ def product_on_basis(self, w1, w2): """ return sum(self.basis()[u] for u in w1.shuffle(w2)) + def antipode_on_basis(self, w): + """ + Return the antipode on the basis element ``w``. + + EXAMPLES:: + + sage: A = ShuffleAlgebra(QQ,'abc') + sage: W = A.basis().keys() + sage: A.antipode_on_basis(W("acb")) + -B[word: bca] + """ + mone = -self.base_ring().one() + return self.term(w.reversal(), mone**len(w)) + def gen(self, i): r""" Return the ``i``-th generator of the algebra. @@ -252,6 +262,21 @@ def gen(self, i): raise IndexError("argument i (= %s) must be between 0 and %s" % (i, n - 1)) return self.algebra_generators()[i] + def some_elements(self): + """ + Return some typical elements. + + EXAMPLES:: + + sage: F = ShuffleAlgebra(ZZ,'xyz') + sage: F.some_elements() + [0, B[word: ], B[word: x], B[word: y], B[word: z], B[word: xz] + B[word: zx]] + """ + gens = list(self.algebra_generators()) + if gens: + gens.append(gens[0] * gens[-1]) + return [self.zero(), self.one()] + gens + def coproduct_on_basis(self, w): """ Return the coproduct of the element of the basis indexed by @@ -324,7 +349,8 @@ def counit(self, S): sage: F.counit(S) 1 """ - return S.monomial_coefficients().get(Word(), 0) + W = self.basis().keys() + return S.coefficient(W()) @cached_method def algebra_generators(self): @@ -623,9 +649,7 @@ def __init__(self, R, names): self._alphabet = names self._alg = ShuffleAlgebra(R, names) CombinatorialFreeModule.__init__(self, R, Words(names), prefix='S', - category=(AlgebrasWithBasis(R), - CommutativeAlgebras(R), - CoalgebrasWithBasis(R))) + category=HopfAlgebrasWithBasis(R).Commutative()) def _repr_(self): """ @@ -731,6 +755,21 @@ def gen(self, i): """ return self.algebra_generators()[i] + def some_elements(self): + """ + Return some typical elements. + + EXAMPLES:: + + sage: F = ShuffleAlgebra(QQ,'xyz').dual_pbw_basis() + sage: F.some_elements() + [0, S[word: ], S[word: x], S[word: y], S[word: z], S[word: zx]] + """ + gens = list(self.algebra_generators()) + if gens: + gens.append(gens[0] * gens[-1]) + return [self.zero(), self.one()] + gens + def shuffle_algebra(self): """ Return the associated shuffle algebra of ``self``. @@ -775,6 +814,38 @@ def product(self, u, v): """ return self(self.expansion(u) * self.expansion(v)) + def antipode(self, elt): + """ + Return the antipode of the element ``elt``. + + EXAMPLES:: + + sage: A = ShuffleAlgebra(QQ, 'ab') + sage: S = A.dual_pbw_basis() + sage: w = S('abaab').antipode(); w + S[word: abaab] - 2*S[word: ababa] - S[word: baaba] + + 3*S[word: babaa] - 6*S[word: bbaaa] + sage: w.antipode() + S[word: abaab] + """ + return self(self.expansion(elt).antipode()) + + def coproduct(self, elt): + """ + Return the coproduct of the element ``elt``. + + EXAMPLES:: + + sage: A = ShuffleAlgebra(QQ, 'ab') + sage: S = A.dual_pbw_basis() + sage: ab = S('ab').coproduct(); ab + S[word: ] # S[word: ab] + S[word: a] # S[word: b] + + S[word: ab] # S[word: ] + S[word: b] # S[word: a] + """ + cp = self.expansion(elt).coproduct() + S2 = self.tensor_square() + return S2.sum(c * self(m[0]).tensor(self(m[1])) for (m, c) in cp) + @lazy_attribute def expansion(self): """ From 0722049f68b4bd11f7d5b4c71c28dbf4ee0d442a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 14 Dec 2019 17:12:44 +0100 Subject: [PATCH 320/340] some more care for shuffle counit --- src/sage/algebras/shuffle_algebra.py | 54 ++++++++++++++++------------ 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/src/sage/algebras/shuffle_algebra.py b/src/sage/algebras/shuffle_algebra.py index 87bb30e1af9..97c0e7eca0b 100644 --- a/src/sage/algebras/shuffle_algebra.py +++ b/src/sage/algebras/shuffle_algebra.py @@ -297,28 +297,8 @@ def coproduct_on_basis(self, w): + B[word: b] # B[word: aa] + B[word: ba] # B[word: a] sage: F.coproduct_on_basis(Word()) B[word: ] # B[word: ] - """ - if not w: - return self.tensor_square().monomial((self.one_basis(), self.one_basis())) - TS = self.tensor_square() - if len(w) == 1: - return TS.sum_of_terms([((w, self.one_basis()), 1), - ((self.one_basis(), w), 1)], distinct=True) - result = self.coproduct_on_basis(Word([w[0]])) - for i in w[1:]: - result = TS.sum_of_terms([((Word(v1) * Word(u1), - Word(v2) * Word(u2)), - coeff1 * coeff2) - for ((u1, u2), coeff1) in self.coproduct_on_basis(Word([i])) - for ((v1, v2), coeff2) in result]) - return result - - def coproduct(self, S): - """ - Return the coproduct of the series ``S``. - - EXAMPLES:: + TESTS:: sage: F = ShuffleAlgebra(QQ,'ab') sage: S = F.an_element(); S @@ -334,8 +314,21 @@ def coproduct(self, S): sage: F.coproduct(F.one()) B[word: ] # B[word: ] """ - return sum([c * self.coproduct_on_basis(i) - for i, c in S.monomial_coefficients().items()]) + if not w: + return self.tensor_square().monomial((self.one_basis(), self.one_basis())) + TS = self.tensor_square() + if len(w) == 1: + return TS.sum_of_terms([((w, self.one_basis()), 1), + ((self.one_basis(), w), 1)], distinct=True) + + result = self.coproduct_on_basis(Word([w[0]])) + for i in w[1:]: + result = TS.sum_of_terms([((Word(v1) * Word(u1), + Word(v2) * Word(u2)), + coeff1 * coeff2) + for ((u1, u2), coeff1) in self.coproduct_on_basis(Word([i])) + for ((v1, v2), coeff2) in result]) + return result def counit(self, S): """ @@ -726,6 +719,21 @@ def one_basis(self): W = self.basis().keys() return W([]) + def counit(self, S): + """ + Return the counit of ``S``. + + EXAMPLES:: + + sage: F = ShuffleAlgebra(QQ,'ab').dual_pbw_basis() + sage: (3*F.gen(0)+5*F.gen(1)**2).counit() + 0 + sage: (4*F.one()).counit() + 4 + """ + W = self.basis().keys() + return S.coefficient(W()) + def algebra_generators(self): """ Return the algebra generators of ``self``. From 065860acee634345916225b3567a9d4c098e6585 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 14 Dec 2019 20:37:52 +0100 Subject: [PATCH 321/340] fix coproduct for shuffle algebra --- src/sage/algebras/shuffle_algebra.py | 33 +++++++++------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/src/sage/algebras/shuffle_algebra.py b/src/sage/algebras/shuffle_algebra.py index 97c0e7eca0b..f6a793382bf 100644 --- a/src/sage/algebras/shuffle_algebra.py +++ b/src/sage/algebras/shuffle_algebra.py @@ -282,6 +282,8 @@ def coproduct_on_basis(self, w): Return the coproduct of the element of the basis indexed by the word ``w``. + The coproduct is given by deconcatenation. + INPUT: - ``w`` -- a word @@ -292,9 +294,8 @@ def coproduct_on_basis(self, w): sage: F.coproduct_on_basis(Word('a')) B[word: ] # B[word: a] + B[word: a] # B[word: ] sage: F.coproduct_on_basis(Word('aba')) - B[word: ] # B[word: aba] + B[word: a] # B[word: ab] + B[word: a] # B[word: ba] - + B[word: aa] # B[word: b] + B[word: ab] # B[word: a] + B[word: aba] # B[word: ] - + B[word: b] # B[word: aa] + B[word: ba] # B[word: a] + B[word: ] # B[word: aba] + B[word: a] # B[word: ba] + + B[word: ab] # B[word: a] + B[word: aba] # B[word: ] sage: F.coproduct_on_basis(Word()) B[word: ] # B[word: ] @@ -306,29 +307,15 @@ def coproduct_on_basis(self, w): sage: F.coproduct(S) B[word: ] # B[word: ] + 2*B[word: ] # B[word: a] + 3*B[word: ] # B[word: b] + B[word: ] # B[word: bab] - + 2*B[word: a] # B[word: ] + B[word: a] # B[word: bb] - + B[word: ab] # B[word: b] + 3*B[word: b] # B[word: ] - + B[word: b] # B[word: ab] + B[word: b] # B[word: ba] - + B[word: ba] # B[word: b] + B[word: bab] # B[word: ] - + B[word: bb] # B[word: a] + + 2*B[word: a] # B[word: ] + 3*B[word: b] # B[word: ] + + B[word: b] # B[word: ab] + B[word: ba] # B[word: b] + + B[word: bab] # B[word: ] sage: F.coproduct(F.one()) B[word: ] # B[word: ] """ - if not w: - return self.tensor_square().monomial((self.one_basis(), self.one_basis())) TS = self.tensor_square() - if len(w) == 1: - return TS.sum_of_terms([((w, self.one_basis()), 1), - ((self.one_basis(), w), 1)], distinct=True) - - result = self.coproduct_on_basis(Word([w[0]])) - for i in w[1:]: - result = TS.sum_of_terms([((Word(v1) * Word(u1), - Word(v2) * Word(u2)), - coeff1 * coeff2) - for ((u1, u2), coeff1) in self.coproduct_on_basis(Word([i])) - for ((v1, v2), coeff2) in result]) - return result + return TS.sum_of_terms([((w[:i], w[i:]), 1) + for i in range(len(w) + 1)], distinct=True) def counit(self, S): """ @@ -848,7 +835,7 @@ def coproduct(self, elt): sage: S = A.dual_pbw_basis() sage: ab = S('ab').coproduct(); ab S[word: ] # S[word: ab] + S[word: a] # S[word: b] - + S[word: ab] # S[word: ] + S[word: b] # S[word: a] + + S[word: ab] # S[word: ] """ cp = self.expansion(elt).coproduct() S2 = self.tensor_square() From d29de54117d3a61b3ff0038e5197a0f565c77635 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 15 Dec 2019 11:37:02 +1000 Subject: [PATCH 322/340] Fixing dual PBW coproduct and adding grading. --- src/sage/algebras/shuffle_algebra.py | 66 +++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 11 deletions(-) diff --git a/src/sage/algebras/shuffle_algebra.py b/src/sage/algebras/shuffle_algebra.py index f6a793382bf..454f33b59c8 100644 --- a/src/sage/algebras/shuffle_algebra.py +++ b/src/sage/algebras/shuffle_algebra.py @@ -16,7 +16,7 @@ # **************************************************************************** from sage.categories.rings import Rings -from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis +from sage.categories.graded_hopf_algebras_with_basis import GradedHopfAlgebrasWithBasis from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.words.alphabet import Alphabet from sage.combinat.words.words import Words @@ -26,6 +26,7 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.misc.misc_c import prod from sage.sets.family import Family +from sage.rings.integer_ring import ZZ class ShuffleAlgebra(CombinatorialFreeModule): @@ -152,7 +153,7 @@ def __init__(self, R, names): self.__ngens = self._alphabet.cardinality() CombinatorialFreeModule.__init__(self, R, Words(names, infinite=False), latex_prefix="", - category=HopfAlgebrasWithBasis(R).Commutative()) + category=GradedHopfAlgebrasWithBasis(R).Commutative()) def variable_names(self): r""" @@ -216,11 +217,20 @@ def product_on_basis(self, w1, w2): sage: A = ShuffleAlgebra(QQ,'abc') sage: W = A.basis().keys() sage: A.product_on_basis(W("acb"), W("cba")) - B[word: acbacb] + B[word: acbcab] + 2*B[word: acbcba] + 2*B[word: accbab] + 4*B[word: accbba] + B[word: cabacb] + B[word: cabcab] + B[word: cabcba] + B[word: cacbab] + 2*B[word: cacbba] + 2*B[word: cbaacb] + B[word: cbacab] + B[word: cbacba] + B[word: acbacb] + B[word: acbcab] + 2*B[word: acbcba] + + 2*B[word: accbab] + 4*B[word: accbba] + B[word: cabacb] + + B[word: cabcab] + B[word: cabcba] + B[word: cacbab] + + 2*B[word: cacbba] + 2*B[word: cbaacb] + B[word: cbacab] + + B[word: cbacba] sage: (a,b,c) = A.algebra_generators() sage: a * (1-b)^2 * c - 2*B[word: abbc] - 2*B[word: abc] + 2*B[word: abcb] + B[word: ac] - 2*B[word: acb] + 2*B[word: acbb] + 2*B[word: babc] - 2*B[word: bac] + 2*B[word: bacb] + 2*B[word: bbac] + 2*B[word: bbca] - 2*B[word: bca] + 2*B[word: bcab] + 2*B[word: bcba] + B[word: ca] - 2*B[word: cab] + 2*B[word: cabb] - 2*B[word: cba] + 2*B[word: cbab] + 2*B[word: cbba] + 2*B[word: abbc] - 2*B[word: abc] + 2*B[word: abcb] + B[word: ac] + - 2*B[word: acb] + 2*B[word: acbb] + 2*B[word: babc] + - 2*B[word: bac] + 2*B[word: bacb] + 2*B[word: bbac] + + 2*B[word: bbca] - 2*B[word: bca] + 2*B[word: bcab] + + 2*B[word: bcba] + B[word: ca] - 2*B[word: cab] + 2*B[word: cabb] + - 2*B[word: cba] + 2*B[word: cbab] + 2*B[word: cbba] """ return sum(self.basis()[u] for u in w1.shuffle(w2)) @@ -332,6 +342,18 @@ def counit(self, S): W = self.basis().keys() return S.coefficient(W()) + def degree_on_basis(self, w): + """ + Return the degree of the element ``w``. + + EXAMPLES:: + + sage: A = ShuffleAlgebra(QQ, 'ab') + sage: [A.degree_on_basis(x.leading_support()) for x in A.some_elements() if x != 0] + [0, 1, 1, 2] + """ + return ZZ(len(w)) + @cached_method def algebra_generators(self): r""" @@ -629,7 +651,7 @@ def __init__(self, R, names): self._alphabet = names self._alg = ShuffleAlgebra(R, names) CombinatorialFreeModule.__init__(self, R, Words(names), prefix='S', - category=HopfAlgebrasWithBasis(R).Commutative()) + category=GradedHopfAlgebrasWithBasis(R).Commutative()) def _repr_(self): """ @@ -819,7 +841,7 @@ def antipode(self, elt): sage: S = A.dual_pbw_basis() sage: w = S('abaab').antipode(); w S[word: abaab] - 2*S[word: ababa] - S[word: baaba] - + 3*S[word: babaa] - 6*S[word: bbaaa] + + 3*S[word: babaa] - 6*S[word: bbaaa] sage: w.antipode() S[word: abaab] """ @@ -833,13 +855,35 @@ def coproduct(self, elt): sage: A = ShuffleAlgebra(QQ, 'ab') sage: S = A.dual_pbw_basis() - sage: ab = S('ab').coproduct(); ab + sage: S('ab').coproduct() S[word: ] # S[word: ab] + S[word: a] # S[word: b] - + S[word: ab] # S[word: ] + + S[word: ab] # S[word: ] + sage: S('ba').coproduct() + S[word: ] # S[word: ba] + S[word: a] # S[word: b] + + S[word: b] # S[word: a] + S[word: ba] # S[word: ] + + TESTS:: + + sage: all(A.tensor_square()(S(x).coproduct()) == x.coproduct() + ....: for x in A.some_elements()) + True + sage: all(S.tensor_square()(A(x).coproduct()) == x.coproduct() + ....: for x in S.some_elements()) + True + """ + return self.tensor_square()(self.expansion(elt).coproduct()) + + def degree_on_basis(self, w): + """ + Return the degree of the element ``w``. + + EXAMPLES:: + + sage: S = ShuffleAlgebra(QQ, 'ab').dual_pbw_basis() + sage: [S.degree_on_basis(x.leading_support()) for x in S.some_elements() if x != 0] + [0, 1, 1, 2] """ - cp = self.expansion(elt).coproduct() - S2 = self.tensor_square() - return S2.sum(c * self(m[0]).tensor(self(m[1])) for (m, c) in cp) + return ZZ(len(w)) @lazy_attribute def expansion(self): From 9d8dcee358a0b9e2b692bb272227eea45eb982f3 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 15 Dec 2019 11:39:19 +1000 Subject: [PATCH 323/340] A few other little PEP8 tweaks. --- src/sage/algebras/shuffle_algebra.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/sage/algebras/shuffle_algebra.py b/src/sage/algebras/shuffle_algebra.py index 454f33b59c8..56cdad7667e 100644 --- a/src/sage/algebras/shuffle_algebra.py +++ b/src/sage/algebras/shuffle_algebra.py @@ -102,9 +102,11 @@ class ShuffleAlgebra(CombinatorialFreeModule): sage: F = ShuffleAlgebra(QQ, 'abc') sage: B = F.basis() sage: B[Word('bb')] * B[Word('ca')] - B[word: bbca] + B[word: bcab] + B[word: bcba] + B[word: cabb] + B[word: cbab] + B[word: cbba] + B[word: bbca] + B[word: bcab] + B[word: bcba] + B[word: cabb] + + B[word: cbab] + B[word: cbba] sage: 1 - B[Word('bb')] * B[Word('ca')] / 2 - B[word: ] - 1/2*B[word: bbca] - 1/2*B[word: bcab] - 1/2*B[word: bcba] - 1/2*B[word: cabb] - 1/2*B[word: cbab] - 1/2*B[word: cbba] + B[word: ] - 1/2*B[word: bbca] - 1/2*B[word: bcab] - 1/2*B[word: bcba] + - 1/2*B[word: cabb] - 1/2*B[word: cbab] - 1/2*B[word: cbba] TESTS:: @@ -305,7 +307,7 @@ def coproduct_on_basis(self, w): B[word: ] # B[word: a] + B[word: a] # B[word: ] sage: F.coproduct_on_basis(Word('aba')) B[word: ] # B[word: aba] + B[word: a] # B[word: ba] - + B[word: ab] # B[word: a] + B[word: aba] # B[word: ] + + B[word: ab] # B[word: a] + B[word: aba] # B[word: ] sage: F.coproduct_on_basis(Word()) B[word: ] # B[word: ] @@ -316,10 +318,10 @@ def coproduct_on_basis(self, w): B[word: ] + 2*B[word: a] + 3*B[word: b] + B[word: bab] sage: F.coproduct(S) B[word: ] # B[word: ] + 2*B[word: ] # B[word: a] - + 3*B[word: ] # B[word: b] + B[word: ] # B[word: bab] - + 2*B[word: a] # B[word: ] + 3*B[word: b] # B[word: ] - + B[word: b] # B[word: ab] + B[word: ba] # B[word: b] - + B[word: bab] # B[word: ] + + 3*B[word: ] # B[word: b] + B[word: ] # B[word: bab] + + 2*B[word: a] # B[word: ] + 3*B[word: b] # B[word: ] + + B[word: b] # B[word: ab] + B[word: ba] # B[word: b] + + B[word: bab] # B[word: ] sage: F.coproduct(F.one()) B[word: ] # B[word: ] """ @@ -477,8 +479,8 @@ def _coerce_map_from_(self, R): Traceback (most recent call last): ... TypeError: no canonical coercion from Shuffle Algebra on 3 generators - ['x', 'y', 'z'] over Finite Field of size 7 to Shuffle Algebra on 3 - generators ['x', 'y', 'z'] over Integer Ring + ['x', 'y', 'z'] over Finite Field of size 7 to Shuffle Algebra on 3 + generators ['x', 'y', 'z'] over Integer Ring TESTS:: @@ -959,3 +961,4 @@ def expand(self): B[word: ab] + 2*B[word: abb] + B[word: bab] """ return self.parent().expansion(self) + From abccb825b933e17c2db6c53b505746f8b60cb455 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 15 Dec 2019 11:41:33 +1000 Subject: [PATCH 324/340] Added connected to the category. --- src/sage/algebras/shuffle_algebra.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/algebras/shuffle_algebra.py b/src/sage/algebras/shuffle_algebra.py index 56cdad7667e..c526f2bf418 100644 --- a/src/sage/algebras/shuffle_algebra.py +++ b/src/sage/algebras/shuffle_algebra.py @@ -153,9 +153,10 @@ def __init__(self, R, names): raise TypeError("argument R must be a ring") self._alphabet = names self.__ngens = self._alphabet.cardinality() + cat = GradedHopfAlgebrasWithBasis(R).Commutative().Connected() CombinatorialFreeModule.__init__(self, R, Words(names, infinite=False), latex_prefix="", - category=GradedHopfAlgebrasWithBasis(R).Commutative()) + category=cat) def variable_names(self): r""" @@ -652,8 +653,9 @@ def __init__(self, R, names): """ self._alphabet = names self._alg = ShuffleAlgebra(R, names) + cat = GradedHopfAlgebrasWithBasis(R).Commutative().Connected() CombinatorialFreeModule.__init__(self, R, Words(names), prefix='S', - category=GradedHopfAlgebrasWithBasis(R).Commutative()) + category=cat) def _repr_(self): """ From 790a38d38f6a716955689f301e07846114f5cc2b Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Sun, 15 Dec 2019 04:50:38 +0000 Subject: [PATCH 325/340] Remove setting CPATH and LIBRARY_PATH on Debian --- src/bin/sage-env | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/bin/sage-env b/src/bin/sage-env index 98db64aeef5..49f29942df0 100644 --- a/src/bin/sage-env +++ b/src/bin/sage-env @@ -342,14 +342,6 @@ export LIBRARY_PATH="${LIBRARY_PATH}$SAGE_LOCAL/lib" [ -z "$CPATH" ] || CPATH="${CPATH}:" export CPATH="${CPATH}$SAGE_LOCAL/include" -# Add Debian multi-arch directories if applicable. -# See http://wiki.debian.org/Multiarch -MULTI_ARCH=`dpkg-architecture -qDEB_BUILD_MULTIARCH 2>/dev/null` -if [ -n "$MULTI_ARCH" ]; then - LIBRARY_PATH="${LIBRARY_PATH}:/usr/lib/$MULTI_ARCH" - CPATH="${CPATH}:/usr/include/$MULTI_ARCH" -fi - SINGULARPATH="$SAGE_LOCAL/share/singular" && export SINGULARPATH SINGULAR_EXECUTABLE="$SAGE_LOCAL/bin/Singular" && export SINGULAR_EXECUTABLE From 3787e452e3db8a54bb7baba27f2ff4c21acece47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 15 Dec 2019 08:52:14 +0100 Subject: [PATCH 326/340] trac 28881 fixing the pyflakes warning --- src/sage/algebras/shuffle_algebra.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sage/algebras/shuffle_algebra.py b/src/sage/algebras/shuffle_algebra.py index c526f2bf418..47918c46052 100644 --- a/src/sage/algebras/shuffle_algebra.py +++ b/src/sage/algebras/shuffle_algebra.py @@ -20,7 +20,6 @@ from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.words.alphabet import Alphabet from sage.combinat.words.words import Words -from sage.combinat.words.word import Word from sage.combinat.words.finite_word import FiniteWord_class from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute @@ -140,7 +139,7 @@ def __init__(self, R, names): sage: F = ShuffleAlgebra(QQ, 'xyz'); F Shuffle Algebra on 3 generators ['x', 'y', 'z'] over Rational Field - sage: TestSuite(F).run() + sage: TestSuite(F).run() # long time TESTS:: @@ -649,7 +648,7 @@ def __init__(self, R, names): EXAMPLES:: sage: D = ShuffleAlgebra(QQ, 'ab').dual_pbw_basis() - sage: TestSuite(D).run() + sage: TestSuite(D).run() # long time """ self._alphabet = names self._alg = ShuffleAlgebra(R, names) @@ -963,4 +962,3 @@ def expand(self): B[word: ab] + 2*B[word: abb] + B[word: bab] """ return self.parent().expansion(self) - From 2dbc617fa82a10953782a18fd5f6111d55dbd869 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 15 Dec 2019 13:39:49 +0100 Subject: [PATCH 327/340] removed deprecated function aliases --- src/sage/combinat/symmetric_group_algebra.py | 6 +----- src/sage/crypto/sbox.py | 9 --------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/src/sage/combinat/symmetric_group_algebra.py b/src/sage/combinat/symmetric_group_algebra.py index d89cfcaf629..ff4b003c9bc 100644 --- a/src/sage/combinat/symmetric_group_algebra.py +++ b/src/sage/combinat/symmetric_group_algebra.py @@ -14,7 +14,6 @@ from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute -from sage.misc.superseded import deprecated_function_alias from sage.combinat.combinatorial_algebra import CombinatorialAlgebra from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.permutation import Permutation, Permutations, from_permutation_group_element @@ -1181,9 +1180,6 @@ def central_orthogonal_idempotent(self, la, block=True): self._idempotent_cache[mu] = ret return ret - cpis = deprecated_function_alias(25942, central_orthogonal_idempotents) - cpi = deprecated_function_alias(25942, central_orthogonal_idempotent) - @lazy_attribute def _blocks_dictionary(self): r""" @@ -1970,7 +1966,7 @@ def epsilon_ik(self, itab, ktab, star=0, mult='l2r'): I = self._indices z_elts = {} epik = epsilon_ik(it, kt, star=star) - for m,c in six.iteritems(epik._monomial_coefficients): + for m, c in six.iteritems(epik._monomial_coefficients): z_elts[I(m)] = BR(c) z = self._from_dict(z_elts) diff --git a/src/sage/crypto/sbox.py b/src/sage/crypto/sbox.py index a73dc2b1069..e722c2ef647 100644 --- a/src/sage/crypto/sbox.py +++ b/src/sage/crypto/sbox.py @@ -20,7 +20,6 @@ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.structure.sage_object import SageObject -from sage.misc.superseded import deprecated_function_alias class SBox(SageObject): r""" @@ -565,8 +564,6 @@ def difference_distribution_table(self): return A - difference_distribution_matrix = deprecated_function_alias(25708, difference_distribution_table) - def maximal_difference_probability_absolute(self): """ Return the difference probability of the difference with the @@ -697,8 +694,6 @@ def linear_approximation_table(self, scale="absolute_bias"): return A - linear_approximation_matrix = deprecated_function_alias(25708, linear_approximation_table) - def maximal_linear_bias_absolute(self): """ Return maximal linear bias, i.e. how often the linear @@ -1386,8 +1381,6 @@ def autocorrelation_table(self): return A - autocorrelation_matrix = deprecated_function_alias(25708, autocorrelation_table) - @cached_method def boomerang_connectivity_table(self): r""" @@ -1455,8 +1448,6 @@ def boomerang_connectivity_table(self): A.set_immutable() return A - boomerang_connectivity_matrix = deprecated_function_alias(25708, boomerang_connectivity_table) - def boomerang_uniformity(self): """ Return the boomerang uniformity From 31ba214f6de9accb70e4f599d4ac559f60ab5651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 15 Dec 2019 14:01:42 +0100 Subject: [PATCH 328/340] refresh the file ell_finite_field (remove deprecated stuff, pep8) --- .../elliptic_curves/ell_finite_field.py | 172 +++++++++--------- 1 file changed, 85 insertions(+), 87 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_finite_field.py b/src/sage/schemes/elliptic_curves/ell_finite_field.py index 822baf54b10..1c17fb6bc04 100644 --- a/src/sage/schemes/elliptic_curves/ell_finite_field.py +++ b/src/sage/schemes/elliptic_curves/ell_finite_field.py @@ -41,7 +41,6 @@ import sage.plot.all as plot - class EllipticCurve_finite_field(EllipticCurve_field, HyperellipticCurve_finite_field): r""" Elliptic curve over a finite field. @@ -51,7 +50,7 @@ class EllipticCurve_finite_field(EllipticCurve_field, HyperellipticCurve_finite_ sage: EllipticCurve(GF(101),[2,3]) Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Finite Field of size 101 - sage: F=GF(101^2, 'a') + sage: F = GF(101^2, 'a') sage: EllipticCurve([F(2),F(3)]) Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Finite Field in a of size 101^2 @@ -89,11 +88,9 @@ def plot(self, *args, **kwds): INPUT: - - ``*args, **kwds`` - all other options are passed to the circle graphing primitive. - EXAMPLES:: sage: E = EllipticCurve(FiniteField(17), [0,1]) @@ -115,25 +112,25 @@ def _points_via_group_structure(self): EXAMPLES:: - sage: S=EllipticCurve(GF(97),[2,3])._points_via_group_structure() + sage: S = EllipticCurve(GF(97),[2,3])._points_via_group_structure() sage: len(S) 100 See :trac:`4687`, where the following example did not work:: - sage: E=EllipticCurve(GF(2),[0, 0, 1, 1, 1]) + sage: E = EllipticCurve(GF(2),[0, 0, 1, 1, 1]) sage: E.points() [(0 : 1 : 0)] :: - sage: E=EllipticCurve(GF(2),[0, 0, 1, 0, 1]) + sage: E = EllipticCurve(GF(2),[0, 0, 1, 0, 1]) sage: E.points() [(0 : 1 : 0), (1 : 0 : 1), (1 : 1 : 1)] :: - sage: E=EllipticCurve(GF(4,'a'),[0, 0, 1, 0, 1]) + sage: E = EllipticCurve(GF(4,'a'),[0, 0, 1, 0, 1]) sage: E.points() [(0 : 1 : 0), (0 : a : 1), (0 : a + 1 : 1), (1 : 0 : 1), (1 : 1 : 1), (a : 0 : 1), (a : 1 : 1), (a + 1 : 0 : 1), (a + 1 : 1 : 1)] """ @@ -377,28 +374,27 @@ def random_element(self): random_point = random_element - def trace_of_frobenius(self): r""" Return the trace of Frobenius acting on this elliptic curve. - .. note:: + .. NOTE:: - This computes the curve cardinality, which may be - time-consuming. + This computes the curve cardinality, which may be + time-consuming. EXAMPLES:: - sage: E=EllipticCurve(GF(101),[2,3]) + sage: E = EllipticCurve(GF(101),[2,3]) sage: E.trace_of_frobenius() 6 - sage: E=EllipticCurve(GF(11^5,'a'),[2,5]) + sage: E = EllipticCurve(GF(11^5,'a'),[2,5]) sage: E.trace_of_frobenius() 802 The following shows that the issue from :trac:`2849` is fixed:: - sage: E=EllipticCurve(GF(3^5,'a'),[-1,-1]) + sage: E = EllipticCurve(GF(3^5,'a'),[-1,-1]) sage: E.trace_of_frobenius() -27 """ @@ -557,10 +553,6 @@ def cardinality(self, algorithm=None, extension_degree=1): except AttributeError: pass - if algorithm in ["sea", "heuristic"]: - from sage.misc.superseded import deprecation - deprecation(16931, "algorithm={!r} is deprecated".format(algorithm)) - algorithm = None jpol = None if algorithm is None: # Check for j in subfield @@ -584,7 +576,7 @@ def cardinality(self, algorithm=None, extension_degree=1): N = self.cardinality_pari() N2 = self.cardinality_bsgs() if N != N2: - raise AssertionError("cardinality with pari=%s but with bsgs=%s"%(N, N2)) + raise AssertionError("cardinality with pari=%s but with bsgs=%s" % (N, N2)) else: raise ValueError("algorithm {!r} is not known".format(algorithm)) @@ -592,9 +584,9 @@ def cardinality(self, algorithm=None, extension_degree=1): return N from .cardinality import (cardinality_bsgs, - cardinality_exhaustive, _cardinality_subfield) + cardinality_exhaustive, _cardinality_subfield) - order = cardinality # alias + order = cardinality # alias def frobenius_polynomial(self): r""" @@ -606,25 +598,25 @@ def frobenius_polynomial(self): curves, Frobenius is an integer a and the polynomial is `(x-a)^2`. - .. note:: + .. NOTE:: - This computes the curve cardinality, which may be - time-consuming. + This computes the curve cardinality, which may be + time-consuming. EXAMPLES:: - sage: E=EllipticCurve(GF(11),[3,3]) + sage: E = EllipticCurve(GF(11),[3,3]) sage: E.frobenius_polynomial() x^2 - 4*x + 11 For some supersingular curves, Frobenius is in Z and the polynomial is a square:: - sage: E=EllipticCurve(GF(25,'a'),[0,0,0,0,1]) + sage: E = EllipticCurve(GF(25,'a'),[0,0,0,0,1]) sage: E.frobenius_polynomial().factor() (x + 5)^2 """ - x=polygen(ZZ) + x = polygen(ZZ) return x**2-self.trace_of_frobenius()*x+self.base_field().cardinality() def frobenius_order(self): @@ -632,22 +624,22 @@ def frobenius_order(self): Return the quadratic order Z[phi] where phi is the Frobenius endomorphism of the elliptic curve - .. note:: + .. NOTE:: - This computes the curve cardinality, which may be - time-consuming. + This computes the curve cardinality, which may be + time-consuming. EXAMPLES:: - sage: E=EllipticCurve(GF(11),[3,3]) + sage: E = EllipticCurve(GF(11),[3,3]) sage: E.frobenius_order() Order in Number Field in phi with defining polynomial x^2 - 4*x + 11 For some supersingular curves, Frobenius is in Z and the Frobenius order is Z:: - sage: E=EllipticCurve(GF(25,'a'),[0,0,0,0,1]) - sage: R=E.frobenius_order() + sage: E = EllipticCurve(GF(25,'a'),[0,0,0,0,1]) + sage: R = E.frobenius_order() sage: R Order in Number Field in phi with defining polynomial x + 5 sage: R.degree() @@ -658,18 +650,18 @@ def frobenius_order(self): def frobenius(self): r""" - Return the frobenius of self as an element of a quadratic order + Return the frobenius of ``self`` as an element of a quadratic order - .. note:: + .. NOTE:: - This computes the curve cardinality, which may be - time-consuming. + This computes the curve cardinality, which may be + time-consuming. Frobenius is only determined up to conjugacy. EXAMPLES:: - sage: E=EllipticCurve(GF(11),[3,3]) + sage: E = EllipticCurve(GF(11),[3,3]) sage: E.frobenius() phi sage: E.frobenius().minpoly() @@ -677,12 +669,12 @@ def frobenius(self): For some supersingular curves, Frobenius is in Z:: - sage: E=EllipticCurve(GF(25,'a'),[0,0,0,0,1]) + sage: E = EllipticCurve(GF(25,'a'),[0,0,0,0,1]) sage: E.frobenius() -5 """ R = self.frobenius_order() - if R.degree()==1: + if R.degree() == 1: return self.frobenius_polynomial().roots(multiplicities=False)[0] else: return R.gen(1) @@ -691,14 +683,16 @@ def cardinality_pari(self): r""" Return the cardinality of ``self`` using PARI. + This uses :pari:`ellcard`. + EXAMPLES:: - sage: p=next_prime(10^3) - sage: E=EllipticCurve(GF(p),[3,4]) + sage: p = next_prime(10^3) + sage: E = EllipticCurve(GF(p),[3,4]) sage: E.cardinality_pari() 1020 - sage: K=GF(next_prime(10^6)) - sage: E=EllipticCurve(K,[1,0,0,1,1]) + sage: K = GF(next_prime(10^6)) + sage: E = EllipticCurve(K,[1,0,0,1,1]) sage: E.cardinality_pari() 999945 @@ -822,13 +816,14 @@ def __iter__(self): def __getitem__(self, n): """ - Return the n'th point in self's __points list. This enables users - to iterate over the curve's point set. + Return the n'th point in self's __points list. + + This enables users to iterate over the curve's point set. EXAMPLES:: - sage: E=EllipticCurve(GF(97),[2,3]) - sage: S=E.points() + sage: E = EllipticCurve(GF(97),[2,3]) + sage: S = E.points() sage: E[10] (10 : 76 : 1) sage: E[15] @@ -890,33 +885,33 @@ def abelian_group(self, debug=False): EXAMPLES:: - sage: E=EllipticCurve(GF(11),[2,5]) + sage: E = EllipticCurve(GF(11),[2,5]) sage: E.abelian_group() Additive abelian group isomorphic to Z/10 embedded in Abelian group of points on Elliptic Curve defined by y^2 = x^3 + 2*x + 5 over Finite Field of size 11 :: - sage: E=EllipticCurve(GF(41),[2,5]) + sage: E = EllipticCurve(GF(41),[2,5]) sage: E.abelian_group() Additive abelian group isomorphic to Z/22 + Z/2 ... :: - sage: F.
=GF(3^6,'a') - sage: E=EllipticCurve([a^4 + a^3 + 2*a^2 + 2*a, 2*a^5 + 2*a^3 + 2*a^2 + 1]) + sage: F. = GF(3^6,'a') + sage: E = EllipticCurve([a^4 + a^3 + 2*a^2 + 2*a, 2*a^5 + 2*a^3 + 2*a^2 + 1]) sage: E.abelian_group() Additive abelian group isomorphic to Z/26 + Z/26 ... :: - sage: F.=GF(101^3,'a') - sage: E=EllipticCurve([2*a^2 + 48*a + 27, 89*a^2 + 76*a + 24]) + sage: F. = GF(101^3,'a') + sage: E = EllipticCurve([2*a^2 + 48*a + 27, 89*a^2 + 76*a + 24]) sage: E.abelian_group() Additive abelian group isomorphic to Z/1031352 ... The group can be trivial:: - sage: E=EllipticCurve(GF(2),[0,0,1,1,1]) + sage: E = EllipticCurve(GF(2),[0,0,1,1,1]) sage: E.abelian_group() Trivial group embedded in Abelian group of points on Elliptic Curve defined by y^2 + y = x^3 + x + 1 over Finite Field of size 2 @@ -981,17 +976,19 @@ def abelian_group(self, debug=False): if debug: print("Getting a new random point") Q = self.random_point() - while Q.is_zero(): Q = self.random_point() + while Q.is_zero(): + Q = self.random_point() npts += 1 if debug: print("Q = ", Q, ": Order(Q) = ", Q.order()) Q1 = n1 * Q - if Q1.is_zero() and npts>=10: # then P1,n1 will not change but we may increase n2 + if Q1.is_zero() and npts >= 10: # then P1,n1 will not change but we may increase n2 if debug: print("Case 2: n2 may increase") - n1a = 1; n1b = n1 + n1a = 1 + n1b = n1 P1a = P1 n1a = n1.prime_to_m_part(N//n1) n1b = n1//n1a @@ -1017,15 +1014,17 @@ def abelian_group(self, debug=False): if debug: assert Q.order() == m Q._order = m - if n2==1: # this is our first nontrivial P2 - P2=Q - n2=m + if n2 == 1: # this is our first nontrivial P2 + P2 = Q + n2 = m if debug: print("Adding second generator ",P2," of order ",n2) print("Subgroup order now ",n1*n2,"=",n1,"*",n2) else: # we must merge P2 and Q: - oldn2=n2 # holds old value - P2,n2=generic.merge_points((P2,n2),(Q,m),operation='+', check=debug) + oldn2 = n2 # holds old value + P2, n2 = generic.merge_points((P2, n2), (Q, m), + operation='+', + check=debug) if debug: assert P2.order() == n2 P2._order = n2 @@ -1034,14 +1033,14 @@ def abelian_group(self, debug=False): print("Replacing second generator by ",P2,end="") print(" of order ",n2, " gaining index ",n2//oldn2) print("Subgroup order now ",n1*n2,"=",n1,"*",n2) - elif not Q1.is_zero(): # Q1 nonzero: n1 will increase + elif not Q1.is_zero(): # Q1 nonzero: n1 will increase if debug: print("Case 1: n1 may increase") - oldn1=n1 + oldn1 = n1 if n2>1: P3=(n1//n2)*P1 # so P2,P3 are a basis for n2-torsion if debug: - assert P3.order()==n2 + assert P3.order() == n2 P3._order=n2 if debug: print("storing generator ",P3," of ",n2,"-torsion") @@ -1415,12 +1414,12 @@ def set_order(self, value, num_checks=8): q = self.base_field().order() a,b = Hasse_bounds(q,1) if not a <= value <= b: - raise ValueError('Value %s illegal (not an integer in the Hasse range)'%value) + raise ValueError('Value %s illegal (not an integer in the Hasse range)' % value) # Is value*random == identity? for i in range(num_checks): G = self.random_point() if value * G != self(0): - raise ValueError('Value %s illegal (multiple of random point not the identity)'%value) + raise ValueError('Value %s illegal (multiple of random point not the identity)' % value) self._order = value @@ -1466,9 +1465,9 @@ def supersingular_j_polynomial(p): try: p = ZZ(p) except TypeError: - raise ValueError("p (=%s) should be a prime number"%p) + raise ValueError("p (=%s) should be a prime number" % p) if not p.is_prime(): - raise ValueError("p (=%s) should be a prime number"%p) + raise ValueError("p (=%s) should be a prime number" % p) J = polygen(GF(p),'j') if p<13: @@ -1478,12 +1477,12 @@ def supersingular_j_polynomial(p): X,T = PolynomialRing(GF(p),2,names=['X','T']).gens() H = sum(binomial(m, i) ** 2 * T ** i for i in range(m + 1)) F = T**2 * (T-1)**2 * X - 256*(T**2-T+1)**3 - R = F.resultant(H,T) - R = prod([fi for fi,e in R([J,0]).factor()]) - if R(0)==0: - R = R//J - if R(1728)==0: - R = R//(J-1728) + R = F.resultant(H, T) + R = prod([fi for fi, e in R([J, 0]).factor()]) + if R(0) == 0: + R = R // J + if R(1728) == 0: + R = R // (J - 1728) return R # For p in [13..300] we have precomputed these polynomials and store @@ -1602,22 +1601,22 @@ def is_j_supersingular(j, proof=True): """ if not is_FiniteFieldElement(j): - raise ValueError("%s must be an element of a finite field"%j) + raise ValueError("%s must be an element of a finite field" % j) F = j.parent() p = F.characteristic() d = F.degree() if j.is_zero(): - return p==3 or p%3==2 + return p == 3 or p % 3 == 2 - if (j-1728).is_zero(): - return p==2 or p%4==3 + if (j - 1728).is_zero(): + return p == 2 or p % 4 == 3 # From now on we know that j != 0, 1728 - if p in (2,3,5,7,11): - return False # since j=0, 1728 are the only s.s. invariants + if p in (2, 3, 5, 7, 11): + return False # since j=0, 1728 are the only s.s. invariants # supersingular j-invariants have degree at most 2: @@ -1658,7 +1657,7 @@ def is_j_supersingular(j, proof=True): if not ((p+1)*P).is_zero(): return False else: - n = None # will hold either p+1 or p-1 later + n = None # will hold either p+1 or p-1 later for i in range(10): P = E.random_element() # avoid 2-torsion; we know that a1=a3=0 and #E>4! @@ -1667,9 +1666,9 @@ def is_j_supersingular(j, proof=True): if n is None: # not yet decided between p+1 and p-1 pP = p*P - if not pP[0]==P[0]: # i.e. pP is neither P nor -P + if not pP[0]==P[0]: # i.e. pP is neither P nor -P return False - if pP[1]==P[1]: # then p*P == P != -P + if pP[1]==P[1]: # then p*P == P != -P n=p-1 else: # then p*P == -P != P n=p+1 @@ -1677,7 +1676,6 @@ def is_j_supersingular(j, proof=True): if not (n*P).is_zero(): return False - # when proof is False we return True for any curve which passes # the probabilistic test: From 591d26c88b3748499a0057df95602e59ba1fe3f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 15 Dec 2019 21:36:38 +0100 Subject: [PATCH 329/340] trac 28888 some details --- .../elliptic_curves/ell_finite_field.py | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_finite_field.py b/src/sage/schemes/elliptic_curves/ell_finite_field.py index 1c17fb6bc04..76fc0f9503b 100644 --- a/src/sage/schemes/elliptic_curves/ell_finite_field.py +++ b/src/sage/schemes/elliptic_curves/ell_finite_field.py @@ -107,8 +107,9 @@ def plot(self, *args, **kwds): def _points_via_group_structure(self): """ - Return a list of all the points on the curve, for prime fields only - (see points() for the general case) + Return a list of all the points on the curve, for prime fields only. + + See points() for the general case. EXAMPLES:: @@ -214,7 +215,7 @@ def points(self): def count_points(self, n=1): """ - Returns the cardinality of this elliptic curve over the base field or extensions. + Return the cardinality of this elliptic curve over the base field or extensions. INPUT: @@ -622,7 +623,7 @@ def frobenius_polynomial(self): def frobenius_order(self): r""" Return the quadratic order Z[phi] where phi is the Frobenius - endomorphism of the elliptic curve + endomorphism of the elliptic curve. .. NOTE:: @@ -650,7 +651,7 @@ def frobenius_order(self): def frobenius(self): r""" - Return the frobenius of ``self`` as an element of a quadratic order + Return the frobenius of ``self`` as an element of a quadratic order. .. NOTE:: @@ -844,7 +845,7 @@ def __getitem__(self, n): @cached_method def abelian_group(self, debug=False): r""" - Returns the abelian group structure of the group of points on this + Return the abelian group structure of the group of points on this elliptic curve. .. warning:: @@ -1120,7 +1121,7 @@ def abelian_group(self, debug=False): def is_isogenous(self, other, field=None, proof=True): """ - Return whether or not self is isogenous to other + Return whether or not self is isogenous to other. INPUT: @@ -1666,12 +1667,12 @@ def is_j_supersingular(j, proof=True): if n is None: # not yet decided between p+1 and p-1 pP = p*P - if not pP[0]==P[0]: # i.e. pP is neither P nor -P + if pP[0] != P[0]: # i.e. pP is neither P nor -P return False - if pP[1]==P[1]: # then p*P == P != -P - n=p-1 + if pP[1] == P[1]: # then p*P == P != -P + n = p - 1 else: # then p*P == -P != P - n=p+1 + n = p + 1 else: if not (n*P).is_zero(): return False From 109b00684c60ea90d69dd23292f3eee87b0df28a Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Mon, 16 Dec 2019 15:47:34 +0100 Subject: [PATCH 330/340] make incidence matrix immutable --- src/sage/geometry/cone.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index 51a63726f01..afb30e59490 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -2760,6 +2760,11 @@ def incidence_matrix(self): [1] [1] [1] + + TESTS:: + + sage: halfspace.incidence_matrix().is_immutable() + True """ normals = self.facet_normals() incidence_matrix = matrix(ZZ, self.nrays(), @@ -2770,6 +2775,7 @@ def incidence_matrix(self): if normal*ray == 0: incidence_matrix[Vindex, Hindex] = 1 + incidence_matrix.set_immutable() return incidence_matrix def intersection(self, other): From b81eaae029000424cb1c9c7669ec37e993d6bac6 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Tue, 19 Nov 2019 09:16:37 +0100 Subject: [PATCH 331/340] implemted incidence matrix for lattice polytope --- src/sage/geometry/lattice_polytope.py | 199 +++++++++++++++----------- 1 file changed, 117 insertions(+), 82 deletions(-) diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index d2a891f01d8..ad0ca49e765 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -322,7 +322,7 @@ def LatticePolytope(data, compute_vertices=True, n=0, lattice=None): except TypeError: raise TypeError("cannot construct a polytope from\n%s" % data) try: - data = tuple(map(lattice, data)) + data = tuple(map(lattice, data)) except TypeError: raise ValueError("points\n%s\nare not in %s!" % (data, lattice)) for p in data: @@ -352,7 +352,7 @@ def ReflexivePolytope(dim, n): first. EXAMPLES: - + The 3rd 2-dimensional polytope is "the diamond":: sage: ReflexivePolytope(2, 3) @@ -407,7 +407,7 @@ def ReflexivePolytopes(dim): :rtype: list of lattice polytopes EXAMPLES: - + There are 16 reflexive polygons:: sage: len(ReflexivePolytopes(2)) @@ -490,7 +490,7 @@ class LatticePolytopeClass(SageObject, collections.Hashable): - ``ambient_vertex_indices`` -- increasing list or tuple of integers, indices of vertices of ``ambient`` generating this polytope; - + - ``ambient_facet_indices`` -- increasing list or tuple of integers, indices of facets of ``ambient`` generating this polytope. @@ -1487,15 +1487,15 @@ def ambient_facet_indices(self): - increasing :class:`tuple` of integers. EXAMPLES: - + The polytope itself is not contained in any of its facets:: sage: o = lattice_polytope.cross_polytope(3) sage: o.ambient_facet_indices() () - + But each of its other faces is contained in one or more facets:: - + sage: face = o.faces(1)[0] sage: face.ambient_facet_indices() (4, 5) @@ -1587,18 +1587,18 @@ def ambient_vertex_indices(self): (0, 1) """ return self._ambient_vertex_indices - + @cached_method def boundary_point_indices(self): r""" Return indices of (relative) boundary lattice points of this polytope. OUTPUT: - + - increasing :class:`tuple` of integers. EXAMPLES: - + All points but the origin are on the boundary of this square:: sage: square = lattice_polytope.cross_polytope(2).polar() @@ -1615,9 +1615,9 @@ def boundary_point_indices(self): in 2-d lattice N sage: square.boundary_point_indices() (0, 1, 2, 3, 4, 5, 7, 8) - + For an edge the boundary is formed by the end points:: - + sage: face = square.edges()[0] sage: face.points() N(-1, -1), @@ -1630,17 +1630,17 @@ def boundary_point_indices(self): return tuple(i for i, c in enumerate(self.distances().columns(copy=False)) if len(c.nonzero_positions()) < self.nfacets()) - + def boundary_points(self): r""" Return (relative) boundary lattice points of this polytope. - + OUTPUT: - a :class:`point collection `. EXAMPLES: - + All points but the origin are on the boundary of this square:: sage: square = lattice_polytope.cross_polytope(2).polar() @@ -1654,9 +1654,9 @@ def boundary_points(self): N( 0, 1), N( 1, 0) in 2-d lattice N - + For an edge the boundary is formed by the end points:: - + sage: face = square.edges()[0] sage: face.boundary_points() N(-1, -1), @@ -1793,15 +1793,15 @@ def distances(self, point=None): def dual(self): r""" Return the dual face under face duality of polar reflexive polytopes. - + This duality extends the correspondence between vertices and facets. - + OUTPUT: - + - a :class:`lattice polytope `. - + EXAMPLES:: - + sage: o = lattice_polytope.cross_polytope(4) sage: e = o.edges()[0]; e 1-d face of 4-d reflexive polytope in 4-d lattice M @@ -1950,7 +1950,7 @@ def face_lattice(self): sage: face.adjacent()[0].vertices() M(1, 0) in 2-d lattice M - + Note that if ``p`` is a face of ``superp``, then the face lattice of ``p`` consists of (appropriate) faces of ``superp``:: @@ -1974,14 +1974,10 @@ def face_lattice(self): """ if self._ambient is self: # We need to compute face lattice on our own. - vertex_to_facets = [] - facet_to_vertices = [[] for _ in range(self.nfacets())] - for i, vertex in enumerate(self.vertices()): - facets = [j for j, normal in enumerate(self.facet_normals()) - if normal * vertex + self.facet_constant(j) == 0] - vertex_to_facets.append(facets) - for j in facets: - facet_to_vertices[j].append(i) + vertex_to_facets = [row.nonzero_positions() + for row in self.incidence_matrix().rows()] + facet_to_vertices = [column.nonzero_positions() + for column in self.incidence_matrix().columns()] def LPFace(vertices, facets): if not facets: @@ -2074,7 +2070,7 @@ def faces(self, dim=None, codim=None): 1-d face of 2-d lattice polytope in 2-d lattice M, 1-d face of 2-d lattice polytope in 2-d lattice M), (2-d lattice polytope in 2-d lattice M,)) - + Its faces of dimension one (i.e., edges):: sage: square.faces(dim=1) @@ -2087,7 +2083,7 @@ def faces(self, dim=None, codim=None): sage: square.faces(codim=1) is square.faces(dim=1) True - + Let's pick a particular face:: sage: face = square.faces(dim=1)[0] @@ -2365,6 +2361,45 @@ def facets(self): # Dictionaries of normal forms _rp_dict = [None] * 4 + def incidence_matrix(self): + """ + Return the incidence matrix. + + .. NOTE:: + + The columns correspond to facets/facet normals + in the order of :meth:`facet_normals`, the rows + correspond to the vertices in the order of + :meth:`vertices`. + + EXAMPLES:: + sage: o = lattice_polytope.cross_polytope(2) + sage: o.incidence_matrix() + [0 0 1 1] + [0 1 1 0] + [1 1 0 0] + [1 0 0 1] + sage: o.faces(1)[0].incidence_matrix() + [1 0] + [0 1] + + sage: o = lattice_polytope.cross_polytope(4) + sage: o.incidence_matrix().column(3).nonzero_positions() + [3, 4, 5, 6] + sage: o.facets()[3].ambient_vertex_indices() + (3, 4, 5, 6) + """ + incidence_matrix = matrix(ZZ, self.nvertices(), + self.nfacets(), 0) + + for Hindex, normal in enumerate(self.facet_normals()): + facet_constant = self.facet_constant(Hindex) + for Vindex, vertex in enumerate(self.vertices()): + if normal*vertex + facet_constant == 0: + incidence_matrix[Vindex, Hindex] = 1 + + return incidence_matrix + @cached_method def index(self): r""" @@ -2435,13 +2470,13 @@ def index(self): def interior_point_indices(self): r""" Return indices of (relative) interior lattice points of this polytope. - + OUTPUT: - + - increasing :class:`tuple` of integers. EXAMPLES: - + The origin is the only interior point of this square:: sage: square = lattice_polytope.cross_polytope(2).polar() @@ -2458,9 +2493,9 @@ def interior_point_indices(self): in 2-d lattice N sage: square.interior_point_indices() (6,) - + Its edges also have a single interior point each:: - + sage: face = square.edges()[0] sage: face.points() N(-1, -1), @@ -2473,33 +2508,33 @@ def interior_point_indices(self): return tuple(i for i, c in enumerate(self.distances().columns(copy=False)) if len(c.nonzero_positions()) == self.nfacets()) - + def interior_points(self): r""" Return (relative) boundary lattice points of this polytope. - + OUTPUT: - a :class:`point collection `. EXAMPLES: - + The origin is the only interior point of this square:: sage: square = lattice_polytope.cross_polytope(2).polar() sage: square.interior_points() N(0, 0) in 2-d lattice N - + Its edges also have a single interior point each:: - + sage: face = square.edges()[0] sage: face.interior_points() N(-1, 0) in 2-d lattice N """ return self.points(self.interior_point_indices()) - + @cached_method def is_reflexive(self): r""" @@ -2832,7 +2867,7 @@ def normal_form(self, algorithm="palp", permutation=False): of ``self`` or a tuple of it and a permutation. EXAMPLES: - + We compute the normal form of the "diamond":: sage: d = LatticePolytope([(1,0), (0,1), (-1,0), (0,-1)]) @@ -2855,9 +2890,9 @@ def normal_form(self, algorithm="palp", permutation=False): 3 sage: d 2-d reflexive polytope #3 in 2-d lattice M - + You can get it in its normal form (in the default lattice) as :: - + sage: lattice_polytope.ReflexivePolytope(2, 3).vertices() M( 1, 0), M( 0, 1), @@ -2904,7 +2939,7 @@ def normal_form(self, algorithm="palp", permutation=False): elif algorithm == "palp_modified": result = self._palp_modified_normal_form(permutation=permutation) else: - raise ValueError('Algorithm must be palp, ' + + raise ValueError('Algorithm must be palp, ' + 'palp_native, or palp_modified.') if permutation: vertices, perm = result @@ -2916,7 +2951,7 @@ def normal_form(self, algorithm="palp", permutation=False): v.set_immutable() vertices = PointCollection(vertices, M) return (vertices, perm) if permutation else vertices - + def _palp_modified_normal_form(self, permutation=False): r""" Return the normal form of ``self`` using the modified PALP algorithm. @@ -3026,7 +3061,7 @@ def _palp_PM_max(self, check=False): maximum under all permutations of its rows and columns. For more more detail, see also :meth:`~sage.matrix.matrix2.Matrix.permutation_normal_form`. - + Instead of using the generic method for computing the permutation normal form, this method uses the PALP algorithm to compute the permutation normal form and its automorphisms concurrently. @@ -3105,7 +3140,7 @@ def index_of_max(iterable): if m > 0: permutations[0][1] = PGE(S_v, j + 1, m + j + 1) * permutations[0][1] first_row = list(PM[0]) - + # Arrange other rows one by one and compare with first row for k in range(1, n_f): # Error for k == 1 already! @@ -3141,13 +3176,13 @@ def index_of_max(iterable): # This row is the same, so we have a symmetry! n_s += 1 else: - # This row is larger, so it becomes the first row and + # This row is larger, so it becomes the first row and # the symmetries reset. first_row = list(PM[k]) permutations = {0: permutations[n_s]} n_s = 1 permutations = {k:permutations[k] for k in permutations if k < n_s} - + b = PM.with_permuted_rows_and_columns(*permutations[0])[0] # Work out the restrictions the current permutations # place on other permutations as a automorphisms @@ -3162,8 +3197,8 @@ def index_of_max(iterable): S[S[i]-1] += 1 else: S[i] = i + 1 - - # We determine the other rows of PM_max in turn by use of perms and + + # We determine the other rows of PM_max in turn by use of perms and # aut on previous rows. for l in range(1, n_f - 1): n_s = len(permutations) @@ -3262,7 +3297,7 @@ def index_of_max(iterable): for s in range(n_p): permutations[n_s] = copy(permutations_bar[s]) n_s += 1 - cf = n_s + cf = n_s permutations = {k:permutations[k] for k in permutations if k < n_s} # If the automorphisms are not already completely restricted, # update them @@ -3543,7 +3578,7 @@ def plot3d(self, def polyhedron(self): r""" Return the Polyhedron object determined by this polytope's vertices. - + EXAMPLES:: sage: o = lattice_polytope.cross_polytope(2) @@ -3551,8 +3586,8 @@ def polyhedron(self): A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 4 vertices """ from sage.geometry.polyhedron.constructor import Polyhedron - return Polyhedron(vertices=[list(v) for v in self._vertices]) - + return Polyhedron(vertices=[list(v) for v in self._vertices]) + def show3d(self): """ Show a 3d picture of the polytope with default settings and without axes or frame. @@ -3604,9 +3639,9 @@ def point(self, i): def points(self, *args, **kwds): r""" Return all lattice points of ``self``. - + INPUT: - + - any arguments given will be passed on to the returned object. OUTPUT: @@ -3668,9 +3703,9 @@ def points(self, *args, **kwds): M( 0, -1, 0), M( 0, 0, 0) in 3-d lattice M - + Only two of the above points: - + sage: p.points(1, 3) M(0, 1, 0), M(0, -1, 0) @@ -4001,9 +4036,9 @@ def vertex_facet_pairing_matrix(self): def vertices(self, *args, **kwds): r""" Return vertices of ``self``. - + INPUT: - + - any arguments given will be passed on to the returned object. OUTPUT: @@ -4135,12 +4170,12 @@ class NefPartition(SageObject, standard basis of $\ZZ^k$. The **dual Cayley polytope** $P^* \subset \overline{N}_\RR$ is the Cayley polytope of the dual nef-partition. - + The **Cayley cone** $C \subset \overline{M}_\RR$ of a nef-partition is the cone spanned by its Cayley polytope. The **dual Cayley cone** $C^\vee \subset \overline{M}_\RR$ is the usual dual cone of $C$. It turns out, that $C^\vee$ is spanned by $P^*$. - + It is also possible to go back from the Cayley cone to the Cayley polytope, since $C$ is a reflexive Gorenstein cone supported by $P$: primitive integral ray generators of $C$ are contained in an affine hyperplane and @@ -4520,7 +4555,7 @@ def dual(self): See Proposition 3.19 in [BN2008]_. .. NOTE:: - + Automatically constructed dual nef-partitions will be ordered, i.e. vertex partition of `\nabla` will look like `\{0, 1, 2\} \sqcup \{3, 4, 5, 6\} \sqcup \{7, 8\}`. @@ -4743,7 +4778,7 @@ def part(self, i, all_points=False): INPUT: - ``i`` -- an integer - + - ``all_points`` -- (default: False) whether to list all lattice points or just vertices @@ -5006,7 +5041,7 @@ def _palp_canonical_order(V, PM_max, permutations): INPUT: - ``V`` -- :class:`point collection `. The vertices. - + - ``PM_max`` -- the maximal vertex-facet pairing matrix - ``permutation`` -- the permutations of the vertices yielding @@ -5093,9 +5128,9 @@ def from_palp_index(i): else: raise ValueError('Cannot convert PALP index ' + i + ' to number.') - return i + return i n = len(permutation) - domain = [from_palp_index(i) for i in permutation] + domain = [from_palp_index(i) for i in permutation] from sage.groups.perm_gps.permgroup_element import make_permgroup_element from sage.groups.perm_gps.permgroup_named import SymmetricGroup S = SymmetricGroup(n) @@ -5185,11 +5220,11 @@ def _read_poly_x_incidences(data, dim): ....: print(f.read()) Incidences as binary numbers [F-vector=(4 4)]: v[d][i]: sum_j Incidence(i'th dim-d-face, j-th vertex) x 2^j - v[0]: 1000 0001 0100 0010 - v[1]: 1001 1100 0011 0110 + v[0]: 1000 0001 0100 0010 + v[1]: 1001 1100 0011 0110 f[d][i]: sum_j Incidence(i'th dim-d-face, j-th facet) x 2^j - f[0]: 0011 0101 1010 1100 - f[1]: 0001 0010 0100 1000 + f[0]: 0011 0101 1010 1100 + f[1]: 0001 0010 0100 1000 sage: f = open(result_name) sage: l = f.readline() sage: lattice_polytope._read_poly_x_incidences(f, 2) @@ -5432,13 +5467,13 @@ def convex_hull(points): def cross_polytope(dim): r""" Return a cross-polytope of the given dimension. - + INPUT: - + - ``dim`` -- an integer. - + OUTPUT: - + - a :class:`lattice polytope `. EXAMPLES:: @@ -5589,11 +5624,11 @@ def read_all_polytopes(file_name): polytopes. OUTPUT: - + - a sequence of polytopes. EXAMPLES: - + We use poly.x to compute two polar polytopes and read them:: sage: d = lattice_polytope.cross_polytope(2) From 2d6093c88480001dc56e392df5a19d768347cc0b Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Mon, 16 Dec 2019 15:54:33 +0100 Subject: [PATCH 332/340] made incidence matrix cached an immutable --- src/sage/geometry/lattice_polytope.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index ad0ca49e765..4e277a4444d 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -2361,6 +2361,7 @@ def facets(self): # Dictionaries of normal forms _rp_dict = [None] * 4 + @cached_method def incidence_matrix(self): """ Return the incidence matrix. @@ -2388,6 +2389,11 @@ def incidence_matrix(self): [3, 4, 5, 6] sage: o.facets()[3].ambient_vertex_indices() (3, 4, 5, 6) + + TESTS:: + + sage: o.incidence_matrix().is_immutable() + True """ incidence_matrix = matrix(ZZ, self.nvertices(), self.nfacets(), 0) @@ -2398,6 +2404,7 @@ def incidence_matrix(self): if normal*vertex + facet_constant == 0: incidence_matrix[Vindex, Hindex] = 1 + incidence_matrix.set_immutable() return incidence_matrix @cached_method From df58d4ba3705aedf929c355afe7347714afff89b Mon Sep 17 00:00:00 2001 From: "E. Madison Bray" Date: Mon, 16 Dec 2019 16:47:22 +0100 Subject: [PATCH 333/340] Trac #28596: Apply less restricted permission mask to extracted source tarballs when building SPKGs. --- build/sage_bootstrap/uncompress/action.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/build/sage_bootstrap/uncompress/action.py b/build/sage_bootstrap/uncompress/action.py index 671e6da63b9..9655f76860c 100644 --- a/build/sage_bootstrap/uncompress/action.py +++ b/build/sage_bootstrap/uncompress/action.py @@ -73,8 +73,9 @@ def unpack_archive(archive, dirname=None): rename = lambda: os.rename(top_level, dirname) retry(rename, OSError, tries=len(archive.names)) - # Apply strict umask to the top-level directory in case it wasn't + # Apply typical umask to the top-level directory in case it wasn't # already; see https://trac.sagemath.org/ticket/24567 - os.chmod(dirname, os.stat(dirname).st_mode & ~0o077) + # and later https://trac.sagemath.org/ticket/28596 + os.chmod(dirname, os.stat(dirname).st_mode & ~0o022) finally: os.chdir(prev_cwd) From 87c694f059e839a4bb12db80037f3c4398b56c2b Mon Sep 17 00:00:00 2001 From: "E. Madison Bray" Date: Mon, 16 Dec 2019 17:03:23 +0100 Subject: [PATCH 334/340] Add an spkg-legacy-uninstall for jmol. --- build/pkgs/jmol/spkg-install | 5 ----- build/pkgs/jmol/spkg-legacy-uninstall | 4 ++++ 2 files changed, 4 insertions(+), 5 deletions(-) create mode 100644 build/pkgs/jmol/spkg-legacy-uninstall diff --git a/build/pkgs/jmol/spkg-install b/build/pkgs/jmol/spkg-install index 27798e62320..a181ebb9536 100644 --- a/build/pkgs/jmol/spkg-install +++ b/build/pkgs/jmol/spkg-install @@ -1,8 +1,3 @@ -# Cleanup of previous installation -rm -rf "${SAGE_SHARE}/jsmol/" -rm -rf "${SAGE_SHARE}/jmol/" -rm -f "${SAGE_LOCAL}/bin/jmol" - # jsmol goes in a dedicated directory sdh_install src/jsmol "${SAGE_SHARE}/" rm -rf src/jsmol diff --git a/build/pkgs/jmol/spkg-legacy-uninstall b/build/pkgs/jmol/spkg-legacy-uninstall new file mode 100644 index 00000000000..51b0a354bdb --- /dev/null +++ b/build/pkgs/jmol/spkg-legacy-uninstall @@ -0,0 +1,4 @@ +# Cleanup of previous installation +rm -rf "${SAGE_SHARE}/jsmol/" +rm -rf "${SAGE_SHARE}/jmol/" +rm -f "${SAGE_LOCAL}/bin/jmol" From 14519a7fa49f50504149256c320ad893420ebbf3 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Mon, 16 Dec 2019 17:14:33 +0100 Subject: [PATCH 335/340] missing empty line --- src/sage/geometry/lattice_polytope.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index 4e277a4444d..f89b192675c 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -2374,6 +2374,7 @@ def incidence_matrix(self): :meth:`vertices`. EXAMPLES:: + sage: o = lattice_polytope.cross_polytope(2) sage: o.incidence_matrix() [0 0 1 1] From 8bdd72df1d6e8e0ce807da2deca8239e657bc559 Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Fri, 26 Apr 2019 20:41:41 +0200 Subject: [PATCH 336/340] 28891: character art/sympy-conversion of symbolic series --- src/sage/functions/other.py | 34 +++++++++++++++++++++++++++++--- src/sage/symbolic/expression.pyx | 19 ++++++++++++++++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index 2c22a61c46e..ec1e87a8174 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -639,8 +639,6 @@ def __init__(self): Order(x) sage: (x^2 + x).Order() Order(x^2 + x) - sage: x.Order()._sympy_() - O(x) TESTS: @@ -650,11 +648,41 @@ def __init__(self): Order """ GinacFunction.__init__(self, "Order", - conversions=dict(sympy='O'), + conversions=dict(), latex_name=r"\mathcal{O}") + def _sympy_(self, arg): + """ + EXAMPLES:: + + sage: x.Order()._sympy_() + O(x) + sage: SR(1).Order()._sympy_() + O(1) + sage: ((x-1)^3).Order()._sympy_() + O((x - 1)**3, (x, 1)) + sage: exp(x).series(x==1, 3)._sympy_() + E + E*(x - 1) + E*(x - 1)**2/2 + O((x - 1)**3, (x, 1)) + + sage: (-(pi-x)^3).Order()._sympy_() + O((x - pi)**3, (x, pi)) + sage: cos(x).series(x==pi, 3)._sympy_() + -1 + (pi - x)**2/2 + O((x - pi)**3, (x, pi)) + """ + roots = arg.solve(arg.default_variable(), algorithm='sympy', + multiplicities=False, explicit_solutions=True) + if len(roots) == 1: + arg = (arg, (roots[0].lhs(), roots[0].rhs())) + elif len(roots) > 1: + raise ValueError("order term %s has multiple roots" % arg) + # else there are no roots, e.g. O(1), so we leave arg unchanged + import sympy + return sympy.O(*sympy.sympify(arg, evaluate=False)) + + Order = Function_Order() + class Function_frac(BuiltinFunction): def __init__(self): r""" diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 9e643de795f..431ab65f317 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -781,6 +781,21 @@ cdef class Expression(CommutativeRingElement): ⎮ ─────── dx ⎮ x + 1 ⌡ + + TESTS: + + Check that :trac:`28891` is fixed:: + + sage: unicode_art(exp(x).series(x, 4)) + 2 3 + x x ⎛ 4⎞ + 1 + x + ── + ── + O⎝x ⎠ + 2 6 + sage: unicode_art(exp(x).series(x==1, 3)) + 2 + ℯ⋅(x - 1) ⎛ 3 ⎞ + ℯ + ℯ⋅(x - 1) + ────────── + O⎝(x - 1) ; x → 1⎠ + 2 """ from sage.typeset.unicode_art import UnicodeArt return UnicodeArt(self._sympy_character_art(True).splitlines()) @@ -5722,6 +5737,8 @@ cdef class Expression(CommutativeRingElement): sage: SR._force_pyobject( (x, x + 1, x + 2) ).operator() <... 'tuple'> + sage: exp(x).series(x,3).operator() + """ cdef operators o cdef unsigned serial @@ -5766,6 +5783,8 @@ cdef class Expression(CommutativeRingElement): return res elif is_exactly_a_exprseq(self._gobj): return tuple + elif is_a_series(self._gobj): + return add_vararg # self._gobj is either a symbol, constant or numeric return None From 50a4975f9a312efb04d645313caa69ee66214e27 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Fri, 13 Dec 2019 08:09:23 +0100 Subject: [PATCH 337/340] make exposed invariants of polyhedron immutable --- src/sage/geometry/polyhedron/base.py | 67 +++++++++++++++---- .../combinatorial_polyhedron/base.pyx | 4 +- 2 files changed, 58 insertions(+), 13 deletions(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index a6ac1046b74..4706f43320b 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -310,6 +310,7 @@ def set_adjacent(h1, h2): Hrep = face.ambient_Hrepresentation() assert(len(Hrep) == codim+2) set_adjacent(Hrep[-2], Hrep[-1]) + M.set_immutable() return M def _vertex_adjacency_matrix(self): @@ -342,6 +343,7 @@ def set_adjacent(v1, v2): Vrep = face.ambient_Vrepresentation() if len(Vrep) == 2: set_adjacent(Vrep[0], Vrep[1]) + M.set_immutable() return M def _delete(self): @@ -634,10 +636,17 @@ def vertex_facet_graph(self, labels=True): sage: H = O.vertex_facet_graph() sage: G.is_isomorphic(H) False - sage: G.reverse_edges(G.edges()) - sage: G.is_isomorphic(H) + sage: G2 = copy(G) + sage: G2.reverse_edges(G2.edges()) + sage: G2.is_isomorphic(H) True + TESTS: + + Check that :trac:`28828` is fixed:: + + sage: G._immutable + True """ # We construct the edges and remove the columns that have all 1s; @@ -655,7 +664,7 @@ def vertex_facet_graph(self, labels=True): if any(entry != 1 for entry in column) for j in range(M.nrows()) if M[j, i] == 1] G.add_edges(edges) - return G + return G.copy(immutable=True) def plot(self, point=None, line=None, polygon=None, # None means unspecified by the user @@ -1916,6 +1925,13 @@ def vertices_matrix(self, base_ring=None): Traceback (most recent call last): ... TypeError: no conversion of this rational to integer + + TESTS: + + Check that :trac:`28828` is fixed:: + + sage: P.vertices_matrix().is_immutable() + True """ if base_ring is None: base_ring = self.base_ring() @@ -1923,6 +1939,7 @@ def vertices_matrix(self, base_ring=None): for i, v in enumerate(self.vertices()): for j in range(self.ambient_dim()): m[j, i] = v[j] + m.set_immutable() return m def ray_generator(self): @@ -2298,6 +2315,13 @@ def vertex_adjacency_matrix(self): (0, 1, 0, 0, 1) A vertex at (1, 0) (0, 0, 0, 0, 1) A ray in the direction (1, 1) (0, 0, 1, 1, 0) A vertex at (3, 0) + + TESTS: + + Check that :trac:`28828` is fixed:: + + sage: P.adjacency_matrix().is_immutable() + True """ return self._vertex_adjacency_matrix() @@ -2372,6 +2396,13 @@ def facet_adjacency_matrix(self): [1 1 0 1 1] [1 1 1 0 1] [1 1 1 1 0] + + TESTS: + + Check that :trac:`28828` is fixed:: + + sage: s4.facet_adjacency_matrix().is_immutable() + True """ return self._facet_adjacency_matrix() @@ -2467,6 +2498,13 @@ def incidence_matrix(self): [1 0 1] [0 1 0] [0 0 1] + + TESTS: + + Check that :trac:`28828` is fixed:: + + sage: R.incidence_matrix().is_immutable() + True """ incidence_matrix = matrix(ZZ, self.n_Vrepresentation(), self.n_Hrepresentation(), 0) @@ -2492,6 +2530,7 @@ def incidence_matrix(self): if self._is_zero(Hvec*Vvec): incidence_matrix[Vindex, Hindex] = 1 + incidence_matrix.set_immutable() return incidence_matrix def base_ring(self): @@ -3285,7 +3324,7 @@ def gale_transform(self): sage: p = Polyhedron(vertices = [[0,0],[0,1],[1,0]]) sage: p2 = p.prism() sage: p2.gale_transform() - [(1, 0), (0, 1), (-1, -1), (-1, 0), (0, -1), (1, 1)] + ((1, 0), (0, 1), (-1, -1), (-1, 0), (0, -1), (1, 1)) REFERENCES: @@ -3305,7 +3344,7 @@ def gale_transform(self): [ [1]+x for x in self.vertex_generator()]) A = A.transpose() A_ker = A.right_kernel() - return A_ker.basis_matrix().transpose().rows() + return tuple(A_ker.basis_matrix().transpose().rows()) @cached_method def normal_fan(self, direction='inner'): @@ -5544,6 +5583,13 @@ def f_vector(self): (A vertex at (1, 0), A vertex at (-1, 0)) sage: P.f_vector() (1, 0, 2, 1) + + TESTS: + + Check that :trac:`28828` is fixed:: + + sage: P.f_vector().is_immutable() + True """ return self.combinatorial_polyhedron().f_vector() @@ -7495,10 +7541,7 @@ def combinatorial_automorphism_group(self, vertex_graph_only=False): G = self.graph() else: G = self.vertex_facet_graph() - group = G.automorphism_group(edge_labels=True) - self._combinatorial_automorphism_group = group - - return self._combinatorial_automorphism_group + return G.automorphism_group(edge_labels=True) @cached_method def restricted_automorphism_group(self, output="abstract"): @@ -7648,14 +7691,14 @@ def restricted_automorphism_group(self, output="abstract"): Permutation Group with generators [(1,2)] sage: G = P.restricted_automorphism_group(output="matrixlist") sage: G - [ + ( [1 0 0 0 0 0] [ -87/55 -82/55 -2/5 38/55 98/55 12/11] [0 1 0 0 0 0] [-142/55 -27/55 -2/5 38/55 98/55 12/11] [0 0 1 0 0 0] [-142/55 -82/55 3/5 38/55 98/55 12/11] [0 0 0 1 0 0] [-142/55 -82/55 -2/5 93/55 98/55 12/11] [0 0 0 0 1 0] [-142/55 -82/55 -2/5 38/55 153/55 12/11] [0 0 0 0 0 1], [ 0 0 0 0 0 1] - ] + ) sage: g = AffineGroup(5, QQ)(G[1]) sage: g [ -87/55 -82/55 -2/5 38/55 98/55] [12/11] @@ -7841,7 +7884,7 @@ def edge_label(i, j, c_ij): matrices.append(A + W) if output == "matrixlist": - return matrices + return tuple(matrices) else: return MatrixGroup(matrices) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index 76d8a981653..52eae4bfe79 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -1237,7 +1237,9 @@ cdef class CombinatorialPolyhedron(SageObject): raise ValueError("could not determine f_vector") from sage.modules.free_module_element import vector from sage.rings.all import ZZ - return vector(ZZ, self._f_vector) + f_vector = vector(ZZ, self._f_vector) + f_vector.set_immutable() + return f_vector def face_iter(self, dimension=None, dual=None): r""" From a7eeece2180be4d91587eb133e7ab73734400f85 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Tue, 17 Dec 2019 15:34:33 +0100 Subject: [PATCH 338/340] make restricted automorphism group as matrixlist immutable --- src/sage/geometry/polyhedron/base.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 4706f43320b..8faa1716ccf 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -7769,6 +7769,11 @@ def restricted_automorphism_group(self, output="abstract"): Traceback (most recent call last): ... ValueError: unknown output 'foobar', valid values are ('abstract', 'permutation', 'matrix', 'matrixlist') + + Check that :trac:`28828` is fixed:: + + sage: P.restricted_automorphism_group(output="matrixlist")[0].is_immutable() + True """ # The algorithm works as follows: # @@ -7883,6 +7888,9 @@ def edge_label(i, j, c_ij): A = sum(V[perm(i)].column() * Vplus[i].row() for i in range(len(V))) matrices.append(A + W) + for mat in matrices: + mat.set_immutable() + if output == "matrixlist": return tuple(matrices) else: From 1f64d51c83d6fa8c56c8aaaf4ed77a743525a938 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Mon, 3 Jun 2019 10:16:41 +0200 Subject: [PATCH 339/340] #26332 Remove the ore_algebra package The version shipped by Sage has been out of date for a while and periodically breaks when Sage makes incompatible changes, while up-to-date versions can easily be installed from pip. --- build/pkgs/ore_algebra/SPKG.txt | 21 --------------------- build/pkgs/ore_algebra/checksums.ini | 4 ---- build/pkgs/ore_algebra/dependencies | 5 ----- build/pkgs/ore_algebra/package-version.txt | 1 - build/pkgs/ore_algebra/spkg-install | 15 --------------- build/pkgs/ore_algebra/type | 1 - src/sage/misc/package.py | 4 ---- 7 files changed, 51 deletions(-) delete mode 100644 build/pkgs/ore_algebra/SPKG.txt delete mode 100644 build/pkgs/ore_algebra/checksums.ini delete mode 100644 build/pkgs/ore_algebra/dependencies delete mode 100644 build/pkgs/ore_algebra/package-version.txt delete mode 100644 build/pkgs/ore_algebra/spkg-install delete mode 100644 build/pkgs/ore_algebra/type diff --git a/build/pkgs/ore_algebra/SPKG.txt b/build/pkgs/ore_algebra/SPKG.txt deleted file mode 100644 index 6facb0dcfe3..00000000000 --- a/build/pkgs/ore_algebra/SPKG.txt +++ /dev/null @@ -1,21 +0,0 @@ -= ore_algebra = - -== Description == - -A Sage implementation of Ore algebras and Ore polynomials. - -Main features for the most common algebras include basic arithmetic and actions; -gcrd and lclm; D-finite closure properties; natural transformations between -related algebras; guessing; desingularization; solvers for polynomials, rational -functions and (generalized) power series. - -== License == - -Distributed under the terms of the GNU General Public License (GPL) - -http://www.gnu.org/licenses/ - -== Dependencies == - -None. - diff --git a/build/pkgs/ore_algebra/checksums.ini b/build/pkgs/ore_algebra/checksums.ini deleted file mode 100644 index ad92b3a247c..00000000000 --- a/build/pkgs/ore_algebra/checksums.ini +++ /dev/null @@ -1,4 +0,0 @@ -tarball=ore_algebra-VERSION.tgz -sha1=0c7ba5bc7b8f6e988e10011ea45af39b78014f27 -md5=584adda6ae7b715fa3b1f9f5d91c6e63 -cksum=1732945549 diff --git a/build/pkgs/ore_algebra/dependencies b/build/pkgs/ore_algebra/dependencies deleted file mode 100644 index 2573414ce8a..00000000000 --- a/build/pkgs/ore_algebra/dependencies +++ /dev/null @@ -1,5 +0,0 @@ -$(PYTHON) | setuptools pip - ----------- -All lines of this file are ignored except the first. -It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/ore_algebra/package-version.txt b/build/pkgs/ore_algebra/package-version.txt deleted file mode 100644 index be586341736..00000000000 --- a/build/pkgs/ore_algebra/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -0.3 diff --git a/build/pkgs/ore_algebra/spkg-install b/build/pkgs/ore_algebra/spkg-install deleted file mode 100644 index 89bb1e8768a..00000000000 --- a/build/pkgs/ore_algebra/spkg-install +++ /dev/null @@ -1,15 +0,0 @@ -if [ -z "$SAGE_LOCAL" ]; then - echo >&2 "SAGE_LOCAL undefined ... exiting" - echo >&2 "Maybe run 'sage --sh'?" - exit 1 -fi - -cd src -echo "building ore_algebra" - -sdh_pip_install . - -if [ $? -ne 0 ]; then - echo >&2 "Error building ore_algebra" - exit 1 -fi diff --git a/build/pkgs/ore_algebra/type b/build/pkgs/ore_algebra/type deleted file mode 100644 index 134d9bc32d5..00000000000 --- a/build/pkgs/ore_algebra/type +++ /dev/null @@ -1 +0,0 @@ -optional diff --git a/src/sage/misc/package.py b/src/sage/misc/package.py index 5aabfc814ff..01ef9e7800e 100644 --- a/src/sage/misc/package.py +++ b/src/sage/misc/package.py @@ -422,15 +422,11 @@ def optional_packages(): sage: from sage.misc.package import optional_packages sage: installed, not_installed = optional_packages() # optional - build - sage: 'ore_algebra' in installed+not_installed # optional - build - True sage: 'beautifulsoup4' in installed+not_installed # optional - build True sage: 'beautifulsoup4' in installed # optional - build beautifulsoup4 True - sage: 'ore_algebra' in installed # optional - build ore_algebra - True """ pkgs = list_packages('optional', local=True) pkgs.update(list_packages('pip', local=True)) From fcadfadd4ee9ca7c2e9e1a37730ca467bc4d839b Mon Sep 17 00:00:00 2001 From: Release Manager Date: Tue, 24 Dec 2019 15:15:11 +0100 Subject: [PATCH 340/340] Updated SageMath version to 9.0.beta10 --- VERSION.txt | 2 +- build/pkgs/configure/checksums.ini | 6 +++--- build/pkgs/configure/package-version.txt | 2 +- src/bin/sage-version.sh | 6 +++--- src/sage/version.py | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index 615e8ce6e5c..088de2c0150 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 9.0.beta9, Release Date: 2019-12-08 +SageMath version 9.0.beta10, Release Date: 2019-12-24 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 5b8c3b855a7..a54baf6cc59 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=01328191e9d2fd853525a20a951ae84b15ebab13 -md5=e69a2028835f1d7d2b685bab4f833b64 -cksum=1396398076 +sha1=c992c5f54672201e05e79385de9a2a6ea4233586 +md5=41e4ba80fbdefa79b38a60edb0733422 +cksum=1355983684 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index a55ce1adebf..442931ec6b3 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -abea10f4aefd6b14aa0598f16dddcca06be0c41b +0bb0717729c70eb363a18beb3ed37424c5775791 diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index caf812d3923..09eb7de5153 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -1,5 +1,5 @@ # Sage version information for shell scripts # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='9.0.beta9' -SAGE_RELEASE_DATE='2019-12-08' -SAGE_VERSION_BANNER='SageMath version 9.0.beta9, Release Date: 2019-12-08' +SAGE_VERSION='9.0.beta10' +SAGE_RELEASE_DATE='2019-12-24' +SAGE_VERSION_BANNER='SageMath version 9.0.beta10, Release Date: 2019-12-24' diff --git a/src/sage/version.py b/src/sage/version.py index 217bcfd0b05..7ee3a2e05ab 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 = '9.0.beta9' -date = '2019-12-08' -banner = 'SageMath version 9.0.beta9, Release Date: 2019-12-08' +version = '9.0.beta10' +date = '2019-12-24' +banner = 'SageMath version 9.0.beta10, Release Date: 2019-12-24'