From 608f2f492f1b1b69f38d78cf878184f26493892e Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Fri, 16 Jul 2021 17:05:40 +0200 Subject: [PATCH 001/253] Trac 32209: allow evaluation of morphisms of affine schemes on points over different rings --- src/sage/schemes/affine/affine_morphism.py | 33 ++++++++++++++++--- .../schemes/projective/projective_morphism.py | 31 +++++++++++++++-- 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/src/sage/schemes/affine/affine_morphism.py b/src/sage/schemes/affine/affine_morphism.py index 63a4f348af9..5e282e56237 100644 --- a/src/sage/schemes/affine/affine_morphism.py +++ b/src/sage/schemes/affine/affine_morphism.py @@ -237,6 +237,28 @@ def __call__(self, x, check=True): sage: f = H([x^2+y^2, y^2, z^2 + y*z]) sage: f(P([1, 1, 1])) (2, 1, 2) + + TESTS: + + Check that :trac:`32209` is fixed:: + + sage: S. = AffineSpace(ZZ, 2) + sage: T. = AffineSpace(ZZ, 2) + sage: h = T.hom([u + v, u*v], S); h + Scheme morphism: + From: Affine Space of dimension 2 over Integer Ring + To: Affine Space of dimension 2 over Integer Ring + Defn: Defined on coordinates by sending (u, v) to + (u + v, u*v) + + sage: F. = GF(4) + sage: P = T(F)(1, a) + sage: h(P) + (a + 1, a) + sage: h(P).domain() + Spectrum of Finite Field in a of size 2^2 + sage: h.change_ring(F)(P) + (a + 1, a) """ from sage.schemes.affine.affine_point import SchemeMorphism_point_affine if check: @@ -245,12 +267,13 @@ def __call__(self, x, check=True): x = self.domain()(x) except (TypeError, NotImplementedError): raise TypeError("%s fails to convert into the map's domain %s, but a `pushforward` method is not properly implemented"%(x, self.domain())) - elif self.domain() != x.codomain(): - raise TypeError("%s fails to convert into the map's domain %s,but a `pushforward` method is not properly implemented"%(x, self.domain())) - # Passes the array of args to _fast_eval - P = self._fast_eval(x._coords) - return self.codomain().point(P, check) + R = x.domain().coordinate_ring() + if R is self.base_ring(): + P = self._fast_eval(x._coords) + else: + P = [f(x._coords) for f in self._polys] + return self.codomain().point_homset(R)(P, check=check) def __eq__(self, right): """ diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index 400af3c3116..9c324cbd859 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -373,6 +373,28 @@ def __call__(self, x, check=True): ... TypeError: [x - z] fails to convert into the map's domain Projective Space of dimension 1 over Integer Ring, but a `pushforward` method is not properly implemented + + TESTS: + + Check that :trac:`32209` is fixed:: + + sage: S. = ProjectiveSpace(ZZ, 1) + sage: T. = ProjectiveSpace(ZZ, 1) + sage: h = T.hom([u^2 + v^2, u*v], S); h + 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 (u : v) to + (u^2 + v^2 : u*v) + + sage: F. = GF(4) + sage: P = T(F)(1, a) + sage: h(P) + (a : a) + sage: h(P).domain() + Spectrum of Finite Field in a of size 2^2 + sage: h.change_ring(F)(P) + (1 : 1) """ from sage.schemes.projective.projective_point import SchemeMorphism_point_projective_ring if check: @@ -396,9 +418,12 @@ def __call__(self, x, check=True): except (TypeError, NotImplementedError): raise TypeError("%s fails to convert into the map's domain %s, but a `pushforward` method is not properly implemented"%(x, self.domain())) - # Passes the array of args to _fast_eval - P = self._fast_eval(x._coords) - return self.codomain().point(P, check) + R = x.domain().coordinate_ring() + if R is self.base_ring(): + P = self._fast_eval(x._coords) + else: + P = [f(x._coords) for f in self._polys] + return self.codomain().point_homset(R)(P, check=check) @lazy_attribute def _fastpolys(self): From db4139091e9c524779271c45aa8450892107fc3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 28 Oct 2021 21:12:10 +0200 Subject: [PATCH 002/253] fix most E722 (first pass) --- .../dynamics/arithmetic_dynamics/berkovich_ds.py | 12 ++++++------ src/sage/geometry/polyhedron/base.py | 2 +- src/sage/geometry/polyhedron/library.py | 2 +- src/sage/graphs/digraph.py | 6 +++--- src/sage/interfaces/polymake.py | 4 ++-- src/sage/modules/free_module.py | 2 +- src/sage/modules/matrix_morphism.py | 6 ++---- src/sage/rings/qqbar.py | 2 +- src/sage/schemes/berkovich/berkovich_space.py | 2 +- .../schemes/product_projective/rational_point.py | 7 ++++--- src/sage/schemes/projective/projective_space.py | 4 ++-- 11 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py b/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py index 8f8578ef8b9..c1cb33e12b5 100644 --- a/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py @@ -238,21 +238,21 @@ def __classcall_private__(cls, dynamical_system, domain=None, ideal=None): if not isinstance(dynamical_system, DynamicalSystem_affine): try: dynamical_system = DynamicalSystem_affine(dynamical_system) - except: + except (TypeError, ValueError): raise TypeError('domain was affine Berkovich space, but dynamical_system did not ' + \ 'convert to an affine dynamical system') if isinstance(domain, Berkovich_Cp_Projective): if not isinstance(dynamical_system, DynamicalSystem_projective): try: dynamical_system = DynamicalSystem_projective(dynamical_system) - except: + except (TypeError, ValueError): raise TypeError('domain was projective Berkovich space, but dynamical_system did not convert ' + \ 'to a projective dynamical system') if not isinstance(dynamical_system, DynamicalSystem): try: dynamical_system = DynamicalSystem(dynamical_system) - except: + except (TypeError, ValueError): raise TypeError('dynamical_system did not convert to a dynamical system') morphism_domain = dynamical_system.domain() @@ -803,7 +803,7 @@ def __call__(self, x, type_3_pole_check=True): if not isinstance(x.parent(), Berkovich_Cp_Projective): try: x = self.domain()(x) - except: + excep (TypeError, ValueError)t: raise TypeError('action of dynamical system not defined on %s' %x.parent()) if x.parent().is_padic_base() != self.domain().is_padic_base(): raise ValueError('x was not backed by the same type of field as f') @@ -893,7 +893,7 @@ def __call__(self, x, type_3_pole_check=True): try: factor_root_field = factor.root_field('a') factor = factor.change_ring(factor_root_field) - except: + except (TypeError, ValueError): raise NotImplementedError('cannot check if poles lie in type III disk') else: factor_root_field = factor.base_ring() @@ -1078,7 +1078,7 @@ def __call__(self, x): if not isinstance(x, Berkovich_Element_Cp_Affine): try: x = self.domain()(x) - except: + except (TypeError, ValueError): raise ValueError('action of dynamical system not defined on %s' %x) proj_system = self.homogenize(1) return proj_system(x.as_projective_point()).as_affine_point() diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index e2e6772defb..2b547775b43 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -5275,7 +5275,7 @@ def _test_dilation(self, tester=None, **options): new_ring = None try: new_ring = self.base_ring().composite_fields()[0] - except: + except (KeyError, AttributeError): # This isn't about testing composite fields. pass if new_ring: diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index 31cec880ccf..8c90ca857db 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -2720,7 +2720,7 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula from sage.combinat.root_system.coxeter_group import CoxeterGroup try: W = CoxeterGroup(coxeter_type) - except: + except (TypeError, ValueError): raise ValueError("cannot build a Coxeter group from {}".format(coxeter_type)) n = W.one().canonical_matrix().rank() weights = W.fundamental_weights() diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index bcf919c4a7d..00bf0246033 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -3352,7 +3352,7 @@ def layout_acyclic_dummy(self, heights=None, rankdir='up', **options): try: l = sorted(levels[i]) levels[i] = l - except: + except TypeError: continue if rankdir=='down' or rankdir=='left': levels.reverse() @@ -3997,7 +3997,7 @@ def _rec_out_branchings(depth): # 2) Pick an edge e outgoing from the source try: s, x, l = next(D.outgoing_edge_iterator(source)) - except: + except StopIteration: return # 3) Find all out_branchings that do not contain e # by first removing it @@ -4214,7 +4214,7 @@ def _rec_in_branchings(depth): # 2) Pick an edge e incoming to the source try: x, s, l = next(D.incoming_edge_iterator(source)) - except: + except StopIteration: return # 3) Find all in_branchings that do not contain e # by first removing it diff --git a/src/sage/interfaces/polymake.py b/src/sage/interfaces/polymake.py index 632455564b2..1e20583a6ca 100644 --- a/src/sage/interfaces/polymake.py +++ b/src/sage/interfaces/polymake.py @@ -362,7 +362,7 @@ def to_str(x): try: x = RDF(x) return '{}'.format(x) - except: + except (TypeError, ValueError): pass raise NotImplementedError @@ -1593,7 +1593,7 @@ def str_to_base_ring(s): if r == '': return matrix(base_ring) return matrix(base_ring, [[str_to_base_ring(s) for s in t.split(' ')] for t in r.split('\n')]) - except: + except Exception: pass if T1: diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 1e3c73da128..b3aa531d9b7 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -463,7 +463,7 @@ def FreeModule(base_ring, rank_or_basis_keys=None, sparse=False, inner_product_m if rank_or_basis_keys is not None: try: rank = sage.rings.integer_ring.ZZ(rank_or_basis_keys) - except: + except (TypeError, ValueError): basis_keys = rank_or_basis_keys if not with_basis: if inner_product_matrix is not None: diff --git a/src/sage/modules/matrix_morphism.py b/src/sage/modules/matrix_morphism.py index 58e670812ff..897eccb6878 100644 --- a/src/sage/modules/matrix_morphism.py +++ b/src/sage/modules/matrix_morphism.py @@ -1418,11 +1418,9 @@ def restrict_domain(self, sub): H = sub.Hom(self.codomain()) try: return H(A, side=self.side()) - except: + except Exception: return H(A) - - def restrict_codomain(self, sub): """ Restrict this matrix morphism to a subspace sub of the codomain. @@ -1503,7 +1501,7 @@ def restrict_codomain(self, sub): return H(self.matrix().transpose().restrict_codomain(V).transpose(), side="right") else: return H(self.matrix().restrict_codomain(V)) - except: + except Exception: return H(self.matrix().restrict_codomain(V)) def restrict(self, sub): diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index ae926cde625..01ba94413f8 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -2650,7 +2650,7 @@ def mk_algebraic(x): aa_numbers = [AA(_) for _ in numbers] numbers = aa_numbers real_case = True - except: + except (ValueError, TypeError): real_case = False # Make the numbers algebraic numbers = [mk_algebraic(_) for _ in numbers] diff --git a/src/sage/schemes/berkovich/berkovich_space.py b/src/sage/schemes/berkovich/berkovich_space.py index 51a0df0a14a..97b8a8266b7 100644 --- a/src/sage/schemes/berkovich/berkovich_space.py +++ b/src/sage/schemes/berkovich/berkovich_space.py @@ -619,7 +619,7 @@ def __init__(self, base, ideal=None): if not is_ProjectiveSpace(base): try: base = ProjectiveSpace(base) - except: + except (TypeError, ValueError): raise ValueError("base of projective Berkovich space must be projective space") if not (is_pAdicField(base.base_ring())): if base.base_ring() not in NumberFields(): diff --git a/src/sage/schemes/product_projective/rational_point.py b/src/sage/schemes/product_projective/rational_point.py index 5239fd88203..8f56fcd8637 100644 --- a/src/sage/schemes/product_projective/rational_point.py +++ b/src/sage/schemes/product_projective/rational_point.py @@ -494,11 +494,12 @@ def parallel_function_combination(point_p_max): continue try: - rat_points.add(X(point)) # checks if this point lies on X or not - except: + rat_points.add(X(point)) + # checks if this point lies on X or not + except (TypeError, ValueError): pass - return [list(_) for _ in rat_points] + return [list(pt) for pt in rat_points] def lift_all_points(): r""" diff --git a/src/sage/schemes/projective/projective_space.py b/src/sage/schemes/projective/projective_space.py index 82763ef7344..36deeab7827 100644 --- a/src/sage/schemes/projective/projective_space.py +++ b/src/sage/schemes/projective/projective_space.py @@ -1693,10 +1693,10 @@ def hyperplane_transformation_matrix(self, plane_1, plane_2): if len(source_points) == N: try: plane(point) - except: + except ValueError: source_points.append(self(point)) base_list = [list(s) for s in source_points] - elif len(source_points) == N+1: + elif len(source_points) == N + 1: Ms = matrix(base_list + [point]) if not any([m == 0 for m in Ms.minors(N + 1)]): source_points.append(self(point)) From cffd35e12c9fd4ef535654947ee167d3f9dfe55a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 28 Oct 2021 21:24:45 +0200 Subject: [PATCH 003/253] no except: in most pyx files --- src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx | 2 +- src/sage/graphs/graph_decompositions/tree_decomposition.pyx | 2 +- src/sage/plot/plot3d/shapes.pyx | 2 +- src/sage/rings/complex_arb.pyx | 2 +- src/sage/rings/polynomial/multi_polynomial_libsingular.pyx | 4 ++-- src/sage/rings/ring_extension_element.pyx | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx index 7a6ee5aa51a..75358e0987c 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +++ b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx @@ -763,7 +763,7 @@ cpdef polynomial_mandelbrot(f, parameter=None, double x_center=0, df = f.derivative(z).univariate_polynomial() critical_pts = df.roots(multiplicities=False) constant_c = True - except: + except PariError: constant_c = False # If c is in the constant term of the polynomial, then the critical points diff --git a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx index e2608da8995..ac4248c00d9 100644 --- a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx +++ b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx @@ -209,7 +209,7 @@ def is_valid_tree_decomposition(G, T): for X in T: try: _ = list(X) - except: + except TypeError: raise ValueError("the vertices of T must be iterables") # 1. The union of the bags equals V diff --git a/src/sage/plot/plot3d/shapes.pyx b/src/sage/plot/plot3d/shapes.pyx index d45770c61b7..340f034c235 100644 --- a/src/sage/plot/plot3d/shapes.pyx +++ b/src/sage/plot/plot3d/shapes.pyx @@ -1360,7 +1360,7 @@ def _validate_threejs_text_style(style): if weight not in ['normal', 'bold']: try: weight = int(weight) - except: + except (TypeError, ValueError): from matplotlib.font_manager import weight_dict try: weight = weight_dict[weight] diff --git a/src/sage/rings/complex_arb.pyx b/src/sage/rings/complex_arb.pyx index 4e09e548f0a..a8f574439ff 100644 --- a/src/sage/rings/complex_arb.pyx +++ b/src/sage/rings/complex_arb.pyx @@ -295,7 +295,7 @@ cdef int acb_calc_func_callback(acb_ptr out, const acb_t inp, void * param, if not isinstance(y, ComplexBall): y = ctx.parent.coerce(y) acb_set(out, ( y).value) - except: + except Exception: ctx.exn_type, ctx.exn_obj, ctx.exn_tb = sys.exc_info() acb_indeterminate(out) return 0 diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index 2c69227760c..5adfc245b92 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -856,7 +856,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): #we can use "Merge" because the monomials are distinct sBucketClearMerge(bucket, &_p, &e) sBucketDestroy(&bucket) - except: + except Exception: sBucketDeleteAndDestroy(&bucket) raise return new_MP(self, _p) @@ -5646,7 +5646,7 @@ def unpickle_MPolynomial_libsingular(MPolynomialRing_libsingular R, d): ln=0 sBucketClearMerge(bucket, &p, &ln) sBucketDestroy(&bucket) - except: + except Exception: sBucketDeleteAndDestroy(&bucket) raise return new_MP(R, p) diff --git a/src/sage/rings/ring_extension_element.pyx b/src/sage/rings/ring_extension_element.pyx index 610291dc620..a0dc7efc39e 100644 --- a/src/sage/rings/ring_extension_element.pyx +++ b/src/sage/rings/ring_extension_element.pyx @@ -162,7 +162,7 @@ cdef class RingExtensionElement(CommutativeAlgebraElement): attribute = getattr(self._backend, name) if callable(attribute): d.append(name) - except: + except AttributeError: pass return sorted(set(d)) From 279b5927981a98f698b7fc7a90ac842b0b3a7721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 28 Oct 2021 21:27:09 +0200 Subject: [PATCH 004/253] fix typo --- src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py b/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py index c1cb33e12b5..ce540d77f73 100644 --- a/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py @@ -803,8 +803,8 @@ def __call__(self, x, type_3_pole_check=True): if not isinstance(x.parent(), Berkovich_Cp_Projective): try: x = self.domain()(x) - excep (TypeError, ValueError)t: - raise TypeError('action of dynamical system not defined on %s' %x.parent()) + except (TypeError, ValueError): + raise TypeError('action of dynamical system not defined on %s' % x.parent()) if x.parent().is_padic_base() != self.domain().is_padic_base(): raise ValueError('x was not backed by the same type of field as f') if x.prime() != self.domain().prime(): From eb4ae950f6caa27cef7b1d04c5b0473d36139ae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 28 Oct 2021 21:48:08 +0200 Subject: [PATCH 005/253] add import --- src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx index 75358e0987c..3d649be8f6f 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +++ b/src/sage/dynamics/complex_dynamics/mandel_julia_helper.pyx @@ -38,8 +38,10 @@ from sage.symbolic.ring import SR from sage.calculus.var import var from sage.rings.fraction_field import is_FractionField from sage.categories.function_fields import FunctionFields +from sage.libs.all import PariError from math import sqrt + def _color_to_RGB(color): """ Convert a color to an RGB triple with values in the interval [0,255]. From bcdb6201a705715c7b995270064b1d734b9ef81c Mon Sep 17 00:00:00 2001 From: Thierry Monteil Date: Thu, 28 Oct 2021 22:51:10 +0200 Subject: [PATCH 006/253] #32788 : fix intentations for libs/giac/giac.pyx --- src/sage/libs/giac/giac.pyx | 1294 +++++++++++++++++------------------ 1 file changed, 647 insertions(+), 647 deletions(-) diff --git a/src/sage/libs/giac/giac.pyx b/src/sage/libs/giac/giac.pyx index 916b66f3bd1..b6f143404fb 100644 --- a/src/sage/libs/giac/giac.pyx +++ b/src/sage/libs/giac/giac.pyx @@ -172,22 +172,22 @@ from sage.interfaces.giac import giac #### Python3 compatibility ############################# if Pyversioninfo[0]>2 : - PythonVersion3 = True + PythonVersion3 = True else: - PythonVersion3 = False + PythonVersion3 = False def decstring23(s): - if PythonVersion3 : - return s.decode() - else: - return s + if PythonVersion3 : + return s.decode() + else: + return s def encstring23(s): - if PythonVersion3 : - return bytes(s,'UTF-8') - else: - return s + if PythonVersion3 : + return bytes(s,'UTF-8') + else: + return s if PythonVersion3: listrange=list,range @@ -810,128 +810,128 @@ include 'auto-methods.pxi' cdef class Pygen(GiacMethods_base): - cdef gen * gptr #pointer to the corresponding C++ element of type giac::gen + cdef gen * gptr #pointer to the corresponding C++ element of type giac::gen - def __cinit__(self, s=None): + def __cinit__(self, s=None): - #NB: the != here gives problems with the __richcmp__ function - #if (s!=None): - # so it's better to use isinstance - if (isinstance(s,None.__class__)): - # Do NOT replace with: self=GIACNULL (cf the doctest in __repr__ - sig_on() - self.gptr = new gen ((GIACNULL).gptr[0]) - sig_off() - return - - if isinstance(s,int): # This looks 100 faster than the str initialisation - if PythonVersion3: - #in python3 int and long are int - if s.bit_length()< Pymaxint.bit_length(): - sig_on() - self.gptr = new gen(s) - sig_off() - else: - sig_on() - self.gptr = new gen(pylongtogen(s)) - sig_off() - else: + #NB: the != here gives problems with the __richcmp__ function + #if (s!=None): + # so it's better to use isinstance + if (isinstance(s,None.__class__)): + # Do NOT replace with: self=GIACNULL (cf the doctest in __repr__ + sig_on() + self.gptr = new gen ((GIACNULL).gptr[0]) + sig_off() + return + + if isinstance(s,int): # This looks 100 faster than the str initialisation + if PythonVersion3: + #in python3 int and long are int + if s.bit_length()< Pymaxint.bit_length(): + sig_on() + self.gptr = new gen(s) + sig_off() + else: + sig_on() + self.gptr = new gen(pylongtogen(s)) + sig_off() + else: sig_on() self.gptr = new gen(s) sig_off() - # - elif isinstance(s,Integer): # for sage int (gmp) - sig_on() - if (abs(s)>Pymaxint): - self.gptr = new gen((s).value) - else: + # + elif isinstance(s,Integer): # for sage int (gmp) + sig_on() + if (abs(s)>Pymaxint): + self.gptr = new gen((s).value) + else: self.gptr = new gen(s) #important for pow to have a int - sig_off() + sig_off() - elif isinstance(s,Rational): # for sage rat (gmp) - #self.gptr = new gen(((Pygen(s.numerator())/Pygen(s.denominator()))).gptr[0]) - # FIXME: it's slow - sig_on() - self.gptr = new gen(GIAC_rdiv(gen(((s.numerator())).value),gen(((s.denominator())).value))) - sig_off() + elif isinstance(s,Rational): # for sage rat (gmp) + #self.gptr = new gen(((Pygen(s.numerator())/Pygen(s.denominator()))).gptr[0]) + # FIXME: it's slow + sig_on() + self.gptr = new gen(GIAC_rdiv(gen(((s.numerator())).value),gen(((s.denominator())).value))) + sig_off() - elif isinstance(s, Matrix): - s = Pygen(s.list()).list2mat(s.ncols()) - sig_on() - self.gptr = new gen((s).gptr[0]) - sig_off() + elif isinstance(s, Matrix): + s = Pygen(s.list()).list2mat(s.ncols()) + sig_on() + self.gptr = new gen((s).gptr[0]) + sig_off() - elif isinstance(s,float): - sig_on() - self.gptr = new gen(s) - sig_off() + elif isinstance(s,float): + sig_on() + self.gptr = new gen(s) + sig_off() - elif isinstance(s,long): - #s=str(s) - #self.gptr = new gen(s,context_ptr) - sig_on() - self.gptr = new gen(pylongtogen(s)) - sig_off() + elif isinstance(s,long): + #s=str(s) + #self.gptr = new gen(s,context_ptr) + sig_on() + self.gptr = new gen(pylongtogen(s)) + sig_off() - elif isinstance(s,Pygen): - #in the test: x,y=Pygen('x,y');((x+2*y).sin()).texpand() - # the y are lost without this case. - sig_on() - self.gptr = new gen((s).gptr[0]) - sig_off() + elif isinstance(s,Pygen): + #in the test: x,y=Pygen('x,y');((x+2*y).sin()).texpand() + # the y are lost without this case. + sig_on() + self.gptr = new gen((s).gptr[0]) + sig_off() - elif isinstance(s, listrange): - sig_on() - self.gptr = new gen(_wrap_pylist(s),0) - sig_off() + elif isinstance(s, listrange): + sig_on() + self.gptr = new gen(_wrap_pylist(s),0) + sig_off() - elif isinstance(s,tuple): - sig_on() - self.gptr = new gen(_wrap_pylist(s),1) - sig_off() + elif isinstance(s,tuple): + sig_on() + self.gptr = new gen(_wrap_pylist(s),1) + sig_off() - # Other types are converted with strings. - else: - if isinstance(s,Expression): - # take account of conversions with key giac in the sage symbol dict - s=SRexpressiontoGiac(s) - if not(isinstance(s,str)): #modif python3 - s=s.__str__() - sig_on() - self.gptr = new gen(encstring23(s),context_ptr) - sig_off() + # Other types are converted with strings. + else: + if isinstance(s,Expression): + # take account of conversions with key giac in the sage symbol dict + s=SRexpressiontoGiac(s) + if not(isinstance(s,str)): #modif python3 + s=s.__str__() + sig_on() + self.gptr = new gen(encstring23(s),context_ptr) + sig_off() - def __dealloc__(self): - del self.gptr + def __dealloc__(self): + del self.gptr - def __repr__(self): + def __repr__(self): try: - # fast evaluation of the complexity of the gen. (it's not the number of char ) - sig_on() - t=GIAC_taille(self.gptr[0], 6000) - sig_off() + # fast evaluation of the complexity of the gen. (it's not the number of char ) + sig_on() + t=GIAC_taille(self.gptr[0], 6000) + sig_off() except: - raise RuntimeError + raise RuntimeError if (t<6000) : - sig_on() - result=decstring23(GIAC_print(self.gptr[0], context_ptr).c_str()) #python3 - sig_off() - return result + sig_on() + result=decstring23(GIAC_print(self.gptr[0], context_ptr).c_str()) #python3 + sig_off() + return result else: - sig_on() - result=str(self.type)+"\nResult is too big for Display. If you really want to see it use print" - sig_off() - return result + sig_on() + result=str(self.type)+"\nResult is too big for Display. If you really want to see it use print" + sig_off() + return result - def __str__(self): + def __str__(self): #if self.gptr == NULL: # return '' sig_on() @@ -939,7 +939,7 @@ cdef class Pygen(GiacMethods_base): sig_off() return result - def __len__(self): + def __len__(self): """ TESTS:: @@ -954,17 +954,17 @@ cdef class Pygen(GiacMethods_base): sig_off() return rep else: - try: - sig_on() - rep=GIAC_size(self.gptr[0],context_ptr).val - sig_off() - #GIAC_size return a gen. we take the int: val - return rep - except: - raise RuntimeError + try: + sig_on() + rep=GIAC_size(self.gptr[0],context_ptr).val + sig_off() + #GIAC_size return a gen. we take the int: val + return rep + except: + raise RuntimeError - def __getitem__(self,i): #TODO?: add gen support for indexes + def __getitem__(self,i): #TODO?: add gen support for indexes """ Lists of 10^6 integers should be translated to giac easily @@ -999,48 +999,48 @@ cdef class Pygen(GiacMethods_base): cdef gen result if(self._type == 7) or (self._type == 12): #if self is a list or a string - if isinstance(i,int) or isinstance(i,Integer): - n=len(self) - if(ii] - sig_off() - return _wrap_gen(result) - except: - raise RuntimeError - else: - raise IndexError('list index %s out of range'%(i)) - else: - if isinstance(i,slice): - sig_on() - result=gen(_getgiacslice(self,i),self._subtype) - sig_off() - return _wrap_gen(result) - # add support for multi indexes - elif isinstance(i,tuple): - if(len(i)==2): - return self[i[0]][i[1]] - elif(len(i)==1): - # in case of a tuple like this: (3,) - return self[i[0]] - else: - return self[i[0],i[1]][tuple(i[2:])] + if isinstance(i,int) or isinstance(i,Integer): + n=len(self) + if(ii] + sig_off() + return _wrap_gen(result) + except: + raise RuntimeError + else: + raise IndexError('list index %s out of range'%(i)) else: - raise TypeError('gen indexes are not yet implemented') + if isinstance(i,slice): + sig_on() + result=gen(_getgiacslice(self,i),self._subtype) + sig_off() + return _wrap_gen(result) + # add support for multi indexes + elif isinstance(i,tuple): + if(len(i)==2): + return self[i[0]][i[1]] + elif(len(i)==1): + # in case of a tuple like this: (3,) + return self[i[0]] + else: + return self[i[0],i[1]][tuple(i[2:])] + else: + raise TypeError('gen indexes are not yet implemented') # Here we add support to formal variable indexes: else: - cmd='%s[%s]'%(self,i) - ans=Pygen(cmd).eval() - # if the answer is a string, it must be an error message because self is not a list or a string - if (ans._type == 12): - raise TypeError("Error executing code in Giac\nCODE:\n\t%s\nGiac ERROR:\n\t%s"%(cmd, ans)) - return ans + cmd='%s[%s]'%(self,i) + ans=Pygen(cmd).eval() + # if the answer is a string, it must be an error message because self is not a list or a string + if (ans._type == 12): + raise TypeError("Error executing code in Giac\nCODE:\n\t%s\nGiac ERROR:\n\t%s"%(cmd, ans)) + return ans - def __setitem__(self,key,value): + def __setitem__(self,key,value): """ Set the value of a coefficient of a giac vector or matrix or list. Warning: It is an in place affectation. @@ -1092,238 +1092,238 @@ cdef class Pygen(GiacMethods_base): - def __iter__(self): - """ - Pygen lists of 10^6 elements should be yield + def __iter__(self): + """ + Pygen lists of 10^6 elements should be yield - TESTS:: + TESTS:: - sage: from sage.libs.giac.giac import libgiac - sage: l = libgiac(range(10^6)) - sage: [ i for i in l ] == list(range(10^6)) - True + sage: from sage.libs.giac.giac import libgiac + sage: l = libgiac(range(10^6)) + sage: [ i for i in l ] == list(range(10^6)) + True - Check for :trac:`18841`:: + Check for :trac:`18841`:: - sage: L = libgiac(range(10)) - sage: next(iter(L)) - 0 - """ - cdef int i - for i in range(len(self)): - yield self[i] + sage: L = libgiac(range(10)) + sage: next(iter(L)) + 0 + """ + cdef int i + for i in range(len(self)): + yield self[i] - def eval(self): + def eval(self): cdef gen result try: - sig_on() - result=GIAC_protecteval(self.gptr[0],giacsettings.eval_level,context_ptr) - sig_off() - return _wrap_gen(result) + sig_on() + result=GIAC_protecteval(self.gptr[0],giacsettings.eval_level,context_ptr) + sig_off() + return _wrap_gen(result) except: - raise RuntimeError + raise RuntimeError - def __add__(self, right): - cdef gen result - if isinstance(right,Pygen)==False: + def __add__(self, right): + cdef gen result + if isinstance(right,Pygen)==False: right=Pygen(right) - # Curiously this case is important: - # otherwise: f=1/(2+sin(5*x)) crash - if isinstance(self,Pygen)==False: + # Curiously this case is important: + # otherwise: f=1/(2+sin(5*x)) crash + if isinstance(self,Pygen)==False: self=Pygen(self) - try: - sig_on() - result= (self).gptr[0] + (right).gptr[0] - sig_off() - return _wrap_gen(result) - except: - raise RuntimeError - - - def __call__(self, *args): - cdef gen result - n=len(args) - if (n>1): - #FIXME? improve with a vector, or improve Pygen(list) - right=Pygen(args).eval() - elif (n==1): - right=Pygen(args[0]) - else: - right=GIACNULL - if isinstance(self,Pygen)==False: - self=Pygen(self) + try: + sig_on() + result= (self).gptr[0] + (right).gptr[0] + sig_off() + return _wrap_gen(result) + except: + raise RuntimeError + + + def __call__(self, *args): + cdef gen result + n=len(args) + if (n>1): + #FIXME? improve with a vector, or improve Pygen(list) + right=Pygen(args).eval() + elif (n==1): + right=Pygen(args[0]) + else: + right=GIACNULL + if isinstance(self,Pygen)==False: + self=Pygen(self) # Some giac errors such as pari_locked are caught by the try # so we can't put the sig_on() in the try. # But now a keyboard interrupt fall back to this sig_on so # it may have left the giac pari locked. - sig_on() - try: - result= ((self).gptr[0])((right).gptr[0],context_ptr) - sig_off() - return _wrap_gen(result) - except: + sig_on() + try: + result= ((self).gptr[0])((right).gptr[0],context_ptr) + sig_off() + return _wrap_gen(result) + except: # The previous computation might have failed due to a pari_lock # So we will not raise an exception yet. tmp=Pygen('pari_unlock()').eval() # if pari was not locked in giac, we have locked it, so unlock it. if(tmp==0): - Pygen('pari_unlock()').eval() - sig_off() - raise + Pygen('pari_unlock()').eval() + sig_off() + raise else: - try: - result= GIAC_eval((right).gptr[0],1,context_ptr) - result= ((self).gptr[0])(result,context_ptr) - sig_off() - return _wrap_gen(result) - except: - sig_off() - raise - - - def __sub__(self, right): - cdef gen result - if isinstance(right,Pygen)==False: + try: + result= GIAC_eval((right).gptr[0],1,context_ptr) + result= ((self).gptr[0])(result,context_ptr) + sig_off() + return _wrap_gen(result) + except: + sig_off() + raise + + + def __sub__(self, right): + cdef gen result + if isinstance(right,Pygen)==False: right=Pygen(right) - if isinstance(self,Pygen)==False: + if isinstance(self,Pygen)==False: self=Pygen(self) - try: - sig_on() - result= (self).gptr[0] - (right).gptr[0] - sig_off() - return _wrap_gen(result) - except: - raise RuntimeError - - def __mul__(self, right): - """ - TESTS:: - - sage: from sage.libs.giac.giac import libgiac - sage: (sqrt(5)*libgiac('x')).factor() # BUG test could give 0 - sqrt(5)*x - sage: (libgiac('x')*sqrt(5)).factor() - sqrt(5)*x - """ - cdef gen result - if isinstance(right,Pygen)==False: + try: + sig_on() + result= (self).gptr[0] - (right).gptr[0] + sig_off() + return _wrap_gen(result) + except: + raise RuntimeError + + def __mul__(self, right): + """ + TESTS:: + + sage: from sage.libs.giac.giac import libgiac + sage: (sqrt(5)*libgiac('x')).factor() # BUG test could give 0 + sqrt(5)*x + sage: (libgiac('x')*sqrt(5)).factor() + sqrt(5)*x + """ + cdef gen result + if isinstance(right,Pygen)==False: right=Pygen(right) - if isinstance(self,Pygen)==False: + if isinstance(self,Pygen)==False: self=Pygen(self) - try: - #result= (self).gptr[0] * (right).gptr[0] - #NB: with the natural previous method, the following error generated by - #giac causes python to quit instead of an error message. - #l=Pygen([1,2]);l.transpose()*l; - sig_on() - result= GIAC_giacmul((self).gptr[0] , (right).gptr[0],context_ptr) - sig_off() - return _wrap_gen(result) - except: - raise RuntimeError + try: + #result= (self).gptr[0] * (right).gptr[0] + #NB: with the natural previous method, the following error generated by + #giac causes python to quit instead of an error message. + #l=Pygen([1,2]);l.transpose()*l; + sig_on() + result= GIAC_giacmul((self).gptr[0] , (right).gptr[0],context_ptr) + sig_off() + return _wrap_gen(result) + except: + raise RuntimeError #PB / in python3 is truediv - def __div__(self, right): - """ - TESTS:: - - sage: from sage.libs.giac.giac import libgiac - sage: (sqrt(3)/libgiac('x')).factor() # BUG test could give 0 - sqrt(3)/x - sage: (libgiac('x')/sqrt(3)).factor() - sqrt(3)*x/3 - """ - cdef gen result - if isinstance(right,Pygen)==False: + def __div__(self, right): + """ + TESTS:: + + sage: from sage.libs.giac.giac import libgiac + sage: (sqrt(3)/libgiac('x')).factor() # BUG test could give 0 + sqrt(3)/x + sage: (libgiac('x')/sqrt(3)).factor() + sqrt(3)*x/3 + """ + cdef gen result + if isinstance(right,Pygen)==False: right=Pygen(right) - if isinstance(self,Pygen)==False: + if isinstance(self,Pygen)==False: self=Pygen(self) - try: - sig_on() - result= GIAC_giacdiv((self).gptr[0] , (right).gptr[0],context_ptr) - sig_off() - return _wrap_gen(result) - except: - raise RuntimeError - - def __truediv__(self, right): - cdef gen result - if isinstance(right,Pygen)==False: + try: + sig_on() + result= GIAC_giacdiv((self).gptr[0] , (right).gptr[0],context_ptr) + sig_off() + return _wrap_gen(result) + except: + raise RuntimeError + + def __truediv__(self, right): + cdef gen result + if isinstance(right,Pygen)==False: right=Pygen(right) - if isinstance(self,Pygen)==False: + if isinstance(self,Pygen)==False: self=Pygen(self) - try: - sig_on() - result= (self).gptr[0] / (right).gptr[0] - sig_off() - return _wrap_gen(result) - except: - raise RuntimeError + try: + sig_on() + result= (self).gptr[0] / (right).gptr[0] + sig_off() + return _wrap_gen(result) + except: + raise RuntimeError - def __pow__(self, right ,ignored): - cdef gen result - if isinstance(right,Pygen)==False: + def __pow__(self, right ,ignored): + cdef gen result + if isinstance(right,Pygen)==False: right=Pygen(right) - if isinstance(self,Pygen)==False: + if isinstance(self,Pygen)==False: self=Pygen(self) - try: - sig_on() - result= GIAC_pow((self).gptr[0],(right).gptr[0], context_ptr ) - sig_off() - return _wrap_gen(result) - except: - raise RuntimeError - - def __mod__(self, right): - cdef gen result - if not isinstance(right,Pygen): + try: + sig_on() + result= GIAC_pow((self).gptr[0],(right).gptr[0], context_ptr ) + sig_off() + return _wrap_gen(result) + except: + raise RuntimeError + + def __mod__(self, right): + cdef gen result + if not isinstance(right,Pygen): right=Pygen(right) - if not isinstance(self,Pygen): + if not isinstance(self,Pygen): self=Pygen(self) - try: - #result= gen(GIAC_makenewvecteur((self).gptr[0],(right).gptr[0]),1) - #to have an integer output: - #result= GIAC_smod(result,context_ptr) - #we give a modular output: - sig_on() - result= GIAC_giacmod((self).gptr[0],(right).gptr[0],context_ptr) - sig_off() - return _wrap_gen(result) - except: - raise RuntimeError - - def __neg__(self): - cdef gen result - if isinstance(self,Pygen)==False: + try: + #result= gen(GIAC_makenewvecteur((self).gptr[0],(right).gptr[0]),1) + #to have an integer output: + #result= GIAC_smod(result,context_ptr) + #we give a modular output: + sig_on() + result= GIAC_giacmod((self).gptr[0],(right).gptr[0],context_ptr) + sig_off() + return _wrap_gen(result) + except: + raise RuntimeError + + def __neg__(self): + cdef gen result + if isinstance(self,Pygen)==False: self=Pygen(self) - try: - sig_on() - result= GIAC_neg((self).gptr[0]) - sig_off() - return _wrap_gen(result) - except: - raise RuntimeError + try: + sig_on() + result= GIAC_neg((self).gptr[0]) + sig_off() + return _wrap_gen(result) + except: + raise RuntimeError - def __pos__(self): - return self + def __pos__(self): + return self - # To be able to use the eval function before the GiacMethods initialisation - def cas_setup(self,*args): + # To be able to use the eval function before the GiacMethods initialisation + def cas_setup(self,*args): return Pygen('cas_setup')(self,*args) - def savegen(self, str filename): + def savegen(self, str filename): """ Archive a Pygen element to a file in giac compressed format. @@ -1349,13 +1349,13 @@ cdef class Pygen(GiacMethods_base): GIAC_archive( encstring23(filename), (self).gptr[0], context_ptr) sig_off() except: - raise RuntimeError + raise RuntimeError - # NB: with giac <= 1.2.3-57 redim doesn't have a non evaluated for so Pygen('redim') fails. - # hence replacement for redim: - def redim(self,a,b=None): + # NB: with giac <= 1.2.3-57 redim doesn't have a non evaluated for so Pygen('redim') fails. + # hence replacement for redim: + def redim(self,a,b=None): """ Increase the size of a matrix when possible, otherwise return self. @@ -1370,58 +1370,58 @@ cdef class Pygen(GiacMethods_base): """ d=self.dim() if d.type()==7: - if(a>d[0] and b>=d[1]): - A=self.semi_augment(Pygen((a-d[0],d[1])).matrix()) - if(b>d[1]): - A=A.augment(Pygen((a,b-d[1])).matrix()) - return A - elif(b>d[1] and a==d[0]): - return self.augment(Pygen((d[0],b-d[1])).matrix()) - else: - return self + if(a>d[0] and b>=d[1]): + A=self.semi_augment(Pygen((a-d[0],d[1])).matrix()) + if(b>d[1]): + A=A.augment(Pygen((a,b-d[1])).matrix()) + return A + elif(b>d[1] and a==d[0]): + return self.augment(Pygen((d[0],b-d[1])).matrix()) + else: + return self else: - raise TypeError("self is not a giac List") + raise TypeError("self is not a giac List") - # def htmlhelp(self, str lang='en'): - # """ - # Open the giac html detailled help about self in an external browser + # def htmlhelp(self, str lang='en'): + # """ + # Open the giac html detailled help about self in an external browser - # There are currently 3 supported languages: 'en', 'fr', 'el' + # There are currently 3 supported languages: 'en', 'fr', 'el' - # """ - # l={'fr':1 , 'en':2, 'el':4} - # if (not lang in ['en', 'fr', 'el']): - # lang='en' - # try: - # url=decstring23(browser_help(self.gptr[0],l[lang])) #python3 - # giacbasedir=decstring23(GIAC_giac_aide_dir()) # python3 - # except: - # raise RuntimeError('giac docs dir not found') - # print(url) - # if os.access(giacbasedir,os.F_OK): - # url='file:'+url - # wwwbrowseropen(url) + # """ + # l={'fr':1 , 'en':2, 'el':4} + # if (not lang in ['en', 'fr', 'el']): + # lang='en' + # try: + # url=decstring23(browser_help(self.gptr[0],l[lang])) #python3 + # giacbasedir=decstring23(GIAC_giac_aide_dir()) # python3 + # except: + # raise RuntimeError('giac docs dir not found') + # print(url) + # if os.access(giacbasedir,os.F_OK): + # url='file:'+url + # wwwbrowseropen(url) - def _help(self): + def _help(self): return self.findhelp().__str__() # def help(self): # return self._help() - def _sage_doc_(self): + def _sage_doc_(self): return self._help() - def __doc__(self): + def __doc__(self): return self._help() - # # # # # # # # # # # # # # # # # - # sage addons - # # # # # # # # # # # # # # # # # - def _latex_(self): + # # # # # # # # # # # # # # # # # + # sage addons + # # # # # # # # # # # # # # # # # + def _latex_(self): r""" You can output Giac expressions in latex. @@ -1447,7 +1447,7 @@ cdef class Pygen(GiacMethods_base): return result - def _integer_(self,Z=None): + def _integer_(self,Z=None): """ Convert giac integers or modular integers to sage Integers (via gmp) @@ -1494,10 +1494,10 @@ cdef class Pygen(GiacMethods_base): return result else: - raise TypeError("Cannot convert non giac integers to Integer") + raise TypeError("Cannot convert non giac integers to Integer") - def _rational_(self,Z=None): + def _rational_(self,Z=None): """ Convert giac rationals to sage rationals @@ -1514,20 +1514,20 @@ cdef class Pygen(GiacMethods_base): # _INT_ or _ZINT if(typ == 0 or typ == 2): - return QQ(ZZ(self)) + return QQ(ZZ(self)) # _FRAC_ elif(typ == 10): # giac _RAT_ try: - result=ZZ(self.numer())/ZZ(self.denom()) - return result + result=ZZ(self.numer())/ZZ(self.denom()) + return result except: - RuntimeError("Failed to convert to QQ") + RuntimeError("Failed to convert to QQ") else: - raise TypeError("Cannot convert non giac _FRAC_ to QQ") + raise TypeError("Cannot convert non giac _FRAC_ to QQ") - def sage(self): + def sage(self): r""" Convert a libgiac expression back to a Sage expression. (could be slow) @@ -1590,29 +1590,29 @@ cdef class Pygen(GiacMethods_base): if (typ != 7) : # self is not a list if ( typ == 0 or typ == 2): - return ZZ(self) + return ZZ(self) elif (typ == 10): - return QQ(self) + return QQ(self) elif (typ == 15): - # modular integer - sig_on() - a = _wrap_gen( (self.gptr.ref_MODptr())[0]) - b = _wrap_gen( (self.gptr.ref_MODptr())[1]) - result = IntegerModRing(ZZ(b))(ZZ(a)) - sig_off() - return result + # modular integer + sig_on() + a = _wrap_gen( (self.gptr.ref_MODptr())[0]) + b = _wrap_gen( (self.gptr.ref_MODptr())[1]) + result = IntegerModRing(ZZ(b))(ZZ(a)) + sig_off() + return result elif (typ == 12): - # string - sig_on() - result=eval(self.__str__()) - sig_off() - return result + # string + sig_on() + result=eval(self.__str__()) + sig_off() + return result else: - return SR(self) + return SR(self) else: # self is a list @@ -1622,7 +1622,7 @@ cdef class Pygen(GiacMethods_base): return result - def _symbolic_(self, R): + def _symbolic_(self, R): r""" Convert self object to the ring R via a basic string evaluation. (slow) @@ -1650,28 +1650,28 @@ cdef class Pygen(GiacMethods_base): sin(π) """ if isinstance(R,SR.__class__): - # Try to convert some functions names to the symbolic ring - lsymbols = symbol_table['giac'].copy() - #lsymbols.update(locals) - try: - result = symbolic_expression_from_string(self.__str__(), lsymbols, - accept_sequence=True, - parser=SR_parser_giac) - return result - - except Exception: - raise NotImplementedError("Unable to parse Giac output: %s" % self.__repr__()) + # Try to convert some functions names to the symbolic ring + lsymbols = symbol_table['giac'].copy() + #lsymbols.update(locals) + try: + result = symbolic_expression_from_string(self.__str__(), lsymbols, + accept_sequence=True, + parser=SR_parser_giac) + return result + + except Exception: + raise NotImplementedError("Unable to parse Giac output: %s" % self.__repr__()) else: - try: - result=R(self.__str__()) - return result + try: + result=R(self.__str__()) + return result - except Exception: - raise NotImplementedError("Unable to parse Giac output: %s" % self.__repr__()) + except Exception: + raise NotImplementedError("Unable to parse Giac output: %s" % self.__repr__()) - def _matrix_(self, R=ZZ): + def _matrix_(self, R=ZZ): r""" Return matrix over the (Sage) ring R where self should be a Giac matrix. The default ring is ZZ. @@ -1706,7 +1706,7 @@ cdef class Pygen(GiacMethods_base): sig_off() return M(entries) - def _vector_(self, R=None): + def _vector_(self, R=None): r""" Return vector over the (Sage) ring R where self should be a Giac matrix. The default ring is ZZ. @@ -1726,19 +1726,19 @@ cdef class Pygen(GiacMethods_base): v = self.dim() try: - n = v._val + n = v._val except: - raise TypeError("Entry is not a giac vector") + raise TypeError("Entry is not a giac vector") from sage.modules.free_module_element import vector sig_on() entries = [R(self[c]) for c in range(n)] sig_off() return vector(R,entries) - # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # - def mplot(self): + def mplot(self): """ Basic export of some 2D plots to sage. Only generic plots are supported. lines, circles, ... are not implemented @@ -1747,28 +1747,28 @@ cdef class Pygen(GiacMethods_base): xyplot=[] plotdata=self if not plotdata.type()=='DOM_LIST': - plotdata=[plotdata] + plotdata=[plotdata] sig_on() for G in plotdata: - if G.dim()>2: # it is not a pnt. Ex: scatterplot + if G.dim()>2: # it is not a pnt. Ex: scatterplot for g in G: xyscat=xyscat+[[(g.real())._double,(g.im())._double]] - else: + else: if G[1].type()=='DOM_LIST': - l=G[1].op() + l=G[1].op() else: - l=G[1][2].op() + l=G[1][2].op() xyplot=[[(u.real())._double,(u.im())._double] for u in l] if (xyscat != []): - result=scatter_plot(xyscat) + result=scatter_plot(xyscat) else: - result=line(xyplot) + result=line(xyplot) sig_off() return result @@ -1776,45 +1776,45 @@ cdef class Pygen(GiacMethods_base): - # # # # # # # # # # # # # # # # # # # # # # # # # - # WARNING: - # - # Do not use things like != in Pygen's __cinit__ - # with this __richcmp__ enabled - # The methods will bug: a=Pygen(2); a.sin() - # - # # # # # # # # # # # # # # # # # # # # # # # # # + # # # # # # # # # # # # # # # # # # # # # # # # # + # WARNING: + # + # Do not use things like != in Pygen's __cinit__ + # with this __richcmp__ enabled + # The methods will bug: a=Pygen(2); a.sin() + # + # # # # # # # # # # # # # # # # # # # # # # # # # - def __richcmp__( self, other,op): - if isinstance(other,Pygen)==False: + def __richcmp__( self, other,op): + if isinstance(other,Pygen)==False: other=Pygen(other) - if isinstance(self,Pygen)==False: + if isinstance(self,Pygen)==False: self=Pygen(self) - try: - sig_on() - result= giacgenrichcmp((self).gptr[0],(other).gptr[0], op, context_ptr ) - sig_off() - except: - raise RuntimeError - if result==1 : - return True - else: - return False - - # - # Some attributes of the gen class: - # - property _type: - def __get__(self): + try: + sig_on() + result= giacgenrichcmp((self).gptr[0],(other).gptr[0], op, context_ptr ) + sig_off() + except: + raise RuntimeError + if result==1 : + return True + else: + return False + + # + # Some attributes of the gen class: + # + property _type: + def __get__(self): sig_on() result=self.gptr.type sig_off() return result - property _subtype: - def __get__(self): + property _subtype: + def __get__(self): sig_on() result=self.gptr.subtype sig_off() @@ -1822,57 +1822,57 @@ cdef class Pygen(GiacMethods_base): - property _val: # immediate int (type _INT_) - """ - immediate int value of an _INT_ type gen. - """ - def __get__(self): + property _val: # immediate int (type _INT_) + """ + immediate int value of an _INT_ type gen. + """ + def __get__(self): if(self._type == 0): - sig_on() - result=self.gptr.val - sig_off() - return result + sig_on() + result=self.gptr.val + sig_off() + return result else: - raise TypeError("Cannot convert non _INT_ giac gen") + raise TypeError("Cannot convert non _INT_ giac gen") - property _double: # immediate double (type _DOUBLE_) - """ - immediate conversion to float for a gen of _DOUBLE_ type. - """ - def __get__(self): + property _double: # immediate double (type _DOUBLE_) + """ + immediate conversion to float for a gen of _DOUBLE_ type. + """ + def __get__(self): if(self._type == 1): - sig_on() - result=self.gptr._DOUBLE_val - sig_off() - return result + sig_on() + result=self.gptr._DOUBLE_val + sig_off() + return result else: - raise TypeError("Cannot convert non _DOUBLE_ giac gen") + raise TypeError("Cannot convert non _DOUBLE_ giac gen") - property help: - def __get__(self): - return self._help() + property help: + def __get__(self): + return self._help() - ################################################### - # Add the others methods - ################################################### - # - # NB: with __getattr__ this is about 10 times slower: [a.normal() for i in range(10**4)] - # than [GiacMethods["normal"](a) for i in range(10**4)] - # - # def __getattr__(self, name): - # return GiacMethods[str(name)](self) - ## + ################################################### + # Add the others methods + ################################################### + # + # NB: with __getattr__ this is about 10 times slower: [a.normal() for i in range(10**4)] + # than [GiacMethods["normal"](a) for i in range(10**4)] + # + # def __getattr__(self, name): + # return GiacMethods[str(name)](self) + ## - #test - def giacAiry_Ai(self, *args): + #test + def giacAiry_Ai(self, *args): cdef gen result=GIAC_Airy_Ai(self.gptr[0], context_ptr) return _wrap_gen(result) - def giacifactor(self, *args): + def giacifactor(self, *args): cdef gen result sig_on() result=GIAC_eval(self.gptr[0], 1, context_ptr) @@ -1929,79 +1929,79 @@ cdef inline _wrap_gen(gen g)except +: ################################################################ cdef vecteur _wrap_pylist(L) except +: - cdef vecteur * V - cdef int i + cdef vecteur * V + cdef int i - if (isinstance(L, tuple) or isinstance(L, listrange)): - n=len(L) - V=new vecteur() + if (isinstance(L, tuple) or isinstance(L, listrange)): + n=len(L) + V=new vecteur() - sig_on() - for i in range(n): - V.push_back((Pygen(L[i])).gptr[0]) - sig_off() - return V[0] - else: - raise TypeError("argument must be a tuple or a list") + sig_on() + for i in range(n): + V.push_back((Pygen(L[i])).gptr[0]) + sig_off() + return V[0] + else: + raise TypeError("argument must be a tuple or a list") ################################# # slice wrapper for a giac list ################################# cdef vecteur _getgiacslice(Pygen L,slice sl) except +: - cdef vecteur * V - cdef int u + cdef vecteur * V + cdef int u - if (L.type()=="DOM_LIST"): - n=len(L) - V=new vecteur() + if (L.type()=="DOM_LIST"): + n=len(L) + V=new vecteur() - sig_on() + sig_on() # for u in range(n)[sl]: #pb python3 - (b,e,st)=sl.indices(n) - for u in range(b,e,st): - V.push_back((L.gptr[0])[u]) - sig_off() - return V[0] - else: - raise TypeError("argument must be a Pygen list and a slice") + (b,e,st)=sl.indices(n) + for u in range(b,e,st): + V.push_back((L.gptr[0])[u]) + sig_off() + return V[0] + else: + raise TypeError("argument must be a Pygen list and a slice") cdef gen pylongtogen(a) except +: - # # - # basic conversion of Python long integers to gen via Horner's Method # - # # - - aneg=False - cdef gen g=gen(0) - cdef gen M - - if (a<0): - aneg=True - a=-a - if Pyversioninfo >= (2,7): - size=a.bit_length() # bit_length python >= 2.7 required. - shift=Pymaxint.bit_length()-1 - else: - size=math.trunc(math.log(a,2))+1 - shift=math.trunc(math.log(Pymaxint)) - M=gen((1<=shift): - size=size-shift - i=int(a>>size) - g=(g*M+gen(i)) - a=a-(i<(1< a) - if aneg: - # when cythonizing with cython 0.24: - # g=-g gives an Invalid operand type for '-' (gen) - g=GIAC_neg(g) - return g; + # # + # basic conversion of Python long integers to gen via Horner's Method # + # # + + aneg=False + cdef gen g=gen(0) + cdef gen M + + if (a<0): + aneg=True + a=-a + if Pyversioninfo >= (2,7): + size=a.bit_length() # bit_length python >= 2.7 required. + shift=Pymaxint.bit_length()-1 + else: + size=math.trunc(math.log(a,2))+1 + shift=math.trunc(math.log(Pymaxint)) + M=gen((1<=shift): + size=size-shift + i=int(a>>size) + g=(g*M+gen(i)) + a=a-(i<(1< a) + if aneg: + # when cythonizing with cython 0.24: + # g=-g gives an Invalid operand type for '-' (gen) + g=GIAC_neg(g) + return g; @@ -2066,78 +2066,78 @@ GiacMethods={} class GiacFunction(Pygen): - # a class to evaluate args before call - """ - A Subclass of Pygen to create functions with evaluating all the args - before call so that they are substitued by their value. - - EXAMPLES:: - - sage: from sage.libs.giac.giac import * - sage: libgiac.simplify(exp(I*pi)) # simplify is a GiacFunction - -1 - sage: libgiac('a:=1') - 1 - sage: libgiac.purge('a') # purge is not a GiacFunction - 1 - sage: libgiac('a') - a - """ - def __call__(self, *args): - cdef gen result - n=len(args) - if (n>1): - #FIXME? improve with a vector, or improve Pygen(list) - right=Pygen(args).eval() - elif (n==1): - right=Pygen(args[0]).eval() - else: - right=GIACNULL - if isinstance(self,Pygen)==False: - self=Pygen(self) + # a class to evaluate args before call + """ + A Subclass of Pygen to create functions with evaluating all the args + before call so that they are substitued by their value. + + EXAMPLES:: + + sage: from sage.libs.giac.giac import * + sage: libgiac.simplify(exp(I*pi)) # simplify is a GiacFunction + -1 + sage: libgiac('a:=1') + 1 + sage: libgiac.purge('a') # purge is not a GiacFunction + 1 + sage: libgiac('a') + a + """ + def __call__(self, *args): + cdef gen result + n=len(args) + if (n>1): + #FIXME? improve with a vector, or improve Pygen(list) + right=Pygen(args).eval() + elif (n==1): + right=Pygen(args[0]).eval() + else: + right=GIACNULL + if isinstance(self,Pygen)==False: + self=Pygen(self) # Some giac errors such as pari_locked are caught by the try # so we can't put the sig_on() in the try. # But now a keyboard interrupt fall back to this sig_on so # it may have left the giac pari locked. - sig_on() - try: - result= ((self).gptr[0])((right).gptr[0],context_ptr) - sig_off() - return _wrap_gen(result) - except: + sig_on() + try: + result= ((self).gptr[0])((right).gptr[0],context_ptr) + sig_off() + return _wrap_gen(result) + except: # The previous computation might have failed due to a pari_lock # So we will not raise an exception yet. tmp=Pygen('pari_unlock()').eval() # if pari was not locked in giac, we have locked it, so unlock it. if(tmp==0): - Pygen('pari_unlock()').eval() - sig_off() - raise + Pygen('pari_unlock()').eval() + sig_off() + raise else: - try: - result= GIAC_eval((right).gptr[0],1,context_ptr) - result= ((self).gptr[0])(result,context_ptr) - sig_off() - return _wrap_gen(result) - except: - sig_off() - raise + try: + result= GIAC_eval((right).gptr[0],1,context_ptr) + result= ((self).gptr[0])(result,context_ptr) + sig_off() + return _wrap_gen(result) + except: + sig_off() + raise class GiacFunctionNoEV(Pygen): - # a class to allow to write the __doc__ attribute. - """ - A Subclass of Pygen to create functions + # a class to allow to write the __doc__ attribute. + """ + A Subclass of Pygen to create functions - EXAMPLES:: + EXAMPLES:: - sage: from sage.libs.giac.giac import * - sage: libgiac('a:=1') - 1 - sage: libgiac.purge('a') # purge is a GiacFunctionNoEV - 1 - sage: libgiac('a') - a - """ + sage: from sage.libs.giac.giac import * + sage: libgiac('a:=1') + 1 + sage: libgiac.purge('a') # purge is a GiacFunctionNoEV + 1 + sage: libgiac('a') + a + """ ############################################################# # Some convenient settings @@ -2150,22 +2150,22 @@ Pygen('add_language(1)').eval(); # Add the french keywords in the giac library l NoEvArgsFunc=['purge','assume','quote'] for i in mostkeywords: - if i in NoEvArgsFunc: - # do not eval args before calling this function. Ex purge - #tmp=Pygen(i) - tmp=GiacFunctionNoEV(i) - else: - tmp=GiacFunction(i) - # in the sage version we remove: globals()[i]=tmp - GiacMethods[i]=tmp + if i in NoEvArgsFunc: + # do not eval args before calling this function. Ex purge + #tmp=Pygen(i) + tmp=GiacFunctionNoEV(i) + else: + tmp=GiacFunction(i) + # in the sage version we remove: globals()[i]=tmp + GiacMethods[i]=tmp # We put the giac names that should not be exported to Python in moremethods. for i in moremethods: - tmp=GiacFunction(i) - GiacMethods[i]=tmp + tmp=GiacFunction(i) + GiacMethods[i]=tmp for i in mostkeywords+moremethods: - GiacMethods[i].__doc__=eval("Pygen."+i+".__doc__") + GiacMethods[i].__doc__=eval("Pygen."+i+".__doc__") # To avoid conflicts we export only these few ones. Most giac keywords will be # avaible through: libgiac.keywordname @@ -2174,36 +2174,36 @@ __all__=['Pygen','giacsettings','libgiac','loadgiacgen','GiacFunction','GiacMeth def loadgiacgen(str filename): - """ - Open a file in giac compressed format to create a Pygen element. - - Use the save method from Pygen elements to create such files. - - In C++ these files can be opened with giac::unarchive and created with - ``giac::archive``. - - EXAMPLES:: - - sage: from sage.libs.giac.giac import * - sage: g=libgiac.texpand('cos(10*a+5*b)') - sage: g.save("fichiertest") # doctest: +SKIP - sage: a=loadgiacgen("fichiertest") # doctest: +SKIP - sage: from tempfile import NamedTemporaryFile - sage: F=NamedTemporaryFile() # chose a temporary file for a test - sage: g.savegen(F.name) - sage: a=loadgiacgen(F.name) - sage: a.tcollect() - cos(10*a+5*b) - sage: F.close() - """ - cdef gen result - try: - sig_on() - result=GIAC_unarchive( encstring23(filename), context_ptr) - sig_off() - return _wrap_gen(result) - except: - raise RuntimeError + """ + Open a file in giac compressed format to create a Pygen element. + + Use the save method from Pygen elements to create such files. + + In C++ these files can be opened with giac::unarchive and created with + ``giac::archive``. + + EXAMPLES:: + + sage: from sage.libs.giac.giac import * + sage: g=libgiac.texpand('cos(10*a+5*b)') + sage: g.save("fichiertest") # doctest: +SKIP + sage: a=loadgiacgen("fichiertest") # doctest: +SKIP + sage: from tempfile import NamedTemporaryFile + sage: F=NamedTemporaryFile() # chose a temporary file for a test + sage: g.savegen(F.name) + sage: a=loadgiacgen(F.name) + sage: a.tcollect() + cos(10*a+5*b) + sage: F.close() + """ + cdef gen result + try: + sig_on() + result=GIAC_unarchive( encstring23(filename), context_ptr) + sig_off() + return _wrap_gen(result) + except: + raise RuntimeError @@ -2227,21 +2227,21 @@ class GiacInstance: """ def __init__(self): - self.__dict__.update(GiacMethods) + self.__dict__.update(GiacMethods) def __call__(self,s): - return _giac(s) + return _giac(s) def _sage_doc_(self): - return _giac.__doc__ + return _giac.__doc__ def eval(self, code, strip=True, **kwds): if strip: - code = code.replace("\n","").strip() + code = code.replace("\n","").strip() return self(code) @@ -2254,8 +2254,8 @@ libgiac=GiacInstance() # trac #23976 (bound threads with SAGE_NUM_THREADS) import os try: - ncpus = int(os.environ['SAGE_NUM_THREADS']) + ncpus = int(os.environ['SAGE_NUM_THREADS']) except KeyError: - ncpus = 1 + ncpus = 1 giacsettings.threads = ncpus From da3e43762af6b5d0b40547d382cbbac3375988fc Mon Sep 17 00:00:00 2001 From: Thierry Monteil Date: Thu, 28 Oct 2021 23:24:29 +0200 Subject: [PATCH 007/253] #32788 : remove useless try/except statements in src/sage/libs/giac/giac.pyx --- src/sage/libs/giac/giac.pyx | 206 +++++++++++++----------------------- 1 file changed, 72 insertions(+), 134 deletions(-) diff --git a/src/sage/libs/giac/giac.pyx b/src/sage/libs/giac/giac.pyx index b6f143404fb..d2104a562d4 100644 --- a/src/sage/libs/giac/giac.pyx +++ b/src/sage/libs/giac/giac.pyx @@ -913,13 +913,10 @@ cdef class Pygen(GiacMethods_base): def __repr__(self): - try: - # fast evaluation of the complexity of the gen. (it's not the number of char ) - sig_on() - t=GIAC_taille(self.gptr[0], 6000) - sig_off() - except: - raise RuntimeError + # fast evaluation of the complexity of the gen. (it's not the number of char ) + sig_on() + t=GIAC_taille(self.gptr[0], 6000) + sig_off() if (t<6000) : sig_on() result=decstring23(GIAC_print(self.gptr[0], context_ptr).c_str()) #python3 @@ -954,14 +951,11 @@ cdef class Pygen(GiacMethods_base): sig_off() return rep else: - try: - sig_on() - rep=GIAC_size(self.gptr[0],context_ptr).val - sig_off() - #GIAC_size return a gen. we take the int: val - return rep - except: - raise RuntimeError + sig_on() + rep=GIAC_size(self.gptr[0],context_ptr).val + sig_off() + #GIAC_size return a gen. we take the int: val + return rep def __getitem__(self,i): #TODO?: add gen support for indexes @@ -1004,13 +998,10 @@ cdef class Pygen(GiacMethods_base): if(ii] - sig_off() - return _wrap_gen(result) - except: - raise RuntimeError + sig_on() + result=self.gptr[0][i] + sig_off() + return _wrap_gen(result) else: raise IndexError('list index %s out of range'%(i)) else: @@ -1116,13 +1107,10 @@ cdef class Pygen(GiacMethods_base): def eval(self): cdef gen result - try: - sig_on() - result=GIAC_protecteval(self.gptr[0],giacsettings.eval_level,context_ptr) - sig_off() - return _wrap_gen(result) - except: - raise RuntimeError + sig_on() + result=GIAC_protecteval(self.gptr[0],giacsettings.eval_level,context_ptr) + sig_off() + return _wrap_gen(result) def __add__(self, right): @@ -1133,14 +1121,10 @@ cdef class Pygen(GiacMethods_base): # otherwise: f=1/(2+sin(5*x)) crash if isinstance(self,Pygen)==False: self=Pygen(self) - - try: - sig_on() - result= (self).gptr[0] + (right).gptr[0] - sig_off() - return _wrap_gen(result) - except: - raise RuntimeError + sig_on() + result= (self).gptr[0] + (right).gptr[0] + sig_off() + return _wrap_gen(result) def __call__(self, *args): @@ -1190,14 +1174,10 @@ cdef class Pygen(GiacMethods_base): right=Pygen(right) if isinstance(self,Pygen)==False: self=Pygen(self) - - try: - sig_on() - result= (self).gptr[0] - (right).gptr[0] - sig_off() - return _wrap_gen(result) - except: - raise RuntimeError + sig_on() + result= (self).gptr[0] - (right).gptr[0] + sig_off() + return _wrap_gen(result) def __mul__(self, right): """ @@ -1214,18 +1194,14 @@ cdef class Pygen(GiacMethods_base): right=Pygen(right) if isinstance(self,Pygen)==False: self=Pygen(self) - - try: - #result= (self).gptr[0] * (right).gptr[0] - #NB: with the natural previous method, the following error generated by - #giac causes python to quit instead of an error message. - #l=Pygen([1,2]);l.transpose()*l; - sig_on() - result= GIAC_giacmul((self).gptr[0] , (right).gptr[0],context_ptr) - sig_off() - return _wrap_gen(result) - except: - raise RuntimeError + #result= (self).gptr[0] * (right).gptr[0] + #NB: with the natural previous method, the following error generated by + #giac causes python to quit instead of an error message. + #l=Pygen([1,2]);l.transpose()*l; + sig_on() + result= GIAC_giacmul((self).gptr[0] , (right).gptr[0],context_ptr) + sig_off() + return _wrap_gen(result) #PB / in python3 is truediv def __div__(self, right): @@ -1243,14 +1219,10 @@ cdef class Pygen(GiacMethods_base): right=Pygen(right) if isinstance(self,Pygen)==False: self=Pygen(self) - - try: - sig_on() - result= GIAC_giacdiv((self).gptr[0] , (right).gptr[0],context_ptr) - sig_off() - return _wrap_gen(result) - except: - raise RuntimeError + sig_on() + result= GIAC_giacdiv((self).gptr[0] , (right).gptr[0],context_ptr) + sig_off() + return _wrap_gen(result) def __truediv__(self, right): cdef gen result @@ -1258,14 +1230,10 @@ cdef class Pygen(GiacMethods_base): right=Pygen(right) if isinstance(self,Pygen)==False: self=Pygen(self) - - try: - sig_on() - result= (self).gptr[0] / (right).gptr[0] - sig_off() - return _wrap_gen(result) - except: - raise RuntimeError + sig_on() + result= (self).gptr[0] / (right).gptr[0] + sig_off() + return _wrap_gen(result) def __pow__(self, right ,ignored): @@ -1274,14 +1242,10 @@ cdef class Pygen(GiacMethods_base): right=Pygen(right) if isinstance(self,Pygen)==False: self=Pygen(self) - - try: - sig_on() - result= GIAC_pow((self).gptr[0],(right).gptr[0], context_ptr ) - sig_off() - return _wrap_gen(result) - except: - raise RuntimeError + sig_on() + result= GIAC_pow((self).gptr[0],(right).gptr[0], context_ptr ) + sig_off() + return _wrap_gen(result) def __mod__(self, right): cdef gen result @@ -1289,31 +1253,23 @@ cdef class Pygen(GiacMethods_base): right=Pygen(right) if not isinstance(self,Pygen): self=Pygen(self) - - try: - #result= gen(GIAC_makenewvecteur((self).gptr[0],(right).gptr[0]),1) - #to have an integer output: - #result= GIAC_smod(result,context_ptr) - #we give a modular output: - sig_on() - result= GIAC_giacmod((self).gptr[0],(right).gptr[0],context_ptr) - sig_off() - return _wrap_gen(result) - except: - raise RuntimeError + #result= gen(GIAC_makenewvecteur((self).gptr[0],(right).gptr[0]),1) + #to have an integer output: + #result= GIAC_smod(result,context_ptr) + #we give a modular output: + sig_on() + result= GIAC_giacmod((self).gptr[0],(right).gptr[0],context_ptr) + sig_off() + return _wrap_gen(result) def __neg__(self): cdef gen result if isinstance(self,Pygen)==False: self=Pygen(self) - - try: - sig_on() - result= GIAC_neg((self).gptr[0]) - sig_off() - return _wrap_gen(result) - except: - raise RuntimeError + sig_on() + result= GIAC_neg((self).gptr[0]) + sig_off() + return _wrap_gen(result) def __pos__(self): return self @@ -1344,12 +1300,9 @@ cdef class Pygen(GiacMethods_base): (x+y+z+2)^10 sage: F.close() """ - try: - sig_on() - GIAC_archive( encstring23(filename), (self).gptr[0], context_ptr) - sig_off() - except: - raise RuntimeError + sig_on() + GIAC_archive( encstring23(filename), (self).gptr[0], context_ptr) + sig_off() @@ -1511,18 +1464,13 @@ cdef class Pygen(GiacMethods_base): True """ typ = self._type - # _INT_ or _ZINT - if(typ == 0 or typ == 2): + if typ == 0 or typ == 2: return QQ(ZZ(self)) # _FRAC_ - elif(typ == 10): + elif typ == 10: # giac _RAT_ - try: - result=ZZ(self.numer())/ZZ(self.denom()) - return result - except: - RuntimeError("Failed to convert to QQ") + return ZZ(self.numer()) / ZZ(self.denom()) else: raise TypeError("Cannot convert non giac _FRAC_ to QQ") @@ -1727,7 +1675,7 @@ cdef class Pygen(GiacMethods_base): v = self.dim() try: n = v._val - except: + except AttributeError: raise TypeError("Entry is not a giac vector") from sage.modules.free_module_element import vector sig_on() @@ -1790,17 +1738,10 @@ cdef class Pygen(GiacMethods_base): other=Pygen(other) if isinstance(self,Pygen)==False: self=Pygen(self) - - try: - sig_on() - result= giacgenrichcmp((self).gptr[0],(other).gptr[0], op, context_ptr ) - sig_off() - except: - raise RuntimeError - if result==1 : - return True - else: - return False + sig_on() + result= giacgenrichcmp((self).gptr[0],(other).gptr[0], op, context_ptr ) + sig_off() + return result == 1 # # Some attributes of the gen class: @@ -2197,13 +2138,10 @@ def loadgiacgen(str filename): sage: F.close() """ cdef gen result - try: - sig_on() - result=GIAC_unarchive( encstring23(filename), context_ptr) - sig_off() - return _wrap_gen(result) - except: - raise RuntimeError + sig_on() + result=GIAC_unarchive( encstring23(filename), context_ptr) + sig_off() + return _wrap_gen(result) From 66ec40edd4ac85ab46852a7d79b9f1ea68b4e17f Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Fri, 29 Oct 2021 10:52:43 +0200 Subject: [PATCH 008/253] codestyle --- src/sage/libs/giac/giac.pyx | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/sage/libs/giac/giac.pyx b/src/sage/libs/giac/giac.pyx index d2104a562d4..a6f4b54509a 100644 --- a/src/sage/libs/giac/giac.pyx +++ b/src/sage/libs/giac/giac.pyx @@ -1129,38 +1129,38 @@ cdef class Pygen(GiacMethods_base): def __call__(self, *args): cdef gen result - n=len(args) - if (n>1): - #FIXME? improve with a vector, or improve Pygen(list) - right=Pygen(args).eval() - elif (n==1): - right=Pygen(args[0]) + n = len(args) + if n > 1: + # FIXME? improve with a vector, or improve Pygen(list) + right = Pygen(args).eval() + elif n == 1: + right = Pygen(args[0]) else: - right=GIACNULL - if isinstance(self,Pygen)==False: - self=Pygen(self) -# Some giac errors such as pari_locked are caught by the try -# so we can't put the sig_on() in the try. -# But now a keyboard interrupt fall back to this sig_on so -# it may have left the giac pari locked. + right = GIACNULL + if isinstance(self, Pygen) == False: + self = Pygen(self) + # Some giac errors such as pari_locked are caught by the try + # so we can't put the sig_on() in the try. + # But now a keyboard interrupt fall back to this sig_on so + # it may have left the giac pari locked. sig_on() try: - result= ((self).gptr[0])((right).gptr[0],context_ptr) + result = (( self).gptr[0])(( right).gptr[0], context_ptr) sig_off() return _wrap_gen(result) except: # The previous computation might have failed due to a pari_lock # So we will not raise an exception yet. - tmp=Pygen('pari_unlock()').eval() + tmp = Pygen('pari_unlock()').eval() # if pari was not locked in giac, we have locked it, so unlock it. - if(tmp==0): + if tmp == 0: Pygen('pari_unlock()').eval() sig_off() raise else: try: - result= GIAC_eval((right).gptr[0],1,context_ptr) - result= ((self).gptr[0])(result,context_ptr) + result = GIAC_eval((right).gptr[0], 1, context_ptr) + result = ((self).gptr[0])(result, context_ptr) sig_off() return _wrap_gen(result) except: From be872c16d193602a548c98b1b18deb24dc2e0d37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 29 Oct 2021 13:42:46 +0200 Subject: [PATCH 009/253] some fixes in giac, schemes, geometry --- src/sage/geometry/polyhedron/base.py | 2 +- src/sage/libs/giac/giac.pyx | 20 ++++--------------- .../schemes/projective/projective_space.py | 2 +- 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index adb0c82959a..e9370d55e35 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -5276,7 +5276,7 @@ def _test_dilation(self, tester=None, **options): new_ring = None try: new_ring = self.base_ring().composite_fields()[0] - except (KeyError, AttributeError): + except (KeyError, AttributeError, TypeError): # This isn't about testing composite fields. pass if new_ring: diff --git a/src/sage/libs/giac/giac.pyx b/src/sage/libs/giac/giac.pyx index d2104a562d4..f736b4b421e 100644 --- a/src/sage/libs/giac/giac.pyx +++ b/src/sage/libs/giac/giac.pyx @@ -171,28 +171,16 @@ from sage.interfaces.giac import giac #### Python3 compatibility ############################# -if Pyversioninfo[0]>2 : - PythonVersion3 = True -else: - PythonVersion3 = False +PythonVersion3 = True def decstring23(s): - if PythonVersion3 : - return s.decode() - else: - return s + return s.decode() def encstring23(s): - if PythonVersion3 : - return bytes(s,'UTF-8') - else: - return s + return bytes(s,'UTF-8') -if PythonVersion3: - listrange=list,range -else: - listrange=list +listrange = list,range ####End of Python3 compatibility######################## diff --git a/src/sage/schemes/projective/projective_space.py b/src/sage/schemes/projective/projective_space.py index 36deeab7827..f1f89b4513c 100644 --- a/src/sage/schemes/projective/projective_space.py +++ b/src/sage/schemes/projective/projective_space.py @@ -1693,7 +1693,7 @@ def hyperplane_transformation_matrix(self, plane_1, plane_2): if len(source_points) == N: try: plane(point) - except ValueError: + except (ValueError, TypeError): source_points.append(self(point)) base_list = [list(s) for s in source_points] elif len(source_points) == N + 1: From 0113b72725babbf822e7be0831c8281db4253a57 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Fri, 29 Oct 2021 14:14:06 +0200 Subject: [PATCH 010/253] code style again --- src/sage/libs/giac/giac.pyx | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/sage/libs/giac/giac.pyx b/src/sage/libs/giac/giac.pyx index a80d9c92907..b888e7e3c9e 100644 --- a/src/sage/libs/giac/giac.pyx +++ b/src/sage/libs/giac/giac.pyx @@ -2014,38 +2014,38 @@ class GiacFunction(Pygen): """ def __call__(self, *args): cdef gen result - n=len(args) - if (n>1): - #FIXME? improve with a vector, or improve Pygen(list) - right=Pygen(args).eval() - elif (n==1): - right=Pygen(args[0]).eval() + n = len(args) + if n > 1: + # FIXME? improve with a vector, or improve Pygen(list) + right = Pygen(args).eval() + elif n == 1: + right = Pygen(args[0]) else: - right=GIACNULL - if isinstance(self,Pygen)==False: - self=Pygen(self) -# Some giac errors such as pari_locked are caught by the try -# so we can't put the sig_on() in the try. -# But now a keyboard interrupt fall back to this sig_on so -# it may have left the giac pari locked. + right = GIACNULL + if isinstance(self, Pygen) == False: + self = Pygen(self) + # Some giac errors such as pari_locked are caught by the try + # so we can't put the sig_on() in the try. + # But now a keyboard interrupt fall back to this sig_on so + # it may have left the giac pari locked. sig_on() try: - result= ((self).gptr[0])((right).gptr[0],context_ptr) + result = (( self).gptr[0])(( right).gptr[0], context_ptr) sig_off() return _wrap_gen(result) except: # The previous computation might have failed due to a pari_lock # So we will not raise an exception yet. - tmp=Pygen('pari_unlock()').eval() + tmp = Pygen('pari_unlock()').eval() # if pari was not locked in giac, we have locked it, so unlock it. - if(tmp==0): + if tmp == 0: Pygen('pari_unlock()').eval() sig_off() raise else: try: - result= GIAC_eval((right).gptr[0],1,context_ptr) - result= ((self).gptr[0])(result,context_ptr) + result = GIAC_eval((right).gptr[0], 1, context_ptr) + result = ((self).gptr[0])(result, context_ptr) sig_off() return _wrap_gen(result) except: From 6c08ce185d4a44e89cf8d2804f0be658a8e95dee Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Fri, 29 Oct 2021 15:02:06 +0200 Subject: [PATCH 011/253] remove blank except in GIAC call --- src/sage/libs/giac/giac.pyx | 58 ++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/src/sage/libs/giac/giac.pyx b/src/sage/libs/giac/giac.pyx index b888e7e3c9e..eb6fed7697e 100644 --- a/src/sage/libs/giac/giac.pyx +++ b/src/sage/libs/giac/giac.pyx @@ -1117,6 +1117,9 @@ cdef class Pygen(GiacMethods_base): def __call__(self, *args): cdef gen result + cdef Pygen pari_unlock = Pygen('pari_unlock()') + cdef gen pari_unlock_result + cdef Pygen right n = len(args) if n > 1: # FIXME? improve with a vector, or improve Pygen(list) @@ -1133,27 +1136,23 @@ cdef class Pygen(GiacMethods_base): # it may have left the giac pari locked. sig_on() try: - result = (( self).gptr[0])(( right).gptr[0], context_ptr) - sig_off() - return _wrap_gen(result) - except: + result = self.gptr[0](right.gptr[0], context_ptr) + except RuntimeError: # The previous computation might have failed due to a pari_lock # So we will not raise an exception yet. - tmp = Pygen('pari_unlock()').eval() + pari_unlock_result = GIAC_eval(pari_unlock.gptr[0], 1, context_ptr) + tmp = _wrap_gen(result) # if pari was not locked in giac, we have locked it, so unlock it. if tmp == 0: - Pygen('pari_unlock()').eval() - sig_off() + pari_unlock_result = GIAC_eval(pari_unlock.gptr[0], 1, context_ptr) + tmp = _wrap_gen(result) raise else: - try: - result = GIAC_eval((right).gptr[0], 1, context_ptr) - result = ((self).gptr[0])(result, context_ptr) - sig_off() - return _wrap_gen(result) - except: - sig_off() - raise + result = GIAC_eval(right.gptr[0], 1, context_ptr) + result = self.gptr[0](result, context_ptr) + finally: + sig_off() + return _wrap_gen(result) def __sub__(self, right): @@ -2014,6 +2013,9 @@ class GiacFunction(Pygen): """ def __call__(self, *args): cdef gen result + cdef Pygen pari_unlock = Pygen('pari_unlock()') + cdef gen pari_unlock_result + cdef Pygen right n = len(args) if n > 1: # FIXME? improve with a vector, or improve Pygen(list) @@ -2030,27 +2032,23 @@ class GiacFunction(Pygen): # it may have left the giac pari locked. sig_on() try: - result = (( self).gptr[0])(( right).gptr[0], context_ptr) - sig_off() - return _wrap_gen(result) - except: + result = ( self).gptr[0](right.gptr[0], context_ptr) + except RuntimeError: # The previous computation might have failed due to a pari_lock # So we will not raise an exception yet. - tmp = Pygen('pari_unlock()').eval() + pari_unlock_result = GIAC_eval(pari_unlock.gptr[0], 1, context_ptr) + tmp = _wrap_gen(result) # if pari was not locked in giac, we have locked it, so unlock it. if tmp == 0: - Pygen('pari_unlock()').eval() - sig_off() + pari_unlock_result = GIAC_eval(pari_unlock.gptr[0], 1, context_ptr) + tmp = _wrap_gen(result) raise else: - try: - result = GIAC_eval((right).gptr[0], 1, context_ptr) - result = ((self).gptr[0])(result, context_ptr) - sig_off() - return _wrap_gen(result) - except: - sig_off() - raise + result = GIAC_eval(right.gptr[0], 1, context_ptr) + result = ( self).gptr[0](result, context_ptr) + finally: + sig_off() + return _wrap_gen(result) class GiacFunctionNoEV(Pygen): # a class to allow to write the __doc__ attribute. From 04a1f01de963dbc6a7c8f67bcbcfadbf1cd9a9c7 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Fri, 29 Oct 2021 22:32:15 +0200 Subject: [PATCH 012/253] fix distinction between two calls --- src/sage/libs/giac/giac.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/libs/giac/giac.pyx b/src/sage/libs/giac/giac.pyx index eb6fed7697e..8b81a39c700 100644 --- a/src/sage/libs/giac/giac.pyx +++ b/src/sage/libs/giac/giac.pyx @@ -2021,7 +2021,7 @@ class GiacFunction(Pygen): # FIXME? improve with a vector, or improve Pygen(list) right = Pygen(args).eval() elif n == 1: - right = Pygen(args[0]) + right = Pygen(args[0]).eval() else: right = GIACNULL if isinstance(self, Pygen) == False: From 9905930022910ded1dbd483896a4a171968eded1 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Fri, 29 Oct 2021 22:39:46 +0200 Subject: [PATCH 013/253] remove code duplication --- src/sage/libs/giac/giac.pyx | 39 +++---------------------------------- 1 file changed, 3 insertions(+), 36 deletions(-) diff --git a/src/sage/libs/giac/giac.pyx b/src/sage/libs/giac/giac.pyx index 8b81a39c700..fc705f9e733 100644 --- a/src/sage/libs/giac/giac.pyx +++ b/src/sage/libs/giac/giac.pyx @@ -2012,43 +2012,10 @@ class GiacFunction(Pygen): a """ def __call__(self, *args): - cdef gen result - cdef Pygen pari_unlock = Pygen('pari_unlock()') - cdef gen pari_unlock_result - cdef Pygen right n = len(args) - if n > 1: - # FIXME? improve with a vector, or improve Pygen(list) - right = Pygen(args).eval() - elif n == 1: - right = Pygen(args[0]).eval() - else: - right = GIACNULL - if isinstance(self, Pygen) == False: - self = Pygen(self) - # Some giac errors such as pari_locked are caught by the try - # so we can't put the sig_on() in the try. - # But now a keyboard interrupt fall back to this sig_on so - # it may have left the giac pari locked. - sig_on() - try: - result = ( self).gptr[0](right.gptr[0], context_ptr) - except RuntimeError: - # The previous computation might have failed due to a pari_lock - # So we will not raise an exception yet. - pari_unlock_result = GIAC_eval(pari_unlock.gptr[0], 1, context_ptr) - tmp = _wrap_gen(result) - # if pari was not locked in giac, we have locked it, so unlock it. - if tmp == 0: - pari_unlock_result = GIAC_eval(pari_unlock.gptr[0], 1, context_ptr) - tmp = _wrap_gen(result) - raise - else: - result = GIAC_eval(right.gptr[0], 1, context_ptr) - result = ( self).gptr[0](result, context_ptr) - finally: - sig_off() - return _wrap_gen(result) + if n == 1: + args = (Pygen(args[0]).eval(),) + return Pygen.__call__(self, *args) class GiacFunctionNoEV(Pygen): # a class to allow to write the __doc__ attribute. From 6281b322d19df99101a2558d575dd7a3ded72885 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 30 Oct 2021 14:06:57 +0200 Subject: [PATCH 014/253] trac #32800: weights in distance, closeness_centrality, shortest_path --- src/sage/graphs/generic_graph.py | 87 +++++++++++++++----------------- 1 file changed, 40 insertions(+), 47 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index df3a9e7dc24..9dbc8658412 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -14657,7 +14657,7 @@ def cluster_transitivity(self): ### Distance - def distance(self, u, v, by_weight=False): + def distance(self, u, v, by_weight=False, weight_function=None, check_weight=True): """ Return the (directed) distance from ``u`` to ``v`` in the (di)graph. @@ -14674,6 +14674,15 @@ def distance(self, u, v, by_weight=False): shortest path. If ``True``, the distance is the sum of edge labels (which are assumed to be numbers). + - ``weight_function`` -- function (default: ``None``); a function that + takes as input an edge ``(u, v, l)`` and outputs its weight. If not + ``None``, ``by_weight`` is automatically set to ``True``. If ``None`` + and ``by_weight`` is ``True``, we use the edge label ``l``, if ``l`` + is not ``None``, else ``1`` as a weight. + + - ``check_weight`` -- boolean (default: ``True``); whether to check that + the ``weight_function`` outputs a number for each edge. + EXAMPLES:: sage: G = graphs.CycleGraph(9) @@ -14693,7 +14702,9 @@ def distance(self, u, v, by_weight=False): sage: G.distance(0, 3, by_weight=True) 3 """ - return self.shortest_path_length(u, v, by_weight=by_weight) + return self.shortest_path_length(u, v, by_weight=by_weight, + weight_function=weight_function, + check_weight=check_weight) def distance_all_pairs(self, by_weight=False, algorithm=None, weight_function=None, check_weight=True): @@ -15558,11 +15569,9 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, ....: for ci, cj in itertools.combinations(c, 2): ....: assert(sum(abs(ci[v] - cj[v]) for v in g if g.degree(v)) < 1e-12) """ - if weight_function is not None: - by_weight=True - elif by_weight: - def weight_function(e): - return 1 if e[2] is None else e[2] + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, + weight_function=weight_function, + check_weight=check_weight) onlyone = False if vert in self: @@ -15576,21 +15585,13 @@ def weight_function(e): if algorithm is None: if not by_weight: algorithm = 'BFS' - else: - for e in self.edge_iterator(): - try: - if float(weight_function(e)) < 0: - algorithm = 'Johnson_Boost' - break - except (ValueError, TypeError): - raise ValueError("the weight function cannot find the" + - " weight of " + str(e)) + weight_function = None + elif any(float(weight_function(e)) < 0 for e in self.edge_iterator()): + algorithm = 'Johnson_Boost' if algorithm is None: algorithm = 'Dijkstra_Boost' if algorithm == 'NetworkX': - if by_weight and check_weight: - self._check_weight_function(weight_function) import networkx if by_weight: if self.is_directed(): @@ -15629,15 +15630,17 @@ def weight_function(e): distances = None if algorithm in ["Floyd-Warshall-Cython", "Floyd-Warshall-Python"]: - distances = self.shortest_path_all_pairs(by_weight,algorithm, - weight_function, - check_weight)[0] + distances = self.shortest_path_all_pairs(algorithm=algorithm, + by_weight=by_weight, + weight_function=weight_function, + check_weight=False)[0] for v in v_iter: if distances is None: - distv = self.shortest_path_lengths(v, by_weight, algorithm, - weight_function, - check_weight) + distv = self.shortest_path_lengths(v, algorithm=algorithm, + by_weight=by_weight, + weight_function=weight_function, + check_weight=False) else: distv = distances[v] try: @@ -15906,38 +15909,28 @@ def shortest_path(self, u, v, by_weight=False, algorithm=None, raise ValueError("vertex '{}' is not in the (di)graph".format(u)) if not self.has_vertex(v): raise ValueError("vertex '{}' is not in the (di)graph".format(v)) + if u == v: + return [u] - if weight_function is not None: - by_weight = True + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, + weight_function=weight_function, + check_weight=check_weight) if algorithm is None: algorithm = 'Dijkstra_Bid' if by_weight else 'BFS_Bid' + elif algorithm in ['BFS', 'BFS_Bid']: + if by_weight: + raise ValueError("the '{}' algorithm does not work on weighted graphs".format(algorithm)) + # We don't want the default weight function + weight_function = None if algorithm in ['BFS', 'Dijkstra_NetworkX', 'Bellman-Ford_Boost']: - all_paths = self.shortest_paths(u, by_weight, algorithm, weight_function, check_weight) + all_paths = self.shortest_paths(u, algorithm=algorithm, by_weight=by_weight, + weight_function=weight_function, check_weight=False) if v in all_paths: return all_paths[v] return [] - - if u == v: # to avoid a NetworkX bug - return [u] - - if by_weight: - if algorithm == 'BFS_Bid': - raise ValueError("the 'BFS_Bid' algorithm does not " - "work on weighted graphs") - - if not weight_function: - def weight_function(e): - return 1 if e[2] is None else e[2] - - if check_weight: - self._check_weight_function(weight_function) - else: - def weight_function(e): - return 1 - - if algorithm == "Dijkstra_Bid": + elif algorithm == "Dijkstra_Bid": return self._backend.bidirectional_dijkstra(u, v, weight_function) elif algorithm == "Dijkstra_Bid_NetworkX": import networkx From 17218d8fd0e528c6ab0a050017438a476327e26e Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 30 Oct 2021 14:14:35 +0200 Subject: [PATCH 015/253] trac #32800: shortest_path_length --- src/sage/graphs/generic_graph.py | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 9dbc8658412..562bee19782 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -16092,15 +16092,20 @@ def shortest_path_length(self, u, v, by_weight=False, algorithm=None, raise ValueError("vertex '{}' is not in the (di)graph".format(u)) if not self.has_vertex(v): raise ValueError("vertex '{}' is not in the (di)graph".format(v)) - if u == v: # to avoid a NetworkX bug return 0 - if weight_function is not None: - by_weight = True + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, + weight_function=weight_function, + check_weight=check_weight) if algorithm is None: algorithm = 'Dijkstra_Bid' if by_weight else 'BFS_Bid' + elif algorithm in ['BFS', 'BFS_Bid']: + if by_weight: + raise ValueError("the '{}' algorithm does not work on weighted graphs".format(algorithm)) + # We don't want the default weight function + weight_function = None if algorithm in ['BFS', 'Dijkstra_NetworkX', 'Bellman-Ford_Boost']: all_path_lengths = self.shortest_path_lengths(u, by_weight, algorithm, weight_function, check_weight) @@ -16109,22 +16114,7 @@ def shortest_path_length(self, u, v, by_weight=False, algorithm=None, from sage.rings.infinity import Infinity return Infinity - if by_weight: - if algorithm == 'BFS_Bid': - raise ValueError("the 'BFS_Bid' algorithm does not " - "work on weighted graphs") - - if not weight_function: - def weight_function(e): - return 1 if e[2] is None else e[2] - - if check_weight: - self._check_weight_function(weight_function) - else: - def weight_function(e): - return 1 - - if algorithm == "Dijkstra_Bid": + elif algorithm == "Dijkstra_Bid": return self._backend.bidirectional_dijkstra(u, v, weight_function, distance_flag=True) elif algorithm == "Dijkstra_Bid_NetworkX": import networkx From 1452941d9042da0fdbab3ad43b28fa4f2b88f909 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 30 Oct 2021 14:51:34 +0200 Subject: [PATCH 016/253] trac #32801: weights in shortest_path_lengths, shortest_path_all_pairs, wiener_index --- src/sage/graphs/generic_graph.py | 73 +++++++++++++------------------- 1 file changed, 30 insertions(+), 43 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index df3a9e7dc24..a573ebdbd6f 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -16641,21 +16641,13 @@ def shortest_path_lengths(self, u, by_weight=False, algorithm=None, sage: d1 == d2 == d3 == d4 True """ - if weight_function is not None: - by_weight = True - elif by_weight: - def weight_function(e): - return 1 if e[2] is None else e[2] - else: - def weight_function(e): - return 1 + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, + weight_function=weight_function, + check_weight=check_weight) if algorithm is None and not by_weight: algorithm = 'BFS' - if by_weight and check_weight: - self._check_weight_function(weight_function) - if algorithm == 'BFS': if by_weight: raise ValueError("the 'BFS' algorithm does not work on weighted graphs") @@ -16931,31 +16923,15 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, ... RuntimeError: Dijkstra algorithm does not work with negative weights, use Bellman-Ford instead """ - if weight_function is not None: - by_weight = True - - if by_weight: - if not weight_function: - def weight_function(e): - return 1 if e[2] is None else e[2] - - if check_weight: - self._check_weight_function(weight_function) - else: - def weight_function(e): - return 1 + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, + weight_function=weight_function, + check_weight=check_weight) if algorithm is None: if by_weight: - for e in self.edge_iterator(): - try: - if weight_function(e) < 0: - algorithm = "Floyd-Warshall_Boost" - break - except (ValueError, TypeError): - raise ValueError("the weight function cannot find the" - " weight of " + e) - if algorithm is None: + if any(weight_function(e) < 0 for e in self.edge_iterator()): + algorithm = "Floyd-Warshall_Boost" + else: algorithm = "Dijkstra_Boost" else: algorithm = "BFS" @@ -17172,26 +17148,37 @@ def wiener_index(self, by_weight=False, algorithm=None, TESTS:: - sage: G.wiener_index(algorithm='BFS', weight_function=lambda e:(e[2] if e[2] is not None else 200)) + sage: weight_function=lambda e:(e[2] if e[2] is not None else 200) + sage: G.wiener_index(algorithm='BFS', weight_function=weight_function) Traceback (most recent call last): ... - ValueError: BFS algorithm does not work on weighted graphs + ValueError: algorithm 'BFS' does not work with weights + sage: G.wiener_index(algorithm='Floyd-Warshall-Cython', weight_function=weight_function) + Traceback (most recent call last): + ... + ValueError: algorithm 'Floyd-Warshall-Cython' does not work with weights sage: Graph([(0, 1, 1)]).wiener_index(algorithm="coco beach") Traceback (most recent call last): ... ValueError: unknown algorithm "coco beach" """ - by_weight = by_weight or (weight_function is not None) - if not self: raise ValueError("Wiener index is not defined for the empty graph") elif self.order() == 1: return 0 - if algorithm == 'BFS' or (algorithm is None and not by_weight): + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, + weight_function=weight_function, + check_weight=check_weight) + + if algorithm in ['BFS', 'Floyd-Warshall-Cython']: if by_weight: - raise ValueError("BFS algorithm does not work on weighted graphs") + raise ValueError("algorithm '{}' does not work with weights".format(algorithm)) + # We don't want the default weight function + weight_function = None + + if algorithm == 'BFS' or (algorithm is None and not by_weight): from .distances_all_pairs import wiener_index return wiener_index(self) @@ -17199,7 +17186,7 @@ def wiener_index(self, by_weight=False, algorithm=None, from .base.boost_graph import wiener_index WI = wiener_index(self, algorithm=algorithm, weight_function=weight_function, - check_weight=check_weight) + check_weight=False) elif (not self.is_connected() or (self.is_directed() and not self.is_strongly_connected())): @@ -17227,7 +17214,7 @@ def wiener_index(self, by_weight=False, algorithm=None, else: distances = self.shortest_path_all_pairs( by_weight=by_weight, algorithm=algorithm, - weight_function=weight_function, check_weight=check_weight)[0] + weight_function=weight_function, check_weight=False)[0] total = sum(sum(u.values()) for u in distances.values()) WI = total if self.is_directed() else (total / 2) @@ -17237,7 +17224,7 @@ def wiener_index(self, by_weight=False, algorithm=None, return WI def average_distance(self, by_weight=False, algorithm=None, - weight_function=None): + weight_function=None, check_weight=True): r""" Return the average distance between vertices of the graph. @@ -17304,7 +17291,7 @@ def average_distance(self, by_weight=False, algorithm=None, if self.order() < 2: raise ValueError("average distance is not defined for empty or one-element graph") WI = self.wiener_index(by_weight=by_weight, algorithm=algorithm, - weight_function=weight_function) + weight_function=weight_function, check_weight=check_weight) f = 1 if self.is_directed() else 2 if WI in ZZ: return QQ((f * WI, self.order() * (self.order() - 1))) From 5b01e7129268c491e66998e2aa787554cf9323eb Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 30 Oct 2021 19:13:22 +0200 Subject: [PATCH 017/253] trac #32800: fix some cases --- src/sage/graphs/generic_graph.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 562bee19782..cfc0273aac6 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -15585,11 +15585,15 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, if algorithm is None: if not by_weight: algorithm = 'BFS' - weight_function = None elif any(float(weight_function(e)) < 0 for e in self.edge_iterator()): algorithm = 'Johnson_Boost' if algorithm is None: algorithm = 'Dijkstra_Boost' + if algorithm in ['BFS', 'Floyd-Warshall-Cython']: + if by_weight: + raise ValueError("algorithm '{}' does not work with weights".format(algorithm)) + # We don't want the default weight function + weight_function = None if algorithm == 'NetworkX': import networkx From 320be0da3752a0afb55948eb395f925f16571f28 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Sat, 11 Sep 2021 17:26:02 -0700 Subject: [PATCH 018/253] trac 32505: finitely presented graded modules --- src/doc/en/reference/modules/index.rst | 15 + src/sage/modules/fp_graded/__init__.py | 12 + src/sage/modules/fp_graded/element.py | 322 ++++ src/sage/modules/fp_graded/free_element.py | 239 +++ src/sage/modules/fp_graded/free_homspace.py | 196 ++ src/sage/modules/fp_graded/free_module.py | 767 ++++++++ src/sage/modules/fp_graded/free_morphism.py | 595 +++++++ src/sage/modules/fp_graded/homspace.py | 521 ++++++ src/sage/modules/fp_graded/module.py | 1087 ++++++++++++ src/sage/modules/fp_graded/morphism.py | 1772 +++++++++++++++++++ 10 files changed, 5526 insertions(+) create mode 100755 src/sage/modules/fp_graded/__init__.py create mode 100755 src/sage/modules/fp_graded/element.py create mode 100755 src/sage/modules/fp_graded/free_element.py create mode 100755 src/sage/modules/fp_graded/free_homspace.py create mode 100755 src/sage/modules/fp_graded/free_module.py create mode 100755 src/sage/modules/fp_graded/free_morphism.py create mode 100755 src/sage/modules/fp_graded/homspace.py create mode 100755 src/sage/modules/fp_graded/module.py create mode 100755 src/sage/modules/fp_graded/morphism.py diff --git a/src/doc/en/reference/modules/index.rst b/src/doc/en/reference/modules/index.rst index d5ff3a70986..fc5c39dba8f 100644 --- a/src/doc/en/reference/modules/index.rst +++ b/src/doc/en/reference/modules/index.rst @@ -57,4 +57,19 @@ Modules sage/modules/multi_filtered_vector_space sage/modules/tensor_operations +Finitely presented graded modules +--------------------------------- + +.. toctree:: + :maxdepth: 2 + + sage/modules/fp_graded/free_module + sage/modules/fp_graded/free_element + sage/modules/fp_graded/free_morphism + sage/modules/fp_graded/free_homspace + sage/modules/fp_graded/module + sage/modules/fp_graded/element + sage/modules/fp_graded/morphism + sage/modules/fp_graded/homspace + .. include:: ../footer.txt diff --git a/src/sage/modules/fp_graded/__init__.py b/src/sage/modules/fp_graded/__init__.py new file mode 100755 index 00000000000..2e5420c89a1 --- /dev/null +++ b/src/sage/modules/fp_graded/__init__.py @@ -0,0 +1,12 @@ +""" +Finitely presented graded left modules over graded connected algebras +""" + + +# TODO: +# +# 1. Why do we need to define __bool__ and __eq__ in element.py? They should be taken care of automatically, once we define __nonzero__. +# 2. inhheritance: free modules, elements, etc., should perhaps inherit from fp versions, or maybe both should inherit from generic classes, to consolidate some methods (like degree, _repr_, others?) +# 3. Test with graded modules over other graded rings. (Should be okay, but add some doctests.) +# +# In __classcall__/__init__ for FP_Modules, allow as input a free module or a morphism of free modules? diff --git a/src/sage/modules/fp_graded/element.py b/src/sage/modules/fp_graded/element.py new file mode 100755 index 00000000000..c7f3b24efe5 --- /dev/null +++ b/src/sage/modules/fp_graded/element.py @@ -0,0 +1,322 @@ +r""" +Elements of finitely presented graded modules + +This class implements construction and basic manipulation of elements of the +Sage parent :class:`sage.modules.fp_graded.module.FP_Module`, which models +finitely presented modules over connected graded algebras. + +AUTHORS: + +- Robert R. Bruner, Michael J. Catanzaro (2012): Initial version. +- Sverre Lunoee--Nielsen and Koen van Woerden (2019-11-29): Updated the + original software to Sage version 8.9. +- Sverre Lunoee--Nielsen (2020-07-01): Refactored the code and added + new documentation and tests. +""" + +#***************************************************************************** +# Copyright (C) 2011 Robert R. Bruner and +# Michael J. Catanzaro +# +# 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 sage.misc.cachefunc import cached_method +from sage.modules.with_basis.indexed_element import IndexedFreeModuleElement + +from .free_element import FreeGradedModuleElement + + +class FP_Element(IndexedFreeModuleElement): + r""" + A module element of a finitely presented graded module over + a connected graded algebra. + + TESTS: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: FP_Module(SteenrodAlgebra(2), [0])([Sq(2)]) + + """ + def free_element(self): + r""" + A lift of this element to the free module F, + if this element is in a quotient of F. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: M = FP_Module(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) + sage: x = M([Sq(1), 1]) + sage: x + + sage: x.parent() + Finitely presented left module on 2 generators and 1 relation over mod 2 Steenrod algebra, milnor basis + sage: x.free_element() + + sage: x.free_element().parent() + Finitely presented free left module on 2 generators over mod 2 Steenrod algebra, milnor basis + """ + C = self.parent().j.codomain() + return C(self.dense_coefficient_list()) + + + @cached_method + def degree(self): + r""" + The degree of this element. + + OUTPUT: The integer degree of this element, or ``None`` if this is the + zero element. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: M = FP_Module(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) + sage: x = M.an_element(7) + + sage: x + + sage: x.degree() + 7 + + The zero element has no degree:: + + sage: (x-x).degree() + Traceback (most recent call last): + ... + ValueError: the zero element does not have a well-defined degree + + TESTS: + + sage: N = FP_Module(SteenrodAlgebra(2), [0], [[Sq(2)]]) + sage: y = Sq(2)*N.generator(0) + sage: y == 0 + True + sage: y.degree() + Traceback (most recent call last): + ... + ValueError: the zero element does not have a well-defined degree + """ + if self.is_zero(): + raise ValueError("the zero element does not have a well-defined degree") + return self.free_element().degree() + + + def _repr_(self): + r""" + Return a string representation of this element. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: M = FP_Module(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) + sage: [M.an_element(n) for n in range(1,10)] + [, + , + , + , + , + , + , + , + ] + """ + return self.free_element()._repr_() + + + def _lmul_(self, a): + r""" + Act by left multiplication on this element by ``a``. + + INPUT: + + - ``a`` -- an element of the algebra this module is defined over. + + OUTPUT: the module element `a\cdot x` where `x` is this module element. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: M = FP_Module(A2, [0,3], [[Sq(2)*Sq(4), Sq(3)]]) + sage: A2.Sq(2)*M.generator(1) + <0, Sq(2)> + sage: A2.Sq(2)*(A2.Sq(1)*A2.Sq(2)*M.generator(0) + M.generator(1)) + + + TESTS: + + sage: elements = [M.an_element(n) for n in range(1,10)] + sage: a = A2.Sq(3) + sage: [a*x for x in elements] + [, + <0, 0>, + , + <0, Sq(1,1)>, + <0, 0>, + , + , + , + <0, Sq(3,2)>] + """ + return self.parent()(a*self.free_element()) + + + def vector_presentation(self): + r""" + A coordinate vector representing this module element when it is non-zero. + + These are coordinates with respect to the basis chosen by + :meth:`sage.modules.fp_graded.module.FP_Module.basis_elements`. + When the element is zero, it has no well defined degree, and this + function returns ``None``. + + OUTPUT: A vector of elements in the ground field of the algebra for + this module when this element is non-zero. Otherwise, the value + ``None``. + + .. SEEALSO:: + + :meth:`sage.modules.fp_graded.module.FP_Module.vector_presentation` + :meth:`sage.modules.fp_graded.module.FP_Module.basis_elements` + :meth:`sage.modules.fp_graded.module.FP_Module.element_from_coordinates` + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: M = FP_Module(A2, (0,1)) + + sage: x = M.an_element(7) + sage: v = x.vector_presentation(); v + (1, 0, 0, 0, 0, 1, 0) + sage: type(v) + + + sage: V = M.vector_presentation(7) + sage: v in V + True + + sage: M.element_from_coordinates(v, 7) == x + True + + We can use the basis for the module elements in the degree of `x`, + together with the coefficients `v` to recreate the element `x`:: + + sage: basis = M.basis_elements(7) + sage: x_ = sum( [c*b for (c,b) in zip(v, basis)] ); x_ + + sage: x == x_ + True + + TESTS: + + sage: M.zero().vector_presentation() is None + True + """ + # We cannot represent the zero element since it does not have a degree, + # and we therefore do not know which vector space it belongs to. + # + # In this case, we could return the integer value 0 since coercion would + # place it inside any vector space. However, this will not work for + # homomorphisms, so we return None to be consistent. + try: + degree = self.free_element().degree() + except ValueError: + return None + + F_n = self.parent().vector_presentation(degree) + return F_n.quotient_map()(self.free_element().vector_presentation()) + + + def __nonzero__(self): + r""" + Determine if this element is non-zero. + + OUTPUT: The boolean value ``True`` if this element is non-zero, and ``False`` + otherwise. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: M = FP_Module(SteenrodAlgebra(2), [0,2,4], [[Sq(4),Sq(2),0]]) + sage: M(0).__nonzero__() + False + sage: M((Sq(6), 0, Sq(2))).__nonzero__() + True + sage: a = M((Sq(1)*Sq(2)*Sq(1)*Sq(4), 0, 0)) + sage: b = M((0, Sq(2)*Sq(2)*Sq(2), 0)) + sage: a.__nonzero__() + True + sage: b.__nonzero__() + True + sage: (a + b).__nonzero__() + False + """ + pres = self.vector_presentation() + if pres is None: + return False + return bool(pres) + + __bool__ = __nonzero__ + + def __eq__(self, other): + r""" + True iff ``self`` and ``other`` are equal. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: M = FP_Module(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) + sage: x = M([Sq(1), 1]) + sage: x + + sage: x == x + True + sage: x == M.zero() + False + sage: x-x == M.zero() + True + """ + try: + return (self - other).is_zero() + except TypeError: + return False + + + def normalize(self): + r""" + A normalized form of ``self``. + + OUTPUT: An instance of this element class representing the same + module element as this element. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: M = FP_Module(SteenrodAlgebra(2), [0,2,4], [[Sq(4),Sq(2),0]]) + + sage: m = M((Sq(6), 0, Sq(2))); m + + sage: m.normalize() + + sage: m == m.normalize() + True + + sage: n = M((Sq(4), Sq(2), 0)); n + + sage: n.normalize() + <0, 0, 0> + sage: n == n.normalize() + True + """ + if self.is_zero(): + return self.parent().zero() + + v = self.vector_presentation() + return self.parent().element_from_coordinates(v, self.degree()) diff --git a/src/sage/modules/fp_graded/free_element.py b/src/sage/modules/fp_graded/free_element.py new file mode 100755 index 00000000000..d7b2bfbc8ed --- /dev/null +++ b/src/sage/modules/fp_graded/free_element.py @@ -0,0 +1,239 @@ +r""" +Elements of finitely generated free graded left modules + +This class implements construction and basic manipulation of +elements of the Sage parent +:class:`sage.modules.fp_graded.free_module.FreeModule`, which models +free graded left modules over connected algebras. + +For an overview of the free module API, see :doc:`free_module`. + +AUTHORS: + +- Robert R. Bruner, Michael J. Catanzaro (2012): Initial version. +- Sverre Lunoee--Nielsen and Koen van Woerden (2019-11-29): Updated the + original software to Sage version 8.9. +- Sverre Lunoee--Nielsen (2020-07-01): Refactored the code and added + new documentation and tests. +""" + +#***************************************************************************** +# Copyright (C) 2019 Robert R. Bruner +# and Michael J. Catanzaro +# +# 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 sage.misc.cachefunc import cached_method +from sage.modules.with_basis.indexed_element import IndexedFreeModuleElement + +class FreeGradedModuleElement(IndexedFreeModuleElement): + r""" + Create a module element of a finitely generated free graded left module + over a connected graded algebra. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: M = FreeGradedModule(SteenrodAlgebra(2), (0, 1)) + + sage: M([0, 0]) + <0, 0> + + sage: M([1, 0]) + <1, 0> + + sage: M([0, 1]) + <0, 1> + + sage: M([Sq(1), 1]) + + """ + def degree(self): + r""" + The degree of this element. + + OUTPUT: the integer degree of this element, or None if this is the zero + element. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import * + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (0,1)) + sage: x = M.an_element(7); x + + sage: x.degree() + 7 + + The zero element has no degree:: + + sage: (x-x).degree() + Traceback (most recent call last): + ... + ValueError: the zero element does not have a well-defined degree + + Neither do non-homogeneous slements + + sage: y = M.an_element(4) + sage: (x+y).degree() + Traceback (most recent call last): + ... + ValueError: this is a nonhomogeneous element, no well-defined degree + """ + if self.is_zero(): + raise ValueError("the zero element does not have a well-defined degree") + degrees = [] + try: + for g, c in zip(self.parent().generator_degrees(), + self.dense_coefficient_list()): + if c: + degrees.append(g + c.degree()) + except ValueError: + raise ValueError("this is a nonhomogeneous element, no well-defined degree") + m = min(degrees) + M = max(degrees) + if m == M: + return m + raise ValueError("this is a nonhomogeneous element, no well-defined degree") + + + def _repr_(self): + r""" + Return a string representation of this element. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import * + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (0,1)) + sage: [M.an_element(n) for n in range(1,10)] + [, + , + , + , + , + , + , + , + ] + """ + return '<%s>' % ', '.join(['%s' % c for c in self.dense_coefficient_list()]) + + + def _lmul_(self, a): + r""" + Act by left multiplication on this element by ``a``. + + INPUT: + + - ``a`` -- an element of the algebra this module is defined over. + + OUTPUT: the module element `a\cdot x` where `x` is this module element. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import * + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: M = FreeGradedModule(A2, (0,0,3)) + sage: A2.Sq(2)*M.generator(1) + <0, Sq(2), 0> + sage: A2.Sq(2)*(A2.Sq(1)*A2.Sq(2)*M.generator(1) + M.generator(2)) + <0, Sq(2,1), Sq(2)> + + TESTS: + + sage: elements = [M.an_element(n) for n in range(1,10)] + sage: a = A2.Sq(3) + sage: [a*x for x in elements] + [, + <0, 0, 0>, + , + <0, 0, Sq(1,1)>, + <0, 0, 0>, + , + , + , + <0, 0, Sq(3,2)>] + """ + return self.parent()((a*c for c in self.dense_coefficient_list())) + + @cached_method + def vector_presentation(self): + r""" + A coordinate vector representing this module element when it is non-zero. + + These are coordinates with respect to the basis chosen by + :meth:`sage.modules.fp_graded.free_module.FreeGradedModule.basis_elements`. + When the element is zero, it has no well defined degree, and this + function returns ``None``. + + OUTPUT: A vector of elements in the ground field of the algebra for + this module when this element is non-zero. Otherwise, the value + ``None``. + + .. SEEALSO:: + + :meth:`sage.modules.fp_graded.free_module.FreeGradedModule.vector_presentation` + :meth:`sage.modules.fp_graded.free_module.FreeGradedModule.basis_elements` + :meth:`sage.modules.fp_graded.free_module.FreeGradedModule.element_from_coordinates` + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import * + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: M = FreeGradedModule(A2, (0,1)) + sage: x = M.an_element(7) + sage: v = x.vector_presentation(); v + (1, 0, 0, 0, 0, 1, 0) + sage: type(v) + + + sage: V = M.vector_presentation(7) + sage: v in V + True + + sage: M.element_from_coordinates(v, 7) == x + True + + We can use the basis for the module elements in the degree of `x`, + together with the coefficients `v` to recreate the element `x`:: + + sage: basis = M.basis_elements(7) + sage: x_ = sum( [c*b for (c,b) in zip(v, basis)] ); x_ + + sage: x == x_ + True + + TESTS: + + sage: M.zero().vector_presentation() is None + True + """ + # We cannot represent the zero element since it does not have a degree, + # and we therefore do not know which vector space it belongs to. + # + # In this case, we could return the integer value 0 since coercion would + # place it inside any vector space. However, this will not work for + # homomorphisms, so we we return None to be consistent. + if self.is_zero(): + return None + + bas_gen = self.parent().basis_elements(self.degree()) + base_vec = self.parent().vector_presentation(self.degree()) + + base_dict = dict(zip(bas_gen, base_vec.basis())) + + # Create a sparse representation of the element. + sparse_coeffs = [x for x in enumerate(self.dense_coefficient_list()) if not x[1].is_zero()] + + vector = base_vec.zero() + for summand_index, algebra_element in sparse_coeffs: + for scalar_coefficient, monomial in zip(algebra_element.coefficients(), algebra_element.monomials()): + vector += scalar_coefficient*base_dict[monomial*self.parent().generator(summand_index)] + + return vector diff --git a/src/sage/modules/fp_graded/free_homspace.py b/src/sage/modules/fp_graded/free_homspace.py new file mode 100755 index 00000000000..ccdfc37ed66 --- /dev/null +++ b/src/sage/modules/fp_graded/free_homspace.py @@ -0,0 +1,196 @@ +r""" +The set of homomorphisms of finitely generated free graded left modules + +This class implements methods for construction and basic manipulation +of homsets of finitely generated free graded left modules over a +connected graded `k`-algebra, where `k` is a field. + +For an overview of the free module API, see :doc:`free_module`. + +TESTS: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: from sage.misc.sage_unittest import TestSuite + sage: A = SteenrodAlgebra(2) + sage: F1 = FreeGradedModule(A, (1,3)) + sage: F2 = FreeGradedModule(A, (2,3)) + sage: homset = Hom(F1, F2); homset + Set of Morphisms from Finitely presented free left module on 2 generators ... + sage: homset([F2((Sq(1), 1)), F2((0, Sq(2)))]) + Module homomorphism of degree 2 defined by sending the generators + [<1, 0>, <0, 1>] + to + [, <0, Sq(2)>] + sage: TestSuite(homset).run() + +AUTHORS: + +- Robert R. Bruner, Michael J. Catanzaro (2012): Initial version. +- Sverre Lunoee--Nielsen and Koen van Woerden (2019-11-29): Updated the + original software to Sage version 8.9. +- Sverre Lunoee--Nielsen (2020-07-01): Refactored the code and added + new documentation and tests. +""" + +#***************************************************************************** +# Copyright (C) 2011 Robert R. Bruner and +# Michael J. Catanzaro +# +# 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 sage.categories.homset import Homset +from sage.misc.cachefunc import cached_method + + +def is_FreeGradedModuleHomspace(x): + r""" + Check if the given object is of type FreeGradedModuleHomspace. + + OUTPUT: The boolean ``True`` if and only if ``x`` is of type + FreeGradedModuleHomspace, and ``False`` otherwise. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: from sage.modules.fp_graded.free_homspace import is_FreeGradedModuleHomspace + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: F = FreeGradedModule(A2, (1,3)) + sage: L = FreeGradedModule(A2, (2,3)) + sage: is_FreeGradedModuleHomspace(Hom(F, L)) + True + + TESTS: + + sage: is_FreeGradedModuleHomspace(0) + False + """ + return isinstance(x, FreeGradedModuleHomspace) + +class FreeGradedModuleHomspace(Homset): + # In the category framework, Elements of the class FP_Module are of the + # class FP_Element, see + # http://doc.sagemath.org/html/en/thematic_tutorials/coercion_and_categories.html#implementing-the-category-framework-for-the-elements + from .free_morphism import FreeGradedModuleMorphism + + Element = FreeGradedModuleMorphism + + def _element_constructor_(self, values): + r""" + Construct any element of this homset. + + This function is used internally by the ()-method when creating + homomorphisms. + + INPUT: + + - ``values`` -- A tuple of values (i.e. elements of the + codomain for this homset) corresponding bijectively to the generators + of the domain of this homset, or the zero integer constant. + + OUTPUT: An instance of the morphism class. The returned morphism is + defined by mapping the module generators in the domain to the given + values. + + OUTPUT: A module homomorphism. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: F = FreeGradedModule(A2, (1,3)) + sage: L = FreeGradedModule(A2, (2,5)) + sage: H = Hom(F, L) + + sage: values = (A2.Sq(4)*L.generator(0), A2.Sq(3)*L.generator(1)) + sage: f = H(values); f + Module homomorphism of degree 5 defined by sending the generators + [<1, 0>, <0, 1>] + to + [, <0, Sq(3)>] + + sage: H(0) + The trivial homomorphism. + """ + from .free_morphism import FreeGradedModuleMorphism + if isinstance(values, FreeGradedModuleMorphism): + return values + elif values == 0 or all(v.is_zero() for v in values): + return self.zero() + else: + return self.element_class(self, values) + + + def _an_element_(self): + r""" + Return a morphism belonging to this homspace. + + OUTPUT: A morphism in this homspace. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: F = FreeGradedModule(A2, (1,3)) + sage: L = FreeGradedModule(A2, (2,3)) + sage: H = Hom(F, L) + sage: H._an_element_() + The trivial homomorphism. + """ + return self.zero() + + + @cached_method + def zero(self): + r""" + Return the trivial morphism of this homspace. + + OUTPUT: The morphism evaluating to the zero element for any element in + the domain. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: F = FreeGradedModule(A2, (1,3)) + sage: L = FreeGradedModule(A2, (2,3)) + sage: H = Hom(F, L) + sage: H.zero() + The trivial homomorphism. + """ + return self.element_class(self, self.codomain().zero()) + + + def identity(self): + r""" + Return the identity morphism, if this is an endomorphism set. + + OUTPUT: The identity endomorphism. + + TESTS: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: L = FreeGradedModule(A2, (2,3)) + sage: H = Hom(L, L) + sage: H.identity() + The identity homomorphism. + + TESTS: + + sage: F = FreeGradedModule(A2, (1,3)) + sage: H = Hom(F, L) + sage: H.identity() + Traceback (most recent call last): + ... + TypeError: this homspace does not consist of endomorphisms + """ + if self.is_endomorphism_set(): + return self.element_class(self, self.codomain().generators()) + else: + raise TypeError('this homspace does not consist of endomorphisms') + diff --git a/src/sage/modules/fp_graded/free_module.py b/src/sage/modules/fp_graded/free_module.py new file mode 100755 index 00000000000..63ab4187cb0 --- /dev/null +++ b/src/sage/modules/fp_graded/free_module.py @@ -0,0 +1,767 @@ +r""" +Finitely generated free graded left modules over connected graded algebras. + +This class implements methods for construction and basic manipulation of +finitely generated free graded modules over connected graded algebras. + +========== +User guide +========== + +Let `p` be a prime number. The mod `p` Steenrod algebra `A_p` +is a connected algebra over the finite field of `p` elements. All modules +presented here will be defined over `A_p`, or one of its sub-Hopf algebras. +E.g.:: + + sage: A = SteenrodAlgebra(p=2) + +The constructor of the module class takes as arguments the algebra +over which the module is defined and an ordered tuple of degrees for +the generators:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: M = FreeGradedModule(algebra=A, generator_degrees=(0,1)); M + Finitely presented free left module on 2 generators over mod 2 Steenrod algebra, milnor basis + +The resulting free module will have generators in the degrees given to its +constructor:: + + sage: M.generator_degrees() + (0, 1) + +The connectivity of a module over a connected graded algebra is the minimum +degree of all its module generators. Thus, if the module is non-trivial, the +connectivity is an integer:: + + sage: M.connectivity() + 0 + +--------------- +Module elements +--------------- + +For an `A`-module with generators `\{g_i\}_{i=1}^N`, any homogeneous element +of degree `n` has the form + +.. MATH:: + + x = \sum_{i=1}^N a_i\cdot g_i\,, + +where `a_i\in A_{n-\deg(g_i)}` for all `i`. The ordered set `\{a_i\}` +is referred to as the coefficients of `x`. + +Module elements are displayed by their algebra coefficients:: + + sage: M.an_element(n=5) + + + sage: M.an_element(n=15) + + +The generators are themselves elements of the module:: + + sage: M.generators() + [<1, 0>, <0, 1>] + +Producing elements from a given set of coefficients is possible using the +module class ()-method:: + + sage: coeffs=[Sq(5), Sq(1,1)] + sage: x = M(coeffs); x + + +The module action produces new elements:: + + sage: Sq(2)*x + + +Each non-zero element has a well-defined degree:: + + sage: x.degree() + 5 + +But the zero element has not:: + + sage: zero = M.zero(); zero + <0, 0> + sage: zero.degree() + Traceback (most recent call last): + ... + ValueError: the zero element does not have a well-defined degree + +Any two elements can be added as long as they are in the same degree:: + + sage: y = M.an_element(5); y + + sage: x + y + + +or when at least one of them is zero:: + + sage: x + zero == x + True + +Finally, additive inverses exist:: + + sage: x - x + <0, 0> + +For every integer `n`, the set of module elements of degree `n` form a +vector space over the ground field `k`. A basis for this vector space can be +computed:: + + sage: M.basis_elements(5) + [, , <0, Sq(1,1)>, <0, Sq(4)>] + +together with a corresponding vector space presentation:: + + sage: M.vector_presentation(5) + Vector space of dimension 4 over Finite Field of size 2 + +Given any element, its coordinates with resepct to this basis can be computed:: + + sage: v = x.vector_presentation(); v + (0, 1, 1, 0) + +Going the other way, any element can be constructed by specifying its +coordinates:: + + sage: x_ = M.element_from_coordinates((0,1,1,0), 5) + sage: x_ + + sage: x_ == x + True + +-------------------- +Module homomorphisms +-------------------- + +Homomorphisms of free graded `A`-modules `M\to N` are linear maps of their +underlying `k`-vector spaces which commute with the `A`-module structure. + +To create a homomorphism, first create the object modelling the set of all +such homomorphisms using the free function ``Hom``:: + + sage: M = FreeGradedModule(A, (0,1)) + sage: N = FreeGradedModule(A, (2,)) + sage: homspace = Hom(M, N); homspace + Set of Morphisms from Finitely presented free left module on 2 generators over mod 2 Steenrod algebra, milnor basis to Finitely presented free left module on 1 generator over mod 2 Steenrod algebra, milnor basis in Category of finite dimensional graded modules with basis over mod 2 Steenrod algebra, milnor basis + +Just as module elements, homomorphisms are created using the ()-method +of the homspace object. The only argument is a list of module elements in the +codomain, corresponding to the module generators of the domain:: + + sage: g = N([1]) # the generator of the codomain module. + sage: values = [Sq(2)*g, Sq(2)*Sq(1)*g] + sage: f = homspace(values) + +The resulting homomorphism is the one sending the `i`-th generator of the +domain to the `i`-th codomain value given:: + + sage: f + Module homomorphism of degree 4 defined by sending the generators + [<1, 0>, <0, 1>] + to + [, ] + +Convenience methods exist for creating the trivial morphism:: + + sage: homspace.zero() + The trivial homomorphism. + +as well as the identity endomorphism:: + + sage: Hom(M, M).identity() + The identity homomorphism. + +Homomorphisms can be evaluated on elements of the domain module:: + + sage: v1 = f(Sq(7)*M.generator(0)); v1 + + + sage: v2 = f(Sq(17)*M.generator(1)); v2 + + +and they respect the module action:: + + sage: v1 == Sq(7)*f(M.generator(0)) + True + + sage: v2 == Sq(17)*f(M.generator(1)) + True + +Any non-trivial homomorphism has a well-defined degree:: + + sage: f.degree() + 4 + +but just as module elements, the trivial homomorphism does not:: + + sage: zero_map = homspace.zero() + sage: zero_map.degree() + Traceback (most recent call last): + ... + ValueError: the zero morphism does not have a well-defined degree + +Any two homomorphisms can be added as long as they are of the same degree:: + + sage: f2 = homspace([Sq(2)*g, Sq(3)*g]) + sage: f + f2 + Module homomorphism of degree 4 defined by sending the generators + [<1, 0>, <0, 1>] + to + [<0>, ] + +or when at least one of them is zero:: + + sage: f + zero_map == f + True + +Finally, additive inverses exist:: + + sage: f - f + The trivial homomorphism. + +The restriction of a homomorphism to the vector space of `n`-dimensional module +elements is a linear transformation:: + + sage: f_4 = f.vector_presentation(4); f_4 + Vector space morphism represented by the matrix: + [0 1 0] + [1 1 1] + [0 1 0] + [0 0 0] + Domain: Vector space of dimension 4 over Finite Field of size 2 + Codomain: Vector space of dimension 3 over Finite Field of size 2 + +This is compatible with the vector presentations of its domain and codomain +modules:: + + sage: f.domain() is M + True + sage: f.codomain() is N + True + sage: f_4.domain() is M.vector_presentation(4) + True + sage: f_4.codomain() is N.vector_presentation(4 + f.degree()) + True + + +AUTHORS: + +- Robert R. Bruner, Michael J. Catanzaro (2012): Initial version. +- Sverre Lunoee--Nielsen and Koen van Woerden (2019-11-29): Updated the + original software to Sage version 8.9. +- Sverre Lunoee--Nielsen (2020-07-01): Refactored the code and added + new documentation and tests. +""" + +#***************************************************************************** +# Copyright (C) 2019 Robert R. Bruner +# and Michael J. Catanzaro +# +# 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 sage.misc.cachefunc import cached_method +from sage.modules.free_module import VectorSpace +from sage.rings.infinity import PlusInfinity +from sage.categories.graded_modules_with_basis import GradedModulesWithBasis +from sage.combinat.free_module import CombinatorialFreeModule + +from .free_element import FreeGradedModuleElement +from .free_homspace import FreeGradedModuleHomspace + +class FreeGradedModule(CombinatorialFreeModule): + r""" + Create a finitely generated free graded module over a connected + graded algebra, with generators in specified degrees. + + INPUT: + + - ``algebra`` -- the connected algebra over which the module is defined. + + - ``generator_degrees`` -- a tuple of integers defining + the number of generators of the module, and their degrees. + + OUTPUT: The finitely generated free graded module on generators with + degrees given by ``generator_degrees``. + + TESTS: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A = SteenrodAlgebra(2) + sage: FreeGradedModule(A, (-2,2,4)) + Finitely presented free left module on 3 generators over mod 2 Steenrod algebra, milnor basis + """ + def __init__(self, algebra, generator_degrees): + r""" + Create a finitely generated free graded module over a connected graded + algebra. + """ + # If generator_degrees is [d_0, d_1, ...], then + # the generators are indexed by (0,d_0), (1,d_1), ... + keys = [(i,deg) for i,deg in enumerate(generator_degrees)] + self._generator_keys = keys + + if not algebra.base_ring().is_field(): + raise ValueError('the ground ring of the algebra must be a field') + + # Call the base class constructor. + CombinatorialFreeModule.__init__(self, algebra, + basis_keys=keys, + element_class=FreeGradedModuleElement, + category=GradedModulesWithBasis(algebra)) + + + def generator_degrees(self): + r""" + The degrees of the module generators. + + OUTPUT: A tuple containing the degrees of the generators for this + module, in the order that the generators were given when this module + was constructed. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import * + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (-2,2,4)) + sage: M.generator_degrees() + (-2, 2, 4) + """ + return tuple(a[1] for a in self._generator_keys) + + + def is_trivial(self): + r""" + Decide if this module is trivial or not. + + OUTPUT: The boolean value ``True`` if the module is trivial, and + ``False`` otherwise. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import * + sage: A = SteenrodAlgebra(2) + sage: FreeGradedModule(A, (-2,2,4)).is_trivial() + False + sage: FreeGradedModule(A, ()).is_trivial() + True + """ + return len(self.generator_degrees()) == 0 + + + def connectivity(self): + r""" + The connectivity of this module. + + OUTPUT: An integer equal to the minimal degree of all the generators, if + this module is non-trivial. Otherwise, `+\infty`. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import * + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (-2,2,4)) + sage: M.connectivity() + -2 + + TESTS: + + sage: M = FreeGradedModule(A, ()) + sage: M.is_trivial() + True + sage: M.connectivity() + +Infinity + """ + return min(self.generator_degrees() + (PlusInfinity(),)) + + + def _element_constructor_(self, coefficients): + r""" + Construct any element of the module. + + This function is used internally by the ()-method when creating + module elements, and should not be called by the user explicitly. + + INPUT: + + - ``coefficients`` -- A tuple of coefficient (i.e. elements of the + algebra for this module), an element of FreeGradedModule, or the zero integer + constant. + + OUTPUT: An instance of the element class with coefficients from + ``coefficients``, the element ``coefficients`` if it already was an + element, or the zero module element. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import * + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (0,2,4)) + + sage: zero = M(0); zero + <0, 0, 0> + + sage: e = M((Sq(4), Sq(2), 1)); e + + + sage: e is M(e) + True + """ + if isinstance(coefficients, self.element_class): + return coefficients + elif not coefficients: + return self.zero() + else: + B = self.basis() + return sum(c*B[b] for (c,b) in zip(coefficients, self._generator_keys)) + + + def an_element(self, n=None): + r""" + Return an element of the module. + + This function chooses deterministically an element of the module in the + given degree. + + INPUT: + + - ``n`` -- the degree of the element to construct. If the default + value ``None`` is given, a degree will be chosen by the function. + + OUTPUT: An element of the given degree. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import * + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (0,2,4)) + sage: M.an_element(172) + + + Zero is the only element in the trivial module:: + + sage: FreeGradedModule(A, ()).an_element() + <> + """ + if len(self.generator_degrees()) == 0: + return self.zero() + + if n == None: + n = max(self.generator_degrees()) + 7 + + coefficients = [] + for g in self.generator_degrees(): + basis = self.base_ring().basis(n - g) if n >= g else () + # All of the algebra generators in basis will bring the + # module generator in dimension g to dimension + # g + (topDimension - g) = topDimension. Picking any one of them + # will do, so we pick the one with index (g (mod l)). + l = len(basis) + if l: + coefficients.append(basis[g % l]) + else: + coefficients.append(self.base_ring().zero()) + + return self(coefficients) + + + def _repr_(self): + r""" + Construct a string representation of the module. + + TESTS: + + sage: from sage.modules.fp_graded.free_module import * + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (0,2,4)) + sage: M._repr_() + 'Finitely presented free left module on 3 generators over mod 2 Steenrod algebra, milnor basis' + """ + return "Finitely presented free left module on %s generator%s over %s"\ + %(len(self.generator_degrees()), "" if len(self.generator_degrees()) == 1 else "s", + self.base_ring()) + + + @cached_method + def basis_elements(self, n): + r""" + A basis for the vector space of degree ``n`` module elements. + + INPUT: + + - ``n`` -- an integer. + + OUTPUT: A sequence of homogeneous module elements of degree ``n`` + which is a basis for the vector space of all degree ``n`` module + elements. + + .. SEEALSO:: + :meth:`vector_presentation`, :meth:`element_from_coordinates` + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import * + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (0,2,4)) + sage: M.basis_elements(8) + [, + , + , + , + <0, Sq(0,2), 0>, + <0, Sq(3,1), 0>, + <0, Sq(6), 0>, + <0, 0, Sq(1,1)>, + <0, 0, Sq(4)>] + """ + basis_n = [] + for i, generator_degree in enumerate(self.generator_degrees()): + l = n - generator_degree + basis_n += [a*self.generator(i) for a in self.base_ring().basis(l)] + + return basis_n + + + @cached_method + def element_from_coordinates(self, coordinates, n): + r""" + The module element of degree ``n`` having the given coordinates + with respect to the basis of module elements given by + :meth:`basis_elements`. + + INPUT: + + - ``coordinates`` -- a sequence of elements of the ground field. + - ``n`` -- an integer. + + OUTPUT: A module element of degree ``n``. + + .. SEEALSO:: + :meth:`vector_presentation`, and :meth:`basis_elements`. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import * + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (0,1)) + sage: x = M.element_from_coordinates((0,1,0,1), 5); x + + sage: basis = M.basis_elements(5) + sage: y = 0*basis[0] + 1*basis[1] + 0*basis[2] + 1*basis[3] + sage: x == y + True + + sage: M.element_from_coordinates((0,0,0,0), 5) + <0, 0> + """ + basis_elements = self.basis_elements(n) + + if len(coordinates) != len(basis_elements): + raise ValueError('the given coordinate vector has incorrect length: %d. ' + 'It should have length %d' % (len(coordinates), len(basis_elements))) + + # Adding the condition `if c != 0` improved performance dramatically in this + # real life example: + # + # sage: rels = [ [Sq(1),0,0,0], [Sq(2),0,0,0], [Sq(4),0,0,0], [Sq(8),0,0,0], [0,Sq(1),0, + # ....: 0], [0,Sq(2),0,0], [0,Sq(4),0,0], [Sq(31),Sq(14),0,0], [0,Sq(20),0,0], [0,0,Sq(1 + # ....: ),0], [0,0,Sq(2),0], [0,Sq(31),Sq(6),0], [0,0,Sq(8),0], [0,0,0,Sq(1)], [0,0,Sq(3 + # ....: 1),Sq(2)], [0,0,0,Sq(4)], [0,0,0,Sq(8)] ] + # ....: + # ....: M = FPA_Module([0, 17, 42, 71], A, relations=rels) + # sage: res = M.resolution(2, top_dim=30, verbose=True) + # + # This function was called a total of 2897 times during the computation, + # and the total running time of the entire computation dropped from + # 57 to 21 seconds by adding the optimization. + # + element = sum([c*element for c, element in zip(coordinates, basis_elements) if c != 0]) + if element == 0: + # The previous sum was over the empty list, yielding the integer + # 0 as a result, rather than a module element. + # Fix this by returning the zero element. + return self.zero() + else: + # The sum defining element is of the correct type, so return it. + return element + + + def __getitem__(self, n): + r""" + A vector space isomorphic to the vector space of module elements of + degree ``n``. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import * + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (0,2,4)) + sage: V = M[4]; V + Vector space of dimension 4 over Finite Field of size 2 + sage: V.dimension() + 4 + + .. SEEALSO:: + This function is an alias for :meth:`vector_presentation`. + """ + return self.vector_presentation(n) + + + @cached_method + def vector_presentation(self, n): + r""" + A vector space over the ground field of the module algebra, + isomorphic to the degree ``n`` elements of this module. + + Let `\mathcal{k}` be the ground field of the algebra over this module is defined, + and let `M_n` be the vector space of module elements of degree ``n``. + + The return value of this function is the vector space + `\mathcal{k}^{r}` where `r = dim(M_n)`. + + The isomorphism between `k^{r}` and `M_n` is given by the + bijection taking the standard basis element `e_i` to the `i`-th + element of the array returned by :meth:`basis_elements`. + + INPUT: + + - ``n`` -- an integer degree. + + OUTPUT: A vector space over the ground field of the algebra over which + this module is defined, isomorphic to the vector space of module + elements of degree ``n``. + + .. SEEALSO:: + :meth:`basis_elements`, :meth:`element_from_coordinates` + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import * + sage: A1 = SteenrodAlgebra(2, profile=[2,1]) + sage: M = FreeGradedModule(A1, (0,)) + sage: M.vector_presentation(3) + Vector space of dimension 2 over Finite Field of size 2 + sage: M.basis_elements(3) + [, ] + sage: [M.vector_presentation(i).dimension() for i in range(-2, 9)] + [0, 0, 1, 1, 1, 2, 1, 1, 1, 0, 0] + """ + return VectorSpace(self.base_ring().base_ring(), len(self.basis_elements(n))) + + + @cached_method + def generator(self, index): + r""" + Return the module generator with the given index. + + OUTPUT: An instance of the element class of this parent. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import * + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (0,2,4)) + sage: M.generator(0) + <1, 0, 0> + sage: M.generator(1) + <0, 1, 0> + sage: M.generator(2) + <0, 0, 1> + """ + try: + key = self._generator_keys[index] + except IndexError: + raise ValueError('the parent module has generators in the index '\ + 'range [0, %s]; generator %s does not exist' %\ + (len(self.generator_degrees()) - 1, index)) + + return self.monomial(self._generator_keys[index]) + + + def generators(self): + r""" + Return all the module generators. + + OUTPUT: A list consisting instances of the element class of this + parent. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import * + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (0,1)) + sage: M.generators() + [<1, 0>, <0, 1>] + """ + return [self.generator(i) for i in range(len(self.generator_degrees()))] + + + def _Hom_(self, Y, category): + r""" + The internal hook used by the free function + :meth:`sage.categories.homset.hom.Hom` to create homsets involving this + parent. + + TESTS: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (0,1)) + sage: M._Hom_(M, category=None) + Set of Morphisms from Finitely presented free left module on 2 generators over mod 2 Steenrod algebra, milnor basis to Finitely presented free left module on 2 generators over mod 2 Steenrod algebra, milnor basis in Category of finite dimensional graded modules with basis over mod 2 Steenrod algebra, milnor basis + """ + return FreeGradedModuleHomspace(self, Y, category) + + + def suspension(self, t): + r""" + Suspend the module by the given integer degree. + + INPUT: + + - ``t`` -- An integer. + + OUTPUT: A module which is isomorphic to this module by a shift + of degrees by the integer ``t``. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import * + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (0,2,4)) + sage: M.suspension(4).generator_degrees() + (4, 6, 8) + sage: M.suspension(-4).generator_degrees() + (-4, -2, 0) + """ + return FreeGradedModule(algebra=self.base_ring(), + generator_degrees=tuple([g + t for g in self.generator_degrees()])) + + + def to_fp_module(self): + """ + Create a finitely presented module from this free module. + + OUTPUT: the finitely presented module having same set of generators + as this module, no relations. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A = SteenrodAlgebra(2) + sage: F = FreeGradedModule(A, (-2,2,4)) + sage: F.to_fp_module() + Finitely presented left module on 3 generators and 0 relations over mod 2 Steenrod algebra, milnor basis + """ + from .module import FP_Module + return FP_Module(algebra=self.base_ring(), + generator_degrees=self.generator_degrees(), + relations=()) + diff --git a/src/sage/modules/fp_graded/free_morphism.py b/src/sage/modules/fp_graded/free_morphism.py new file mode 100755 index 00000000000..e58de46fb16 --- /dev/null +++ b/src/sage/modules/fp_graded/free_morphism.py @@ -0,0 +1,595 @@ +r""" +Homomorphisms of finitely generated free graded left modules + +This class implements construction and basic manipulation of elements +of the Sage parent +:class:`sage.modules.fp_graded.free_homspace.FreeGradedModuleHomspace`, +which models homomorphisms of free graded left modules over connected +algebras. + +For an overview of the free module API, see :doc:`free_module`. + +AUTHORS: + +- Robert R. Bruner, Michael J. Catanzaro (2012): Initial version. +- Sverre Lunoee--Nielsen and Koen van Woerden (2019-11-29): Updated the + original software to Sage version 8.9. +- Sverre Lunoee--Nielsen (2020-07-01): Refactored the code and added + new documentation and tests. +""" + +#***************************************************************************** +# Copyright (C) 2019 Robert R. Bruner +# and Michael J. Catanzaro +# +# 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 absolute_import + +from inspect import isfunction + +from sage.categories.homset import Hom +from sage.categories.morphism import Morphism +from sage.misc.cachefunc import cached_method + +from .free_homspace import is_FreeGradedModuleHomspace + + +class FreeGradedModuleMorphism(Morphism): + r""" + Create a homomorphism between finitely generated free graded modules. + + INPUT: + + - ``parent`` -- A homspace in the category of finitely generated free + modules. + + - ``values`` -- A list of elements in the codomain. Each element + corresponds (by their ordering) to a module generator in the domain. + + OUTPUT: A module homomorphism defined by sending each generator to its + corresponding value. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A = SteenrodAlgebra(2) + sage: F1 = FreeGradedModule(A, (4,5)) + sage: F2 = FreeGradedModule(A, (3,4)) + sage: F3 = FreeGradedModule(A, (2,3)) + sage: H1 = Hom(F1, F2) + sage: H2 = Hom(F2, F3) + sage: f = H1( ( F2((Sq(4), 0)), F2((0, Sq(4))) ) ) + sage: g = H2( ( F3((Sq(2), 0)), F3((Sq(3), Sq(2))) ) ) + sage: g*f + Module homomorphism of degree 4 defined by sending the generators + [<1, 0>, <0, 1>] + to + [, ] + + TESTS: + + A non-example because the degree is not well-defined:: + + sage: M = FreeGradedModule(A, (0, 0)) + sage: N = FreeGradedModule(A, (0,)) + sage: H = Hom(M, N) + sage: g = N.generator(0) + sage: H([Sq(1)*g, Sq(2)*g]) + Traceback (most recent call last): + ... + ValueError: ill-defined homomorphism: degrees do not match + """ + + def __init__(self, parent, values): + r""" + Create a homomorphism between finitely generated free graded modules. + """ + if not is_FreeGradedModuleHomspace(parent): + raise TypeError('the parent (%s) must be a f.p. free module homset' % parent) + + # Get the values. + C = parent.codomain() + D = parent.domain() + if isfunction(values): + _values = [C(values(g)) for g in D.generators()] + elif values == 0: + _values = len(D.generator_degrees())*[C(0)] + else: + _values = [C(a) for a in values] + + # Check the homomorphism is well defined. + if len(D.generator_degrees()) != len(_values): + raise ValueError('the number of values must equal the number of '\ + 'generators in the domain. Invalid argument: %s' % _values) + + # Compute the degree. + if all(v.is_zero() for v in _values): + # The zero homomorphism does not get a degree. + _degree = None + else: + degrees = [] + for i, value in enumerate(_values): + if not value.is_zero(): + x = value.degree() + xx = D.generator_degrees()[i] + degrees.append(x-xx) + + _degree = min(degrees) + if _degree != max(degrees): + raise ValueError('ill-defined homomorphism: degrees do not match') + + self._degree = _degree + self._values = _values + + Morphism.__init__(self, parent) + + + def degree(self): + r""" + The degree of this homomorphism. + + OUTPUT: The degree of this homomorphism. Raise an error if this is + the trivial homomorphism. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A = SteenrodAlgebra(2) + sage: homspace = Hom(FreeGradedModule(A, (0,1)), FreeGradedModule(A, (0,))) + sage: N = homspace.codomain() + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: f = homspace(values) + sage: f.degree() + 5 + + The zero homomorphism has no degree:: + + sage: homspace.zero().degree() + Traceback (most recent call last): + ... + ValueError: the zero morphism does not have a well-defined degree + """ + if self._degree is None: + # The zero morphism has no degree. + raise ValueError("the zero morphism does not have a well-defined degree") + return self._degree + + + def values(self): + r""" + The values under this homomorphism corresponding to the generators of + the domain module. + + OUTPUT: A sequence of elements of the codomain module. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A = SteenrodAlgebra(2) + sage: homspace = Hom(FreeGradedModule(A, (0,1)), FreeGradedModule(A, (2,))) + sage: N = homspace.codomain() + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: f = homspace(values) + sage: f.values() + [, ] + sage: homspace.zero().values() + [<0>, <0>] + """ + return self._values + + + def _richcmp_(self, other, op): + r""" + Compare this homomorphism to the given homomorphism. + + INPUT: + + - ``other`` -- An instance of this class. + + - ``op`` -- An integer specifying the comparison operation to be + carried out: If ``op`` == 2, then return ``True`` if and only if the + homomorphisms are equal. If ``op`` == 3, then return ``True `` if + and only if the homomorphisms are not equal. Otherwise, + return ``False``. + + OUTPUT: A boolean. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A = SteenrodAlgebra(2) + sage: homspace = Hom(FreeGradedModule(A, (0,1)), FreeGradedModule(A, (2,))) + sage: N = homspace.codomain() + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: f = homspace(values) + sage: f._richcmp_(f, op=2) + True + sage: f._richcmp_(f, op=3) + False + """ + + try: + same = (self - other).is_zero() + except ValueError: + return False + + # Equality + if op == 2: + return same + + # Non-equality + if op == 3: + return not same + + return False + + + def _add_(self, g): + r""" + The pointwise sum of this and the given homomorphism. + + Pointwise addition of two homomorphisms `f` and `g` with the same domain + and codomain is given by the formula `(f+g)(x) = f(x) + g(x)` for + every `x` in the domain of `f`. + + INPUT: + + - ``g`` -- A homomorphism with the same domain and codomain as this + homomorphism. + + OUTPUT: The pointwise sum homomorphism of this and the given + homomorphism. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A = SteenrodAlgebra(2) + sage: homspace = Hom(FreeGradedModule(A, (0,1)), FreeGradedModule(A, (2,))) + sage: N = homspace.codomain() + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: f = homspace(values) + sage: ff = f.__add__(f) + sage: ff.is_zero() + True + sage: ff.__add__(f) == f + True + sage: ff = f + f + sage: ff.is_zero() + True + """ + if self.domain() != g.domain(): + raise ValueError('morphisms do not have the same domain') + elif self.codomain() != g.codomain(): + raise ValueError('morphisms do not have the same codomain') + elif self.is_zero(): + return g + elif g.is_zero(): + return self + elif self.degree() and g.degree() and self.degree() != g.degree(): + raise ValueError('morphisms do not have the same degree') + + v = [self(x) + g(x) for x in self.domain().generators()] + return self.parent()(v) + + + def _neg_(self): + r""" + The additive inverse of this homomorphism with respect to the group + structure given by pointwise sum. + + OUTPUT: An instance of this class. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A = SteenrodAlgebra(2) + sage: homspace = Hom(FreeGradedModule(A, (0,1)), FreeGradedModule(A, (2,))) + sage: N = homspace.codomain() + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: f = homspace(values) + sage: f_inverse = -f; f_inverse + Module homomorphism of degree 7 defined by sending the generators + [<1, 0>, <0, 1>] + to + [, ] + sage: (f + f_inverse).is_zero() + True + """ + return self.parent()([-x for x in self.values()]) + + + def _sub_(self, g): + r""" + The pointwise difference between this and the given homomorphism. + + OUTPUT: An instance of this class. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A = SteenrodAlgebra(2) + sage: homspace = Hom(FreeGradedModule(A, (0,1)), FreeGradedModule(A, (2,))) + sage: N = homspace.codomain() + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: f = homspace(values) + sage: values2 = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: g = homspace(values2) + sage: f - g + The trivial homomorphism. + """ + return self + (-g) + + + # Define __mul__ rather than _mul_, since we want to allow + # "multiplication" by morphisms from different homsets. + def __mul__(self, g): + r""" + The composition of the given homomorphism ``g``, followed by this + homomorphism. + + OUTPUT: A homomorphism from the domain of this homomorphism, into the + codomain of the homomorphism ``g``. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (0,1)) + sage: N = FreeGradedModule(A, (2,)) + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: f = Hom(M, N)(values) + sage: values2 = [Sq(2)*M.generator(0)] + sage: g = Hom(N, M)(values2) + sage: fg = f * g; fg + Module homomorphism of degree 7 defined by sending the generators + [<1>] + to + [] + sage: fg.is_endomorphism() + True + + TESTS: + + sage: fg == f.__mul__(g) + True + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (0,1)) + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: f = Hom(M, N)(values) + sage: f * f + Traceback (most recent call last): + ... + ValueError: morphisms are not composable + """ + if self.parent().domain() != g.parent().codomain(): + raise ValueError('morphisms are not composable') + homset = Hom(g.parent().domain(), self.parent().codomain()) + return homset([self(g(x)) for x in g.domain().generators()]) + + + def is_zero(self): + r""" + Decide if this homomomorphism is trivial. + + OUTPUT: The boolean value ``True`` if this homomorphism is trivial, and + ``False`` otherwise. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (0,1)) + sage: N = FreeGradedModule(A, (2,)) + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: f = Hom(M, N)(values) + sage: f.is_zero() + False + sage: (f-f).is_zero() + True + """ + return all(v.is_zero() for v in self.values()) + + + def is_identity(self): + r""" + Decide if this homomomorphism is the identity endomorphism. + + OUTPUT: The boolean value ``True`` if this homomorphism is the + identity, and ``False`` otherwise. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (0,1)) + sage: N = FreeGradedModule(A, (2,)) + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: f = Hom(M, N)(values) + sage: f.is_identity() + False + sage: id = Hom(M, M)(M.generators()); id + The identity homomorphism. + sage: id.is_identity() + True + """ + if self.parent().is_endomorphism_set(): + return self.parent().identity() == self + else: + return False + + + def __call__(self, x): + r""" + Evaluate the homomorphism at the given domain element ``x``. + + INPUT: + + - ``x`` -- An element of the domain of this morphism. + + OUTPUT: The module element of the codomain which is the value of ``x`` + under this homomorphism. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (0,1)) + sage: N = FreeGradedModule(A, (2,)) + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: f = Hom(M, N)(values) + sage: f.__call__(M.generator(0)) + + sage: f.__call__(M.generator(1)) + + """ + if x.parent() != self.domain(): + raise ValueError('cannot evaluate morphism on element not in the domain') + + value = sum([c*v for c, v in zip( + x.dense_coefficient_list(), self.values())], self.codomain()(0)) + + return value + + + def _repr_(self): + r""" + A string representation of this homomorphism. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (0,1)) + sage: N = FreeGradedModule(A, (2,)) + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + + sage: Hom(M, N)(values)._repr_() + 'Module homomorphism of degree 7 defined by sending the generators\n [<1, 0>, <0, 1>]\nto\n [, ]' + + sage: Hom(M, N).zero()._repr_() + 'The trivial homomorphism.' + + sage: Hom(M, M).identity()._repr_() + 'The identity homomorphism.' + """ + if self.is_zero(): + return "The trivial homomorphism." + elif self.is_identity(): + return "The identity homomorphism." + else: + r = "Module homomorphism of degree {} defined by sending the generators\n {}\nto\n {}" + return r.format(self.degree(), self.domain().generators(), self.values()) + + + def vector_presentation(self, n): + r""" + The restriction of this homomorphism to the domain module elements of + degree ``n``. + + The restriction of a non-zero module homomorphism to the vector space of + module elements of degree `n` is a linear function into the vector space + of elements of degree `n+d` belonging to the codomain. Here `d` is the + degree of this homomorphism. + + When this homomorphism is zero, it has no well defined degree so the + function cannot be presented since we do not know the degree of its + codomain. In this case, an error is raised. + + INPUT: + + - ``n`` -- An integer degree. + + OUTPUT: A linear function of finite dimensional vector spaces over the + ground field of the algebra for this module. The domain is isomorphic + to the vector space of domain elements of degree ``n`` of this free + module, via the choice of basis given by + :meth:`sage.modules.fp_graded.free_module.FreeGradedModule.basis_elements`. + If the morphism is zero, an error is raised. + + .. SEEALSO:: + + :meth:`sage.modules.fp_graded.free_module.FreeGradedModule.vector_presentation`, + :meth:`sage.modules.fp_graded.free_module.FreeGradedModule.basis_elements`. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (0,1)) + sage: N = FreeGradedModule(A, (2,)) + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: f = Hom(M, N)(values) + sage: f.vector_presentation(0) + Vector space morphism represented by the matrix: + [0 1] + Domain: Vector space of dimension 1 over Finite Field of size 2 + Codomain: Vector space of dimension 2 over Finite Field of size 2 + sage: f.vector_presentation(1) + Vector space morphism represented by the matrix: + [0 0 0] + [0 1 0] + Domain: Vector space of dimension 2 over Finite Field of size 2 + Codomain: Vector space of dimension 3 over Finite Field of size 2 + sage: f.vector_presentation(2) + Vector space morphism represented by the matrix: + [0 0 1 1] + [0 0 0 0] + Domain: Vector space of dimension 2 over Finite Field of size 2 + Codomain: Vector space of dimension 4 over Finite Field of size 2 + + TESTS: + + sage: F = FreeGradedModule(A, (0,)) + sage: z = Hom(F, F)([0]) + sage: z.is_zero() + True + sage: z.vector_presentation(0) + Traceback (most recent call last): + ... + ValueError: the zero map has no vector presentation + """ + # The trivial map has no degree, so we can not create the codomain + # of the linear transformation. + if self.is_zero(): + raise ValueError("the zero map has no vector presentation") + + D_n = self.domain().vector_presentation(n) + C_n = self.codomain().vector_presentation(n + self.degree()) + + values = [self(e) for e in self.domain().basis_elements(n)] + return Hom(D_n, C_n)([ + C_n.zero() if e.is_zero() else e.vector_presentation() for e in values]) + + def to_fp_module(self): + r""" + Create a finitely presented module from this morphism. + + OUTPUT: The finitely presented module having presentation + equal to this morphism. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import * + sage: A = SteenrodAlgebra(2) + sage: F1 = FreeGradedModule(A, (2,)) + sage: F2 = FreeGradedModule(A, (0,)) + sage: v = F2([Sq(2)]) + sage: pres = Hom(F1, F2)([v]) + sage: M = pres.to_fp_module(); M + Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis + sage: M.generator_degrees() + (0,) + sage: M.relations() + [] + """ + from .module import FP_Module + return FP_Module(algebra=self.base_ring(), + generator_degrees=self.codomain().generator_degrees(), + relations=tuple([r.dense_coefficient_list() for r in self.values()])) diff --git a/src/sage/modules/fp_graded/homspace.py b/src/sage/modules/fp_graded/homspace.py new file mode 100755 index 00000000000..dcb17f191b6 --- /dev/null +++ b/src/sage/modules/fp_graded/homspace.py @@ -0,0 +1,521 @@ +r""" +The set of homomorphisms of finitely presented graded modules + +This class implements methods for construction and basic +manipulation of homsets of finitely presented graded modules over a connected +graded `k`-algebra, where `k` is a field. + +.. NOTE:: This class is intended for private use by + :class:`sage.modules.fp_steenrod.fpa_homspace.FPA_ModuleHomspace`. + +TESTS: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.misc.sage_unittest import TestSuite + sage: A = SteenrodAlgebra(2, profile=(3,2,1)) + sage: F = FP_Module(A, [1,3]) + sage: L = FP_Module(A, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]) + sage: homset = Hom(F, L); homset + Set of Morphisms from Finitely presented left module on 2 generators ... + sage: homset.an_element() + Module homomorphism of degree 0 defined by sending the generators + [<1, 0>, <0, 1>] + to + [<0, 0>, ] + sage: homset([L((A.Sq(1), 1)), L((0, A.Sq(2)))]) + Module homomorphism of degree 2 defined by sending the generators + [<1, 0>, <0, 1>] + to + [, <0, Sq(2)>] + sage: Hom(F, L) ([L((A.Sq(1), 1)), L((0, A.Sq(2)))]).kernel() + Module homomorphism of degree 0 defined by sending the generators + [<1, 0>, <0, 1>] + to + (<0, 1>, ) + +AUTHORS: + +- Robert R. Bruner, Michael J. Catanzaro (2012): Initial version. +- Sverre Lunoee--Nielsen and Koen van Woerden (2019-11-29): Updated the + original software to Sage version 8.9. +- Sverre Lunoee--Nielsen (2020-07-01): Refactored the code and added + new documentation and tests. +""" + +#***************************************************************************** +# Copyright (C) 2011 Robert R. Bruner and +# Michael J. Catanzaro +# +# 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 absolute_import + +from sage.categories.homset import Homset + +from sage.categories.homset import Hom + +def is_FP_ModuleHomspace(x): + r""" + Check if the given object is of type FP_ModuleHomspace. + + OUTPUT: A boolean which is True if ``x`` is of type FP_ModuleHomspace. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.homspace import is_FP_ModuleHomspace + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: F = FP_Module(A2, [1,3]) + sage: L = FP_Module(A2, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]) + sage: is_FP_ModuleHomspace(Hom(F, L)) + True + sage: is_FP_ModuleHomspace(0) + False + """ + return isinstance(x, FP_ModuleHomspace) + + +class FP_ModuleHomspace(Homset): + # FP_ModuleMorphism contains reference to is_FP_ModuleHomspace, so this import + # statement must not appear before that function. + from .morphism import FP_ModuleMorphism + + # In the category framework, Elements of the class FP_ModuleHomspace are of the + # class FP_ModuleMorphism, see + # http://doc.sagemath.org/html/en/thematic_tutorials/coercion_and_categories.html#implementing-the-category-framework-for-the-elements + Element = FP_ModuleMorphism + + def _element_constructor_(self, values): + r""" + Constructs a morphism contained in this homset. + + This function is not part of the public API, but is used by :meth:Hom + method to create morphisms. + + INPUT: + + - ``values`` -- An iterable of FP_Elements of the codomain. + + OUTPUT: A module homomorphism in this homspace sending the generators + of the domain module to the given values. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: F = FP_Module(A2, [1,3]) + sage: L = FP_Module(A2, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]) + + sage: homset = Hom(F, L) + sage: v1 = L([A2.Sq(1), 1]) + sage: v2 = L([0, A2.Sq(2)]) + sage: f = homset._element_constructor_([v1, v2]) + + Rather than calling ``_element_constructor_`` explicitly, one + can call it implicitly, using the ``call`` syntax:: + + sage: f = homset([v1, v2]); f + Module homomorphism of degree 2 defined by sending the generators + [<1, 0>, <0, 1>] + to + [, <0, Sq(2)>] + + One can construct a homomorphism from another homomorhism:: + + sage: g = homset(f) + sage: f == g + True + + And there is a convenient way of making the trivial homomorphism:: + + sage: z = homset(0); z + The trivial homomorphism. + """ + if isinstance(values, self.element_class): + return values + elif values == 0: + return self.zero() + else: + return self.element_class(self, values) + + + def an_element(self, n=0): + r""" + Create a homomorphism belonging to this homset. + + INPUT: + + - ``n`` -- an integer degree. (optional, default: 0) + + OUTPUT: A module homomorphism of degree ``n``. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A = SteenrodAlgebra(2) + sage: HZ = FP_Module(A, [0], relations=[[Sq(1)]]) + + sage: Hom(HZ, HZ).an_element(3) + Module homomorphism of degree 3 defined by sending the generators + [<1>] + to + [] + + TESTS: + + sage: K = FP_Module(A, [0, 0], [[Sq(2), 0]]) # Using a zero coefficient in the relations. + sage: Hom(K, K).an_element(4) + Module homomorphism of degree 4 defined by sending the generators + [<1, 0>, <0, 1>] + to + [<0, 0>, ] + + sage: K = FP_Module(A, [0, 0], [[Sq(2), 0], [0,0], [Sq(4), Sq(2)*Sq(2)]]) + sage: Hom(K, K).an_element(n=3) + Module homomorphism of degree 3 defined by sending the generators + [<1, 0>, <0, 1>] + to + [<0, 0>, ] + """ + return self._basis_elements(n, basis=False) + + + def basis_elements(self, n): + r""" + Compute a basis for the vector space of degree ``n`` morphisms. + + INPUT: + + - ``n`` -- an integer degree. + + OUTPUT: A basis for the set of all module homomorphisms of degree ``n``. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A = SteenrodAlgebra(2) + sage: Hko = FP_Module(A, [0], relations=[[Sq(2)], [Sq(1)]]) + + sage: Hom(Hko, Hko).basis_elements(21) + [Module homomorphism of degree 21 defined by sending the generators + [<1>] + to + [], + Module homomorphism of degree 21 defined by sending the generators + [<1>] + to + []] + """ + return self._basis_elements(n, basis=True) + + + def zero(self): + r""" + Create the trivial homomorphism in this homset. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: F = FP_Module(A2, [1,3]) + sage: L = FP_Module(A2, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]) + + sage: z = Hom(F, L).zero(); z + The trivial homomorphism. + + sage: z(F.an_element(5)) + <0, 0> + + sage: z(F.an_element(23)) + <0, 0> + """ + return self.element_class(self, [self.codomain().zero() for g in self.domain().generator_degrees()]) + + + def identity(self): + r""" + Create the identity homomorphism. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: L = FP_Module(A2, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]) + + sage: id = Hom(L, L).identity(); id + The identity homomorphism. + + sage: e = L.an_element(5) + sage: e == id(e) + True + + It is an error to call this function when the homset is not a + set of endomorphisms:: + + sage: F = FP_Module(A2, [1,3]) + sage: Hom(F,L).identity() + Traceback (most recent call last): + ... + TypeError: this homspace does not consist of endomorphisms + """ + if self.is_endomorphism_set(): + return self.element_class(self, self.codomain().generators()) + else: + raise TypeError('this homspace does not consist of endomorphisms') + + + def _basis_elements(self, n, basis): + r""" + Compute a basis for the vector space of degree ``n`` homomorphisms. + + This function is private and used by :meth:`basis_elements` and + :meth:`an_element`. + + INPUT: + + - ``n`` -- an integer degree. + - ``basis`` -- boolean to decide if a basis should be returned, or just + a single homomorphism. + + OUTPUT: A basis for the set of all module homomorphisms of degree ``n`` + if ``basis`` is True. Otherwise a single element is returned. In the + latter case, this homomorphism is non-trivial if the vector space of all + homomorphisms is non-trivial. + + TESTS: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A = SteenrodAlgebra(2) + sage: Hko = FP_Module(A, [0], relations=[[Sq(2)], [Sq(1)]]) + sage: Hom(Hko, Hko)._basis_elements(21, basis=True) + [Module homomorphism of degree 21 defined by sending the generators + [<1>] + to + [], + Module homomorphism of degree 21 defined by sending the generators + [<1>] + to + []] + + sage: Hom(Hko, Hko)._basis_elements(21, basis=False) + Module homomorphism of degree 21 defined by sending the generators + [<1>] + to + [] + + sage: F = FP_Module(A, [0]) + sage: Hom(F, Hko)._basis_elements(21, basis=False) + Module homomorphism of degree 21 defined by sending the generators + [<1>] + to + [] + + sage: Hom(F, Hko)._basis_elements(21, basis=False) + Module homomorphism of degree 21 defined by sending the generators + [<1>] + to + [] + + Hom(FPA_Module([0], A, [[Sq(1)]]), FPA_Module([-2], A, [[Sq(1)]])).an_element(0) + The trivial homomorphism. + + Test corner cases involving trivial modules: + + sage: F = FP_Module(A, [0]) # A module without relations. + sage: Z0 = FP_Module(A, []) # A trivial module. + sage: Z1 = FP_Module(A, [0], [[1]]) # A trivial module with a redundant generator and relation. + + Hom(FPA_Module([-1], A), F)._basis_elements(0, basis=True) + [] + Hom(FPA_Module([-1], A), F)._basis_elements(0, basis=False) + The trivial homomorphism. + + sage: from itertools import product + sage: for D,C in product([(F, 'Free'), (Hko, 'Hko'), (Z0, 'Trivial'), (Z1, 'Trivial with redundant generator')], repeat=2): + ....: print('Hom(%s, %s):' % (D[1], C[1])) + ....: print(' basis==False:\n %s' % Hom(D[0], C[0])._basis_elements(n=7, basis=False)) + ....: print(' basis==True:\n %s' % Hom(D[0], C[0])._basis_elements(n=7, basis=True)) + Hom(Free, Free): + basis==False: + Module homomorphism of degree 7 defined by sending the generators + [<1>] + to + [] + basis==True: + [Module homomorphism of degree 7 defined by sending the generators + [<1>] + to + [], Module homomorphism of degree 7 defined by sending the generators + [<1>] + to + [], Module homomorphism of degree 7 defined by sending the generators + [<1>] + to + [], Module homomorphism of degree 7 defined by sending the generators + [<1>] + to + []] + Hom(Free, Hko): + basis==False: + Module homomorphism of degree 7 defined by sending the generators + [<1>] + to + [] + basis==True: + [Module homomorphism of degree 7 defined by sending the generators + [<1>] + to + []] + Hom(Free, Trivial): + basis==False: + The trivial homomorphism. + basis==True: + [] + Hom(Free, Trivial with redundant generator): + basis==False: + The trivial homomorphism. + basis==True: + [] + Hom(Hko, Free): + basis==False: + The trivial homomorphism. + basis==True: + [] + Hom(Hko, Hko): + basis==False: + Module homomorphism of degree 7 defined by sending the generators + [<1>] + to + [] + basis==True: + [Module homomorphism of degree 7 defined by sending the generators + [<1>] + to + []] + Hom(Hko, Trivial): + basis==False: + The trivial homomorphism. + basis==True: + [] + Hom(Hko, Trivial with redundant generator): + basis==False: + The trivial homomorphism. + basis==True: + [] + Hom(Trivial, Free): + basis==False: + The trivial homomorphism. + basis==True: + [] + Hom(Trivial, Hko): + basis==False: + The trivial homomorphism. + basis==True: + [] + Hom(Trivial, Trivial): + basis==False: + The trivial homomorphism. + basis==True: + [] + Hom(Trivial, Trivial with redundant generator): + basis==False: + The trivial homomorphism. + basis==True: + [] + Hom(Trivial with redundant generator, Free): + basis==False: + The trivial homomorphism. + basis==True: + [] + Hom(Trivial with redundant generator, Hko): + basis==False: + The trivial homomorphism. + basis==True: + [] + Hom(Trivial with redundant generator, Trivial): + basis==False: + The trivial homomorphism. + basis==True: + [] + Hom(Trivial with redundant generator, Trivial with redundant generator): + basis==False: + The trivial homomorphism. + basis==True: + [] + """ + from .morphism import _CreateRelationsMatrix + + M = self.domain() + N = self.codomain() + + def _trivial_case(): + ''' + The return value if there are no non-trivial homomorphisms. + ''' + if basis: + # Since the vector space of homomorphisms is trivial, the basis + # is the empty set. + return [] + else: + # Since the vector space of homomorphisms is trivial, it contains + # only the trivial homomorphism. + return self.zero() + + # Deal with the trivial cases first. Note that this covers the case + # where the domain or codomain have no generators. + if N.is_trivial() or M.is_trivial(): + return _trivial_case() + + # Then deal with the case where the domain has no relations. + elif not M.has_relations(): + res = [] + num_generators = len(M.generators()) + for i, g in enumerate(M.generators()): + # The i'th generator can go to any of these basis elements: + base = N[(g.degree() + n)] + for value in base: + values = [N.zero() if i != j else value for j in range(num_generators)] + res.append(Hom(M,N)(values)) + if not basis: + return res[0] + + else: + # Note that this list is non-empty since we dealt with the trivial + # case above. + source_degs = [g.degree() + n for g in M.generators()] + + # Note that this list is non-empty since we dealt with the free + # case above. + target_degs = [r.degree() + n for r in M.relations()] + + block_matrix, R = _CreateRelationsMatrix( + N, [r.dense_coefficient_list() for r in M.relations()], source_degs, target_degs) + + ker = R.right_kernel() + + res = [] + for b in ker.basis(): + n = 0 + + xs = [] + for j,X in enumerate(block_matrix[0]): + k = X.domain().dimension() + xs.append(N.element_from_coordinates(b[n:n+k], source_degs[j])) + n += k + + res.append(Hom(M, N)(xs)) + if not basis: + return res[0] + + # If the code above found a non-trivial homomorphism and ``basis==False``, + # it will have terminated by now. + if len(res) == 0: + return _trivial_case() + else: + return res + diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py new file mode 100755 index 00000000000..c347a6cb2c4 --- /dev/null +++ b/src/sage/modules/fp_graded/module.py @@ -0,0 +1,1087 @@ +r""" +Finitely presented graded modules + +This class implements methods for construction and basic manipulation of +finitely presented graded modules over connected graded algebras. + +.. NOTE:: This class was designed for use by + :class:`sage.modules.fp_graded.fpa_module.FPA_Module`. + As a consequence, all tests and examples consider modules over the + the Steenrod algebra (or a finite sub-Hopf algebra of it). + + However, this class does not assume that the algebra is the Steenrod + algebra and could be a starting point for developers wanting to extend + Sage further. + +============== +Implementation +============== + +Let `R` be a connected graded algebra. A finitely presented module over `R` +is isomorphic to the cokernel of an `R`-linear homomorphism `f:F_1 \to F_0` +of finitely generated free modules: The generators of `F_0` corresponds to the +generators of the module, and the generators of `F_1` corresponds to its +relations, via the map `f`. + +The class constructor of this module class is given a set of generators and +relations, and uses them to construct a presentation, using the class +:class:`sage.modules.fp_graded.free_morphism.FreeGradedModuleMorphism`. + +This package was designed with homological algebra in mind, and its API +focuses on maps rather than objects. A good example of this is the kernel +function :meth:`sage.modules.fp_graded.morphism.FP_ModuleMorphism.kernel` +which computes the kernel of a homomorphism `f: M\to N`. Its return value is +not an instance of the module class, but rather an injective homomorphism +`i: K\to M` with the property that `\operatorname{im}(i) = \ker(f)`. + +AUTHORS: + +- Robert R. Bruner, Michael J. Catanzaro (2012): Initial version. +- Sverre Lunoee--Nielsen and Koen van Woerden (2019-11-29): Updated the + original software to Sage version 8.9. +- Sverre Lunoee--Nielsen (2020-07-01): Refactored the code and added + new documentation and tests. +""" + +#***************************************************************************** +# Copyright (C) 2011 Robert R. Bruner and +# Michael J. Catanzaro +# +# 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 sage.categories.homset import Hom +from sage.misc.cachefunc import cached_method +from sage.rings.infinity import PlusInfinity +from sage.categories.graded_modules_with_basis import GradedModulesWithBasis +from sage.combinat.free_module import CombinatorialFreeModule + +from .free_module import FreeGradedModule +from .free_element import FreeGradedModuleElement +from .element import FP_Element + +# These are not free modules over the algebra, but they are free as +# vector spaces. They have a distinguished set of generators over the +# algebra, and as long as the algebra has a vector space basis +# implemented in Sage, the modules will have a vector space basis as well. +class FP_Module(CombinatorialFreeModule): + r""" + Create a finitely presented module over a connected graded algebra. + + INPUT: + + - ``algebra`` -- The algebra over which the module is defined. + + - ``generator_degrees`` -- A tuple of integer degrees. + + - ``relations`` -- A tuple of relations. A relation is a tuple of + coefficients `(c_1, \ldots, c_n)`, ordered so that they + correspond to the module generators. + + OUTPUT: The finitely presented module over ``algebra`` with + presentation given by ``generator_degrees`` and ``relations``. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) + + sage: M = FP_Module(A3, [0, 1], [[Sq(2), Sq(1)]]) + sage: M.generators() + [<1, 0>, <0, 1>] + sage: M.relations() + [] + sage: M.is_trivial() + False + + sage: Z = FP_Module(A3, []) + sage: Z.generators() + [] + sage: Z.relations() + [] + sage: Z.is_trivial() + True + """ + @staticmethod + def __classcall_private__(cls, algebra, generator_degrees, relations=()): + r""" + Normalize input to ensure a unique representation. + + INPUT: + + - ``generator_degrees`` -- an iterable of integer degrees. + + - ``algebra`` -- the connected graded algebra over which the module is defined. + + - ``relations`` -- an iterable of relations. A relation is a tuple of + coefficients `(c_1, \ldots, c_n)` corresponding to the module + generators. + + OUTPUT: The finitely presented module with presentation given by + the ``generator_degrees`` and ``relations``. + + TESTS: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) + sage: FP_Module(A3, [0, 1], [[Sq(2), Sq(1)]]) + Finitely presented left module on 2 generators and 1 relation over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] + """ + return super(FP_Module, cls).__classcall__(cls, + algebra=algebra, + generator_degrees=tuple(generator_degrees), + relations=tuple([tuple([algebra(x) for x in r]) for r in relations])) + + + def __init__(self, algebra, generator_degrees, relations=()): + r""" + Create a finitely presented module over a connected graded algebra. + """ + self._generator_degrees = generator_degrees + self._relations = relations + # if generator_degrees is [d_0, d_1, ...], then + # the generators are indexed by (0,d_0), (1,d_1), ... + keys = [(i,deg) for i,deg in enumerate(generator_degrees)] + self._generator_keys = keys + + # The free module on the generators of the module. + generatorModule = FreeGradedModule(algebra, + generator_degrees) + # Use the coefficients given for the relations and make module elements + # from them. Filter out the zero elements, as they are redundant. + rels = [v for v in [generatorModule(r) for r in relations] if not v.is_zero()] + + # The free module for the relations of the module. + relationsModule = FreeGradedModule(algebra, + tuple([r.degree() for r in rels])) + + # The module we want to model is the cokernel of the + # following morphism. + self.j = Hom(relationsModule, generatorModule)(rels) + + # Call the base class constructor. + CombinatorialFreeModule.__init__(self, algebra, + basis_keys=keys, + element_class=FP_Element, + category=GradedModulesWithBasis(algebra)) + + + def _free_module(self): + """ + The free module of which this is a quotient + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A = SteenrodAlgebra() + sage: M = FP_Module(A, [0, 1], [[Sq(2), Sq(1)]]) + sage: M.generators() + [<1, 0>, <0, 1>] + sage: F = M._free_module() + sage: F.generators() + [<1, 0>, <0, 1>] + """ + return self.j.codomain() + + @classmethod + def from_free_module(cls, free_module): + r""" + Initialize from a finitely generated free module. + + INPUT: + + - ``free_module`` -- a finitely generated free module. + + OUTPUT: the finitely presented module having same set of generators + as ``free_module``, and no relations. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import * + sage: from sage.modules.fp_graded.module import * + sage: A = SteenrodAlgebra(2) + sage: F = FreeGradedModule(A, (-2,2,4)) + sage: FP_Module.from_free_module(F) + Finitely presented left module on 3 generators and 0 relations over mod 2 Steenrod algebra, milnor basis + """ + return cls(algebra=free_module.base_ring(), + generator_degrees=free_module.generator_degrees(), + relations=()) + + + @classmethod + def from_free_module_morphism(cls, morphism): + r""" + Create a finitely presented module from a morphism of finitely + generated free modules. + + INPUT: + + - ``morphism`` -- a morphism between finitely generated free modules. + + OUTPUT: + + The finitely presented module having presentation equal to the + homomorphism ``morphism``. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import * + sage: from sage.modules.fp_graded.module import * + sage: A = SteenrodAlgebra(2) + sage: F1 = FreeGradedModule(A, (2,)) + sage: F2 = FreeGradedModule(A, (0,)) + sage: v = F2([Sq(2)]) + sage: pres = Hom(F1, F2)([v]) + sage: M = FP_Module.from_free_module_morphism(pres); M + Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis + sage: M.generator_degrees() + (0,) + sage: M.relations() + [] + """ + return cls(algebra=morphism.base_ring(), + generator_degrees=morphism.codomain().generator_degrees(), + relations=tuple([r.dense_coefficient_list() for r in morphism.values()])) + + + def change_ring(self, algebra): + r""" + Change the base ring of this module. + + INPUT: + + - ``algebra`` -- a connected graded algebra. + + OUTPUT: The finitely presented module over ``algebra`` defined with the + exact same number of generators of the same degrees and relations as + this module. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import * + sage: A = SteenrodAlgebra(2) + sage: A2 = SteenrodAlgebra(2,profile=(3,2,1)) + + sage: M = FP_Module(A, [0,1], [[Sq(2), Sq(1)]]) + sage: M_ = M.change_ring(A2); M_ + Finitely presented left module on 2 generators and 1 relation over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + + sage: # Changing back yields the original module. + sage: M_.change_ring(A) is M + True + """ + # self.relations() consists of module elements. We need to extra the coefficients. + relations = tuple(r.dense_coefficient_list() for r in self.relations()) + return FP_Module(algebra, self.generator_degrees(), relations) + + + def _element_constructor_(self, x): + r""" + Construct any element of this module. + + This function is used internally by the ()-method when creating + module elements, and should not be called by the user explicitly. + + INPUT: + + - ``x`` -- A tuple of coefficients, an element of FP_Module, or the + zero integer constant. + + OUTPUT: An instance of the element class with coefficients from ``x``, + the element ``x`` if it already was an element, or the zero element. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import * + sage: A = SteenrodAlgebra(2) + sage: M = FP_Module(A, [0,2,4], [[Sq(4), Sq(2), 0]]) + + sage: # Creating an element from coefficients: + sage: e = M((Sq(6), 0, Sq(2))); e + + sage: e in M + True + + sage: # Special syntax for creating the zero element: + sage: z = M(0); z + <0, 0, 0> + sage: z.is_zero() + True + + sage: # Creating an element from another element returns a reference to itself: + sage: M(e) + + sage: e is M(e) + True + """ + if isinstance(x, self.element_class): + return x + if not x: + return self.zero() + B = self.basis() + if isinstance(x, FreeGradedModuleElement): + if x.parent() == self._free_module(): + # x.parent() should have the same generator list as self. + coeffs = x.monomial_coefficients() + return sum(coeffs[idx]*B[idx] for idx in coeffs) + raise ValueError("element is not in this module") + return sum(c*B[b] for (c,b) in zip(x, self._generator_keys)) + + + def _repr_(self): + r""" + Construct a string representation of the module. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import * + sage: A = SteenrodAlgebra(2) + sage: M = FP_Module(A, [0,2,4], [[Sq(4),Sq(2),0]]); M + Finitely presented left module on 3 generators and 1 relation over mod 2 Steenrod algebra, milnor basis + sage: N = FP_Module(A, [0,1], [[Sq(2),Sq(1)], [Sq(2)*Sq(1),Sq(2)]]); N + Finitely presented left module on 2 generators and 2 relations over mod 2 Steenrod algebra, milnor basis + sage: F = FP_Module(A, [2]); F + Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis + """ + return "Finitely presented left module on %s generator%s and %s relation%s over %s"\ + %(len(self._free_module().generator_degrees()), "" if len(self._free_module().generator_degrees()) == 1 else "s", + len(self.j.values()), "" if len(self.j.values()) == 1 else "s", + self.base_ring()) + + + def connectivity(self): + r""" + The connectivity of this module. + + Since a finitely presented module over a connected algebra is in + particular bounded below, the connectivity is an integer when the + module is non-trivial, and `+\infty` when the module is trivial. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A = SteenrodAlgebra(2) + + sage: M = FP_Module(A, [0,2,4], [[0, Sq(5), Sq(3)], [Sq(7), 0, Sq(2)*Sq(1)]]) + sage: M.connectivity() + 0 + + sage: G = FP_Module(A, [0,2], [[1,0]]) + sage: G.connectivity() + 2 + + TESTS: + + sage: C = FP_Module(SteenrodAlgebra(2, profile=(3,2,1)), [0], relations=[[Sq(1)], [0]]) + sage: C.connectivity() + 0 + + sage: F = FP_Module(A, [-1]) + sage: F.connectivity() + -1 + + sage: F = FP_Module(A, []) + sage: F.connectivity() + +Infinity + + sage: F = FP_Module(A, [0], [[1]]) + sage: F.connectivity() + +Infinity + """ + # In case there are no relations, the connectivity is the equal to + # the connectivity of the free module on the generators. + if self.j._degree == None: + return self._free_module().connectivity() + + # We must check that the generator(s) in the free generator module are + # not hit by relations, since we are not guaranteed that the + # presentation we have is minimal. + X = [x for x in self.generator_degrees()] + X.sort() + + previous = None + for k in X: + if previous != None and k == previous: + continue + if not self.j.vector_presentation(k - self.j._degree).is_surjective(): + return k + previous = k + + return PlusInfinity() + + + def is_trivial(self): + r""" + Decide if this module is isomorphic to the trivial module. + + OUTPUT: Returns ``True`` if the relations generate every non-zero + element of the module, and ``False`` otherwise. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A = SteenrodAlgebra(2) + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + + sage: M = FP_Module(A2, []) + sage: M.is_trivial() + True + + sage: N = FP_Module(A, [1,2]) + sage: N.is_trivial() + False + + sage: P = FP_Module(A, [1,2], [[1,0], [0,1]]) + sage: P.is_trivial() + True + + TESTS: + + sage: C = FP_Module(SteenrodAlgebra(2, profile=(3,2,1)), [0], [[Sq(1)], [0]]) + sage: C.is_trivial() + False + + sage: C = FP_Module(SteenrodAlgebra(2), [0], [[Sq(1)], [1]]) + sage: C.is_trivial() + True + """ + return self.connectivity() == PlusInfinity() + + + def has_relations(self): + r""" + Return ``True`` if no relations are defined, and ``False`` + otherwise. + + .. NOTE:: + + This module is free if this function returns ``False``, but a free + module can have (redundant) relations. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + + sage: F = FP_Module(A2, [1,2]) + sage: F.has_relations() + False + + sage: M = FP_Module(A2, [1,2], [[Sq(2), Sq(1)]]) + sage: M.has_relations() + True + + sage: # A free module constructed with a redundant + ....: # generator and relation. + sage: N = FP_Module(A2, [0,0], [[0, 1]]) + sage: N.has_relations() + True + sage: # Computing a minimal presentation reveals an + ....: # isomorphic module with no relations. + sage: N_min = N.min_presentation().domain() + sage: N_min.has_relations() + False + """ + return not self.j.is_zero() + + + def an_element(self, n=None): + r""" + An element of this module. + + This function chooses deterministically an element, i.e the output + depends only on the module and its input ``n``. + + INPUT: + + - ``n`` -- The degree of the element to construct. If the default + value ``None`` is given, a degree will be chosen by the function. + + OUTPUT: A module element of the given degree. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import * + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: M = FP_Module(A2, [0,2,4], [[0, Sq(5), Sq(3)], [Sq(7), 0, Sq(2)*Sq(1)]]) + + sage: [M.an_element(i) for i in range(10)] + [<1, 0, 0>, + , + , + , + , + , + , + , + , + ] + """ + a_free_element = self._free_module().an_element(n) + return self(a_free_element) + + + @cached_method + def basis_elements(self, n, verbose=False): + r""" + A basis for the vector space of degree ``n`` module elements. + + INPUT: + + - ``n`` -- an integer. + + - ``verbose`` -- A boolean to control if log messages should be emitted. + (optional, default: ``False``) + + OUTPUT: A list of homogeneous module elements of degree ``n`` which is + a basis for the vector space of all degree ``n`` module elements. + + .. SEEALSO:: + + :meth:`vector_presentation`, :meth:`element_from_coordinates` + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import * + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: M = FP_Module(A2, [0,2], [[Sq(4), Sq(2)], [0, Sq(6)]]) + + sage: M.basis_elements(4) + [, ] + + sage: M.basis_elements(5) + [, , <0, Sq(0,1)>] + + sage: M.basis_elements(25) + [] + + sage: M.basis_elements(0) + [<1, 0>] + + sage: M.basis_elements(2) + [, <0, 1>] + + TESTS: + + sage: Z0 = FP_Module(A2, []) + sage: Z0.basis_elements(n=10) + [] + + sage: Z1 = FP_Module(A2, [1], [[1]]) + sage: Z1.basis_elements(n=10) + [] + """ + return [self.element_from_coordinates(x, n) for\ + x in self.vector_presentation(n, verbose).basis()] + + + @cached_method + def element_from_coordinates(self, coordinates, n): + r""" + The module element in degree ``n`` having the given coordinates with + respect to the basis returned by :meth:`basis_elements`. + + This function is inverse to + :meth:`sage.modules.fp_graded.element.FP_Element.vector_presentation`. + + INPUT: + + - ``coordinates`` -- a vector of coordinates. + + - ``n`` -- the degree of the element to construct. + + OUTPUT: A module element of degree ``n`` having the given coordinates + with respect to the basis returned by :meth:`basis_elements`. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import * + sage: A = SteenrodAlgebra(2) + sage: M = FP_Module(A, [0], [[Sq(4)], [Sq(7)], [Sq(4)*Sq(9)]]) + + sage: M.vector_presentation(12).dimension() + 3 + sage: x = M.element_from_coordinates((0,1,0), 12); x + + + Applying the inverse function brings us back to the coordinate form:: + + sage: x.vector_presentation() + (0, 1, 0) + + TESTS: + + sage: M.element_from_coordinates((0,1,0,0), 12) + Traceback (most recent call last): + ... + ValueError: the given coordinate vector has incorrect length: 4. It should have length 3 + + .. SEEALSO:: + + :meth:`sage.modules.fp_graded.module.FP_Module.vector_presentation` + """ + M_n = self.vector_presentation(n) + + if len(coordinates) != M_n.dimension(): + raise ValueError('the given coordinate vector has incorrect length: %d. ' + 'It should have length %d' % (len(coordinates), M_n.dimension())) + + free_element = self._free_module().element_from_coordinates( + M_n.lift(coordinates), n) + + return self(free_element.dense_coefficient_list()) + + + def __getitem__(self, n): + r""" + A basis for the vector space of degree ``n`` module elements. + + INPUT: + + - ``n`` -- an integer. + + OUTPUT: A list of homogeneous module elements of degree ``n`` which is + a basis for the vector space of all degree ``n`` module elements. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A = SteenrodAlgebra(2) + sage: M = FP_Module(A, [0,2,4], [[Sq(4),Sq(2),0]]) + + sage: M[4] + [, , <0, 0, 1>] + + .. SEEALSO:: + + :meth:`basis_elements` + """ + return self.basis_elements(n) + + + @cached_method + def vector_presentation(self, n, verbose=False): + r""" + A vector space isomorphic to the vector space of module elements of + degree ``n``. + + INPUT: + + - ``n`` -- The degree of the presentation. + + OUTPUT: A vector space. + + .. SEEALSO:: + + :meth:`basis_elements`, :meth:`element_from_coordinates` + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import * + sage: A = SteenrodAlgebra(2) + sage: M = FP_Module(A, [0,2,4], [[Sq(4),Sq(2),0]]) + + sage: V = M.vector_presentation(4) + sage: V.dimension() + 3 + + sage: len(M.basis_elements(4)) + 3 + """ + # Get the vector space presentation of the free module on the + # module generators. + F_n = self._free_module().vector_presentation(n) + + # Compute the sub vector space generated by the relations. + spanning_set = [] + + if verbose: + num_total_iterations = 0 + for relation in self.j.values(): + if relation.is_zero(): + continue + + num_total_iterations += len(self.base_ring().basis(n - relation.degree())) + + progress = 0 + iteration_count = 0 + + for relation in self.j.values(): + + if relation.is_zero(): + continue + + for a in self.base_ring().basis(n - relation.degree()): + if verbose: + iteration_count += 1 + prog = int(100*iteration_count/num_total_iterations) + if prog > progress: + progress = prog + print('Progress: %d/100' % prog) + + # assert: isinstance(FreeElement, relation) + v = (a*relation).vector_presentation() + if not v is None: + spanning_set.append(v) + + R_n = F_n.subspace(spanning_set) + + # Return the quotient of the free part by the relations. + return F_n/R_n + + + def _Hom_(self, Y, category): + r""" + The internal hook used by the free function + :meth:`sage.categories.homset.hom.Hom` to create homsets involving + this parent class. + + TESTS: + + sage: from sage.modules.fp_graded.module import * + sage: A = SteenrodAlgebra(2) + sage: F = FP_Module(A, [1,3]); + sage: L = FP_Module(A, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]); + + sage: homset = Hom(F, L); homset + Set of Morphisms from Finitely presented left module on 2 generators ... + """ + from .homspace import FP_ModuleHomspace + if not isinstance(Y, self.__class__): + raise ValueError('cannot create homspace between incompatible types:\n%s ->\n%s' % (self.__class__, type(Y))) + if Y.base_ring() != self.base_ring(): + raise ValueError('the modules are not defined over the same base ring') + + return FP_ModuleHomspace(self, Y, category) + + + def generator_degrees(self): + r""" + The degrees of the generators for this module. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import * + sage: A4 = SteenrodAlgebra(2, profile=(4,3,2,1)) + sage: N = FP_Module(A4, [0, 1], [[Sq(2), Sq(1)]]) + + sage: N.generator_degrees() + (0, 1) + """ + return self._generator_degrees + + + def generators(self): + r""" + The generators of this module. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A4 = SteenrodAlgebra(2, profile=(4,3,2,1)) + + sage: M = FP_Module(A4, [0,2,3]) + sage: M.generators() + [<1, 0, 0>, <0, 1, 0>, <0, 0, 1>] + + sage: N = FP_Module(A4, [0, 1], [[Sq(2), Sq(1)]]) + sage: N.generators() + [<1, 0>, <0, 1>] + + sage: Z = FP_Module(A4, []) + sage: Z.generators() + [] + """ + return [self.generator(i) for i in range(len(self.generator_degrees()))] + + + def generator(self, index): + r""" + The module generator with the given index. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import * + sage: A4 = SteenrodAlgebra(2, profile=(4,3,2,1)) + + sage: M = FP_Module(A4, [0,2,3]) + sage: M.generator(0) + <1, 0, 0> + + sage: N = FP_Module(A4, [0, 1], [[Sq(2), Sq(1)]]) + sage: N.generator(1) + <0, 1> + """ + return self(self._free_module().generator(index)) + + + def relations(self): + r""" + The relations of this module. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import * + sage: A4 = SteenrodAlgebra(2, profile=(4,3,2,1)) + + sage: M = FP_Module(A4, [0,2,3]) + sage: M.relations() + [] + + sage: N = FP_Module(A4, [0, 1], [[Sq(2), Sq(1)]]) + sage: N.relations() + [] + + sage: Z = FP_Module(A4, []) + sage: Z.relations() + [] + """ + return self.j.values() + + + def relation(self, index): + r""" + The module relation of the given index. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import * + sage: A4 = SteenrodAlgebra(2, profile=(4,3,2,1)) + sage: N = FP_Module(A4, [0, 1], [[Sq(2), Sq(1)]]) + sage: N.relation(0) + + """ + return self.j.values()[index] + + + def min_presentation(self, top_dim=None, verbose=False): + r""" + A minimal presentation of this module. + + OUTPUT: An isomorphism `M \to self`, where `M` has minimal presentation. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import * + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + + sage: M = FP_Module(A2, [0,1], [[Sq(2),Sq(1)],[0,Sq(2)],[Sq(3),0]]) + sage: i = M.min_presentation() + sage: M_min = i.domain() + + sage: # i is an isomorphism between M_min and M: + sage: i.codomain() is M + True + sage: i.is_injective() + True + sage: i.is_surjective() + True + + sage: # There are more relations in M than in M_min: + sage: M.relations() + [, <0, Sq(2)>, ] + sage: M_min.relations() + [, <0, Sq(2)>] + + TESTS: + + sage: T = FP_Module(A2, [0], [[1]]) + sage: T_min = T.min_presentation().domain() + sage: T_min.is_trivial() + True + sage: T_min + Finitely presented left module on 0 generators and 0 relations over ... + """ + return Hom(self, self).identity().image(top_dim, verbose) + + + def suspension(self, t): + r""" + The suspension of this module by the given degree. + + INPUT: + + - ``t`` -- An integer degree by which the module is suspended. + + OUTPUT: A module which is identical to this module by a shift of + degrees by the integer ``t``. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import * + sage: A = SteenrodAlgebra(2) + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + + sage: Y = FP_Module(A2, [0], [[Sq(1)]]) + sage: X = Y.suspension(4) + sage: X.generator_degrees() + (4,) + sage: X.relations() + [] + + sage: M = FP_Module(A, [2,3], [[Sq(2), Sq(1)], [0, Sq(2)]]) + sage: Q = M.suspension(1) + sage: Q.generator_degrees() + (3, 4) + sage: Q.relations() + [, <0, Sq(2)>] + sage: Q = M.suspension(-3) + sage: Q.generator_degrees() + (-1, 0) + sage: Q = M.suspension(0) + sage: Q.generator_degrees() + (2, 3) + """ + return FP_Module( + algebra=self.base_ring(), + generator_degrees=tuple([g + t for g in self.generator_degrees()]), + relations=self._relations) + + + def submodule(self, spanning_elements): + r""" + The submodule of this module spanned by the given elements. + + INPUT: + + - ``spanning_elements`` - An iterable of elements of this module. + + OUTPUT: The inclusion of the submodule into this module. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import * + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + + sage: M = FP_Module(A2, [0,1], [[Sq(2),Sq(1)]]) + sage: i = M.submodule([M.generator(0)]) + sage: i.codomain() is M + True + sage: i.is_injective() + True + sage: i.domain().generator_degrees() + (0,) + sage: i.domain().relations() + [] + """ + # Create the free graded module on the set of spanning elements. + degs = [x.degree() for x in spanning_elements] + F = FP_Module(self.base_ring(), tuple(degs)) + + # The submodule is the module generated by the spanning elements. + return Hom(F, self)(spanning_elements).image() + + + def resolution(self, k, top_dim=None, verbose=False): + r""" + A resolution of this module of length ``k``. + + INPUT: + + - ``k`` -- An non-negative integer. + + - ``verbose`` -- A boolean to control if log messages should be emitted. + (optional, default: ``False``) + + OUTPUT: A list of homomorphisms `[\epsilon, f_1, \ldots, f_k]` such that + + `f_i: F_i \to F_{i-1}` for `1, <0, 1>] + to + (<1, 0>, <0, 1>)] + sage: res = M.resolution(4, verbose=True) + Computing f_1 (1/4) + Computing f_2 (2/4) + Resolving the kernel in the range of dimensions [2, 25]: 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25. + Computing f_3 (3/4) + Resolving the kernel in the range of dimensions [8, 31]: 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31. + Computing f_4 (4/4) + Resolving the kernel in the range of dimensions [9, 33]: 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33. + sage: len(res) + 5 + sage: res + [Module homomorphism of degree 0 defined by sending the generators + [<1, 0>, <0, 1>] + to + (<1, 0>, <0, 1>), + Module homomorphism of degree 0 defined by sending the generators + [<1>] + to + (,), + Module homomorphism of degree 0 defined by sending the generators + [<1>] + to + (,), + Module homomorphism of degree 0 defined by sending the generators + [<1, 0>, <0, 1>] + to + (, ), + Module homomorphism of degree 0 defined by sending the generators + [<1, 0>, <0, 1>] + to + (, )] + sage: for i in range(len(res)-1): + ....: if not (res[i]*res[i+1]).is_zero(): + ....: print('The result is not a complex.') + """ + def _print_progress(i, k): + if verbose: + print ('Computing f_%d (%d/%d)' % (i, i, k)) + + if k < 0: + raise ValueError('the length of the resolution must be non-negative') + + complex = [] + + # Epsilon: F_0 -> M + F_0 = FP_Module.from_free_module(self._free_module()) + epsilon = Hom(F_0, self)(tuple(self.generators())) + complex.append(epsilon) + + if k == 0: + return complex + + # f_1: F_1 -> F_0 + _print_progress(1, k) + F_1 = FP_Module.from_free_module(self.j.domain()) + pres = Hom(F_1, F_0)(tuple([ F_0(x.dense_coefficient_list()) for x in self.j.values() ])) + + complex.append(pres) + + from .morphism import FP_ModuleMorphism + + # f_i: F_i -> F_i-1, for i > 1 + for i in range(2, k+1): + _print_progress(i, k) + + f = complex[i-1] + complex.append( + FP_ModuleMorphism._resolve_kernel( + f, + top_dim=top_dim, + verbose=verbose)) + + return complex + diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py new file mode 100755 index 00000000000..f46b9fb5349 --- /dev/null +++ b/src/sage/modules/fp_graded/morphism.py @@ -0,0 +1,1772 @@ +r""" +Homomorphisms of finitely presented graded modules + +This class implements construction and basic manipulation of elements of the +Sage parent :class:`sage.modules.fp_graded.homspace.FP_ModuleHomspace`, +which models homomorphisms of finitely presented graded modules over connected +algebras. + +.. NOTE:: This class is intended for private use by its derived class + :class:`sage.modules.fp_steenrod.fpa_morphism.FPA_ModuleMorphism`. + +AUTHORS: + +- Robert R. Bruner, Michael J. Catanzaro (2012): Initial version. +- Sverre Lunoee--Nielsen and Koen van Woerden (2019-11-29): Updated the + original software to Sage version 8.9. +- Sverre Lunoee--Nielsen (2020-07-01): Refactored the code and added + new documentation and tests. +""" + +#***************************************************************************** +# Copyright (C) 2011 Robert R. Bruner +# and Michael J. Catanzaro +# +# 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 absolute_import +from __future__ import print_function + +import sys + +from sage.categories.homset import End +from sage.categories.homset import Hom +from sage.categories.morphism import Morphism +from sage.misc.cachefunc import cached_method +from .element import FP_Element +from sage.rings.infinity import PlusInfinity + + +def _CreateRelationsMatrix(module, relations, source_degs, target_degs): + r""" + The action by the given relations can be written as multiplication by + the matrix `R = (r_{ij})_{i,j}` where each entry is an algebra element and + each row in the matrix contains the coefficients of a single relation. + + For a given source degree, `n`, the multiplication by `r_{ij}` restricts to + a linear transformation `M_n\to M_{n + \deg(r_{ij})}`. This function returns + the matrix of linear transformations gotten by restricting `R` to the given + source degrees. + + INPUT: + + - ``module`` -- The module where the relations acts. + - ``relations`` -- A list of lists of algebra coefficients defining the + matrix `R`. + - ``source_degs`` -- A list of integer degrees. Its length should be + equal to the number of columns of `R`. + - ``target_degs`` -- A list of integer degrees. Its length should be + equal to the number of rows of `R`. + + Furthermore must the degrees given by the input satisfy the following: + + `\text{source_degs[j]} + \deg(r_{i,j}) = \text{target_degs[i]}` + + for all `i, j`. + + OUTPUT: + + - ``block_matrix`` -- A list of lists representing a matrix of linear + transformations `(T_{ij})`. Each transformtion `T_{ij}` is the linear map + representing multiplication by the coefficient `r_{ij}` restricted to + the module elements of degree ``source_degs[j]``. + - ``R`` -- A matrix representing ``block_matrix`` as a single linear + transformation. + + TESTS: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.morphism import _CreateRelationsMatrix + sage: A = SteenrodAlgebra(p=2) + sage: blocks, R = _CreateRelationsMatrix(FP_Module(A, [0]), [[Sq(2)]], [4], [6]) + + sage: blocks + [[Vector space morphism represented by the matrix: + [0 1 0] + [0 1 1] + Domain: Vector space quotient V/W of dimension 2 over Finite Field of size 2 where + V: Vector space of dimension 2 over Finite Field of size 2 + W: Vector space of degree 2 and dimension 0 over Finite Field of size 2 + Basis matrix: + [] + Codomain: Vector space quotient V/W of dimension 3 over Finite Field of size 2 where + V: Vector space of dimension 3 over Finite Field of size 2 + W: Vector space of degree 3 and dimension 0 over Finite Field of size 2 + Basis matrix: + []]] + + sage: R + [0 0] + [1 1] + [0 1] + """ + from sage.matrix.constructor import matrix + + if len(relations) == 0: + raise ValueError('no relations given, can not build matrix') + + # Create the block matrix of linear transformations. + block_matrix = [] + for i, r_i in enumerate(relations): + row = [] + target_space = module.vector_presentation(target_degs[i]) + + for j, r_ij in enumerate(r_i): + + values = [] + for b in module.basis_elements(source_degs[j]): + w = r_ij*b + values.append( + target_space.zero() if w.is_zero() else w.vector_presentation()) + + row.append( + Hom(module.vector_presentation(source_degs[j]), target_space)(values)) + + block_matrix.append(row) + + # Deal with the case of zero dimensional matrices first. + total_source_dim = 0 + for el in block_matrix[0]: + total_source_dim += el.domain().dimension() + total_target_dim = 0 + for row in block_matrix: + total_target_dim += row[0].codomain().dimension() + if total_source_dim == 0: + return block_matrix, matrix(total_target_dim, 0) + elif total_target_dim == 0: + return block_matrix, matrix(0, total_source_dim) + + # Create a matrix from the matrix of linear transformations. + entries = [] + for j in range(len(block_matrix[0])): + for n in range(block_matrix[0][j].domain().dimension()): + column = [] + for i in range(len(block_matrix)): + lin_trans = block_matrix[i][j] + column += lin_trans(lin_trans.domain().basis()[n]) + entries.append(column) + + return block_matrix, matrix(module.base_ring().base_ring(), entries).transpose() + + +class FP_ModuleMorphism(Morphism): + r""" + Create a homomorphism between finitely presented graded modules. + + INPUT: + + - ``parent`` -- A homspace of finitely presented graded modules. + - ``values`` -- A list of elements in the codomain. Each element + corresponds to a module generator in the domain. + + OUTPUT: A module homomorphism defined by sending the generator with + index `i` to the corresponding element in ``values``. + + .. NOTE:: Never use this constructor explicitly, but rather the parent's + call method, or this class' __call__ method. The reason for this + is that the dynamic type of the element class changes as a + consequence of the category system. + + TESTS: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: # Trying to map the generators of a non-free module into a + sage: # free module: + sage: A = SteenrodAlgebra(2) + sage: F = FP_Module(A, [2,3]) + sage: Q = FP_Module(A, [2,3], relations=[[Sq(6), Sq(5)]]) + sage: m = Hom(F, Q)( (F((Sq(1), 0)), F((0, 1))) ) + Traceback (most recent call last): + ... + ValueError: ill-defined homomorphism: degrees do not match + + sage: # Trying to map the generators of a non-free module into a + sage: # free module: + sage: w = Hom(Q, F)( (F((1, 0)), F((0, 1))) ) + Traceback (most recent call last): + ... + ValueError: relation is not sent to zero + """ + def __init__(self, parent, values): + r""" + Create a homomorphism between finitely presented graded modules. + """ + + from .homspace import is_FP_ModuleHomspace + + if not is_FP_ModuleHomspace(parent): + raise TypeError('parent (=%s) must be a fp module hom space' % parent) + + self.free_morphism = Hom(parent.domain().j.codomain(), parent.codomain().j.codomain())([v.free_element() for v in values]) + self._values = values + + # Call the base class constructor. + Morphism.__init__(self, parent) + + # Check that the homomorphism is well defined. + for relation in parent.domain().relations(): + # The relation is an element in the free part of the domain. + img = self.free_morphism(relation) + # if not FP_Element(parent.codomain(), self.free_morphism(relation)).is_zero(): + if parent.codomain()(img): + raise ValueError('relation %s is not sent to zero' % relation) + + + def change_ring(self, algebra): + r""" + Change the base ring of this module homomorphism. + + INPUT: + + - ``algebra`` -- a graded algebra. + + OUTPUT: An instance of this class. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) + sage: M = FP_Module(A2, [0], relations=[[Sq(1)]]) + sage: N = FP_Module(A2, [0], relations=[[Sq(4)],[Sq(1)]]) + + sage: f = Hom(M,N)([A2.Sq(3)*N.generator(0)]); f + Module homomorphism of degree 3 defined by sending the generators + [<1>] + to + [] + + sage: f.base_ring() + sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + + sage: g = f.change_ring(A3) + sage: g.base_ring() + sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] + """ + new_codomain = self.codomain().change_ring(algebra) + # We have to change the ring for the values, too: + new_values = [] + for v in self._values: + new_values.append(new_codomain([algebra(a) for a in v.dense_coefficient_list()])) + return Hom(self.domain().change_ring(algebra), new_codomain)(new_values) + + + def degree(self): + r""" + The degree of this homomorphism. + + OUTPUT: The integer degree of this homomorphism. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import * + sage: A = SteenrodAlgebra(2) + sage: M = FP_Module(A, [0,1], [[Sq(2), Sq(1)]]) + sage: N = FP_Module(A, [2], [[Sq(4)]]) + sage: homspace = Hom(M, N) + + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: f = homspace(values) + sage: f.degree() + 7 + + The trivial homomorphism has no degree:: + + sage: homspace.zero().degree() + Traceback (most recent call last): + ... + ValueError: the zero morphism does not have a well-defined degree + + TESTS: + + sage: M = FP_Module(SteenrodAlgebra(p=2), [7]) + sage: N = FP_Module(SteenrodAlgebra(p=2), [0], relations=[[Sq(1)]]) + sage: f = Hom(M,N)([Sq(1)*N.generator(0)]) + sage: f == Hom(M,N).zero() + True + sage: f.degree() + Traceback (most recent call last): + ... + ValueError: the zero morphism does not have a well-defined degree + """ + if self.is_zero(): + # The zero morphism has no degree. + raise ValueError("the zero morphism does not have a well-defined degree") + return self.free_morphism.degree() + + + def values(self): + r""" + The values under this homomorphism of the module generators of the + domain module. + + OUTPUT: A sequence of module elements of the codomain. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import * + sage: A = SteenrodAlgebra(2) + sage: M = FP_Module(A, [0,1], [[Sq(2), Sq(1)]]) + sage: N = FP_Module(A, [2], [[Sq(4)]]) + sage: homspace = Hom(M, N) + + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: f = homspace(values) + + sage: f.values() + [, ] + + sage: homspace.zero().values() + [<0>, <0>] + """ + return self._values + + + def _richcmp_(self, other, op): + r""" + Compare this homomorphism to the given homomorphism. + + Implementation of this function allows Sage to make sense of the == + operator for instances of this class. + + INPUT: + + - ``other`` -- An instance of this class. + + - ``op`` -- An integer specifying the comparison operation to be + carried out: If ``op`` == 2, then return ``True`` if and only if the + homomorphisms are equal. If ``op`` == 3, then return ``True `` if + and only if the homomorphisms are not equal. Otherwise, + return ``False``. + + OUTPUT: A boolean. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import * + sage: A = SteenrodAlgebra(2) + sage: M = FP_Module(A, [0,1], [[Sq(2), Sq(1)]]) + sage: N = FP_Module(A, [2], [[Sq(4)]]) + sage: homspace = Hom(M, N) + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: f = homspace(values) + sage: f._richcmp_(f, op=2) + True + sage: f._richcmp_(f, op=3) + False + """ + try: + same = (self - other).is_zero() + except ValueError: + return False + + # Equality + if op == 2: + return same + + # Non-equality + if op == 3: + return not same + + return False + + + def __add__(self, g): + r""" + The pointwise sum of this and the given homomorphism. + + Pointwise addition of two homomorphisms `f` and `g` with the same domain + and codomain is given by the formula `(f+g)(x) = f(x) + g(x)` for + every `x` in the domain of `f`. + + INPUT: + + - ``g`` -- A homomorphism with the same domain and codomain as this + homomorphism. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import * + sage: A = SteenrodAlgebra(2) + sage: M = FP_Module(A, [0,1], [[Sq(2), Sq(1)]]) + sage: N = FP_Module(A, [2], [[Sq(4)]]) + sage: homspace = Hom(M, N) + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: f = homspace(values) + sage: ff = f.__add__(f) + sage: ff.is_zero() + True + sage: ff.__add__(f) == f + True + """ + if self.domain() != g.domain(): + raise ValueError('morphisms do not have the same domain') + elif self.codomain() != g.codomain(): + raise ValueError('morphisms do not have the same codomain') + if self.is_zero(): + return g + if g.is_zero(): + return self + if self.degree() and g.degree() and self.degree() != g.degree(): + raise ValueError('morphisms do not have the same degree') + + v = [self(x) + g(x) for x in self.domain().generators()] + + return self.parent()(v) + + + def __neg__(self): + r""" + The additive inverse of this homomorphism with respect to the group + structure given by pointwise sum. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import * + sage: A = SteenrodAlgebra(2) + sage: M = FP_Module(A, [0,1], [[Sq(2), Sq(1)]]) + sage: N = FP_Module(A, [2], [[Sq(4)]]) + sage: homspace = Hom(M, N) + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: f = homspace(values) + sage: f_inverse = f.__neg__(); f_inverse + Module homomorphism of degree 7 defined by sending the generators + [<1, 0>, <0, 1>] + to + [, ] + sage: (f + f_inverse).is_zero() + True + """ + return self.parent()([-x for x in self._values]) + + + def __sub__(self, g): + r""" + The difference between this and the given homomorphism, with + respect to the group structure given by pointwise sum. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import * + sage: A = SteenrodAlgebra(2) + sage: M = FP_Module(A, [0]) + sage: N = FP_Module(A, [0], [[Sq(4)]]) + sage: f = Hom(M, N)( [Sq(3)*N.generator(0)] ) + sage: g = Hom(M, N)( [Sq(0,1)*N.generator(0)] ) + sage: f.__sub__(g) + Module homomorphism of degree 3 defined by sending the generators + [<1>] + to + [] + + sage: f = Hom(M, N)( [Sq(4)*N.generator(0)] ) # the zero map + sage: g = Hom(M, N)( [Sq(1,1)*N.generator(0)] ) + sage: f.__sub__(g) + Module homomorphism of degree 4 defined by sending the generators + [<1>] + to + [] + """ + return self.__add__(g.__neg__()) + + + def __mul__(self, g): + r""" + The composition of the given homomorphism ``g``, followed by this + homomorphisms. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A = SteenrodAlgebra(2) + sage: M = FP_Module(A, [0], [[Sq(1,2)]]) + sage: N = FP_Module(A, [0], [[Sq(2,2)]]) + sage: f = Hom(M, N)( [Sq(2)*N.generator(0)] ) + sage: g = Hom(N, M)( [Sq(2,2)*M.generator(0)] ) + sage: fg = f.__mul__(g); fg + Module homomorphism of degree 10 defined by sending the generators + [<1>] + to + [] + sage: fg.is_endomorphism() + True + + TESTS: + + sage: from sage.modules.fp_graded.free_module import * + sage: A = SteenrodAlgebra(2) + sage: M = FP_Module(A, (0,1)) + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: f = Hom(M, N)(values) + sage: f.__mul__(f) + Traceback (most recent call last): + ... + ValueError: morphisms not composable + """ + if self.parent().domain() != g.parent().codomain(): + raise ValueError('morphisms not composable') + homset = Hom(g.parent().domain(), self.parent().codomain()) + return homset([self(g(x)) for x in g.domain().generators()]) + + + @cached_method + def is_zero(self): + r""" + Decide if this homomomorphism is the zero homomorphism. + + OUTPUT: The boolean value ``True`` if this homomorphism is trivial, and + ``False`` otherwise. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A = SteenrodAlgebra(2) + sage: M = FP_Module(A, [0,1], [[Sq(2), Sq(1)]]) + sage: N = FP_Module(A, [2], [[Sq(4)]]) + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + + sage: f = Hom(M, N)(values) + sage: f.is_zero() + False + + sage: (f-f).is_zero() + True + """ + return all([x.is_zero() for x in self._values]) + + + @cached_method + def is_identity(self): + r""" + Decide if this homomomorphism is the identity endomorphism. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import * + sage: A = SteenrodAlgebra(2) + sage: M = FP_Module(A, [0,1], [[Sq(2), Sq(1)]]) + sage: N = FP_Module(A, [2], [[Sq(4)]]) + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + + sage: f = Hom(M, N)(values) + sage: f.is_identity() + False + + sage: id = Hom(M, M)(M.generators()); id + The identity homomorphism. + + sage: id.is_identity() + True + """ + if self.parent().is_endomorphism_set(): + return self.parent().identity() == self + else: + return False + + + def __call__(self, x): + r""" + Evaluate the homomorphism at the given domain element ``x``. + + INPUT: + + - ``x`` - An element of the domain of the homomorphism. + + OUTPUT: The module element of the codomain which is the value of ``x`` + under this homomorphism. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import * + sage: A = SteenrodAlgebra(2) + sage: M = FP_Module(A, [0,1], [[Sq(2), Sq(1)]]) + sage: N = FP_Module(A, [2], [[Sq(4)]]) + + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: f = Hom(M, N)(values) + + sage: f.__call__(M.generator(0)) + + + sage: f.__call__(M.generator(1)) + + """ + if x.parent() != self.domain(): + raise ValueError('cannot evaluate morphism on element not in domain') + + return self.codomain()(self.free_morphism(x.free_element())) + + + def _repr_(self): + r""" + A string representation of this homomorphism. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import * + sage: A = SteenrodAlgebra(2) + sage: M = FP_Module(A, [0,1], [[Sq(2), Sq(1)]]) + sage: N = FP_Module(A, [2], [[Sq(4)]]) + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: Hom(M, N)(values)._repr_() + 'Module homomorphism of degree 7 defined by sending the generators\n [<1, 0>, <0, 1>]\nto\n [, ]' + sage: Hom(M, N).zero()._repr_() + 'The trivial homomorphism.' + sage: Hom(M, M).identity()._repr_() + 'The identity homomorphism.' + """ + if self.is_zero(): + return "The trivial homomorphism." + elif self.is_identity(): + return "The identity homomorphism." + else: + return "Module homomorphism of degree %d defined by sending "\ + "the generators\n %s\nto\n %s" % (self.degree(), self.domain().generators(), self._values) + + + @cached_method + def vector_presentation(self, n): + r""" + The restriction of this homomorphism to the domain module elements of + degree ``n``. + + The restriction of a non-zero module homomorphism to the vectorspace of + module elements of degree `n` is a linear function into the vectorspace + of elements of degree `n+d` belonging to the codomain. Here `d` is the + degree of this homomorphism. + + When this homomorphism is zero, it has no well defined degree so the + function cannot be presented since we do not know the degree of its + codomain. In this case, the return value is ``None``. + + INPUT: + + - ``n`` -- An integer degree. + + OUTPUT: A linear function of finite dimensional vectorspaces over the + ground field of the algebra for this module. The domain is isomorphic + to the vectorspace of domain elements of degree ``n`` of this free + module, via the choice of basis given by + :meth:`sage.modules.fp_graded.free_module.FreeGradedModule.basis_elements`. + If the morphism is zero, the value ``None`` is returned. + + .. SEEALSO:: + + :meth:`sage.modules.fp_graded.module.FP_Module.vector_presentation`, + :meth:`sage.modules.fp_graded.module.FP_Module.basis_elements`. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A = SteenrodAlgebra(2) + sage: M = FP_Module(A, [0,1], [[Sq(2), Sq(1)]]) + sage: N = FP_Module(A, [2], [[Sq(4)]]) + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: f = Hom(M, N)(values) + sage: f.vector_presentation(0) + Vector space morphism represented by the matrix: + [0] + Domain: Vector space quotient V/W of dimension 1 over Finite Field of size 2 where + V: Vector space of dimension 1 over Finite Field of size 2 + W: Vector space of degree 1 and dimension 0 over Finite Field of size 2 + Basis matrix: + [] + Codomain: Vector space quotient V/W of dimension 1 over Finite Field of size 2 where + V: Vector space of dimension 2 over Finite Field of size 2 + W: Vector space of degree 2 and dimension 1 over Finite Field of size 2 + Basis matrix: + [0 1] + sage: f.vector_presentation(1) + Vector space morphism represented by the matrix: + [0 0] + [0 1] + Domain: Vector space quotient V/W of dimension 2 over Finite Field of size 2 where + V: Vector space of dimension 2 over Finite Field of size 2 + W: Vector space of degree 2 and dimension 0 over Finite Field of size 2 + Basis matrix: + [] + Codomain: Vector space quotient V/W of dimension 2 over Finite Field of size 2 where + V: Vector space of dimension 3 over Finite Field of size 2 + W: Vector space of degree 3 and dimension 1 over Finite Field of size 2 + Basis matrix: + [0 1 1] + sage: f.vector_presentation(2) + Vector space morphism represented by the matrix: + [0 0] + Domain: Vector space quotient V/W of dimension 1 over Finite Field of size 2 where + V: Vector space of dimension 2 over Finite Field of size 2 + W: Vector space of degree 2 and dimension 1 over Finite Field of size 2 + Basis matrix: + [1 1] + Codomain: Vector space quotient V/W of dimension 2 over Finite Field of size 2 where + V: Vector space of dimension 4 over Finite Field of size 2 + W: Vector space of degree 4 and dimension 2 over Finite Field of size 2 + Basis matrix: + [0 0 1 0] + [0 0 0 1] + + + TESTS: + + sage: F = FP_Module(A, [0]) + sage: Q = FP_Module(A, [0], [[Sq(2)]]) + sage: z = Hom(F, Q)([Sq(2)*Q.generator(0)]) + sage: z.is_zero() + True + sage: z.vector_presentation(0) is None + True + """ + # The trivial map has no degree, so we can not create the codomain + # of the linear transformation. + if self.is_zero(): + return None + + D_n = self.domain().vector_presentation(n) + C_n = self.codomain().vector_presentation(self.degree() + n) + + values = [self(e) for e in self.domain().basis_elements(n)] + + return Hom(D_n, C_n)([ + C_n.zero() if e.is_zero() else e.vector_presentation() for e in values]) + + + def solve(self, x): + r""" + Find an element in the inverse image of the given element. + + INPUT: + + - ``x`` -- An element of the codomain of this morphism. + + OUTPUT: An element of the domain which maps to ``x`` under this + morphism, or ``None`` if ``x`` was not in the image of this morphism. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A = SteenrodAlgebra(2) + sage: M = FP_Module(A, [0], [[Sq(3)]]) + sage: N = FP_Module(A, [0], [[Sq(2,2)]]) + sage: f = Hom(M, N)( [Sq(2)*N.generator(0)] ) + sage: y = Sq(1,1)*N.generator(0); y + + sage: x = f.solve(y); x + + sage: y == f(x) + True + + Trying to lift an element which is not in the image results in a ``None`` value:: + + sage: z = f.solve(Sq(1)*N.generator(0)) + sage: z is None + True + + TESTS: + + sage: f.solve(Sq(2,2)*M.generator(0)) + Traceback (most recent call last): + ... + ValueError: the given element is not in the codomain of this homomorphism + """ + if x.parent() != self.codomain(): + raise ValueError('the given element is not in the codomain of this homomorphism') + + # The zero element lifts over all morphisms. + if x.is_zero(): + return self.domain().zero() + + # Handle the trivial homomorphism since it does not have a well defined + # degree. + if self.is_zero(): + return None + + # Handle the case where both the morhism and the element is non-trivial. + n = x.degree() - self.degree() + f_n = self.vector_presentation(n) + + v = x.vector_presentation() + + # Return None if ``x`` cannot be lifted. + if not v in f_n.image(): + return None + + u = f_n.matrix().solve_left(v) + return self.domain().element_from_coordinates(u, n) + + + def lift(self, f, verbose=False): + r""" + A lift of this homomorphism over the given homomorphism ``f``. + + INPUT: + + - ``f`` -- A homomorphism with codomain equal to the codomain of this + homomorphism. + - ``verbose`` -- A boolean to enable progress messages. (optional, + default: ``False``) + + OUTPUT: A homomorphism `g` with the property that this homomorphism + equals `f\circ g`. If no lift exist, ``None`` is returned. + + ALGORITHM: + + Let `L` be the domain of this homomorphism, and choose `x_1, \ldots, x_N` + such that `f(x_i) = self(g_i)` where the `g_i`'s are the module + generators of `L`. + + The linear function sending `g_i` to `x_i` for every `i` is well + defined if and only if the vector `x = (x_1,\ldots, x_N)` lies + in the nullspace of the coefficient matrix `R = (r_{ij})` given by the + relations of `L`. + + Let `k \in \ker(f)` solve the matrix equation: + + `R\cdot k = R\cdot x`. + + Define a module homomorphism by sending the generators of `L` to + `x_1 - k_1, \ldots, x_N - k_N`. This is well defined, and is also a + lift of this homomorphism over `f`. + + Note that it does not matter how we choose the initial elements `x_i`: + If `x'` is another choice then `x' - x\in \ker(f)` and + `R\cdot k = R\cdot x` if and only if `R\cdot (k + x' - x) = R\cdot x'`. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A = SteenrodAlgebra(2) + + Lifting a map from a free module is always possible:: + + sage: M = FP_Module(A, [0], [[Sq(3)]]) + sage: N = FP_Module(A, [0], [[Sq(2,2)]]) + sage: F = FP_Module(A, [0]) + sage: f = Hom(M,N)([Sq(2)*N.generator(0)]) + sage: k = Hom(F,N)([Sq(1)*Sq(2)*N.generator(0)]) + sage: f_ = k.lift(f) + sage: f*f_ == k + True + sage: f_ + Module homomorphism of degree 1 defined by sending the generators + [<1>] + to + [] + + A split projection:: + + sage: A_plus_HZ = FP_Module(A, [0,0], [[0, Sq(1)]]) + sage: HZ = FP_Module(A, [0], [[Sq(1)]]) + sage: q = Hom(A_plus_HZ, HZ)([HZ([1]), HZ([1])]) + sage: # We can construct a splitting of `q` manually: + sage: split = Hom(HZ,A_plus_HZ)([A_plus_HZ.generator(1)]) + sage: q*split + The identity homomorphism. + sage: # Thus, lifting the identity homomorphism over `q` should be possible: + sage: id = Hom(HZ,HZ).identity() + sage: j = id.lift(q); j + Module homomorphism of degree 0 defined by sending the generators + [<1>] + to + [<0, 1>] + sage: q*j + The identity homomorphism. + + Lifting over the inclusion of the image sub module:: + + sage: A = SteenrodAlgebra(2) + sage: M = FP_Module(A, [0], relations=[[Sq(0,1)]]) + sage: f = Hom(M,M)([Sq(2)*M.generator(0)]) + sage: im = f.image(top_dim=10) + sage: f.lift(im) + Module homomorphism of degree 2 defined by sending the generators + [<1>] + to + [<1>] + + When a lift cannot be found, the ``None`` value is returned. By setting the + verbose argument to ``True``, an explanation of why the lifting failed will + be displayed:: + + sage: F2 = FP_Module(A, [0,0]) + sage: non_surjection = Hom(F2, F2)([F2([1, 0]), F2([0, 0])]) + sage: lift = Hom(F2, F2).identity().lift(non_surjection, verbose=True) + The generators of the domain of this homomorphism do not map into the image of the homomorphism we are lifting over. + sage: lift is None + True + + TESTS: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A = SteenrodAlgebra(2) + sage: # The trivial map often involved in corner cases.. + sage: trivial_map = Hom(FP_Module(A, [0]), FP_Module(A, [])).zero() + sage: trivial_map.lift(trivial_map) + The trivial homomorphism. + + sage: F = FP_Module(A, [0]) + sage: HZ = FP_Module(A, [0], relations=[[Sq(1)]]) + sage: f = Hom(F,HZ)(HZ.generators()) + sage: split = Hom(HZ, HZ).identity().lift(f, verbose=True) + The homomorphism cannot be lifted in any way such that the relations of the domain are respected: matrix equation has no solutions + sage: split is None + True + + sage: Hom(F, F).identity().lift(f, verbose=true) + Traceback (most recent call last): + ... + ValueError: the codomains of this homomorphism and the homomorphism we are lifting over are different + + sage: f.lift(Hom(HZ, HZ).zero(), verbose=True) + This homomorphism cannot lift over a trivial homomorphism since it is non-trivial. + + sage: Ap = SteenrodAlgebra(p=2, profile=(2,2,2,1)) + sage: Hko = FP_Module(Ap, [0], [[Sq(2)], [Sq(1)]]) + sage: f = Hom(Hko, Hko)([(Ap.Sq(0,0,3) + Ap.Sq(0,2,0,1))*Hko.generator(0)]) + sage: f*f == 0 + True + sage: k = f.kernel() # long time + sage: f.lift(k) # long time + Module homomorphism of degree 21 defined by sending the generators + [<1>] + to + [<0, Sq(1), 0>] + + Corner cases involving trivial maps:: + + sage: M = FP_Module(A, [1]) + sage: M1 = FP_Module(A, [0]) + sage: M2 = FP_Module(A, [0], [[Sq(1)]]) + sage: q = Hom(M1, M2)([M2.generator(0)]) + sage: z = Hom(M, M2).zero() + sage: lift = z.lift(q) + sage: lift.domain() is M and lift.codomain() is M1 + True + + .. SEEALSO:: + :meth:`split` + """ + from sage.modules.free_module_element import vector + + # self + # L -------> N + # \ ^ + # \ | + # lift \ | f + # \ | + # _| | + # M + L = self.domain() + N = self.codomain() + M = f.domain() + + # It is an error to call this function with incompatible arguments. + if not f.codomain() is N: + raise ValueError('the codomains of this homomorphism and the homomorphism '\ + 'we are lifting over are different') + + # The trivial map lifts over any other map. + if self.is_zero(): + return Hom(L, M).zero() + + # A non-trivial map never lifts over the trivial map. + if f.is_zero(): + if verbose: + print('This homomorphism cannot lift over a trivial homomorphism since it is non-trivial.') + return None + + xs = [f.solve(self(g)) for g in L.generators()] + + # If some of the generators are not in the image of f, there is no + # hope finding a lift. + if None in xs: + if verbose: + print('The generators of the domain of this homomorphism do '\ + 'not map into the image of the homomorphism we are lifting over.') + return None + + # If L is free there are no relations to take into consideration. + if not L.has_relations(): + return Hom(L, M)(xs) + + # The degree of the lifted map f_. + lift_deg = self.degree() - f.degree() + + # Compute the kernel of f. The equations we will solve will live in + # this submodule. + iK = f.kernel(top_dim=max([r.degree() + lift_deg for r in L.relations()])) + + source_degs = [g.degree() + lift_deg for g in L.generators()] + target_degs = [r.degree() + lift_deg for r in L.relations()] + + # Act on the liftings xs by the relations. + ys = [] + K = iK.domain() + all_zero = True + + for r in L.relations(): + target_degree = r.degree() + lift_deg + + y = iK.solve(sum([c*x for c,x in zip(r.dense_coefficient_list(), xs)])) + if y is None: + if verbose: + print('The homomorphism cannot be lifted in any ' + 'way such that the relations of the domain are ' + 'respected.') + return None + + if y.is_zero(): + dim = len(K[target_degree]) + ys += dim*[0] # The zero vector of the appropriate dimension. + else: + all_zero = False + ys += list(y.vector_presentation()) + + # If the initial guess already fits the relations, we are done. + if all_zero: + return Hom(L, M)(xs) + + block_matrix, R = _CreateRelationsMatrix( + K, [r.dense_coefficient_list() for r in L.relations()], source_degs, target_degs) + + try: + solution = R.solve_right(vector(ys)) + except ValueError as error: + if str(error) == 'matrix equation has no solutions': + if verbose: + print('The homomorphism cannot be lifted in any ' + 'way such that the relations of the domain ' + 'are respected: %s' % error) + + return None + else: + raise ValueError(error) + + # Interpret the solution vector as a vector in the direct sum + # $ K_1\oplus K_2\oplus \ldots \oplus K_n $. + n = 0 + for j, source_degree in enumerate(source_degs): + + source_dimension = block_matrix[0][j].domain().dimension() + + w = K.element_from_coordinates( + solution[n:n + source_dimension], source_degree) + + # Subtract the solution w_i from our initial choice of lift + # for the generator g_i. + xs[j] -= iK(w) + + n += source_degree + + return Hom(L, M)(xs) + + + def split(self, verbose=False): + r""" + A split of this homomorphism. + + INPUT: + + - ``verbose`` -- A boolean to enable progress messages. (optional, + default: ``False``) + + OUTPUT: A homomorphism with the property that the composite + homomorphism `self \circ f = id` is the identity homomorphism. If no + such split exist, ``None`` is returned. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A = SteenrodAlgebra(2) + sage: M = FP_Module(A, [0,0], [[0, Sq(1)]]) + sage: N = FP_Module(A, [0], [[Sq(1)]]) + sage: p = Hom(M, N)([N.generator(0), N.generator(0)]) + sage: s = p.split(); s + Module homomorphism of degree 0 defined by sending the generators + [<1>] + to + [<0, 1>] + sage: # Verify that `s` is a splitting: + sage: p*s + The identity homomorphism. + + TESTS: + + sage: F = FP_Module(A, [0]) + sage: N = FP_Module(A, [0], [[Sq(1)]]) + sage: p = Hom(F, N)([N.generator(0)]) + sage: p.split(verbose=True) is None + The homomorphism cannot be lifted in any way such that the relations of the domain are respected: matrix equation has no solutions + True + + .. SEEALSO:: + :meth:`lift` + """ + id = End(self.codomain()).identity() + return id.lift(self, verbose) + + + def homology(self, f, top_dim=None, verbose=False): + r""" + Compute the sub-quotient module `H(self, f) = \ker(self)/\operatorname{im}(f)`, in + a range of degrees. + + For a pair of composable morphisms `f: M\to N` and `g: N \to Q` of + finitely presented modules, the homology module is a finitely + presented quotient of the kernel sub module `\ker(g) \subset N`. + + INPUT: + + - ``f`` -- A homomorphism with codomain equal to the domain of this + homomorphism, and image contained in the kernel of this homomorphism. + + - ``top_dim`` -- An integer used by this function to stop the + computation at the given degree, or the value ``None`` if no termination + should be enforced. (optional, default: ``None``) + + - ``verbose`` -- A boolean to enable progress messages. (optional, + default: ``False``) + + OUTPUT: A quotient homomorphism `\ker(self) \to H`, where `H` is + isomorphic to `H(self, f)` in degrees less than or equal to ``top_dim``. + + .. NOTE:: + + If the algebra for this module is finite, then no ``top_dim`` + needs to be specified in order to ensure that this function terminates. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A = SteenrodAlgebra(2, profile=(3,2,1)) + sage: M = FP_Module(A, [0], [[Sq(3)]]) + sage: N = FP_Module(A, [0], [[Sq(2,2)]]) + sage: F = FP_Module(A, [0]) + sage: f = Hom(M,N)([A.Sq(2)*N.generator(0)]) + sage: g = Hom(F, M)([A.Sq(4)*A.Sq(1,2)*M.generator(0)]) + sage: ho = f.homology(g) + sage: ho.codomain() + Finitely presented left module on 1 generator and 5 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + sage: ho.codomain().is_trivial() + False + """ + k = self.kernel(top_dim, verbose) + f_ = f.lift(k) + if f_ is None: + raise ValueError('the image of the given homomorphism is not contained ' + 'in the kernel of this homomorphism. The homology is ' + 'therefore not defined for this pair of maps') + + return f_.cokernel() + + + def suspension(self, t): + r""" + The suspension of this morphism by the given degree ``t``. + + INPUT: + + - ``t`` -- An integer by which the morphism is suspended. + + OUTPUT: The morphism which is the suspension of this morphism by the + degree ``t``. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A = SteenrodAlgebra(2) + sage: F1 = FP_Module(A, [4,5]) + sage: F2 = FP_Module(A, [5]) + + sage: f = Hom(F1, F2)( ( F2([Sq(4)]), F2([Sq(5)]) ) ); f + Module homomorphism of degree 5 defined by sending the generators + [<1, 0>, <0, 1>] + to + (, ) + + sage: e1 = F1([1, 0]) + sage: e2 = F1([0, 1]) + sage: f(e1) + + sage: f(e2) + + + sage: sf = f.suspension(4); sf + Module homomorphism of degree 5 defined by sending the generators + [<1, 0>, <0, 1>] + to + [, ] + + sage: sf.domain() is f.domain().suspension(4) + True + + sage: sf.codomain() is f.codomain().suspension(4) + True + """ + if t == 0: + return self + else: + D = self.domain().suspension(t) + C = self.codomain().suspension(t) + return Hom(D, C)([C(x.free_element().dense_coefficient_list()) for x in self._values]) + + + def cokernel(self): + r""" + Compute the cokernel of this homomorphism. + + OUTPUT: The natural projection from the codomain of this homomorphism + to its cokernel. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A1 = SteenrodAlgebra(2, profile=(2,1)) + sage: M = FP_Module(A1, [0], [[Sq(2)]]) + sage: F = FP_Module(A1, [0]) + + sage: r = Hom(F, M)([A1.Sq(1)*M.generator(0)]) + sage: co = r.cokernel(); co + Module homomorphism of degree 0 defined by sending the generators + [<1>] + to + [<1>] + + sage: co.domain().is_trivial() + False + """ + from .module import FP_Module + new_relations = [x.dense_coefficient_list() for x in self.codomain().relations()] +\ + [x.dense_coefficient_list() for x in self._values] + + coker = FP_Module(self.base_ring(), + self.codomain().generator_degrees(), + relations=tuple(new_relations)) + + projection = Hom(self.codomain(), coker)(coker.generators()) + + return projection + + + def kernel(self, top_dim=None, verbose=False): + r""" + Compute the kernel of this homomorphism. + + INPUT: + + - ``top_dim`` -- An integer used by this function to stop the + computation at the given degree, or the value ``None`` if no + termination should be enforced. (optional, default: ``None``) + + - ``verbose`` -- A boolean to enable progress messages. (optional, + default: ``False``) + + OUTPUT: A homomorphism into `\ker(self)` which is an isomorphism in + degrees less than or equal to ``top_dim``. + + .. NOTE:: + + If the algebra for this module is finite, then no ``top_dim`` needs + to be specified in order to ensure that this function terminates. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) + sage: F = FP_Module(A3, [1,3]); + sage: L = FP_Module(A3, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]); + sage: H = Hom(F, L); + + sage: H([L((A3.Sq(1), 1)), L((0, A3.Sq(2)))]).kernel() # long time + Module homomorphism of degree 0 defined by sending the generators + [<1, 0>, <0, 1>] + to + (<0, 1>, ) + + sage: M = FP_Module(A3, [0,7], [[Sq(1), 0], [Sq(2), 0], [Sq(4), 0], [Sq(8), Sq(1)], [0, Sq(7)], [0, Sq(0,1,1)+Sq(4,2)]]) + sage: F2 = FP_Module(A3, [0], [[Sq(1)], [Sq(2)], [Sq(4)], [Sq(8)], [Sq(15)]]) + sage: H = Hom(M, F2) + sage: f = H([F2([1]), F2([0])]) + + sage: K = f.kernel(verbose=True, top_dim=17) + 1. Computing the generators of the kernel presentation: + Resolving the kernel in the range of dimensions [0, 17]: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17. + 2. Computing the relations of the kernel presentation: + Resolving the kernel in the range of dimensions [7, 17]: 7 8 9 10 11 12 13 14 15 16 17. + + sage: K.domain().generators() + [<1>] + sage: K.domain().relations() + [, + , + , + ] + + sage: K + Module homomorphism of degree 0 defined by sending the generators + [<1>] + to + (<0, 1>,) + """ + if verbose: + print('1. Computing the generators of the kernel presentation:') + j0 = self._resolve_kernel(top_dim, verbose) + if verbose: + print('2. Computing the relations of the kernel presentation:') + j1 = j0._resolve_kernel(top_dim, verbose) + + # Create a module isomorphic to the ker(self). + K = j1.to_fp_module() + + # Return an injection of K into the domain of self such that + # its image equals ker(self). + return Hom(K, j0.codomain())(j0.values()) + + + def image(self, top_dim=None, verbose=False): + r""" + Compute the image of this homomorphism. + + INPUT: + + - ``top_dim`` -- An integer used by this function to stop the + computation at the given degree, or the value ``None`` if no + termination should be enforced. (optional, default: ``None``) + + - ``verbose`` -- A boolean to enable progress messages. (optional, + default: ``False``) + + OUTPUT: A homomorphism into `\operatorname{im}(self)` which is an + isomorphism in degrees less than or equal to ``top_dim``. + + .. NOTE:: + + If the algebra for this module is finite, then no ``top_dim`` + needs to be specified in order to ensure that this function + terminates. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) + sage: F = FP_Module(A3, [1,3]); + sage: L = FP_Module(A3, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]); + sage: H = Hom(F, L); + + sage: H([L((A3.Sq(1), 1)), L((0, A3.Sq(2)))]).image() # long time + Module homomorphism of degree 0 defined by sending the generators + [<1>] + to + (,) + + sage: M = FP_Module(A3, [0,7], [[Sq(1), 0], [Sq(2), 0], [Sq(4), 0], [Sq(8), Sq(1)], [0, Sq(7)], [0, Sq(0,1,1)+Sq(4,2)]]) + sage: F2 = FP_Module(A3, [0], [[Sq(1)], [Sq(2)], [Sq(4)], [Sq(8)], [Sq(15)]]) + sage: H = Hom(M, F2) + sage: f = H([F2([1]), F2([0])]) + sage: K = f.image(verbose=True, top_dim=17) + 1. Computing the generators of the image presentation: + Resolving the image in the range of dimensions [0, 17]: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17. + 2. Computing the relations of the image presentation: + Resolving the kernel in the range of dimensions [0, 17]: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17. + + sage: K.is_injective() # long time + True + sage: K.domain().generator_degrees() + (0,) + sage: K.domain().relations() + [, , , ] + sage: K.domain().is_trivial() + False + + """ + if verbose: + print('1. Computing the generators of the image presentation:') + j0 = self._resolve_image(top_dim, verbose) + if verbose: + print('2. Computing the relations of the image presentation:') + j1 = j0._resolve_kernel(top_dim, verbose) + + # Create a module isomorphic to the im(self). + I = j1.to_fp_module() + + # Return an injection of I into the codomain of self such that + # its image equals im(self) + return Hom(I, j0.codomain())(j0.values()) + + + def is_injective(self, top_dim=None, verbose=False): + r""" + Return ``True`` if and only if this homomorphism has a trivial kernel. + + INPUT: + + - ``top_dim`` -- An integer used by this function to stop the + computation at the given degree, or the value ``None`` if no termination + should be enforced. (optional, default: ``None``) + + - ``verbose`` -- A boolean to enable progress messages. (optional, + default: ``False``) + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A = SteenrodAlgebra(2) + + sage: K = FP_Module(A, [2], [[Sq(2)]]) + sage: HZ = FP_Module(A, [0], [[Sq(1)]]) + + sage: f = Hom(K, HZ)([Sq(2)*HZ([1])]) + sage: f.is_injective(top_dim=23) + True + + TESTS: + + sage: Z = FP_Module(A, []) + sage: Hom(Z, HZ).zero().is_injective(top_dim=8) + True + + """ + j0 = self._resolve_kernel(top_dim, verbose) + return j0.domain().is_trivial() + + + def is_surjective(self): + r""" + Return ``True`` if and only if this homomorphism has a trivial cokernel. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A = SteenrodAlgebra(2) + sage: F = FP_Module(A, [0]) + + sage: f = Hom(F,F)([Sq(1)*F.generator(0)]) + sage: f.is_surjective() + False + + TESTS: + + sage: Z = FP_Module(A, []) + sage: Hom(F, Z).zero().is_surjective() + True + + """ + return self.cokernel().is_zero() + + + def _resolve_kernel(self, top_dim=None, verbose=False): + r""" + Resolve the kernel of this homomorphism by a free module. + + INPUT: + + - ``top_dim`` -- An integer used by this function to stop the + computation at the given degree, or the value ``None`` if no termination + should be enforced. (optional, default: ``None``) + + - ``verbose`` -- A boolean to enable progress messages. (optional, + default: ``False``) + + OUTPUT: A homomorphism `j: F \rightarrow D` where `D` is the domain of + this homomorphism, `F` is free and such that + `\ker(self) = \operatorname{im}(j)` in all degrees less than or equal + to ``top_dim``. + + .. NOTE:: + + If the algebra for this module is finite, then no ``top_dim`` + needs to be specified in order to ensure that this function terminates. + + TESTS: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A = SteenrodAlgebra(2) + sage: F = FP_Module(A, [0,0]) + sage: L = FP_Module(A, [0,0], [[Sq(3),Sq(0,1)], [0,Sq(2)]]) + sage: f = Hom(F, L)([L([Sq(2),0]), L([0, Sq(2)])]) + sage: f._resolve_kernel() + Traceback (most recent call last): + ... + ValueError: a top dimension must be specified for this calculation to terminate + sage: f._resolve_kernel(top_dim=20) + Module homomorphism of degree 0 defined by sending the generators + [<1, 0, 0>, <0, 1, 0>, <0, 0, 1>] + to + (<0, 1>, , ) + sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) + sage: f.change_ring(A3)._resolve_kernel() # long time + Module homomorphism of degree 0 defined by sending the generators + [<1, 0, 0>, <0, 1, 0>, <0, 0, 1>] + to + (<0, 1>, , ) + """ + # Let + # + # 1) `j` be a homomorphism into `\ker(self)`, and + # 2) 'n' be an integer. + # + # The induction loop starts each iteration assuming that that `j` is onto + # the kernel in degrees below `n`. Each iteration of the loop then + # extends the map `j` minimally so that `j_n` becomes onto the kernel. + # + # This induction step is then repeated for all `n \leq` ``top_dim``. + # + + if self.is_zero(): + # Epsilon: F_0 -> M + M = self.domain() + F_0 = self.domain().j.codomain().to_fp_module() + epsilon = Hom(F_0, M)(tuple(M.generators())) + return epsilon + + # Create the trivial module F_ to start with. + F_ = self.domain().__class__(self.base_ring(), ()) + j = Hom(F_, self.domain())(()) + + dim = self.domain().connectivity() + if dim == PlusInfinity(): + if verbose: + print ('The domain of the morphism is trivial, so there is nothing to resolve.') + return j + + limit = PlusInfinity() if not self.base_ring().is_finite() else\ + (self.base_ring().top_class().degree() + max(self.domain().generator_degrees())) + + if not top_dim is None: + limit = min(top_dim, limit) + + if limit == PlusInfinity(): + raise ValueError('a top dimension must be specified for this calculation to terminate') + + if verbose: + if dim > limit: + print('The dimension range is empty: [%d, %d]' % (dim, limit)) + else: + print('Resolving the kernel in the range of dimensions [%d, %d]:' % (dim, limit), end='') + + # The induction loop. + for n in range(dim, limit+1): + + if verbose: + print(' %d' % n, end='') + sys.stdout.flush() + + # We have taken care of the case when self is zero, so the + # vector presentation exists. + self_n = self.vector_presentation(n) + kernel_n = self_n.kernel() + + if kernel_n.dimension() == 0: + continue + + generator_degrees = tuple((x.degree() for x in F_.generators())) + + if j.is_zero(): + # The map j is not onto in degree `n` of the kernel. + new_generator_degrees = tuple(kernel_n.dimension()*(n,)) + F_ = self.domain().__class__(self.base_ring(), + generator_degrees + new_generator_degrees) + + new_values = tuple([ + self.domain().element_from_coordinates(q, n) for q in kernel_n.basis()]) + + else: + Q_n = kernel_n.quotient(j.vector_presentation(n).image()) + + if Q_n.dimension() == 0: + continue + + # The map j is not onto in degree `n` of the kernel. + new_generator_degrees = tuple(Q_n.dimension()*(n,)) + F_ = self.domain().__class__(self.base_ring(), + generator_degrees + new_generator_degrees) + + new_values = tuple([ + self.domain().element_from_coordinates(Q_n.lift(q), n) for q in Q_n.basis()]) + + # Create a new homomorphism which is surjective onto the kernel + # in all degrees less than, and including `n`. + j = Hom(F_, self.domain()) (j.values() + new_values) + + if verbose: + print('.') + return j + + + def _resolve_image(self, top_dim=None, verbose=False): + r""" + Resolve the image of this homomorphism by a free module. + + INPUT: + + - ``top_dim`` -- An integer used by this function to stop the + computation at the given degree, or the value ``None`` if no termination + should be enforced. (optional, default: ``None``) + + - ``verbose`` -- A boolean to enable progress messages. (optional, + default: ``False``) + + OUTPUT: A homomorphism `j: F \rightarrow C` where `C` is the codomain + of this homomorphism, `F` is free, and + `\operatorname{im}(self) = \operatorname{im}(j)` in all degrees less + than or equal to ``top_dim``. + + .. NOTE:: + + If the algebra for this module is finite, then no ``top_dim`` needs + to be specified in order to ensure that this function terminates. + + TESTS: + + sage: from sage.modules.fp_graded.module import * + sage: A = SteenrodAlgebra(2) + sage: F = FP_Module(A, [0,0]) + sage: L = FP_Module(A, [0,0], [[Sq(3),Sq(0,1)], [0,Sq(2)]]) + sage: f = Hom(F, L)([L([Sq(2),0]), L([0, Sq(2)])]) + sage: f._resolve_image() + Traceback (most recent call last): + ... + ValueError: a top dimension must be specified for this calculation to terminate + sage: f._resolve_image(top_dim=20) + Module homomorphism of degree 0 defined by sending the generators + [<1>] + to + (,) + sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) + sage: f.change_ring(A3)._resolve_image() # long time + Module homomorphism of degree 0 defined by sending the generators + [<1>] + to + (,) + """ + # Let + # + # 1) `j` be a homomorphism into `\im(self)`, and + # 2) 'n' be an integer. + # + # The induction loop starts each iteration assuming that that `j` is onto + # the image in degrees below `n`. Each iteration of the loop then + # extends the map `j` minimally so that `j_n` becomes onto the image. + # + # This induction step is then repeated for all `n \leq` ``top_dim``. + # + + # Create the trivial module F_ to start with. + F_ = self.domain().__class__(self.base_ring(), ()) + j = Hom(F_, self.codomain())(()) + + dim = self.codomain().connectivity() + if dim == PlusInfinity(): + if verbose: + print ('The codomain of the morphism is trivial, so there is nothing to resolve.') + return j + + self_degree = self.degree() + if self_degree is None: + if verbose: + print ('The homomorphism is trivial, so there is nothing to resolve.') + return j + + degree_values = [0] + [v.degree() for v in self.values() if v] + limit = PlusInfinity() if not self.base_ring().is_finite() else\ + (self.base_ring().top_class().degree() + max(degree_values)) + + if not top_dim is None: + limit = min(top_dim, limit) + + if limit == PlusInfinity(): + raise ValueError('a top dimension must be specified for this calculation to terminate') + + if verbose: + if dim > limit: + print('The dimension range is empty: [%d, %d]' % (dim, limit)) + else: + print('Resolving the image in the range of dimensions [%d, %d]:' % (dim, limit), end='') + + for n in range(dim, limit+1): + + if verbose: + print(' %d' % n, end='') + sys.stdout.flush() + + self_n = self.vector_presentation(n - self_degree) + image_n = self_n.image() + + if image_n.dimension() == 0: + continue + + + generator_degrees = tuple((x.degree() for x in F_.generators())) + if j.is_zero(): + # The map j is not onto in degree `n` of the image. + new_generator_degrees = tuple(image_n.dimension()*(n,)) + F_ = self.domain().__class__(self.base_ring(), + generator_degrees + new_generator_degrees) + + new_values = tuple([ + self.codomain().element_from_coordinates(q, n) for q in image_n.basis()]) + + else: + + j_n = j.vector_presentation(n) + Q_n = image_n.quotient(j_n.image()) + + if Q_n.dimension() == 0: + continue + + # The map j is not onto in degree `n` of the image. + new_generator_degrees = tuple(Q_n.dimension()*(n,)) + F_ = self.domain().__class__(self.base_ring(), + generator_degrees + new_generator_degrees) + + new_values = tuple([ + self.codomain().element_from_coordinates(Q_n.lift(q), n) for q in Q_n.basis()]) + + # Create a new homomorphism which is surjective onto the image + # in all degrees less than, and including `n`. + j = Hom(F_, self.codomain()) (j.values() + new_values) + + if verbose: + print('.') + return j + + def to_fp_module(self): + r""" + Create a finitely presented module from this morphism. + + OUTPUT: The finitely presented module having presentation + equal to this morphism, as long as the domain and codomain are free. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FP_Module + sage: A = SteenrodAlgebra(2) + sage: F1 = FP_Module(A, (2,)) + sage: F2 = FP_Module(A, (0,)) + sage: v = F2([Sq(2)]) + sage: pres = Hom(F1, F2)([v]) + sage: M = pres.to_fp_module(); M + Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis + sage: M.generator_degrees() + (0,) + sage: M.relations() + [] + + sage: F3 = FP_Module(A, (0,), [[Sq(4)]]) + sage: pres = Hom(F1, F3)([v]) + sage: pres.to_fp_module() + Traceback (most recent call last): + ... + ValueError: this is not a morphism between free modules + """ + if self.domain().has_relations() or self.codomain().has_relations(): + raise ValueError("this is not a morphism between free modules") + from .module import FP_Module + return FP_Module(algebra=self.base_ring(), + generator_degrees=self.codomain().generator_degrees(), + relations=tuple([r.dense_coefficient_list() for r in self.values()])) + From fab508ad23b72e96a9e367956325f24c100bb18b Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Mon, 13 Sep 2021 13:54:52 -0700 Subject: [PATCH 019/253] trac 32505: clear out __init__.py --- src/sage/modules/fp_graded/__init__.py | 12 ------------ src/sage/modules/fp_graded/module.py | 11 +++++++++++ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/sage/modules/fp_graded/__init__.py b/src/sage/modules/fp_graded/__init__.py index 2e5420c89a1..e69de29bb2d 100755 --- a/src/sage/modules/fp_graded/__init__.py +++ b/src/sage/modules/fp_graded/__init__.py @@ -1,12 +0,0 @@ -""" -Finitely presented graded left modules over graded connected algebras -""" - - -# TODO: -# -# 1. Why do we need to define __bool__ and __eq__ in element.py? They should be taken care of automatically, once we define __nonzero__. -# 2. inhheritance: free modules, elements, etc., should perhaps inherit from fp versions, or maybe both should inherit from generic classes, to consolidate some methods (like degree, _repr_, others?) -# 3. Test with graded modules over other graded rings. (Should be okay, but add some doctests.) -# -# In __classcall__/__init__ for FP_Modules, allow as input a free module or a morphism of free modules? diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index c347a6cb2c4..8e2d5105793 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -1,3 +1,14 @@ +# TODO: +# +# 1. Why do we need to define __bool__ and __eq__ in element.py? They should be taken care of automatically, once we define __nonzero__. +# 2. inhheritance: free modules, elements, etc., should perhaps inherit from fp versions, or maybe both should inherit from generic classes, to consolidate some methods (like degree, _repr_, others?) +# 3. Test with graded modules over other graded rings. (Should be okay, but add some doctests.) +# +# In __classcall__/__init__ for FP_Modules, allow as input a free module or a morphism of free modules? + + + + r""" Finitely presented graded modules From c0930162820c778598afea7de7119c624a0c40fe Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Tue, 28 Sep 2021 13:39:53 -0700 Subject: [PATCH 020/253] trac 32505: - change TESTS: to TESTS:: where appropriate - remove is_CLASS functions, replace by isinstance(-, CLASS) - rename FP_Element to FPElement, and similar - rename x.free_element() to x.lift_to_free() --- src/sage/modules/fp_graded/element.py | 74 +++--- src/sage/modules/fp_graded/free_element.py | 4 +- src/sage/modules/fp_graded/free_homspace.py | 34 +-- src/sage/modules/fp_graded/free_module.py | 14 +- src/sage/modules/fp_graded/free_morphism.py | 16 +- src/sage/modules/fp_graded/homspace.py | 90 +++---- src/sage/modules/fp_graded/module.py | 166 ++++++------- src/sage/modules/fp_graded/morphism.py | 253 ++++++++++---------- 8 files changed, 302 insertions(+), 349 deletions(-) diff --git a/src/sage/modules/fp_graded/element.py b/src/sage/modules/fp_graded/element.py index c7f3b24efe5..4d9901490ac 100755 --- a/src/sage/modules/fp_graded/element.py +++ b/src/sage/modules/fp_graded/element.py @@ -2,7 +2,7 @@ Elements of finitely presented graded modules This class implements construction and basic manipulation of elements of the -Sage parent :class:`sage.modules.fp_graded.module.FP_Module`, which models +Sage parent :class:`sage.modules.fp_graded.module.FPModule`, which models finitely presented modules over connected graded algebras. AUTHORS: @@ -31,34 +31,34 @@ from .free_element import FreeGradedModuleElement -class FP_Element(IndexedFreeModuleElement): +class FPElement(IndexedFreeModuleElement): r""" A module element of a finitely presented graded module over a connected graded algebra. - TESTS: + TESTS:: - sage: from sage.modules.fp_graded.module import FP_Module - sage: FP_Module(SteenrodAlgebra(2), [0])([Sq(2)]) + sage: from sage.modules.fp_graded.module import FPModule + sage: FPModule(SteenrodAlgebra(2), [0])([Sq(2)]) """ - def free_element(self): + def lift_to_free(self): r""" A lift of this element to the free module F, if this element is in a quotient of F. EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module - sage: M = FP_Module(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) + sage: from sage.modules.fp_graded.module import FPModule + sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) sage: x = M([Sq(1), 1]) sage: x sage: x.parent() Finitely presented left module on 2 generators and 1 relation over mod 2 Steenrod algebra, milnor basis - sage: x.free_element() + sage: x.lift_to_free() - sage: x.free_element().parent() + sage: x.lift_to_free().parent() Finitely presented free left module on 2 generators over mod 2 Steenrod algebra, milnor basis """ C = self.parent().j.codomain() @@ -75,8 +75,8 @@ def degree(self): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module - sage: M = FP_Module(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) + sage: from sage.modules.fp_graded.module import FPModule + sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) sage: x = M.an_element(7) sage: x @@ -91,9 +91,9 @@ def degree(self): ... ValueError: the zero element does not have a well-defined degree - TESTS: + TESTS:: - sage: N = FP_Module(SteenrodAlgebra(2), [0], [[Sq(2)]]) + sage: N = FPModule(SteenrodAlgebra(2), [0], [[Sq(2)]]) sage: y = Sq(2)*N.generator(0) sage: y == 0 True @@ -104,7 +104,7 @@ def degree(self): """ if self.is_zero(): raise ValueError("the zero element does not have a well-defined degree") - return self.free_element().degree() + return self.lift_to_free().degree() def _repr_(self): @@ -113,8 +113,8 @@ def _repr_(self): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module - sage: M = FP_Module(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) + sage: from sage.modules.fp_graded.module import FPModule + sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) sage: [M.an_element(n) for n in range(1,10)] [, , @@ -126,7 +126,7 @@ def _repr_(self): , ] """ - return self.free_element()._repr_() + return self.lift_to_free()._repr_() def _lmul_(self, a): @@ -141,15 +141,15 @@ def _lmul_(self, a): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) - sage: M = FP_Module(A2, [0,3], [[Sq(2)*Sq(4), Sq(3)]]) + sage: M = FPModule(A2, [0,3], [[Sq(2)*Sq(4), Sq(3)]]) sage: A2.Sq(2)*M.generator(1) <0, Sq(2)> sage: A2.Sq(2)*(A2.Sq(1)*A2.Sq(2)*M.generator(0) + M.generator(1)) - TESTS: + TESTS:: sage: elements = [M.an_element(n) for n in range(1,10)] sage: a = A2.Sq(3) @@ -164,7 +164,7 @@ def _lmul_(self, a): , <0, Sq(3,2)>] """ - return self.parent()(a*self.free_element()) + return self.parent()(a*self.lift_to_free()) def vector_presentation(self): @@ -172,7 +172,7 @@ def vector_presentation(self): A coordinate vector representing this module element when it is non-zero. These are coordinates with respect to the basis chosen by - :meth:`sage.modules.fp_graded.module.FP_Module.basis_elements`. + :meth:`sage.modules.fp_graded.module.FPModule.basis_elements`. When the element is zero, it has no well defined degree, and this function returns ``None``. @@ -182,15 +182,15 @@ def vector_presentation(self): .. SEEALSO:: - :meth:`sage.modules.fp_graded.module.FP_Module.vector_presentation` - :meth:`sage.modules.fp_graded.module.FP_Module.basis_elements` - :meth:`sage.modules.fp_graded.module.FP_Module.element_from_coordinates` + :meth:`sage.modules.fp_graded.module.FPModule.vector_presentation` + :meth:`sage.modules.fp_graded.module.FPModule.basis_elements` + :meth:`sage.modules.fp_graded.module.FPModule.element_from_coordinates` EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) - sage: M = FP_Module(A2, (0,1)) + sage: M = FPModule(A2, (0,1)) sage: x = M.an_element(7) sage: v = x.vector_presentation(); v @@ -214,7 +214,7 @@ def vector_presentation(self): sage: x == x_ True - TESTS: + TESTS:: sage: M.zero().vector_presentation() is None True @@ -226,12 +226,12 @@ def vector_presentation(self): # place it inside any vector space. However, this will not work for # homomorphisms, so we return None to be consistent. try: - degree = self.free_element().degree() + degree = self.lift_to_free().degree() except ValueError: return None F_n = self.parent().vector_presentation(degree) - return F_n.quotient_map()(self.free_element().vector_presentation()) + return F_n.quotient_map()(self.lift_to_free().vector_presentation()) def __nonzero__(self): @@ -243,8 +243,8 @@ def __nonzero__(self): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module - sage: M = FP_Module(SteenrodAlgebra(2), [0,2,4], [[Sq(4),Sq(2),0]]) + sage: from sage.modules.fp_graded.module import FPModule + sage: M = FPModule(SteenrodAlgebra(2), [0,2,4], [[Sq(4),Sq(2),0]]) sage: M(0).__nonzero__() False sage: M((Sq(6), 0, Sq(2))).__nonzero__() @@ -271,8 +271,8 @@ def __eq__(self, other): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module - sage: M = FP_Module(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) + sage: from sage.modules.fp_graded.module import FPModule + sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) sage: x = M([Sq(1), 1]) sage: x @@ -298,8 +298,8 @@ def normalize(self): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module - sage: M = FP_Module(SteenrodAlgebra(2), [0,2,4], [[Sq(4),Sq(2),0]]) + sage: from sage.modules.fp_graded.module import FPModule + sage: M = FPModule(SteenrodAlgebra(2), [0,2,4], [[Sq(4),Sq(2),0]]) sage: m = M((Sq(6), 0, Sq(2))); m diff --git a/src/sage/modules/fp_graded/free_element.py b/src/sage/modules/fp_graded/free_element.py index d7b2bfbc8ed..e3fab6821ee 100755 --- a/src/sage/modules/fp_graded/free_element.py +++ b/src/sage/modules/fp_graded/free_element.py @@ -145,7 +145,7 @@ def _lmul_(self, a): sage: A2.Sq(2)*(A2.Sq(1)*A2.Sq(2)*M.generator(1) + M.generator(2)) <0, Sq(2,1), Sq(2)> - TESTS: + TESTS:: sage: elements = [M.an_element(n) for n in range(1,10)] sage: a = A2.Sq(3) @@ -209,7 +209,7 @@ def vector_presentation(self): sage: x == x_ True - TESTS: + TESTS:: sage: M.zero().vector_presentation() is None True diff --git a/src/sage/modules/fp_graded/free_homspace.py b/src/sage/modules/fp_graded/free_homspace.py index ccdfc37ed66..7bf639a6fd1 100755 --- a/src/sage/modules/fp_graded/free_homspace.py +++ b/src/sage/modules/fp_graded/free_homspace.py @@ -7,7 +7,7 @@ For an overview of the free module API, see :doc:`free_module`. -TESTS: +TESTS:: sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: from sage.misc.sage_unittest import TestSuite @@ -47,33 +47,9 @@ from sage.misc.cachefunc import cached_method -def is_FreeGradedModuleHomspace(x): - r""" - Check if the given object is of type FreeGradedModuleHomspace. - - OUTPUT: The boolean ``True`` if and only if ``x`` is of type - FreeGradedModuleHomspace, and ``False`` otherwise. - - EXAMPLES:: - - sage: from sage.modules.fp_graded.free_module import FreeGradedModule - sage: from sage.modules.fp_graded.free_homspace import is_FreeGradedModuleHomspace - sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) - sage: F = FreeGradedModule(A2, (1,3)) - sage: L = FreeGradedModule(A2, (2,3)) - sage: is_FreeGradedModuleHomspace(Hom(F, L)) - True - - TESTS: - - sage: is_FreeGradedModuleHomspace(0) - False - """ - return isinstance(x, FreeGradedModuleHomspace) - class FreeGradedModuleHomspace(Homset): - # In the category framework, Elements of the class FP_Module are of the - # class FP_Element, see + # In the category framework, Elements of the class FPModule are of the + # class FPElement, see # http://doc.sagemath.org/html/en/thematic_tutorials/coercion_and_categories.html#implementing-the-category-framework-for-the-elements from .free_morphism import FreeGradedModuleMorphism @@ -171,7 +147,7 @@ def identity(self): OUTPUT: The identity endomorphism. - TESTS: + EXAMPLES:: sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) @@ -180,7 +156,7 @@ def identity(self): sage: H.identity() The identity homomorphism. - TESTS: + TESTS:: sage: F = FreeGradedModule(A2, (1,3)) sage: H = Hom(F, L) diff --git a/src/sage/modules/fp_graded/free_module.py b/src/sage/modules/fp_graded/free_module.py index 63ab4187cb0..9b3807416b3 100755 --- a/src/sage/modules/fp_graded/free_module.py +++ b/src/sage/modules/fp_graded/free_module.py @@ -274,7 +274,6 @@ from sage.combinat.free_module import CombinatorialFreeModule from .free_element import FreeGradedModuleElement -from .free_homspace import FreeGradedModuleHomspace class FreeGradedModule(CombinatorialFreeModule): r""" @@ -291,7 +290,7 @@ class FreeGradedModule(CombinatorialFreeModule): OUTPUT: The finitely generated free graded module on generators with degrees given by ``generator_degrees``. - TESTS: + TESTS:: sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: A = SteenrodAlgebra(2) @@ -371,7 +370,7 @@ def connectivity(self): sage: M.connectivity() -2 - TESTS: + TESTS:: sage: M = FreeGradedModule(A, ()) sage: M.is_trivial() @@ -476,7 +475,7 @@ def _repr_(self): r""" Construct a string representation of the module. - TESTS: + TESTS:: sage: from sage.modules.fp_graded.free_module import * sage: A = SteenrodAlgebra(2) @@ -709,7 +708,7 @@ def _Hom_(self, Y, category): :meth:`sage.categories.homset.hom.Hom` to create homsets involving this parent. - TESTS: + TESTS:: sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: A = SteenrodAlgebra(2) @@ -717,6 +716,7 @@ def _Hom_(self, Y, category): sage: M._Hom_(M, category=None) Set of Morphisms from Finitely presented free left module on 2 generators over mod 2 Steenrod algebra, milnor basis to Finitely presented free left module on 2 generators over mod 2 Steenrod algebra, milnor basis in Category of finite dimensional graded modules with basis over mod 2 Steenrod algebra, milnor basis """ + from .free_homspace import FreeGradedModuleHomspace return FreeGradedModuleHomspace(self, Y, category) @@ -760,8 +760,8 @@ def to_fp_module(self): sage: F.to_fp_module() Finitely presented left module on 3 generators and 0 relations over mod 2 Steenrod algebra, milnor basis """ - from .module import FP_Module - return FP_Module(algebra=self.base_ring(), + from .module import FPModule + return FPModule(algebra=self.base_ring(), generator_degrees=self.generator_degrees(), relations=()) diff --git a/src/sage/modules/fp_graded/free_morphism.py b/src/sage/modules/fp_graded/free_morphism.py index e58de46fb16..cb2ad663be5 100755 --- a/src/sage/modules/fp_graded/free_morphism.py +++ b/src/sage/modules/fp_graded/free_morphism.py @@ -37,8 +37,6 @@ from sage.categories.morphism import Morphism from sage.misc.cachefunc import cached_method -from .free_homspace import is_FreeGradedModuleHomspace - class FreeGradedModuleMorphism(Morphism): r""" @@ -72,7 +70,7 @@ class FreeGradedModuleMorphism(Morphism): to [, ] - TESTS: + TESTS:: A non-example because the degree is not well-defined:: @@ -90,9 +88,11 @@ def __init__(self, parent, values): r""" Create a homomorphism between finitely generated free graded modules. """ - if not is_FreeGradedModuleHomspace(parent): + from .free_homspace import FreeGradedModuleHomspace + if not isinstance(parent, FreeGradedModuleHomspace): raise TypeError('the parent (%s) must be a f.p. free module homset' % parent) + # Get the values. C = parent.codomain() D = parent.domain() @@ -354,7 +354,7 @@ def __mul__(self, g): sage: fg.is_endomorphism() True - TESTS: + TESTS:: sage: fg == f.__mul__(g) True @@ -544,7 +544,7 @@ def vector_presentation(self, n): Domain: Vector space of dimension 2 over Finite Field of size 2 Codomain: Vector space of dimension 4 over Finite Field of size 2 - TESTS: + TESTS:: sage: F = FreeGradedModule(A, (0,)) sage: z = Hom(F, F)([0]) @@ -589,7 +589,7 @@ def to_fp_module(self): sage: M.relations() [] """ - from .module import FP_Module - return FP_Module(algebra=self.base_ring(), + from .module import FPModule + return FPModule(algebra=self.base_ring(), generator_degrees=self.codomain().generator_degrees(), relations=tuple([r.dense_coefficient_list() for r in self.values()])) diff --git a/src/sage/modules/fp_graded/homspace.py b/src/sage/modules/fp_graded/homspace.py index dcb17f191b6..5723710511f 100755 --- a/src/sage/modules/fp_graded/homspace.py +++ b/src/sage/modules/fp_graded/homspace.py @@ -8,13 +8,13 @@ .. NOTE:: This class is intended for private use by :class:`sage.modules.fp_steenrod.fpa_homspace.FPA_ModuleHomspace`. -TESTS: +TESTS:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: from sage.misc.sage_unittest import TestSuite sage: A = SteenrodAlgebra(2, profile=(3,2,1)) - sage: F = FP_Module(A, [1,3]) - sage: L = FP_Module(A, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]) + sage: F = FPModule(A, [1,3]) + sage: L = FPModule(A, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]) sage: homset = Hom(F, L); homset Set of Morphisms from Finitely presented left module on 2 generators ... sage: homset.an_element() @@ -59,36 +59,16 @@ from sage.categories.homset import Hom -def is_FP_ModuleHomspace(x): - r""" - Check if the given object is of type FP_ModuleHomspace. - OUTPUT: A boolean which is True if ``x`` is of type FP_ModuleHomspace. +class FPModuleHomspace(Homset): + # FPModuleMorphism imports FPModuleHomspace, so this import should + # not happen at the top level. + from .morphism import FPModuleMorphism - EXAMPLES:: - - sage: from sage.modules.fp_graded.module import FP_Module - sage: from sage.modules.fp_graded.homspace import is_FP_ModuleHomspace - sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) - sage: F = FP_Module(A2, [1,3]) - sage: L = FP_Module(A2, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]) - sage: is_FP_ModuleHomspace(Hom(F, L)) - True - sage: is_FP_ModuleHomspace(0) - False - """ - return isinstance(x, FP_ModuleHomspace) - - -class FP_ModuleHomspace(Homset): - # FP_ModuleMorphism contains reference to is_FP_ModuleHomspace, so this import - # statement must not appear before that function. - from .morphism import FP_ModuleMorphism - - # In the category framework, Elements of the class FP_ModuleHomspace are of the - # class FP_ModuleMorphism, see + # In the category framework, Elements of the class FPModuleHomspace are of the + # class FPModuleMorphism, see # http://doc.sagemath.org/html/en/thematic_tutorials/coercion_and_categories.html#implementing-the-category-framework-for-the-elements - Element = FP_ModuleMorphism + Element = FPModuleMorphism def _element_constructor_(self, values): r""" @@ -99,17 +79,17 @@ def _element_constructor_(self, values): INPUT: - - ``values`` -- An iterable of FP_Elements of the codomain. + - ``values`` -- An iterable of FPElements of the codomain. OUTPUT: A module homomorphism in this homspace sending the generators of the domain module to the given values. EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) - sage: F = FP_Module(A2, [1,3]) - sage: L = FP_Module(A2, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]) + sage: F = FPModule(A2, [1,3]) + sage: L = FPModule(A2, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]) sage: homset = Hom(F, L) sage: v1 = L([A2.Sq(1), 1]) @@ -156,9 +136,9 @@ def an_element(self, n=0): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) - sage: HZ = FP_Module(A, [0], relations=[[Sq(1)]]) + sage: HZ = FPModule(A, [0], relations=[[Sq(1)]]) sage: Hom(HZ, HZ).an_element(3) Module homomorphism of degree 3 defined by sending the generators @@ -166,16 +146,16 @@ def an_element(self, n=0): to [] - TESTS: + TESTS:: - sage: K = FP_Module(A, [0, 0], [[Sq(2), 0]]) # Using a zero coefficient in the relations. + sage: K = FPModule(A, [0, 0], [[Sq(2), 0]]) # Using a zero coefficient in the relations. sage: Hom(K, K).an_element(4) Module homomorphism of degree 4 defined by sending the generators [<1, 0>, <0, 1>] to [<0, 0>, ] - sage: K = FP_Module(A, [0, 0], [[Sq(2), 0], [0,0], [Sq(4), Sq(2)*Sq(2)]]) + sage: K = FPModule(A, [0, 0], [[Sq(2), 0], [0,0], [Sq(4), Sq(2)*Sq(2)]]) sage: Hom(K, K).an_element(n=3) Module homomorphism of degree 3 defined by sending the generators [<1, 0>, <0, 1>] @@ -197,9 +177,9 @@ def basis_elements(self, n): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) - sage: Hko = FP_Module(A, [0], relations=[[Sq(2)], [Sq(1)]]) + sage: Hko = FPModule(A, [0], relations=[[Sq(2)], [Sq(1)]]) sage: Hom(Hko, Hko).basis_elements(21) [Module homomorphism of degree 21 defined by sending the generators @@ -220,10 +200,10 @@ def zero(self): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) - sage: F = FP_Module(A2, [1,3]) - sage: L = FP_Module(A2, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]) + sage: F = FPModule(A2, [1,3]) + sage: L = FPModule(A2, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]) sage: z = Hom(F, L).zero(); z The trivial homomorphism. @@ -243,9 +223,9 @@ def identity(self): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) - sage: L = FP_Module(A2, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]) + sage: L = FPModule(A2, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]) sage: id = Hom(L, L).identity(); id The identity homomorphism. @@ -257,7 +237,7 @@ def identity(self): It is an error to call this function when the homset is not a set of endomorphisms:: - sage: F = FP_Module(A2, [1,3]) + sage: F = FPModule(A2, [1,3]) sage: Hom(F,L).identity() Traceback (most recent call last): ... @@ -287,11 +267,11 @@ def _basis_elements(self, n, basis): latter case, this homomorphism is non-trivial if the vector space of all homomorphisms is non-trivial. - TESTS: + TESTS:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) - sage: Hko = FP_Module(A, [0], relations=[[Sq(2)], [Sq(1)]]) + sage: Hko = FPModule(A, [0], relations=[[Sq(2)], [Sq(1)]]) sage: Hom(Hko, Hko)._basis_elements(21, basis=True) [Module homomorphism of degree 21 defined by sending the generators [<1>] @@ -308,7 +288,7 @@ def _basis_elements(self, n, basis): to [] - sage: F = FP_Module(A, [0]) + sage: F = FPModule(A, [0]) sage: Hom(F, Hko)._basis_elements(21, basis=False) Module homomorphism of degree 21 defined by sending the generators [<1>] @@ -326,9 +306,9 @@ def _basis_elements(self, n, basis): Test corner cases involving trivial modules: - sage: F = FP_Module(A, [0]) # A module without relations. - sage: Z0 = FP_Module(A, []) # A trivial module. - sage: Z1 = FP_Module(A, [0], [[1]]) # A trivial module with a redundant generator and relation. + sage: F = FPModule(A, [0]) # A module without relations. + sage: Z0 = FPModule(A, []) # A trivial module. + sage: Z1 = FPModule(A, [0], [[1]]) # A trivial module with a redundant generator and relation. Hom(FPA_Module([-1], A), F)._basis_elements(0, basis=True) [] diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index 8e2d5105793..014a45dc708 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -4,7 +4,7 @@ # 2. inhheritance: free modules, elements, etc., should perhaps inherit from fp versions, or maybe both should inherit from generic classes, to consolidate some methods (like degree, _repr_, others?) # 3. Test with graded modules over other graded rings. (Should be okay, but add some doctests.) # -# In __classcall__/__init__ for FP_Modules, allow as input a free module or a morphism of free modules? +# In __classcall__/__init__ for FPModules, allow as input a free module or a morphism of free modules? @@ -40,7 +40,7 @@ This package was designed with homological algebra in mind, and its API focuses on maps rather than objects. A good example of this is the kernel -function :meth:`sage.modules.fp_graded.morphism.FP_ModuleMorphism.kernel` +function :meth:`sage.modules.fp_graded.morphism.FPModuleMorphism.kernel` which computes the kernel of a homomorphism `f: M\to N`. Its return value is not an instance of the module class, but rather an injective homomorphism `i: K\to M` with the property that `\operatorname{im}(i) = \ker(f)`. @@ -73,13 +73,13 @@ from .free_module import FreeGradedModule from .free_element import FreeGradedModuleElement -from .element import FP_Element +from .element import FPElement # These are not free modules over the algebra, but they are free as # vector spaces. They have a distinguished set of generators over the # algebra, and as long as the algebra has a vector space basis # implemented in Sage, the modules will have a vector space basis as well. -class FP_Module(CombinatorialFreeModule): +class FPModule(CombinatorialFreeModule): r""" Create a finitely presented module over a connected graded algebra. @@ -98,10 +98,10 @@ class FP_Module(CombinatorialFreeModule): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) - sage: M = FP_Module(A3, [0, 1], [[Sq(2), Sq(1)]]) + sage: M = FPModule(A3, [0, 1], [[Sq(2), Sq(1)]]) sage: M.generators() [<1, 0>, <0, 1>] sage: M.relations() @@ -109,7 +109,7 @@ class FP_Module(CombinatorialFreeModule): sage: M.is_trivial() False - sage: Z = FP_Module(A3, []) + sage: Z = FPModule(A3, []) sage: Z.generators() [] sage: Z.relations() @@ -135,14 +135,14 @@ def __classcall_private__(cls, algebra, generator_degrees, relations=()): OUTPUT: The finitely presented module with presentation given by the ``generator_degrees`` and ``relations``. - TESTS: + TESTS:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) - sage: FP_Module(A3, [0, 1], [[Sq(2), Sq(1)]]) + sage: FPModule(A3, [0, 1], [[Sq(2), Sq(1)]]) Finitely presented left module on 2 generators and 1 relation over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] """ - return super(FP_Module, cls).__classcall__(cls, + return super(FPModule, cls).__classcall__(cls, algebra=algebra, generator_degrees=tuple(generator_degrees), relations=tuple([tuple([algebra(x) for x in r]) for r in relations])) @@ -177,7 +177,7 @@ def __init__(self, algebra, generator_degrees, relations=()): # Call the base class constructor. CombinatorialFreeModule.__init__(self, algebra, basis_keys=keys, - element_class=FP_Element, + element_class=FPElement, category=GradedModulesWithBasis(algebra)) @@ -187,9 +187,9 @@ def _free_module(self): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra() - sage: M = FP_Module(A, [0, 1], [[Sq(2), Sq(1)]]) + sage: M = FPModule(A, [0, 1], [[Sq(2), Sq(1)]]) sage: M.generators() [<1, 0>, <0, 1>] sage: F = M._free_module() @@ -216,7 +216,7 @@ def from_free_module(cls, free_module): sage: from sage.modules.fp_graded.module import * sage: A = SteenrodAlgebra(2) sage: F = FreeGradedModule(A, (-2,2,4)) - sage: FP_Module.from_free_module(F) + sage: FPModule.from_free_module(F) Finitely presented left module on 3 generators and 0 relations over mod 2 Steenrod algebra, milnor basis """ return cls(algebra=free_module.base_ring(), @@ -248,7 +248,7 @@ def from_free_module_morphism(cls, morphism): sage: F2 = FreeGradedModule(A, (0,)) sage: v = F2([Sq(2)]) sage: pres = Hom(F1, F2)([v]) - sage: M = FP_Module.from_free_module_morphism(pres); M + sage: M = FPModule.from_free_module_morphism(pres); M Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis sage: M.generator_degrees() (0,) @@ -278,7 +278,7 @@ def change_ring(self, algebra): sage: A = SteenrodAlgebra(2) sage: A2 = SteenrodAlgebra(2,profile=(3,2,1)) - sage: M = FP_Module(A, [0,1], [[Sq(2), Sq(1)]]) + sage: M = FPModule(A, [0,1], [[Sq(2), Sq(1)]]) sage: M_ = M.change_ring(A2); M_ Finitely presented left module on 2 generators and 1 relation over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] @@ -288,7 +288,7 @@ def change_ring(self, algebra): """ # self.relations() consists of module elements. We need to extra the coefficients. relations = tuple(r.dense_coefficient_list() for r in self.relations()) - return FP_Module(algebra, self.generator_degrees(), relations) + return FPModule(algebra, self.generator_degrees(), relations) def _element_constructor_(self, x): @@ -300,7 +300,7 @@ def _element_constructor_(self, x): INPUT: - - ``x`` -- A tuple of coefficients, an element of FP_Module, or the + - ``x`` -- A tuple of coefficients, an element of FPModule, or the zero integer constant. OUTPUT: An instance of the element class with coefficients from ``x``, @@ -310,7 +310,7 @@ def _element_constructor_(self, x): sage: from sage.modules.fp_graded.module import * sage: A = SteenrodAlgebra(2) - sage: M = FP_Module(A, [0,2,4], [[Sq(4), Sq(2), 0]]) + sage: M = FPModule(A, [0,2,4], [[Sq(4), Sq(2), 0]]) sage: # Creating an element from coefficients: sage: e = M((Sq(6), 0, Sq(2))); e @@ -352,11 +352,11 @@ def _repr_(self): sage: from sage.modules.fp_graded.module import * sage: A = SteenrodAlgebra(2) - sage: M = FP_Module(A, [0,2,4], [[Sq(4),Sq(2),0]]); M + sage: M = FPModule(A, [0,2,4], [[Sq(4),Sq(2),0]]); M Finitely presented left module on 3 generators and 1 relation over mod 2 Steenrod algebra, milnor basis - sage: N = FP_Module(A, [0,1], [[Sq(2),Sq(1)], [Sq(2)*Sq(1),Sq(2)]]); N + sage: N = FPModule(A, [0,1], [[Sq(2),Sq(1)], [Sq(2)*Sq(1),Sq(2)]]); N Finitely presented left module on 2 generators and 2 relations over mod 2 Steenrod algebra, milnor basis - sage: F = FP_Module(A, [2]); F + sage: F = FPModule(A, [2]); F Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis """ return "Finitely presented left module on %s generator%s and %s relation%s over %s"\ @@ -375,32 +375,32 @@ def connectivity(self): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) - sage: M = FP_Module(A, [0,2,4], [[0, Sq(5), Sq(3)], [Sq(7), 0, Sq(2)*Sq(1)]]) + sage: M = FPModule(A, [0,2,4], [[0, Sq(5), Sq(3)], [Sq(7), 0, Sq(2)*Sq(1)]]) sage: M.connectivity() 0 - sage: G = FP_Module(A, [0,2], [[1,0]]) + sage: G = FPModule(A, [0,2], [[1,0]]) sage: G.connectivity() 2 - TESTS: + TESTS:: - sage: C = FP_Module(SteenrodAlgebra(2, profile=(3,2,1)), [0], relations=[[Sq(1)], [0]]) + sage: C = FPModule(SteenrodAlgebra(2, profile=(3,2,1)), [0], relations=[[Sq(1)], [0]]) sage: C.connectivity() 0 - sage: F = FP_Module(A, [-1]) + sage: F = FPModule(A, [-1]) sage: F.connectivity() -1 - sage: F = FP_Module(A, []) + sage: F = FPModule(A, []) sage: F.connectivity() +Infinity - sage: F = FP_Module(A, [0], [[1]]) + sage: F = FPModule(A, [0], [[1]]) sage: F.connectivity() +Infinity """ @@ -435,29 +435,29 @@ def is_trivial(self): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) - sage: M = FP_Module(A2, []) + sage: M = FPModule(A2, []) sage: M.is_trivial() True - sage: N = FP_Module(A, [1,2]) + sage: N = FPModule(A, [1,2]) sage: N.is_trivial() False - sage: P = FP_Module(A, [1,2], [[1,0], [0,1]]) + sage: P = FPModule(A, [1,2], [[1,0], [0,1]]) sage: P.is_trivial() True - TESTS: + TESTS:: - sage: C = FP_Module(SteenrodAlgebra(2, profile=(3,2,1)), [0], [[Sq(1)], [0]]) + sage: C = FPModule(SteenrodAlgebra(2, profile=(3,2,1)), [0], [[Sq(1)], [0]]) sage: C.is_trivial() False - sage: C = FP_Module(SteenrodAlgebra(2), [0], [[Sq(1)], [1]]) + sage: C = FPModule(SteenrodAlgebra(2), [0], [[Sq(1)], [1]]) sage: C.is_trivial() True """ @@ -476,20 +476,20 @@ def has_relations(self): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) - sage: F = FP_Module(A2, [1,2]) + sage: F = FPModule(A2, [1,2]) sage: F.has_relations() False - sage: M = FP_Module(A2, [1,2], [[Sq(2), Sq(1)]]) + sage: M = FPModule(A2, [1,2], [[Sq(2), Sq(1)]]) sage: M.has_relations() True sage: # A free module constructed with a redundant ....: # generator and relation. - sage: N = FP_Module(A2, [0,0], [[0, 1]]) + sage: N = FPModule(A2, [0,0], [[0, 1]]) sage: N.has_relations() True sage: # Computing a minimal presentation reveals an @@ -519,7 +519,7 @@ def an_element(self, n=None): sage: from sage.modules.fp_graded.module import * sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) - sage: M = FP_Module(A2, [0,2,4], [[0, Sq(5), Sq(3)], [Sq(7), 0, Sq(2)*Sq(1)]]) + sage: M = FPModule(A2, [0,2,4], [[0, Sq(5), Sq(3)], [Sq(7), 0, Sq(2)*Sq(1)]]) sage: [M.an_element(i) for i in range(10)] [<1, 0, 0>, @@ -560,7 +560,7 @@ def basis_elements(self, n, verbose=False): sage: from sage.modules.fp_graded.module import * sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) - sage: M = FP_Module(A2, [0,2], [[Sq(4), Sq(2)], [0, Sq(6)]]) + sage: M = FPModule(A2, [0,2], [[Sq(4), Sq(2)], [0, Sq(6)]]) sage: M.basis_elements(4) [, ] @@ -577,13 +577,13 @@ def basis_elements(self, n, verbose=False): sage: M.basis_elements(2) [, <0, 1>] - TESTS: + TESTS:: - sage: Z0 = FP_Module(A2, []) + sage: Z0 = FPModule(A2, []) sage: Z0.basis_elements(n=10) [] - sage: Z1 = FP_Module(A2, [1], [[1]]) + sage: Z1 = FPModule(A2, [1], [[1]]) sage: Z1.basis_elements(n=10) [] """ @@ -598,7 +598,7 @@ def element_from_coordinates(self, coordinates, n): respect to the basis returned by :meth:`basis_elements`. This function is inverse to - :meth:`sage.modules.fp_graded.element.FP_Element.vector_presentation`. + :meth:`sage.modules.fp_graded.element.FPElement.vector_presentation`. INPUT: @@ -613,7 +613,7 @@ def element_from_coordinates(self, coordinates, n): sage: from sage.modules.fp_graded.module import * sage: A = SteenrodAlgebra(2) - sage: M = FP_Module(A, [0], [[Sq(4)], [Sq(7)], [Sq(4)*Sq(9)]]) + sage: M = FPModule(A, [0], [[Sq(4)], [Sq(7)], [Sq(4)*Sq(9)]]) sage: M.vector_presentation(12).dimension() 3 @@ -625,7 +625,7 @@ def element_from_coordinates(self, coordinates, n): sage: x.vector_presentation() (0, 1, 0) - TESTS: + TESTS:: sage: M.element_from_coordinates((0,1,0,0), 12) Traceback (most recent call last): @@ -634,7 +634,7 @@ def element_from_coordinates(self, coordinates, n): .. SEEALSO:: - :meth:`sage.modules.fp_graded.module.FP_Module.vector_presentation` + :meth:`sage.modules.fp_graded.module.FPModule.vector_presentation` """ M_n = self.vector_presentation(n) @@ -661,9 +661,9 @@ def __getitem__(self, n): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) - sage: M = FP_Module(A, [0,2,4], [[Sq(4),Sq(2),0]]) + sage: M = FPModule(A, [0,2,4], [[Sq(4),Sq(2),0]]) sage: M[4] [, , <0, 0, 1>] @@ -695,7 +695,7 @@ def vector_presentation(self, n, verbose=False): sage: from sage.modules.fp_graded.module import * sage: A = SteenrodAlgebra(2) - sage: M = FP_Module(A, [0,2,4], [[Sq(4),Sq(2),0]]) + sage: M = FPModule(A, [0,2,4], [[Sq(4),Sq(2),0]]) sage: V = M.vector_presentation(4) sage: V.dimension() @@ -752,23 +752,23 @@ def _Hom_(self, Y, category): :meth:`sage.categories.homset.hom.Hom` to create homsets involving this parent class. - TESTS: + TESTS:: sage: from sage.modules.fp_graded.module import * sage: A = SteenrodAlgebra(2) - sage: F = FP_Module(A, [1,3]); - sage: L = FP_Module(A, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]); + sage: F = FPModule(A, [1,3]); + sage: L = FPModule(A, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]); sage: homset = Hom(F, L); homset Set of Morphisms from Finitely presented left module on 2 generators ... """ - from .homspace import FP_ModuleHomspace + from .homspace import FPModuleHomspace if not isinstance(Y, self.__class__): raise ValueError('cannot create homspace between incompatible types:\n%s ->\n%s' % (self.__class__, type(Y))) if Y.base_ring() != self.base_ring(): raise ValueError('the modules are not defined over the same base ring') - return FP_ModuleHomspace(self, Y, category) + return FPModuleHomspace(self, Y, category) def generator_degrees(self): @@ -779,7 +779,7 @@ def generator_degrees(self): sage: from sage.modules.fp_graded.module import * sage: A4 = SteenrodAlgebra(2, profile=(4,3,2,1)) - sage: N = FP_Module(A4, [0, 1], [[Sq(2), Sq(1)]]) + sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]]) sage: N.generator_degrees() (0, 1) @@ -793,18 +793,18 @@ def generators(self): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A4 = SteenrodAlgebra(2, profile=(4,3,2,1)) - sage: M = FP_Module(A4, [0,2,3]) + sage: M = FPModule(A4, [0,2,3]) sage: M.generators() [<1, 0, 0>, <0, 1, 0>, <0, 0, 1>] - sage: N = FP_Module(A4, [0, 1], [[Sq(2), Sq(1)]]) + sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]]) sage: N.generators() [<1, 0>, <0, 1>] - sage: Z = FP_Module(A4, []) + sage: Z = FPModule(A4, []) sage: Z.generators() [] """ @@ -820,11 +820,11 @@ def generator(self, index): sage: from sage.modules.fp_graded.module import * sage: A4 = SteenrodAlgebra(2, profile=(4,3,2,1)) - sage: M = FP_Module(A4, [0,2,3]) + sage: M = FPModule(A4, [0,2,3]) sage: M.generator(0) <1, 0, 0> - sage: N = FP_Module(A4, [0, 1], [[Sq(2), Sq(1)]]) + sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]]) sage: N.generator(1) <0, 1> """ @@ -840,15 +840,15 @@ def relations(self): sage: from sage.modules.fp_graded.module import * sage: A4 = SteenrodAlgebra(2, profile=(4,3,2,1)) - sage: M = FP_Module(A4, [0,2,3]) + sage: M = FPModule(A4, [0,2,3]) sage: M.relations() [] - sage: N = FP_Module(A4, [0, 1], [[Sq(2), Sq(1)]]) + sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]]) sage: N.relations() [] - sage: Z = FP_Module(A4, []) + sage: Z = FPModule(A4, []) sage: Z.relations() [] """ @@ -863,7 +863,7 @@ def relation(self, index): sage: from sage.modules.fp_graded.module import * sage: A4 = SteenrodAlgebra(2, profile=(4,3,2,1)) - sage: N = FP_Module(A4, [0, 1], [[Sq(2), Sq(1)]]) + sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]]) sage: N.relation(0) """ @@ -881,7 +881,7 @@ def min_presentation(self, top_dim=None, verbose=False): sage: from sage.modules.fp_graded.module import * sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) - sage: M = FP_Module(A2, [0,1], [[Sq(2),Sq(1)],[0,Sq(2)],[Sq(3),0]]) + sage: M = FPModule(A2, [0,1], [[Sq(2),Sq(1)],[0,Sq(2)],[Sq(3),0]]) sage: i = M.min_presentation() sage: M_min = i.domain() @@ -899,9 +899,9 @@ def min_presentation(self, top_dim=None, verbose=False): sage: M_min.relations() [, <0, Sq(2)>] - TESTS: + TESTS:: - sage: T = FP_Module(A2, [0], [[1]]) + sage: T = FPModule(A2, [0], [[1]]) sage: T_min = T.min_presentation().domain() sage: T_min.is_trivial() True @@ -928,14 +928,14 @@ def suspension(self, t): sage: A = SteenrodAlgebra(2) sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) - sage: Y = FP_Module(A2, [0], [[Sq(1)]]) + sage: Y = FPModule(A2, [0], [[Sq(1)]]) sage: X = Y.suspension(4) sage: X.generator_degrees() (4,) sage: X.relations() [] - sage: M = FP_Module(A, [2,3], [[Sq(2), Sq(1)], [0, Sq(2)]]) + sage: M = FPModule(A, [2,3], [[Sq(2), Sq(1)], [0, Sq(2)]]) sage: Q = M.suspension(1) sage: Q.generator_degrees() (3, 4) @@ -948,7 +948,7 @@ def suspension(self, t): sage: Q.generator_degrees() (2, 3) """ - return FP_Module( + return FPModule( algebra=self.base_ring(), generator_degrees=tuple([g + t for g in self.generator_degrees()]), relations=self._relations) @@ -969,7 +969,7 @@ def submodule(self, spanning_elements): sage: from sage.modules.fp_graded.module import * sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) - sage: M = FP_Module(A2, [0,1], [[Sq(2),Sq(1)]]) + sage: M = FPModule(A2, [0,1], [[Sq(2),Sq(1)]]) sage: i = M.submodule([M.generator(0)]) sage: i.codomain() is M True @@ -982,7 +982,7 @@ def submodule(self, spanning_elements): """ # Create the free graded module on the set of spanning elements. degs = [x.degree() for x in spanning_elements] - F = FP_Module(self.base_ring(), tuple(degs)) + F = FPModule(self.base_ring(), tuple(degs)) # The submodule is the module generated by the spanning elements. return Hom(F, self)(spanning_elements).image() @@ -1016,7 +1016,7 @@ def resolution(self, k, top_dim=None, verbose=False): sage: from sage.modules.fp_graded.module import * sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) - sage: M = FP_Module(A2, [0,1], [[Sq(2), Sq(1)]]) + sage: M = FPModule(A2, [0,1], [[Sq(2), Sq(1)]]) sage: M.resolution(0) [Module homomorphism of degree 0 defined by sending the generators [<1, 0>, <0, 1>] @@ -1067,7 +1067,7 @@ def _print_progress(i, k): complex = [] # Epsilon: F_0 -> M - F_0 = FP_Module.from_free_module(self._free_module()) + F_0 = FPModule.from_free_module(self._free_module()) epsilon = Hom(F_0, self)(tuple(self.generators())) complex.append(epsilon) @@ -1076,12 +1076,12 @@ def _print_progress(i, k): # f_1: F_1 -> F_0 _print_progress(1, k) - F_1 = FP_Module.from_free_module(self.j.domain()) + F_1 = FPModule.from_free_module(self.j.domain()) pres = Hom(F_1, F_0)(tuple([ F_0(x.dense_coefficient_list()) for x in self.j.values() ])) complex.append(pres) - from .morphism import FP_ModuleMorphism + from .morphism import FPModuleMorphism # f_i: F_i -> F_i-1, for i > 1 for i in range(2, k+1): @@ -1089,7 +1089,7 @@ def _print_progress(i, k): f = complex[i-1] complex.append( - FP_ModuleMorphism._resolve_kernel( + FPModuleMorphism._resolve_kernel( f, top_dim=top_dim, verbose=verbose)) diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py index f46b9fb5349..9758e1ea6f6 100755 --- a/src/sage/modules/fp_graded/morphism.py +++ b/src/sage/modules/fp_graded/morphism.py @@ -2,7 +2,7 @@ Homomorphisms of finitely presented graded modules This class implements construction and basic manipulation of elements of the -Sage parent :class:`sage.modules.fp_graded.homspace.FP_ModuleHomspace`, +Sage parent :class:`sage.modules.fp_graded.homspace.FPModuleHomspace`, which models homomorphisms of finitely presented graded modules over connected algebras. @@ -38,7 +38,6 @@ from sage.categories.homset import Hom from sage.categories.morphism import Morphism from sage.misc.cachefunc import cached_method -from .element import FP_Element from sage.rings.infinity import PlusInfinity @@ -78,12 +77,12 @@ def _CreateRelationsMatrix(module, relations, source_degs, target_degs): - ``R`` -- A matrix representing ``block_matrix`` as a single linear transformation. - TESTS: + TESTS:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: from sage.modules.fp_graded.morphism import _CreateRelationsMatrix sage: A = SteenrodAlgebra(p=2) - sage: blocks, R = _CreateRelationsMatrix(FP_Module(A, [0]), [[Sq(2)]], [4], [6]) + sage: blocks, R = _CreateRelationsMatrix(FPModule(A, [0]), [[Sq(2)]], [4], [6]) sage: blocks [[Vector space morphism represented by the matrix: @@ -154,7 +153,7 @@ def _CreateRelationsMatrix(module, relations, source_degs, target_degs): return block_matrix, matrix(module.base_ring().base_ring(), entries).transpose() -class FP_ModuleMorphism(Morphism): +class FPModuleMorphism(Morphism): r""" Create a homomorphism between finitely presented graded modules. @@ -172,14 +171,14 @@ class FP_ModuleMorphism(Morphism): is that the dynamic type of the element class changes as a consequence of the category system. - TESTS: + TESTS:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: # Trying to map the generators of a non-free module into a sage: # free module: sage: A = SteenrodAlgebra(2) - sage: F = FP_Module(A, [2,3]) - sage: Q = FP_Module(A, [2,3], relations=[[Sq(6), Sq(5)]]) + sage: F = FPModule(A, [2,3]) + sage: Q = FPModule(A, [2,3], relations=[[Sq(6), Sq(5)]]) sage: m = Hom(F, Q)( (F((Sq(1), 0)), F((0, 1))) ) Traceback (most recent call last): ... @@ -196,13 +195,12 @@ def __init__(self, parent, values): r""" Create a homomorphism between finitely presented graded modules. """ + from .homspace import FPModuleHomspace - from .homspace import is_FP_ModuleHomspace - - if not is_FP_ModuleHomspace(parent): + if not isinstance(parent, FPModuleHomspace): raise TypeError('parent (=%s) must be a fp module hom space' % parent) - self.free_morphism = Hom(parent.domain().j.codomain(), parent.codomain().j.codomain())([v.free_element() for v in values]) + self.free_morphism = Hom(parent.domain().j.codomain(), parent.codomain().j.codomain())([v.lift_to_free() for v in values]) self._values = values # Call the base class constructor. @@ -212,7 +210,6 @@ def __init__(self, parent, values): for relation in parent.domain().relations(): # The relation is an element in the free part of the domain. img = self.free_morphism(relation) - # if not FP_Element(parent.codomain(), self.free_morphism(relation)).is_zero(): if parent.codomain()(img): raise ValueError('relation %s is not sent to zero' % relation) @@ -229,11 +226,11 @@ def change_ring(self, algebra): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) - sage: M = FP_Module(A2, [0], relations=[[Sq(1)]]) - sage: N = FP_Module(A2, [0], relations=[[Sq(4)],[Sq(1)]]) + sage: M = FPModule(A2, [0], relations=[[Sq(1)]]) + sage: N = FPModule(A2, [0], relations=[[Sq(4)],[Sq(1)]]) sage: f = Hom(M,N)([A2.Sq(3)*N.generator(0)]); f Module homomorphism of degree 3 defined by sending the generators @@ -266,8 +263,8 @@ def degree(self): sage: from sage.modules.fp_graded.module import * sage: A = SteenrodAlgebra(2) - sage: M = FP_Module(A, [0,1], [[Sq(2), Sq(1)]]) - sage: N = FP_Module(A, [2], [[Sq(4)]]) + sage: M = FPModule(A, [0,1], [[Sq(2), Sq(1)]]) + sage: N = FPModule(A, [2], [[Sq(4)]]) sage: homspace = Hom(M, N) sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] @@ -282,10 +279,10 @@ def degree(self): ... ValueError: the zero morphism does not have a well-defined degree - TESTS: + TESTS:: - sage: M = FP_Module(SteenrodAlgebra(p=2), [7]) - sage: N = FP_Module(SteenrodAlgebra(p=2), [0], relations=[[Sq(1)]]) + sage: M = FPModule(SteenrodAlgebra(p=2), [7]) + sage: N = FPModule(SteenrodAlgebra(p=2), [0], relations=[[Sq(1)]]) sage: f = Hom(M,N)([Sq(1)*N.generator(0)]) sage: f == Hom(M,N).zero() True @@ -311,8 +308,8 @@ def values(self): sage: from sage.modules.fp_graded.module import * sage: A = SteenrodAlgebra(2) - sage: M = FP_Module(A, [0,1], [[Sq(2), Sq(1)]]) - sage: N = FP_Module(A, [2], [[Sq(4)]]) + sage: M = FPModule(A, [0,1], [[Sq(2), Sq(1)]]) + sage: N = FPModule(A, [2], [[Sq(4)]]) sage: homspace = Hom(M, N) sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] @@ -350,8 +347,8 @@ def _richcmp_(self, other, op): sage: from sage.modules.fp_graded.module import * sage: A = SteenrodAlgebra(2) - sage: M = FP_Module(A, [0,1], [[Sq(2), Sq(1)]]) - sage: N = FP_Module(A, [2], [[Sq(4)]]) + sage: M = FPModule(A, [0,1], [[Sq(2), Sq(1)]]) + sage: N = FPModule(A, [2], [[Sq(4)]]) sage: homspace = Hom(M, N) sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] sage: f = homspace(values) @@ -393,8 +390,8 @@ def __add__(self, g): sage: from sage.modules.fp_graded.module import * sage: A = SteenrodAlgebra(2) - sage: M = FP_Module(A, [0,1], [[Sq(2), Sq(1)]]) - sage: N = FP_Module(A, [2], [[Sq(4)]]) + sage: M = FPModule(A, [0,1], [[Sq(2), Sq(1)]]) + sage: N = FPModule(A, [2], [[Sq(4)]]) sage: homspace = Hom(M, N) sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] sage: f = homspace(values) @@ -429,8 +426,8 @@ def __neg__(self): sage: from sage.modules.fp_graded.module import * sage: A = SteenrodAlgebra(2) - sage: M = FP_Module(A, [0,1], [[Sq(2), Sq(1)]]) - sage: N = FP_Module(A, [2], [[Sq(4)]]) + sage: M = FPModule(A, [0,1], [[Sq(2), Sq(1)]]) + sage: N = FPModule(A, [2], [[Sq(4)]]) sage: homspace = Hom(M, N) sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] sage: f = homspace(values) @@ -454,8 +451,8 @@ def __sub__(self, g): sage: from sage.modules.fp_graded.module import * sage: A = SteenrodAlgebra(2) - sage: M = FP_Module(A, [0]) - sage: N = FP_Module(A, [0], [[Sq(4)]]) + sage: M = FPModule(A, [0]) + sage: N = FPModule(A, [0], [[Sq(4)]]) sage: f = Hom(M, N)( [Sq(3)*N.generator(0)] ) sage: g = Hom(M, N)( [Sq(0,1)*N.generator(0)] ) sage: f.__sub__(g) @@ -482,10 +479,10 @@ def __mul__(self, g): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) - sage: M = FP_Module(A, [0], [[Sq(1,2)]]) - sage: N = FP_Module(A, [0], [[Sq(2,2)]]) + sage: M = FPModule(A, [0], [[Sq(1,2)]]) + sage: N = FPModule(A, [0], [[Sq(2,2)]]) sage: f = Hom(M, N)( [Sq(2)*N.generator(0)] ) sage: g = Hom(N, M)( [Sq(2,2)*M.generator(0)] ) sage: fg = f.__mul__(g); fg @@ -496,11 +493,11 @@ def __mul__(self, g): sage: fg.is_endomorphism() True - TESTS: + TESTS:: sage: from sage.modules.fp_graded.free_module import * sage: A = SteenrodAlgebra(2) - sage: M = FP_Module(A, (0,1)) + sage: M = FPModule(A, (0,1)) sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] sage: f = Hom(M, N)(values) sage: f.__mul__(f) @@ -524,10 +521,10 @@ def is_zero(self): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) - sage: M = FP_Module(A, [0,1], [[Sq(2), Sq(1)]]) - sage: N = FP_Module(A, [2], [[Sq(4)]]) + sage: M = FPModule(A, [0,1], [[Sq(2), Sq(1)]]) + sage: N = FPModule(A, [2], [[Sq(4)]]) sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] sage: f = Hom(M, N)(values) @@ -549,8 +546,8 @@ def is_identity(self): sage: from sage.modules.fp_graded.module import * sage: A = SteenrodAlgebra(2) - sage: M = FP_Module(A, [0,1], [[Sq(2), Sq(1)]]) - sage: N = FP_Module(A, [2], [[Sq(4)]]) + sage: M = FPModule(A, [0,1], [[Sq(2), Sq(1)]]) + sage: N = FPModule(A, [2], [[Sq(4)]]) sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] sage: f = Hom(M, N)(values) @@ -584,8 +581,8 @@ def __call__(self, x): sage: from sage.modules.fp_graded.module import * sage: A = SteenrodAlgebra(2) - sage: M = FP_Module(A, [0,1], [[Sq(2), Sq(1)]]) - sage: N = FP_Module(A, [2], [[Sq(4)]]) + sage: M = FPModule(A, [0,1], [[Sq(2), Sq(1)]]) + sage: N = FPModule(A, [2], [[Sq(4)]]) sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] sage: f = Hom(M, N)(values) @@ -599,7 +596,7 @@ def __call__(self, x): if x.parent() != self.domain(): raise ValueError('cannot evaluate morphism on element not in domain') - return self.codomain()(self.free_morphism(x.free_element())) + return self.codomain()(self.free_morphism(x.lift_to_free())) def _repr_(self): @@ -610,8 +607,8 @@ def _repr_(self): sage: from sage.modules.fp_graded.module import * sage: A = SteenrodAlgebra(2) - sage: M = FP_Module(A, [0,1], [[Sq(2), Sq(1)]]) - sage: N = FP_Module(A, [2], [[Sq(4)]]) + sage: M = FPModule(A, [0,1], [[Sq(2), Sq(1)]]) + sage: N = FPModule(A, [2], [[Sq(4)]]) sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] sage: Hom(M, N)(values)._repr_() 'Module homomorphism of degree 7 defined by sending the generators\n [<1, 0>, <0, 1>]\nto\n [, ]' @@ -657,15 +654,15 @@ def vector_presentation(self, n): .. SEEALSO:: - :meth:`sage.modules.fp_graded.module.FP_Module.vector_presentation`, - :meth:`sage.modules.fp_graded.module.FP_Module.basis_elements`. + :meth:`sage.modules.fp_graded.module.FPModule.vector_presentation`, + :meth:`sage.modules.fp_graded.module.FPModule.basis_elements`. EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) - sage: M = FP_Module(A, [0,1], [[Sq(2), Sq(1)]]) - sage: N = FP_Module(A, [2], [[Sq(4)]]) + sage: M = FPModule(A, [0,1], [[Sq(2), Sq(1)]]) + sage: N = FPModule(A, [2], [[Sq(4)]]) sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] sage: f = Hom(M, N)(values) sage: f.vector_presentation(0) @@ -711,10 +708,10 @@ def vector_presentation(self, n): [0 0 0 1] - TESTS: + TESTS:: - sage: F = FP_Module(A, [0]) - sage: Q = FP_Module(A, [0], [[Sq(2)]]) + sage: F = FPModule(A, [0]) + sage: Q = FPModule(A, [0], [[Sq(2)]]) sage: z = Hom(F, Q)([Sq(2)*Q.generator(0)]) sage: z.is_zero() True @@ -748,10 +745,10 @@ def solve(self, x): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) - sage: M = FP_Module(A, [0], [[Sq(3)]]) - sage: N = FP_Module(A, [0], [[Sq(2,2)]]) + sage: M = FPModule(A, [0], [[Sq(3)]]) + sage: N = FPModule(A, [0], [[Sq(2,2)]]) sage: f = Hom(M, N)( [Sq(2)*N.generator(0)] ) sage: y = Sq(1,1)*N.generator(0); y @@ -766,7 +763,7 @@ def solve(self, x): sage: z is None True - TESTS: + TESTS:: sage: f.solve(Sq(2,2)*M.generator(0)) Traceback (most recent call last): @@ -838,14 +835,14 @@ def lift(self, f, verbose=False): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) Lifting a map from a free module is always possible:: - sage: M = FP_Module(A, [0], [[Sq(3)]]) - sage: N = FP_Module(A, [0], [[Sq(2,2)]]) - sage: F = FP_Module(A, [0]) + sage: M = FPModule(A, [0], [[Sq(3)]]) + sage: N = FPModule(A, [0], [[Sq(2,2)]]) + sage: F = FPModule(A, [0]) sage: f = Hom(M,N)([Sq(2)*N.generator(0)]) sage: k = Hom(F,N)([Sq(1)*Sq(2)*N.generator(0)]) sage: f_ = k.lift(f) @@ -859,8 +856,8 @@ def lift(self, f, verbose=False): A split projection:: - sage: A_plus_HZ = FP_Module(A, [0,0], [[0, Sq(1)]]) - sage: HZ = FP_Module(A, [0], [[Sq(1)]]) + sage: A_plus_HZ = FPModule(A, [0,0], [[0, Sq(1)]]) + sage: HZ = FPModule(A, [0], [[Sq(1)]]) sage: q = Hom(A_plus_HZ, HZ)([HZ([1]), HZ([1])]) sage: # We can construct a splitting of `q` manually: sage: split = Hom(HZ,A_plus_HZ)([A_plus_HZ.generator(1)]) @@ -879,7 +876,7 @@ def lift(self, f, verbose=False): Lifting over the inclusion of the image sub module:: sage: A = SteenrodAlgebra(2) - sage: M = FP_Module(A, [0], relations=[[Sq(0,1)]]) + sage: M = FPModule(A, [0], relations=[[Sq(0,1)]]) sage: f = Hom(M,M)([Sq(2)*M.generator(0)]) sage: im = f.image(top_dim=10) sage: f.lift(im) @@ -892,24 +889,24 @@ def lift(self, f, verbose=False): verbose argument to ``True``, an explanation of why the lifting failed will be displayed:: - sage: F2 = FP_Module(A, [0,0]) + sage: F2 = FPModule(A, [0,0]) sage: non_surjection = Hom(F2, F2)([F2([1, 0]), F2([0, 0])]) sage: lift = Hom(F2, F2).identity().lift(non_surjection, verbose=True) The generators of the domain of this homomorphism do not map into the image of the homomorphism we are lifting over. sage: lift is None True - TESTS: + TESTS:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) sage: # The trivial map often involved in corner cases.. - sage: trivial_map = Hom(FP_Module(A, [0]), FP_Module(A, [])).zero() + sage: trivial_map = Hom(FPModule(A, [0]), FPModule(A, [])).zero() sage: trivial_map.lift(trivial_map) The trivial homomorphism. - sage: F = FP_Module(A, [0]) - sage: HZ = FP_Module(A, [0], relations=[[Sq(1)]]) + sage: F = FPModule(A, [0]) + sage: HZ = FPModule(A, [0], relations=[[Sq(1)]]) sage: f = Hom(F,HZ)(HZ.generators()) sage: split = Hom(HZ, HZ).identity().lift(f, verbose=True) The homomorphism cannot be lifted in any way such that the relations of the domain are respected: matrix equation has no solutions @@ -925,7 +922,7 @@ def lift(self, f, verbose=False): This homomorphism cannot lift over a trivial homomorphism since it is non-trivial. sage: Ap = SteenrodAlgebra(p=2, profile=(2,2,2,1)) - sage: Hko = FP_Module(Ap, [0], [[Sq(2)], [Sq(1)]]) + sage: Hko = FPModule(Ap, [0], [[Sq(2)], [Sq(1)]]) sage: f = Hom(Hko, Hko)([(Ap.Sq(0,0,3) + Ap.Sq(0,2,0,1))*Hko.generator(0)]) sage: f*f == 0 True @@ -938,9 +935,9 @@ def lift(self, f, verbose=False): Corner cases involving trivial maps:: - sage: M = FP_Module(A, [1]) - sage: M1 = FP_Module(A, [0]) - sage: M2 = FP_Module(A, [0], [[Sq(1)]]) + sage: M = FPModule(A, [1]) + sage: M1 = FPModule(A, [0]) + sage: M2 = FPModule(A, [0], [[Sq(1)]]) sage: q = Hom(M1, M2)([M2.generator(0)]) sage: z = Hom(M, M2).zero() sage: lift = z.lift(q) @@ -1080,10 +1077,10 @@ def split(self, verbose=False): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) - sage: M = FP_Module(A, [0,0], [[0, Sq(1)]]) - sage: N = FP_Module(A, [0], [[Sq(1)]]) + sage: M = FPModule(A, [0,0], [[0, Sq(1)]]) + sage: N = FPModule(A, [0], [[Sq(1)]]) sage: p = Hom(M, N)([N.generator(0), N.generator(0)]) sage: s = p.split(); s Module homomorphism of degree 0 defined by sending the generators @@ -1094,10 +1091,10 @@ def split(self, verbose=False): sage: p*s The identity homomorphism. - TESTS: + TESTS:: - sage: F = FP_Module(A, [0]) - sage: N = FP_Module(A, [0], [[Sq(1)]]) + sage: F = FPModule(A, [0]) + sage: N = FPModule(A, [0], [[Sq(1)]]) sage: p = Hom(F, N)([N.generator(0)]) sage: p.split(verbose=True) is None The homomorphism cannot be lifted in any way such that the relations of the domain are respected: matrix equation has no solutions @@ -1141,11 +1138,11 @@ def homology(self, f, top_dim=None, verbose=False): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2, profile=(3,2,1)) - sage: M = FP_Module(A, [0], [[Sq(3)]]) - sage: N = FP_Module(A, [0], [[Sq(2,2)]]) - sage: F = FP_Module(A, [0]) + sage: M = FPModule(A, [0], [[Sq(3)]]) + sage: N = FPModule(A, [0], [[Sq(2,2)]]) + sage: F = FPModule(A, [0]) sage: f = Hom(M,N)([A.Sq(2)*N.generator(0)]) sage: g = Hom(F, M)([A.Sq(4)*A.Sq(1,2)*M.generator(0)]) sage: ho = f.homology(g) @@ -1177,10 +1174,10 @@ def suspension(self, t): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) - sage: F1 = FP_Module(A, [4,5]) - sage: F2 = FP_Module(A, [5]) + sage: F1 = FPModule(A, [4,5]) + sage: F2 = FPModule(A, [5]) sage: f = Hom(F1, F2)( ( F2([Sq(4)]), F2([Sq(5)]) ) ); f Module homomorphism of degree 5 defined by sending the generators @@ -1212,7 +1209,7 @@ def suspension(self, t): else: D = self.domain().suspension(t) C = self.codomain().suspension(t) - return Hom(D, C)([C(x.free_element().dense_coefficient_list()) for x in self._values]) + return Hom(D, C)([C(x.lift_to_free().dense_coefficient_list()) for x in self._values]) def cokernel(self): @@ -1224,10 +1221,10 @@ def cokernel(self): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A1 = SteenrodAlgebra(2, profile=(2,1)) - sage: M = FP_Module(A1, [0], [[Sq(2)]]) - sage: F = FP_Module(A1, [0]) + sage: M = FPModule(A1, [0], [[Sq(2)]]) + sage: F = FPModule(A1, [0]) sage: r = Hom(F, M)([A1.Sq(1)*M.generator(0)]) sage: co = r.cokernel(); co @@ -1239,11 +1236,11 @@ def cokernel(self): sage: co.domain().is_trivial() False """ - from .module import FP_Module + from .module import FPModule new_relations = [x.dense_coefficient_list() for x in self.codomain().relations()] +\ [x.dense_coefficient_list() for x in self._values] - coker = FP_Module(self.base_ring(), + coker = FPModule(self.base_ring(), self.codomain().generator_degrees(), relations=tuple(new_relations)) @@ -1275,10 +1272,10 @@ def kernel(self, top_dim=None, verbose=False): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) - sage: F = FP_Module(A3, [1,3]); - sage: L = FP_Module(A3, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]); + sage: F = FPModule(A3, [1,3]); + sage: L = FPModule(A3, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]); sage: H = Hom(F, L); sage: H([L((A3.Sq(1), 1)), L((0, A3.Sq(2)))]).kernel() # long time @@ -1287,8 +1284,8 @@ def kernel(self, top_dim=None, verbose=False): to (<0, 1>, ) - sage: M = FP_Module(A3, [0,7], [[Sq(1), 0], [Sq(2), 0], [Sq(4), 0], [Sq(8), Sq(1)], [0, Sq(7)], [0, Sq(0,1,1)+Sq(4,2)]]) - sage: F2 = FP_Module(A3, [0], [[Sq(1)], [Sq(2)], [Sq(4)], [Sq(8)], [Sq(15)]]) + sage: M = FPModule(A3, [0,7], [[Sq(1), 0], [Sq(2), 0], [Sq(4), 0], [Sq(8), Sq(1)], [0, Sq(7)], [0, Sq(0,1,1)+Sq(4,2)]]) + sage: F2 = FPModule(A3, [0], [[Sq(1)], [Sq(2)], [Sq(4)], [Sq(8)], [Sq(15)]]) sage: H = Hom(M, F2) sage: f = H([F2([1]), F2([0])]) @@ -1351,10 +1348,10 @@ def image(self, top_dim=None, verbose=False): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) - sage: F = FP_Module(A3, [1,3]); - sage: L = FP_Module(A3, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]); + sage: F = FPModule(A3, [1,3]); + sage: L = FPModule(A3, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]); sage: H = Hom(F, L); sage: H([L((A3.Sq(1), 1)), L((0, A3.Sq(2)))]).image() # long time @@ -1363,8 +1360,8 @@ def image(self, top_dim=None, verbose=False): to (,) - sage: M = FP_Module(A3, [0,7], [[Sq(1), 0], [Sq(2), 0], [Sq(4), 0], [Sq(8), Sq(1)], [0, Sq(7)], [0, Sq(0,1,1)+Sq(4,2)]]) - sage: F2 = FP_Module(A3, [0], [[Sq(1)], [Sq(2)], [Sq(4)], [Sq(8)], [Sq(15)]]) + sage: M = FPModule(A3, [0,7], [[Sq(1), 0], [Sq(2), 0], [Sq(4), 0], [Sq(8), Sq(1)], [0, Sq(7)], [0, Sq(0,1,1)+Sq(4,2)]]) + sage: F2 = FPModule(A3, [0], [[Sq(1)], [Sq(2)], [Sq(4)], [Sq(8)], [Sq(15)]]) sage: H = Hom(M, F2) sage: f = H([F2([1]), F2([0])]) sage: K = f.image(verbose=True, top_dim=17) @@ -1413,19 +1410,19 @@ def is_injective(self, top_dim=None, verbose=False): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) - sage: K = FP_Module(A, [2], [[Sq(2)]]) - sage: HZ = FP_Module(A, [0], [[Sq(1)]]) + sage: K = FPModule(A, [2], [[Sq(2)]]) + sage: HZ = FPModule(A, [0], [[Sq(1)]]) sage: f = Hom(K, HZ)([Sq(2)*HZ([1])]) sage: f.is_injective(top_dim=23) True - TESTS: + TESTS:: - sage: Z = FP_Module(A, []) + sage: Z = FPModule(A, []) sage: Hom(Z, HZ).zero().is_injective(top_dim=8) True @@ -1440,17 +1437,17 @@ def is_surjective(self): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) - sage: F = FP_Module(A, [0]) + sage: F = FPModule(A, [0]) sage: f = Hom(F,F)([Sq(1)*F.generator(0)]) sage: f.is_surjective() False - TESTS: + TESTS:: - sage: Z = FP_Module(A, []) + sage: Z = FPModule(A, []) sage: Hom(F, Z).zero().is_surjective() True @@ -1481,12 +1478,12 @@ def _resolve_kernel(self, top_dim=None, verbose=False): If the algebra for this module is finite, then no ``top_dim`` needs to be specified in order to ensure that this function terminates. - TESTS: + TESTS:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) - sage: F = FP_Module(A, [0,0]) - sage: L = FP_Module(A, [0,0], [[Sq(3),Sq(0,1)], [0,Sq(2)]]) + sage: F = FPModule(A, [0,0]) + sage: L = FPModule(A, [0,0], [[Sq(3),Sq(0,1)], [0,Sq(2)]]) sage: f = Hom(F, L)([L([Sq(2),0]), L([0, Sq(2)])]) sage: f._resolve_kernel() Traceback (most recent call last): @@ -1620,12 +1617,12 @@ def _resolve_image(self, top_dim=None, verbose=False): If the algebra for this module is finite, then no ``top_dim`` needs to be specified in order to ensure that this function terminates. - TESTS: + TESTS:: sage: from sage.modules.fp_graded.module import * sage: A = SteenrodAlgebra(2) - sage: F = FP_Module(A, [0,0]) - sage: L = FP_Module(A, [0,0], [[Sq(3),Sq(0,1)], [0,Sq(2)]]) + sage: F = FPModule(A, [0,0]) + sage: L = FPModule(A, [0,0], [[Sq(3),Sq(0,1)], [0,Sq(2)]]) sage: f = Hom(F, L)([L([Sq(2),0]), L([0, Sq(2)])]) sage: f._resolve_image() Traceback (most recent call last): @@ -1743,10 +1740,10 @@ def to_fp_module(self): EXAMPLES:: - sage: from sage.modules.fp_graded.module import FP_Module + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) - sage: F1 = FP_Module(A, (2,)) - sage: F2 = FP_Module(A, (0,)) + sage: F1 = FPModule(A, (2,)) + sage: F2 = FPModule(A, (0,)) sage: v = F2([Sq(2)]) sage: pres = Hom(F1, F2)([v]) sage: M = pres.to_fp_module(); M @@ -1756,7 +1753,7 @@ def to_fp_module(self): sage: M.relations() [] - sage: F3 = FP_Module(A, (0,), [[Sq(4)]]) + sage: F3 = FPModule(A, (0,), [[Sq(4)]]) sage: pres = Hom(F1, F3)([v]) sage: pres.to_fp_module() Traceback (most recent call last): @@ -1765,8 +1762,8 @@ def to_fp_module(self): """ if self.domain().has_relations() or self.codomain().has_relations(): raise ValueError("this is not a morphism between free modules") - from .module import FP_Module - return FP_Module(algebra=self.base_ring(), + from .module import FPModule + return FPModule(algebra=self.base_ring(), generator_degrees=self.codomain().generator_degrees(), relations=tuple([r.dense_coefficient_list() for r in self.values()])) From b595530ceeda6ef3703a8596e412016d3119dfdc Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Fri, 1 Oct 2021 10:58:05 -0700 Subject: [PATCH 021/253] trac 32505: minor cleanup --- src/sage/modules/fp_graded/free_module.py | 2 +- src/sage/modules/fp_graded/module.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/modules/fp_graded/free_module.py b/src/sage/modules/fp_graded/free_module.py index 9b3807416b3..4243bb5f842 100755 --- a/src/sage/modules/fp_graded/free_module.py +++ b/src/sage/modules/fp_graded/free_module.py @@ -304,7 +304,7 @@ def __init__(self, algebra, generator_degrees): """ # If generator_degrees is [d_0, d_1, ...], then # the generators are indexed by (0,d_0), (1,d_1), ... - keys = [(i,deg) for i,deg in enumerate(generator_degrees)] + keys = list(enumerate(generator_degrees)) self._generator_keys = keys if not algebra.base_ring().is_field(): diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index 014a45dc708..f7f5b87efd7 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -156,7 +156,7 @@ def __init__(self, algebra, generator_degrees, relations=()): self._relations = relations # if generator_degrees is [d_0, d_1, ...], then # the generators are indexed by (0,d_0), (1,d_1), ... - keys = [(i,deg) for i,deg in enumerate(generator_degrees)] + keys = list(enumerate(generator_degrees)) self._generator_keys = keys # The free module on the generators of the module. From 9058e9a16c448b285bc2457a0bf703daeed81711 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Fri, 8 Oct 2021 10:59:13 -0700 Subject: [PATCH 022/253] trac 32505: change category for free modules --- src/sage/modules/fp_graded/free_module.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/modules/fp_graded/free_module.py b/src/sage/modules/fp_graded/free_module.py index 4243bb5f842..84ddf9d60f3 100755 --- a/src/sage/modules/fp_graded/free_module.py +++ b/src/sage/modules/fp_graded/free_module.py @@ -270,7 +270,7 @@ from sage.misc.cachefunc import cached_method from sage.modules.free_module import VectorSpace from sage.rings.infinity import PlusInfinity -from sage.categories.graded_modules_with_basis import GradedModulesWithBasis +from sage.categories.graded_modules import GradedModules from sage.combinat.free_module import CombinatorialFreeModule from .free_element import FreeGradedModuleElement @@ -314,7 +314,7 @@ def __init__(self, algebra, generator_degrees): CombinatorialFreeModule.__init__(self, algebra, basis_keys=keys, element_class=FreeGradedModuleElement, - category=GradedModulesWithBasis(algebra)) + category=GradedModules(algebra).WithBasis()) def generator_degrees(self): From c0093e2583b60c0061fdb98dcfeac5fe92d39750 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Fri, 8 Oct 2021 11:19:07 -0700 Subject: [PATCH 023/253] trac 32505: use __bool__ instead of __nonzero__ --- src/sage/modules/fp_graded/element.py | 15 +++++++-------- src/sage/modules/fp_graded/module.py | 6 ++---- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/sage/modules/fp_graded/element.py b/src/sage/modules/fp_graded/element.py index 4d9901490ac..a9b6b8ecf84 100755 --- a/src/sage/modules/fp_graded/element.py +++ b/src/sage/modules/fp_graded/element.py @@ -234,7 +234,7 @@ def vector_presentation(self): return F_n.quotient_map()(self.lift_to_free().vector_presentation()) - def __nonzero__(self): + def __bool__(self): r""" Determine if this element is non-zero. @@ -245,17 +245,17 @@ def __nonzero__(self): sage: from sage.modules.fp_graded.module import FPModule sage: M = FPModule(SteenrodAlgebra(2), [0,2,4], [[Sq(4),Sq(2),0]]) - sage: M(0).__nonzero__() + sage: M(0) != 0 + False + sage: M((Sq(6), 0, Sq(2))) == 0 False - sage: M((Sq(6), 0, Sq(2))).__nonzero__() - True sage: a = M((Sq(1)*Sq(2)*Sq(1)*Sq(4), 0, 0)) sage: b = M((0, Sq(2)*Sq(2)*Sq(2), 0)) - sage: a.__nonzero__() + sage: a != 0 True - sage: b.__nonzero__() + sage: bool(b) True - sage: (a + b).__nonzero__() + sage: bool(a + b) False """ pres = self.vector_presentation() @@ -263,7 +263,6 @@ def __nonzero__(self): return False return bool(pres) - __bool__ = __nonzero__ def __eq__(self, other): r""" diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index f7f5b87efd7..aa046a4dc82 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -1,10 +1,8 @@ # TODO: # -# 1. Why do we need to define __bool__ and __eq__ in element.py? They should be taken care of automatically, once we define __nonzero__. -# 2. inhheritance: free modules, elements, etc., should perhaps inherit from fp versions, or maybe both should inherit from generic classes, to consolidate some methods (like degree, _repr_, others?) -# 3. Test with graded modules over other graded rings. (Should be okay, but add some doctests.) +# - Test with graded modules over other graded rings. (Should be okay, but add some doctests.) # -# In __classcall__/__init__ for FPModules, allow as input a free module or a morphism of free modules? +# - In __classcall__/__init__ for FPModules, allow as input a free module or a morphism of free modules? From dfe23879d9bbba959ec114996e760194dc8c8ea0 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Fri, 8 Oct 2021 15:01:28 -0700 Subject: [PATCH 024/253] trac 32505: change inheritance for FPModule --- src/sage/modules/fp_graded/element.py | 21 ++- src/sage/modules/fp_graded/free_element.py | 49 ++++++- src/sage/modules/fp_graded/homspace.py | 2 +- src/sage/modules/fp_graded/module.py | 161 ++++++++++++++++----- src/sage/modules/fp_graded/morphism.py | 12 +- 5 files changed, 198 insertions(+), 47 deletions(-) diff --git a/src/sage/modules/fp_graded/element.py b/src/sage/modules/fp_graded/element.py index a9b6b8ecf84..8e652f2806f 100755 --- a/src/sage/modules/fp_graded/element.py +++ b/src/sage/modules/fp_graded/element.py @@ -62,7 +62,7 @@ def lift_to_free(self): Finitely presented free left module on 2 generators over mod 2 Steenrod algebra, milnor basis """ C = self.parent().j.codomain() - return C(self.dense_coefficient_list()) + return C(self.coefficients()) @cached_method @@ -107,6 +107,25 @@ def degree(self): return self.lift_to_free().degree() + def coefficients(self): + """ + Return a list of all coefficients of ``self``. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FPModule + sage: A = SteenrodAlgebra() + sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) + sage: x = M([Sq(1), 1]) + sage: x.coefficients() + [Sq(1), 1] + sage: y = Sq(2) * M.generator(1) + sage: y.coefficients() + [0, Sq(2)] + """ + return [self[i] for i in sorted(self.parent().basis().keys())] + + def _repr_(self): r""" Return a string representation of this element. diff --git a/src/sage/modules/fp_graded/free_element.py b/src/sage/modules/fp_graded/free_element.py index e3fab6821ee..dec3d6da587 100755 --- a/src/sage/modules/fp_graded/free_element.py +++ b/src/sage/modules/fp_graded/free_element.py @@ -53,6 +53,24 @@ class FreeGradedModuleElement(IndexedFreeModuleElement): sage: M([Sq(1), 1]) """ + + def coefficients(self): + """ + Return a list of all coefficients of ``self``. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A = SteenrodAlgebra() + sage: M = FreeGradedModule(SteenrodAlgebra(2), (0, 1)) + sage: x = M.an_element(7); x + + sage: x.coefficients() + [Sq(0,0,1), Sq(3,1)] + """ + return self.dense_coefficient_list() + + def degree(self): r""" The degree of this element. @@ -90,7 +108,7 @@ def degree(self): degrees = [] try: for g, c in zip(self.parent().generator_degrees(), - self.dense_coefficient_list()): + self.coefficients()): if c: degrees.append(g + c.degree()) except ValueError: @@ -102,13 +120,34 @@ def degree(self): raise ValueError("this is a nonhomogeneous element, no well-defined degree") + def lift_to_free(self): + """ + This returns the module itself. + + It is provided for compatibility with the method of the same + name for :class:`sage.modules.fp_graded.module.FPModule`. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (0,1)) + sage: x = M.an_element() + sage: x.lift_to_free() == x + True + sage: x.lift_to_free() is x + True + """ + return self + + def _repr_(self): r""" Return a string representation of this element. EXAMPLES:: - sage: from sage.modules.fp_graded.free_module import * + sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: A = SteenrodAlgebra(2) sage: M = FreeGradedModule(A, (0,1)) sage: [M.an_element(n) for n in range(1,10)] @@ -122,7 +161,7 @@ def _repr_(self): , ] """ - return '<%s>' % ', '.join(['%s' % c for c in self.dense_coefficient_list()]) + return '<%s>' % ', '.join(['%s' % c for c in self.coefficients()]) def _lmul_(self, a): @@ -160,7 +199,7 @@ def _lmul_(self, a): , <0, 0, Sq(3,2)>] """ - return self.parent()((a*c for c in self.dense_coefficient_list())) + return self.parent()((a*c for c in self.coefficients())) @cached_method def vector_presentation(self): @@ -229,7 +268,7 @@ def vector_presentation(self): base_dict = dict(zip(bas_gen, base_vec.basis())) # Create a sparse representation of the element. - sparse_coeffs = [x for x in enumerate(self.dense_coefficient_list()) if not x[1].is_zero()] + sparse_coeffs = [x for x in enumerate(self.coefficients()) if not x[1].is_zero()] vector = base_vec.zero() for summand_index, algebra_element in sparse_coeffs: diff --git a/src/sage/modules/fp_graded/homspace.py b/src/sage/modules/fp_graded/homspace.py index 5723710511f..fc076309c11 100755 --- a/src/sage/modules/fp_graded/homspace.py +++ b/src/sage/modules/fp_graded/homspace.py @@ -474,7 +474,7 @@ def _trivial_case(): target_degs = [r.degree() + n for r in M.relations()] block_matrix, R = _CreateRelationsMatrix( - N, [r.dense_coefficient_list() for r in M.relations()], source_degs, target_degs) + N, [r.coefficients() for r in M.relations()], source_degs, target_degs) ker = R.right_kernel() diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index aa046a4dc82..2b624faa85b 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -66,8 +66,13 @@ from sage.categories.homset import Hom from sage.misc.cachefunc import cached_method from sage.rings.infinity import PlusInfinity -from sage.categories.graded_modules_with_basis import GradedModulesWithBasis -from sage.combinat.free_module import CombinatorialFreeModule +from sage.categories.graded_modules import GradedModules +from sage.modules.module import Module +from sage.structure.indexed_generators import IndexedGenerators +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.parent import Parent +from sage.misc.lazy_attribute import lazy_attribute +from sage.structure.element import parent from .free_module import FreeGradedModule from .free_element import FreeGradedModuleElement @@ -77,7 +82,7 @@ # vector spaces. They have a distinguished set of generators over the # algebra, and as long as the algebra has a vector space basis # implemented in Sage, the modules will have a vector space basis as well. -class FPModule(CombinatorialFreeModule): +class FPModule(Module, IndexedGenerators, UniqueRepresentation): r""" Create a finitely presented module over a connected graded algebra. @@ -172,11 +177,14 @@ def __init__(self, algebra, generator_degrees, relations=()): # following morphism. self.j = Hom(relationsModule, generatorModule)(rels) - # Call the base class constructor. - CombinatorialFreeModule.__init__(self, algebra, - basis_keys=keys, - element_class=FPElement, - category=GradedModulesWithBasis(algebra)) + # Call the base class constructors. + cat = GradedModules(algebra).WithBasis() + IndexedGenerators.__init__(self, keys) + Module.__init__(self, algebra, category=cat) + Parent.__init__(self, base=algebra, category=cat) + + + element_class = FPElement def _free_module(self): @@ -196,6 +204,7 @@ def _free_module(self): """ return self.j.codomain() + @classmethod def from_free_module(cls, free_module): r""" @@ -210,8 +219,8 @@ def from_free_module(cls, free_module): EXAMPLES:: - sage: from sage.modules.fp_graded.free_module import * - sage: from sage.modules.fp_graded.module import * + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) sage: F = FreeGradedModule(A, (-2,2,4)) sage: FPModule.from_free_module(F) @@ -239,8 +248,8 @@ def from_free_module_morphism(cls, morphism): EXAMPLES:: - sage: from sage.modules.fp_graded.free_module import * - sage: from sage.modules.fp_graded.module import * + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) sage: F1 = FreeGradedModule(A, (2,)) sage: F2 = FreeGradedModule(A, (0,)) @@ -255,7 +264,7 @@ def from_free_module_morphism(cls, morphism): """ return cls(algebra=morphism.base_ring(), generator_degrees=morphism.codomain().generator_degrees(), - relations=tuple([r.dense_coefficient_list() for r in morphism.values()])) + relations=tuple([r.coefficients() for r in morphism.values()])) def change_ring(self, algebra): @@ -272,7 +281,7 @@ def change_ring(self, algebra): EXAMPLES:: - sage: from sage.modules.fp_graded.module import * + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) sage: A2 = SteenrodAlgebra(2,profile=(3,2,1)) @@ -285,10 +294,90 @@ def change_ring(self, algebra): True """ # self.relations() consists of module elements. We need to extra the coefficients. - relations = tuple(r.dense_coefficient_list() for r in self.relations()) + relations = tuple(r.coefficients() for r in self.relations()) return FPModule(algebra, self.generator_degrees(), relations) + def __contains__(self, x): + """ + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FPModule + sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) + sage: x = M([Sq(1), 1]) + sage: x in M + True + sage: N = FPModule(SteenrodAlgebra(2), [0], [[Sq(2)]]) + sage: y = Sq(2)*N.generator(0) + sage: y in M + False + """ + return parent(x) == self + + + def _from_dict(self, d, coerce=False, remove_zeros=True): + r""" + Construct an element of ``self`` from an ``{index: coefficient}`` + dictionary. + + INPUT: ``d``, a dictionary + + This code is taken from the method of the same name for + ``sage.combinat.free_module.FreeModule``. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FPModule + sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) + sage: x = M.an_element() + sage: M._from_dict(x.monomial_coefficients()) == x + True + """ + assert isinstance(d, dict) + if coerce: + R = self.base_ring() + d = {key: R(coeff) for key, coeff in d.items()} + if remove_zeros: + d = {key: coeff for key, coeff in d.items() if coeff} + return self.element_class(self, d) + + + def _monomial(self, index): + """ + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FPModule + sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) + sage: M._monomial((0,0)) + <1, 0> + sage: M._monomial((1,1)) + <0, 1> + """ + return self._from_dict({index: self.base_ring().one()}, remove_zeros=False) + + @lazy_attribute + def monomial(self): + """ + Return the basis element indexed by ``i``. + + INPUT: + + - ``i`` -- an element of the index set + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FPModule + sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) + sage: M.monomial((0,0)) + <1, 0> + sage: M.monomial((1,1)) + <0, 1> + """ + # Should use a real Map, as soon as combinatorial_classes are enumerated sets, and therefore parents + from sage.categories.poor_man_map import PoorManMap + return PoorManMap(self._monomial, domain=self._indices, codomain=self, name="Term map") + + def _element_constructor_(self, x): r""" Construct any element of this module. @@ -306,7 +395,7 @@ def _element_constructor_(self, x): EXAMPLES:: - sage: from sage.modules.fp_graded.module import * + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) sage: M = FPModule(A, [0,2,4], [[Sq(4), Sq(2), 0]]) @@ -330,9 +419,13 @@ def _element_constructor_(self, x): """ if isinstance(x, self.element_class): return x + ngens = len(self._generator_keys) + if ngens == 0: # the trivial module + return self._free_module().zero() if not x: - return self.zero() - B = self.basis() + x = [self.base_ring().zero()] * ngens + from sage.combinat.family import Family + B = Family(self._indices, self.monomial) if isinstance(x, FreeGradedModuleElement): if x.parent() == self._free_module(): # x.parent() should have the same generator list as self. @@ -348,7 +441,7 @@ def _repr_(self): EXAMPLES:: - sage: from sage.modules.fp_graded.module import * + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) sage: M = FPModule(A, [0,2,4], [[Sq(4),Sq(2),0]]); M Finitely presented left module on 3 generators and 1 relation over mod 2 Steenrod algebra, milnor basis @@ -515,7 +608,7 @@ def an_element(self, n=None): EXAMPLES:: - sage: from sage.modules.fp_graded.module import * + sage: from sage.modules.fp_graded.module import FPModule sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) sage: M = FPModule(A2, [0,2,4], [[0, Sq(5), Sq(3)], [Sq(7), 0, Sq(2)*Sq(1)]]) @@ -556,7 +649,7 @@ def basis_elements(self, n, verbose=False): EXAMPLES:: - sage: from sage.modules.fp_graded.module import * + sage: from sage.modules.fp_graded.module import FPModule sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) sage: M = FPModule(A2, [0,2], [[Sq(4), Sq(2)], [0, Sq(6)]]) @@ -609,7 +702,7 @@ def element_from_coordinates(self, coordinates, n): EXAMPLES:: - sage: from sage.modules.fp_graded.module import * + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) sage: M = FPModule(A, [0], [[Sq(4)], [Sq(7)], [Sq(4)*Sq(9)]]) @@ -643,7 +736,7 @@ def element_from_coordinates(self, coordinates, n): free_element = self._free_module().element_from_coordinates( M_n.lift(coordinates), n) - return self(free_element.dense_coefficient_list()) + return self(free_element.coefficients()) def __getitem__(self, n): @@ -691,7 +784,7 @@ def vector_presentation(self, n, verbose=False): EXAMPLES:: - sage: from sage.modules.fp_graded.module import * + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) sage: M = FPModule(A, [0,2,4], [[Sq(4),Sq(2),0]]) @@ -752,7 +845,7 @@ def _Hom_(self, Y, category): TESTS:: - sage: from sage.modules.fp_graded.module import * + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) sage: F = FPModule(A, [1,3]); sage: L = FPModule(A, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]); @@ -775,7 +868,7 @@ def generator_degrees(self): EXAMPLES:: - sage: from sage.modules.fp_graded.module import * + sage: from sage.modules.fp_graded.module import FPModule sage: A4 = SteenrodAlgebra(2, profile=(4,3,2,1)) sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]]) @@ -815,7 +908,7 @@ def generator(self, index): EXAMPLES:: - sage: from sage.modules.fp_graded.module import * + sage: from sage.modules.fp_graded.module import FPModule sage: A4 = SteenrodAlgebra(2, profile=(4,3,2,1)) sage: M = FPModule(A4, [0,2,3]) @@ -835,7 +928,7 @@ def relations(self): EXAMPLES:: - sage: from sage.modules.fp_graded.module import * + sage: from sage.modules.fp_graded.module import FPModule sage: A4 = SteenrodAlgebra(2, profile=(4,3,2,1)) sage: M = FPModule(A4, [0,2,3]) @@ -859,7 +952,7 @@ def relation(self, index): EXAMPLES:: - sage: from sage.modules.fp_graded.module import * + sage: from sage.modules.fp_graded.module import FPModule sage: A4 = SteenrodAlgebra(2, profile=(4,3,2,1)) sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]]) sage: N.relation(0) @@ -876,7 +969,7 @@ def min_presentation(self, top_dim=None, verbose=False): EXAMPLES:: - sage: from sage.modules.fp_graded.module import * + sage: from sage.modules.fp_graded.module import FPModule sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) sage: M = FPModule(A2, [0,1], [[Sq(2),Sq(1)],[0,Sq(2)],[Sq(3),0]]) @@ -922,7 +1015,7 @@ def suspension(self, t): EXAMPLES:: - sage: from sage.modules.fp_graded.module import * + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) @@ -964,7 +1057,7 @@ def submodule(self, spanning_elements): EXAMPLES:: - sage: from sage.modules.fp_graded.module import * + sage: from sage.modules.fp_graded.module import FPModule sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) sage: M = FPModule(A2, [0,1], [[Sq(2),Sq(1)]]) @@ -1012,7 +1105,7 @@ def resolution(self, k, top_dim=None, verbose=False): EXAMPLES:: - sage: from sage.modules.fp_graded.module import * + sage: from sage.modules.fp_graded.module import FPModule sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) sage: M = FPModule(A2, [0,1], [[Sq(2), Sq(1)]]) sage: M.resolution(0) @@ -1075,7 +1168,7 @@ def _print_progress(i, k): # f_1: F_1 -> F_0 _print_progress(1, k) F_1 = FPModule.from_free_module(self.j.domain()) - pres = Hom(F_1, F_0)(tuple([ F_0(x.dense_coefficient_list()) for x in self.j.values() ])) + pres = Hom(F_1, F_0)(tuple([ F_0(x.coefficients()) for x in self.j.values() ])) complex.append(pres) diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py index 9758e1ea6f6..24573f7cde3 100755 --- a/src/sage/modules/fp_graded/morphism.py +++ b/src/sage/modules/fp_graded/morphism.py @@ -249,7 +249,7 @@ def change_ring(self, algebra): # We have to change the ring for the values, too: new_values = [] for v in self._values: - new_values.append(new_codomain([algebra(a) for a in v.dense_coefficient_list()])) + new_values.append(new_codomain([algebra(a) for a in v.coefficients()])) return Hom(self.domain().change_ring(algebra), new_codomain)(new_values) @@ -1008,7 +1008,7 @@ def lift(self, f, verbose=False): for r in L.relations(): target_degree = r.degree() + lift_deg - y = iK.solve(sum([c*x for c,x in zip(r.dense_coefficient_list(), xs)])) + y = iK.solve(sum([c*x for c,x in zip(r.coefficients(), xs)])) if y is None: if verbose: print('The homomorphism cannot be lifted in any ' @@ -1028,7 +1028,7 @@ def lift(self, f, verbose=False): return Hom(L, M)(xs) block_matrix, R = _CreateRelationsMatrix( - K, [r.dense_coefficient_list() for r in L.relations()], source_degs, target_degs) + K, [r.coefficients() for r in L.relations()], source_degs, target_degs) try: solution = R.solve_right(vector(ys)) @@ -1237,8 +1237,8 @@ def cokernel(self): False """ from .module import FPModule - new_relations = [x.dense_coefficient_list() for x in self.codomain().relations()] +\ - [x.dense_coefficient_list() for x in self._values] + new_relations = [x.coefficients() for x in self.codomain().relations()] +\ + [x.coefficients() for x in self._values] coker = FPModule(self.base_ring(), self.codomain().generator_degrees(), @@ -1765,5 +1765,5 @@ def to_fp_module(self): from .module import FPModule return FPModule(algebra=self.base_ring(), generator_degrees=self.codomain().generator_degrees(), - relations=tuple([r.dense_coefficient_list() for r in self.values()])) + relations=tuple([r.coefficients() for r in self.values()])) From b5c789541fab53e4163c636e646d59e6caa2bbed Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Sat, 20 Nov 2021 15:51:10 -0800 Subject: [PATCH 025/253] trac 32505: add axiom "FinitelyPresented" for modules and use it. Change _repr_ for the zero element. Fix pyflakes warnings and other small syntax issues. Full doctest coverage. --- src/sage/categories/category_with_axiom.py | 2 +- src/sage/categories/modules.py | 52 +++++++++++++++++++++ src/sage/modules/fp_graded/element.py | 14 +++--- src/sage/modules/fp_graded/free_element.py | 17 ++++--- src/sage/modules/fp_graded/free_homspace.py | 2 - src/sage/modules/fp_graded/free_module.py | 50 +++++++++++--------- src/sage/modules/fp_graded/free_morphism.py | 20 ++++++-- src/sage/modules/fp_graded/homspace.py | 10 ++-- src/sage/modules/fp_graded/module.py | 42 +++++++++-------- src/sage/modules/fp_graded/morphism.py | 29 ++++++++---- 10 files changed, 161 insertions(+), 77 deletions(-) diff --git a/src/sage/categories/category_with_axiom.py b/src/sage/categories/category_with_axiom.py index cbd3823ab5e..14e897cc080 100644 --- a/src/sage/categories/category_with_axiom.py +++ b/src/sage/categories/category_with_axiom.py @@ -1679,7 +1679,7 @@ class ``Sets.Finite``), or in a separate file (typically in a class "Facade", "Finite", "Infinite","Enumerated", "Complete", "Nilpotent", - "FiniteDimensional", "Connected", + "FiniteDimensional", "FinitelyPresented", "Connected", "FinitelyGeneratedAsLambdaBracketAlgebra", "WithBasis", "Irreducible", diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index 7139c413bcc..ef425254340 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -351,6 +351,26 @@ def FiniteDimensional(self): """ return self._with_axiom("FiniteDimensional") + @cached_method + def FinitelyPresented(self): + r""" + Return the full subcategory of the finitely presented objects of ``self``. + + EXAMPLES:: + + sage: Modules(ZZ).FinitelyPresented() + Category of finitely presented modules over Integer Ring + sage: A = SteenrodAlgebra(2) + sage: from sage.modules.fp_graded.module import FPModule + sage: FPModule(A, [0, 1], [[Sq(2), Sq(1)]]).category() + Category of finitely presented graded modules with basis over mod 2 Steenrod algebra, milnor basis + + TESTS:: + + sage: TestSuite(Modules(ZZ).FinitelyPresented()).run() + """ + return self._with_axiom("FinitelyPresented") + @cached_method def Filtered(self, base_ring=None): r""" @@ -514,6 +534,38 @@ def extra_super_categories(self): else: return [] + class FinitelyPresented(CategoryWithAxiom_over_base_ring): + + def extra_super_categories(self): + """ + Implement the fact that a finitely presented module over a finite + ring is finite. + + EXAMPLES:: + + sage: Modules(IntegerModRing(4)).FiniteDimensional().extra_super_categories() + [Category of finite sets] + sage: Modules(ZZ).FiniteDimensional().extra_super_categories() + [] + sage: Modules(GF(5)).FiniteDimensional().is_subcategory(Sets().Finite()) + True + sage: Modules(ZZ).FiniteDimensional().is_subcategory(Sets().Finite()) + False + + sage: Modules(Rings().Finite()).FiniteDimensional().is_subcategory(Sets().Finite()) + True + sage: Modules(Rings()).FiniteDimensional().is_subcategory(Sets().Finite()) + False + """ + base_ring = self.base_ring() + FiniteSets = Sets().Finite() + if (isinstance(base_ring, Category) and + base_ring.is_subcategory(FiniteSets)) or \ + base_ring in FiniteSets: + return [FiniteSets] + else: + return [] + Filtered = LazyImport('sage.categories.filtered_modules', 'FilteredModules') Graded = LazyImport('sage.categories.graded_modules', 'GradedModules') Super = LazyImport('sage.categories.super_modules', 'SuperModules') diff --git a/src/sage/modules/fp_graded/element.py b/src/sage/modules/fp_graded/element.py index 8e652f2806f..3fae2d5fa51 100755 --- a/src/sage/modules/fp_graded/element.py +++ b/src/sage/modules/fp_graded/element.py @@ -28,8 +28,6 @@ from sage.misc.cachefunc import cached_method from sage.modules.with_basis.indexed_element import IndexedFreeModuleElement -from .free_element import FreeGradedModuleElement - class FPElement(IndexedFreeModuleElement): r""" @@ -70,8 +68,8 @@ def degree(self): r""" The degree of this element. - OUTPUT: The integer degree of this element, or ``None`` if this is the - zero element. + OUTPUT: The integer degree of this element, or raise an error + if this is the zero element. EXAMPLES:: @@ -174,10 +172,10 @@ def _lmul_(self, a): sage: a = A2.Sq(3) sage: [a*x for x in elements] [, - <0, 0>, + 0, , <0, Sq(1,1)>, - <0, 0>, + 0, , , , @@ -215,7 +213,7 @@ def vector_presentation(self): sage: v = x.vector_presentation(); v (1, 0, 0, 0, 0, 1, 0) sage: type(v) - + sage: V = M.vector_presentation(7) sage: v in V @@ -329,7 +327,7 @@ def normalize(self): sage: n = M((Sq(4), Sq(2), 0)); n sage: n.normalize() - <0, 0, 0> + 0 sage: n == n.normalize() True """ diff --git a/src/sage/modules/fp_graded/free_element.py b/src/sage/modules/fp_graded/free_element.py index dec3d6da587..d3a23b812ce 100755 --- a/src/sage/modules/fp_graded/free_element.py +++ b/src/sage/modules/fp_graded/free_element.py @@ -42,7 +42,7 @@ class FreeGradedModuleElement(IndexedFreeModuleElement): sage: M = FreeGradedModule(SteenrodAlgebra(2), (0, 1)) sage: M([0, 0]) - <0, 0> + 0 sage: M([1, 0]) <1, 0> @@ -75,8 +75,8 @@ def degree(self): r""" The degree of this element. - OUTPUT: the integer degree of this element, or None if this is the zero - element. + OUTPUT: the integer degree of this element, or raise an error + if this is the zero element. EXAMPLES:: @@ -161,7 +161,10 @@ def _repr_(self): , ] """ - return '<%s>' % ', '.join(['%s' % c for c in self.coefficients()]) + if self: + return '<%s>' % ', '.join(['%s' % c for c in self.coefficients()]) + else: + return '0' def _lmul_(self, a): @@ -190,10 +193,10 @@ def _lmul_(self, a): sage: a = A2.Sq(3) sage: [a*x for x in elements] [, - <0, 0, 0>, + 0, , <0, 0, Sq(1,1)>, - <0, 0, 0>, + 0, , , , @@ -230,7 +233,7 @@ def vector_presentation(self): sage: v = x.vector_presentation(); v (1, 0, 0, 0, 0, 1, 0) sage: type(v) - + sage: V = M.vector_presentation(7) sage: v in V diff --git a/src/sage/modules/fp_graded/free_homspace.py b/src/sage/modules/fp_graded/free_homspace.py index 7bf639a6fd1..83913bba351 100755 --- a/src/sage/modules/fp_graded/free_homspace.py +++ b/src/sage/modules/fp_graded/free_homspace.py @@ -72,8 +72,6 @@ def _element_constructor_(self, values): defined by mapping the module generators in the domain to the given values. - OUTPUT: A module homomorphism. - EXAMPLES:: sage: from sage.modules.fp_graded.free_module import FreeGradedModule diff --git a/src/sage/modules/fp_graded/free_module.py b/src/sage/modules/fp_graded/free_module.py index 84ddf9d60f3..a5f2aa5d68d 100755 --- a/src/sage/modules/fp_graded/free_module.py +++ b/src/sage/modules/fp_graded/free_module.py @@ -1,8 +1,9 @@ r""" Finitely generated free graded left modules over connected graded algebras. -This class implements methods for construction and basic manipulation of -finitely generated free graded modules over connected graded algebras. +This class implements methods for construction and basic manipulation +of finitely generated free graded modules over connected graded +algebras with a given graded basis. ========== User guide @@ -83,7 +84,7 @@ But the zero element has not:: sage: zero = M.zero(); zero - <0, 0> + 0 sage: zero.degree() Traceback (most recent call last): ... @@ -104,7 +105,7 @@ Finally, additive inverses exist:: sage: x - x - <0, 0> + 0 For every integer `n`, the set of module elements of degree `n` form a vector space over the ground field `k`. A basis for this vector space can be @@ -210,7 +211,7 @@ Module homomorphism of degree 4 defined by sending the generators [<1, 0>, <0, 1>] to - [<0>, ] + [0, ] or when at least one of them is zero:: @@ -282,13 +283,11 @@ class FreeGradedModule(CombinatorialFreeModule): INPUT: - - ``algebra`` -- the connected algebra over which the module is defined. - - - ``generator_degrees`` -- a tuple of integers defining - the number of generators of the module, and their degrees. + - ``algebra`` -- the graded connected algebra over which the module is + defined. This algebra must be equipped with a graded basis. - OUTPUT: The finitely generated free graded module on generators with - degrees given by ``generator_degrees``. + - ``generator_degrees`` -- tuple of integers defining the number + of generators of the module, and their degrees. TESTS:: @@ -301,6 +300,15 @@ def __init__(self, algebra, generator_degrees): r""" Create a finitely generated free graded module over a connected graded algebra. + + OUTPUT: The finitely generated free graded module on generators with + degrees given by ``generator_degrees``. + + TESTS:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A = SteenrodAlgebra(2) + sage: TestSuite(FreeGradedModule(A, (-2,2,4))).run() """ # If generator_degrees is [d_0, d_1, ...], then # the generators are indexed by (0,d_0), (1,d_1), ... @@ -314,7 +322,7 @@ def __init__(self, algebra, generator_degrees): CombinatorialFreeModule.__init__(self, algebra, basis_keys=keys, element_class=FreeGradedModuleElement, - category=GradedModules(algebra).WithBasis()) + category=GradedModules(algebra).WithBasis().FiniteDimensional()) def generator_degrees(self): @@ -352,7 +360,7 @@ def is_trivial(self): sage: FreeGradedModule(A, ()).is_trivial() True """ - return len(self.generator_degrees()) == 0 + return not len(self.generator_degrees()) def connectivity(self): @@ -405,7 +413,7 @@ def _element_constructor_(self, coefficients): sage: M = FreeGradedModule(A, (0,2,4)) sage: zero = M(0); zero - <0, 0, 0> + 0 sage: e = M((Sq(4), Sq(2), 1)); e @@ -447,12 +455,12 @@ def an_element(self, n=None): Zero is the only element in the trivial module:: sage: FreeGradedModule(A, ()).an_element() - <> + 0 """ - if len(self.generator_degrees()) == 0: + if not len(self.generator_degrees()): return self.zero() - if n == None: + if n is None: n = max(self.generator_degrees()) + 7 coefficients = [] @@ -492,6 +500,8 @@ def _repr_(self): def basis_elements(self, n): r""" A basis for the vector space of degree ``n`` module elements. + This returns a basis as a vector space over the base field, + not a basis as a free module over the algebra. INPUT: @@ -558,7 +568,7 @@ def element_from_coordinates(self, coordinates, n): True sage: M.element_from_coordinates((0,0,0,0), 5) - <0, 0> + 0 """ basis_elements = self.basis_elements(n) @@ -675,14 +685,12 @@ def generator(self, index): <0, 0, 1> """ try: - key = self._generator_keys[index] + return self.monomial(self._generator_keys[index]) except IndexError: raise ValueError('the parent module has generators in the index '\ 'range [0, %s]; generator %s does not exist' %\ (len(self.generator_degrees()) - 1, index)) - return self.monomial(self._generator_keys[index]) - def generators(self): r""" diff --git a/src/sage/modules/fp_graded/free_morphism.py b/src/sage/modules/fp_graded/free_morphism.py index cb2ad663be5..adbcd3b6e11 100755 --- a/src/sage/modules/fp_graded/free_morphism.py +++ b/src/sage/modules/fp_graded/free_morphism.py @@ -35,7 +35,6 @@ from sage.categories.homset import Hom from sage.categories.morphism import Morphism -from sage.misc.cachefunc import cached_method class FreeGradedModuleMorphism(Morphism): @@ -50,9 +49,6 @@ class FreeGradedModuleMorphism(Morphism): - ``values`` -- A list of elements in the codomain. Each element corresponds (by their ordering) to a module generator in the domain. - OUTPUT: A module homomorphism defined by sending each generator to its - corresponding value. - EXAMPLES:: sage: from sage.modules.fp_graded.free_module import FreeGradedModule @@ -87,6 +83,20 @@ class FreeGradedModuleMorphism(Morphism): def __init__(self, parent, values): r""" Create a homomorphism between finitely generated free graded modules. + + OUTPUT: A module homomorphism defined by sending each + generator to its corresponding value. + + TESTS:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (0, 0)) + sage: N = FreeGradedModule(A, (0,)) + sage: H = Hom(M, N) + sage: g = N.generator(0) + sage: TestSuite(H).run() + sage: TestSuite(g).run() """ from .free_homspace import FreeGradedModuleHomspace if not isinstance(parent, FreeGradedModuleHomspace): @@ -179,7 +189,7 @@ def values(self): sage: f.values() [, ] sage: homspace.zero().values() - [<0>, <0>] + [0, 0] """ return self._values diff --git a/src/sage/modules/fp_graded/homspace.py b/src/sage/modules/fp_graded/homspace.py index fc076309c11..002fee86db5 100755 --- a/src/sage/modules/fp_graded/homspace.py +++ b/src/sage/modules/fp_graded/homspace.py @@ -21,7 +21,7 @@ Module homomorphism of degree 0 defined by sending the generators [<1, 0>, <0, 1>] to - [<0, 0>, ] + [0, ] sage: homset([L((A.Sq(1), 1)), L((0, A.Sq(2)))]) Module homomorphism of degree 2 defined by sending the generators [<1, 0>, <0, 1>] @@ -153,14 +153,14 @@ def an_element(self, n=0): Module homomorphism of degree 4 defined by sending the generators [<1, 0>, <0, 1>] to - [<0, 0>, ] + [0, ] sage: K = FPModule(A, [0, 0], [[Sq(2), 0], [0,0], [Sq(4), Sq(2)*Sq(2)]]) sage: Hom(K, K).an_element(n=3) Module homomorphism of degree 3 defined by sending the generators [<1, 0>, <0, 1>] to - [<0, 0>, ] + [0, ] """ return self._basis_elements(n, basis=False) @@ -209,10 +209,10 @@ def zero(self): The trivial homomorphism. sage: z(F.an_element(5)) - <0, 0> + 0 sage: z(F.an_element(23)) - <0, 0> + 0 """ return self.element_class(self, [self.codomain().zero() for g in self.domain().generator_degrees()]) diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index 2b624faa85b..49d807d2e33 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -1,17 +1,9 @@ -# TODO: -# -# - Test with graded modules over other graded rings. (Should be okay, but add some doctests.) -# -# - In __classcall__/__init__ for FPModules, allow as input a free module or a morphism of free modules? - - - - r""" Finitely presented graded modules -This class implements methods for construction and basic manipulation of -finitely presented graded modules over connected graded algebras. +This class implements methods for construction and basic manipulation +of finitely presented graded modules over connected graded algebras +with a given graded basis. .. NOTE:: This class was designed for use by :class:`sage.modules.fp_graded.fpa_module.FPA_Module`. @@ -88,17 +80,15 @@ class FPModule(Module, IndexedGenerators, UniqueRepresentation): INPUT: - - ``algebra`` -- The algebra over which the module is defined. + - ``algebra`` -- the graded connected algebra over which the module is + defined. This algebra must be equipped with a graded basis. - - ``generator_degrees`` -- A tuple of integer degrees. + - ``generator_degrees`` -- tuple of integer degrees. - - ``relations`` -- A tuple of relations. A relation is a tuple of + - ``relations`` -- tuple of relations. A relation is a tuple of coefficients `(c_1, \ldots, c_n)`, ordered so that they correspond to the module generators. - OUTPUT: The finitely presented module over ``algebra`` with - presentation given by ``generator_degrees`` and ``relations``. - EXAMPLES:: sage: from sage.modules.fp_graded.module import FPModule @@ -154,6 +144,16 @@ def __classcall_private__(cls, algebra, generator_degrees, relations=()): def __init__(self, algebra, generator_degrees, relations=()): r""" Create a finitely presented module over a connected graded algebra. + + OUTPUT: The finitely presented module over ``algebra`` with + presentation given by ``generator_degrees`` and ``relations``. + + TESTS:: + + sage: from sage.modules.fp_graded.module import FPModule + sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) + sage: M = FPModule(A3, [0, 1], [[Sq(2), Sq(1)]]) + sage: TestSuite(M).run() """ self._generator_degrees = generator_degrees self._relations = relations @@ -178,7 +178,7 @@ def __init__(self, algebra, generator_degrees, relations=()): self.j = Hom(relationsModule, generatorModule)(rels) # Call the base class constructors. - cat = GradedModules(algebra).WithBasis() + cat = GradedModules(algebra).WithBasis().FinitelyPresented() IndexedGenerators.__init__(self, keys) Module.__init__(self, algebra, category=cat) Parent.__init__(self, base=algebra, category=cat) @@ -407,7 +407,7 @@ def _element_constructor_(self, x): sage: # Special syntax for creating the zero element: sage: z = M(0); z - <0, 0, 0> + 0 sage: z.is_zero() True @@ -497,7 +497,7 @@ def connectivity(self): """ # In case there are no relations, the connectivity is the equal to # the connectivity of the free module on the generators. - if self.j._degree == None: + if self.j._degree is None: return self._free_module().connectivity() # We must check that the generator(s) in the free generator module are @@ -632,6 +632,8 @@ def an_element(self, n=None): def basis_elements(self, n, verbose=False): r""" A basis for the vector space of degree ``n`` module elements. + Note that this returns a basis as a vector space over the + base field. INPUT: diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py index 24573f7cde3..31bcfd841b3 100755 --- a/src/sage/modules/fp_graded/morphism.py +++ b/src/sage/modules/fp_graded/morphism.py @@ -163,9 +163,6 @@ class FPModuleMorphism(Morphism): - ``values`` -- A list of elements in the codomain. Each element corresponds to a module generator in the domain. - OUTPUT: A module homomorphism defined by sending the generator with - index `i` to the corresponding element in ``values``. - .. NOTE:: Never use this constructor explicitly, but rather the parent's call method, or this class' __call__ method. The reason for this is that the dynamic type of the element class changes as a @@ -174,8 +171,10 @@ class FPModuleMorphism(Morphism): TESTS:: sage: from sage.modules.fp_graded.module import FPModule - sage: # Trying to map the generators of a non-free module into a - sage: # free module: + + Trying to map the generators of a non-free module into a + free module:: + sage: A = SteenrodAlgebra(2) sage: F = FPModule(A, [2,3]) sage: Q = FPModule(A, [2,3], relations=[[Sq(6), Sq(5)]]) @@ -184,8 +183,9 @@ class FPModuleMorphism(Morphism): ... ValueError: ill-defined homomorphism: degrees do not match - sage: # Trying to map the generators of a non-free module into a - sage: # free module: + Trying to map the generators of a non-free module into a + free module:: + sage: w = Hom(Q, F)( (F((1, 0)), F((0, 1))) ) Traceback (most recent call last): ... @@ -194,6 +194,19 @@ class FPModuleMorphism(Morphism): def __init__(self, parent, values): r""" Create a homomorphism between finitely presented graded modules. + + OUTPUT: A module homomorphism defined by sending the generator + with index `i` to the corresponding element in ``values``. + + TESTS:: + + sage: from sage.modules.fp_graded.module import FPModule + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) + sage: M = FPModule(A2, [0], relations=[[Sq(1)]]) + sage: N = FPModule(A2, [0], relations=[[Sq(4)],[Sq(1)]]) + sage: f = Hom(M,N)([A2.Sq(3)*N.generator(0)]) + sage: TestSuite(f).run() """ from .homspace import FPModuleHomspace @@ -319,7 +332,7 @@ def values(self): [, ] sage: homspace.zero().values() - [<0>, <0>] + [0, 0] """ return self._values From d3df701affc8d1b24775fca5d1ae9bb8d9135e1a Mon Sep 17 00:00:00 2001 From: Thierry Monteil Date: Sat, 30 Oct 2021 14:25:21 +0200 Subject: [PATCH 026/253] #32788 : ensure bare except: statements will not reappear --- src/tox.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tox.ini b/src/tox.ini index 08abc70e5f6..55b12a974b0 100644 --- a/src/tox.ini +++ b/src/tox.ini @@ -84,9 +84,10 @@ description = # E711: comparison to None should be ‘if cond is None:’ # E712: comparison to True should be ‘if cond is True:’ or ‘if cond:’ # E721: do not compare types, use isinstance() + # E722: do not use bare except, specify exception instead # See https://pycodestyle.pycqa.org/en/latest/intro.html#error-codes deps = pycodestyle -commands = pycodestyle --select E401,E70,W605,E711,E712,E721 {posargs:{toxinidir}/sage/} +commands = pycodestyle --select E401,E70,W605,E711,E712,E721,E722 {posargs:{toxinidir}/sage/} [pycodestyle] max-line-length = 160 From e92b905a359977dce92a0b8118d26fd41877ac48 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Wed, 10 Nov 2021 18:56:22 +0100 Subject: [PATCH 027/253] mark polymake_expect import as optional --- src/sage/interfaces/polymake.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/interfaces/polymake.py b/src/sage/interfaces/polymake.py index c5da77ddd23..6cbcb62d7b1 100644 --- a/src/sage/interfaces/polymake.py +++ b/src/sage/interfaces/polymake.py @@ -2114,7 +2114,7 @@ def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if EXAMPLES:: - sage: from sage.interfaces.polymake import polymake_expect as polymake + sage: from sage.interfaces.polymake import polymake_expect as polymake # optional - polymake_expect sage: p = polymake.cube(3) # optional - polymake_expect # indirect doctest Here we see that remarks printed by polymake are displayed if From f463e49b287475f9751e16d8d241fc030b606953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 18 Nov 2021 11:19:21 +0100 Subject: [PATCH 028/253] comment before --- src/sage/schemes/product_projective/rational_point.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/schemes/product_projective/rational_point.py b/src/sage/schemes/product_projective/rational_point.py index 8f56fcd8637..fd9153da37e 100644 --- a/src/sage/schemes/product_projective/rational_point.py +++ b/src/sage/schemes/product_projective/rational_point.py @@ -494,8 +494,8 @@ def parallel_function_combination(point_p_max): continue try: - rat_points.add(X(point)) # checks if this point lies on X or not + rat_points.add(X(point)) except (TypeError, ValueError): pass From 456d46589245c71e45d842bc0973caf99546d9e5 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Mon, 6 Dec 2021 09:49:37 +0100 Subject: [PATCH 029/253] LLL,min,max,short_vectors for IntegralLattice --- ...free_quadratic_module_integer_symmetric.py | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index d872452021b..ac8d990fa71 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -61,6 +61,7 @@ from sage.arith.misc import gcd from sage.combinat.root_system.cartan_matrix import CartanMatrix from sage.misc.cachefunc import cached_method +from sage.quadratic_forms.all import QuadraticForm ############################################################################### # @@ -1374,6 +1375,149 @@ def tensor_product(self, other, discard_basis=False): basis=basis_matrix, inner_product_matrix=ambient.inner_product_matrix()) + @cached_method + def quadratic_form(self): + r""" + Return the quadratic form given by `q(x)=(x,x)`. + + Examples:: + + sage: L = IntegralLattice("A2") + sage: q = L.quadratic_form() + sage: q + Quadratic form in 2 variables over Integer Ring with coefficients: + [ 2 -2 ] + [ * 2 ] + """ + return QuadraticForm(2*self.gram_matrix()) + + @cached_method + def minimum(self): + r""" + Return the minimum of this lattice. + + .. Math:: + + \min\{x^2 | x \in L\setminus \{0\}\} + + EXAMPLES:: + + sage: L = IntegralLattice('A2') + sage: L.minimum() + 2 + sage: L.twist(-1).minimum() + -Infinity + """ + p, n = self.signature_pair() + if self.rank()==0: + raise ValueError("The empty set does not have a minimum") + if n != 0: + from sage.rings.infinity import MinusInfinity + return MinusInfinity() + mpari = self.gram_matrix().__pari__().qfminim(None, 0)[1] + return mpari + + @cached_method + def maximum(self): + r""" + Return the maximum of this lattice. + + .. Math:: + + \max\{x^2 | x \in L\setminus \{0\}\} + + + EXAMPLES:: + + sage: L = IntegralLattice('A2') + sage: L.maximum() + +Infinity + sage: L.twist(-1).maximum() + -2 + """ + if self.rank()==0: + raise ValueError("The empty set does not have a maximum.") + p, n = self.signature_pair() + if p != 0: + from sage.rings.infinity import PlusInfinity + return PlusInfinity() + mpari = (-self.gram_matrix()).__pari__().qfminim(None, 0)[1] + return -mpari + + + min = minimum + max = maximum + + def LLL(self): + r""" + Return this lattice with an LLL reduced basis. + + EXAMPLES:: + + sage: L = IntegralLattice('A2') + sage: L.lll() == L + True + sage: G = matrix(ZZ,3,[0,1,0, 1,0,0, 0,0,7]) + sage: V = matrix(ZZ,3,[-14,-15,-15, -4,1,16, -5,-5,-4]) + sage: L = IntegralLattice(V*G*V.T) + sage: L.lll().gram_matrix() + [0 0 1] + [0 7 0] + [1 0 0] + """ + p, n = self.signature_pair() + if p*n != 0: + from sage.env import SAGE_EXTCODE + from sage.interfaces.gp import gp + from sage.libs.pari import pari + m = self.gram_matrix().__pari__() + gp.read(SAGE_EXTCODE + "/pari/simon/qfsolve.gp") + m = gp.eval('qflllgram_indefgoon(%s)'%m) + # convert the output string to sage + G, U = pari(m).sage() + assert G == U.T*self.gram_matrix()*U + U = U.T + else: + e = 1 + if n != 0: + e = -1 + U = (e*self.gram_matrix().change_ring(ZZ)).LLL_gram().T + return self.sublattice(U*self.basis_matrix()) + + lll = LLL + + def short_vectors(self, n, **kwargs): + r""" + Return the short vectors of length `< n`. + + INPUT: + + - ``n`` -- an integer + - further key word arguments are passed on to + :meth:`sage.quadratic_forms.short_vector_list_up_to_length`. + + OUTPUT: + + - a list `L` where ``L[k]`` is the list of vectors of lengths `k` + + EXAMPLES:: + + sage: A2 = IntegralLattice('A2') + sage: A2.short_vectors(3) + [[(0, 0)], [], [(1, 1), (-1, -1), (0, 1), (0, -1), (1, 0), (-1, 0)]] + sage: A2.short_vectors(3,up_to_sign_flag=True) + [[(0, 0)], [], [(1, 1), (0, 1), (1, 0)]] + """ + p, m = self.signature_pair() + if p*m != 0: + raise NotImplementedError("The lattice has to be positive definite.") + e = 1 + if m != 0: + e = -1 + q = QuadraticForm(e*2*self.gram_matrix()) + short = q.short_vector_list_up_to_length(n, *kwargs) + return [[self(v*self.basis_matrix()) for v in L] for L in short] + def twist(self, s, discard_basis=False): r""" Return the lattice with inner product matrix scaled by ``s``. From 2d9a84ef7965b3613129d02107d243bc7c779d80 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 6 Dec 2021 21:34:54 -0800 Subject: [PATCH 030/253] git grep -l 'misc.all import' | xargs sed -i.bak 's/misc.all import tmp_/misc.temporary_file import tmp_/' --- src/sage/combinat/designs/ext_rep.py | 2 +- src/sage/databases/sql_db.py | 2 +- src/sage/interfaces/phc.py | 2 +- src/sage/misc/citation.pyx | 2 +- src/sage/misc/persist.pyx | 2 +- src/sage/repl/ipython_extension.py | 4 ++-- src/sage/sat/solvers/dimacs.py | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/combinat/designs/ext_rep.py b/src/sage/combinat/designs/ext_rep.py index 57f3b7eb636..533d22e865d 100644 --- a/src/sage/combinat/designs/ext_rep.py +++ b/src/sage/combinat/designs/ext_rep.py @@ -42,7 +42,7 @@ from urllib.request import urlopen -from sage.misc.all import tmp_filename +from sage.misc.temporary_file import tmp_filename XML_NAMESPACE = 'http://designtheory.org/xml-namespace' diff --git a/src/sage/databases/sql_db.py b/src/sage/databases/sql_db.py index 5a14e45be94..8cbc2d0f34f 100644 --- a/src/sage/databases/sql_db.py +++ b/src/sage/databases/sql_db.py @@ -80,7 +80,7 @@ import sqlite3 as sqlite import os import re -from sage.misc.all import tmp_filename +from sage.misc.temporary_file import tmp_filename from sage.structure.sage_object import SageObject sqlite_keywords = ['ABORT','ACTION','ADD','AFTER','ALL','ALTER','ANALYZE', diff --git a/src/sage/interfaces/phc.py b/src/sage/interfaces/phc.py index bfd0806c97c..ee95eb99e19 100644 --- a/src/sage/interfaces/phc.py +++ b/src/sage/interfaces/phc.py @@ -36,7 +36,7 @@ import pexpect import random -from sage.misc.all import tmp_filename +from sage.misc.temporary_file import tmp_filename from sage.rings.real_mpfr import RR from sage.rings.all import CC from sage.rings.integer import Integer diff --git a/src/sage/misc/citation.pyx b/src/sage/misc/citation.pyx index 19231769501..0fdd53ae5ff 100644 --- a/src/sage/misc/citation.pyx +++ b/src/sage/misc/citation.pyx @@ -3,7 +3,7 @@ Dependency usage tracking for citations """ -from sage.misc.all import tmp_filename +from sage.misc.temporary_file import tmp_filename from sage.env import SAGE_LOCAL, SAGE_VENV systems = {} diff --git a/src/sage/misc/persist.pyx b/src/sage/misc/persist.pyx index 2a3a61fdce0..1f5aee9762d 100644 --- a/src/sage/misc/persist.pyx +++ b/src/sage/misc/persist.pyx @@ -1111,7 +1111,7 @@ def unpickle_all(dir, debug=False, run_test_suite=False): # This could use instead Python's tarfile module if dir.endswith('.tar.bz2'): # create a temporary directory - from sage.misc.all import tmp_dir + from sage.misc.temporary_file import tmp_dir T = tmp_dir() # extract tarball to it os.system('cd "%s"; bunzip2 -c "%s" | tar fx - '%(T, os.path.abspath(dir))) diff --git a/src/sage/repl/ipython_extension.py b/src/sage/repl/ipython_extension.py index ded5cdbde78..0898c5334e0 100644 --- a/src/sage/repl/ipython_extension.py +++ b/src/sage/repl/ipython_extension.py @@ -35,7 +35,7 @@ sage: import os, re sage: from sage.repl.interpreter import get_test_shell - sage: from sage.misc.all import tmp_dir + sage: from sage.misc.temporary_file import tmp_dir sage: shell = get_test_shell() sage: TMP = tmp_dir() @@ -106,7 +106,7 @@ def runfile(self, s): sage: import os sage: from sage.repl.interpreter import get_test_shell - sage: from sage.misc.all import tmp_dir + sage: from sage.misc.temporary_file import tmp_dir sage: shell = get_test_shell() sage: tmp = os.path.join(tmp_dir(), 'run_cell.py') sage: with open(tmp, 'w') as f: diff --git a/src/sage/sat/solvers/dimacs.py b/src/sage/sat/solvers/dimacs.py index abc94569f59..7fb9ef7c667 100644 --- a/src/sage/sat/solvers/dimacs.py +++ b/src/sage/sat/solvers/dimacs.py @@ -32,7 +32,7 @@ import shlex from sage.sat.solvers.satsolver import SatSolver -from sage.misc.all import tmp_filename +from sage.misc.temporary_file import tmp_filename from time import sleep From 5a8d76e2a504501dbbea1dd2e1feb34c413e1e7d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 6 Dec 2021 21:45:17 -0800 Subject: [PATCH 031/253] Remove imports from sage.misc.all --- src/sage/combinat/binary_tree.py | 1 - src/sage/combinat/root_system/pieri_factors.py | 5 +++-- src/sage/lfunctions/dokchitser.py | 6 ++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/binary_tree.py b/src/sage/combinat/binary_tree.py index 01a1b0bdc13..5c89e138742 100644 --- a/src/sage/combinat/binary_tree.py +++ b/src/sage/combinat/binary_tree.py @@ -1916,7 +1916,6 @@ def canopee(self): Here is a less trivial implementation of this:: sage: from sage.sets.finite_set_map_cy import fibers - sage: from sage.misc.all import attrcall sage: def baxter(n): ....: f = fibers(lambda t: tuple(t.canopee()), ....: BinaryTrees(n)) diff --git a/src/sage/combinat/root_system/pieri_factors.py b/src/sage/combinat/root_system/pieri_factors.py index e9befac2eb3..c2e098af316 100644 --- a/src/sage/combinat/root_system/pieri_factors.py +++ b/src/sage/combinat/root_system/pieri_factors.py @@ -12,14 +12,15 @@ from sage.misc.cachefunc import cached_method from sage.misc.constant_function import ConstantFunction -from sage.misc.all import prod, attrcall +from sage.misc.call import attrcall +from sage.misc.misc_c import prod from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.rings.integer import Integer from sage.rings.rational_field import QQ from sage.rings.infinity import infinity -from sage.arith.all import binomial +from sage.arith.misc import binomial import sage.combinat.ranker from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet from sage.combinat.root_system.root_system import RootSystem diff --git a/src/sage/lfunctions/dokchitser.py b/src/sage/lfunctions/dokchitser.py index d7dadb7343e..8d0b85e22c8 100644 --- a/src/sage/lfunctions/dokchitser.py +++ b/src/sage/lfunctions/dokchitser.py @@ -32,8 +32,10 @@ import string from sage.structure.sage_object import SageObject -from sage.rings.all import ComplexField, Integer -from sage.misc.all import sage_eval, SAGE_TMP +from sage.rings.all import ComplexField +from sage.rings.integer import Integer +from sage.misc.sage_eval import sage_eval +from sage.misc.misc import SAGE_TMP from sage.misc.verbose import verbose import sage.interfaces.gp from sage.env import SAGE_EXTCODE From 97b4dfde64984e1276fb563a2ee7b4f6d85962f8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 6 Dec 2021 21:46:30 -0800 Subject: [PATCH 032/253] git grep -l 'misc.all import' | xargs sed -i.bak 's/misc.all import sage_eval/misc.sage_eval import sage_eval/' --- src/sage/modular/buzzard.py | 2 +- src/sage/rings/cfinite_sequence.py | 2 +- src/sage/symbolic/units.py | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/modular/buzzard.py b/src/sage/modular/buzzard.py index c83f4dcaca6..194988cf207 100644 --- a/src/sage/modular/buzzard.py +++ b/src/sage/modular/buzzard.py @@ -19,7 +19,7 @@ ############################################################################# from sage.interfaces.gp import Gp -from sage.misc.all import sage_eval +from sage.misc.sage_eval import sage_eval _gp = None diff --git a/src/sage/rings/cfinite_sequence.py b/src/sage/rings/cfinite_sequence.py index b73764ce5d2..68b0cd183e7 100644 --- a/src/sage/rings/cfinite_sequence.py +++ b/src/sage/rings/cfinite_sequence.py @@ -103,7 +103,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.interfaces.gp import Gp -from sage.misc.all import sage_eval +from sage.misc.sage_eval import sage_eval _gp = None diff --git a/src/sage/symbolic/units.py b/src/sage/symbolic/units.py index 86db0b94ce4..c5259354d9a 100644 --- a/src/sage/symbolic/units.py +++ b/src/sage/symbolic/units.py @@ -497,7 +497,7 @@ def evalunitdict(): sage: sage.symbolic.units.evalunitdict() """ - from sage.misc.all import sage_eval + from sage.misc.sage_eval import sage_eval for key, value in unitdict.items(): unitdict[key] = dict([(a,sage_eval(repr(b))) for a, b in value.items()]) @@ -978,7 +978,7 @@ def unit_derivations_expr(v): Z = unit_derivations[v] if isinstance(Z,str): d = dict([(x,str_to_unit(x)) for x in vars_in_str(Z)]) - from sage.misc.all import sage_eval + from sage.misc.sage_eval import sage_eval Z = sage_eval(Z, d) unit_derivations[v] = Z return Z @@ -1387,7 +1387,7 @@ def base_units(unit): sage: sage.symbolic.units.base_units(var('x')) x """ - from sage.misc.all import sage_eval + from sage.misc.sage_eval import sage_eval if str(unit) not in unit_to_type: return unit elif unit_to_type[str(unit)] == 'si_prefixes' or unit_to_type[str(unit)] == 'unit_multipliers': @@ -1451,7 +1451,7 @@ def convert_temperature(expr, target): if len(expr.variables()) != 1: raise ValueError("Cannot convert") elif target is None or unit_to_type[str(target)] == 'temperature': - from sage.misc.all import sage_eval + from sage.misc.sage_eval import sage_eval expr_temp = expr.variables()[0] coeff = expr/expr_temp if target is not None: From e72dc8e8e260c713156391245db33ce99cfda52d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 6 Dec 2021 22:08:14 -0800 Subject: [PATCH 033/253] Remove more imports from sage.misc.all --- src/sage/numerical/interactive_simplex_method.py | 9 +++------ src/sage/quadratic_forms/genera/genus.py | 3 ++- src/sage/rings/polynomial/cyclotomic.pyx | 3 ++- .../rings/polynomial/multi_polynomial_libsingular.pyx | 2 +- src/sage/rings/polynomial/real_roots.pyx | 3 ++- src/sage/schemes/affine/affine_space.py | 4 ++-- src/sage/schemes/elliptic_curves/ell_tate_curve.py | 3 ++- .../schemes/projective/projective_rational_point.py | 3 ++- src/sage/schemes/projective/projective_space.py | 10 +++++----- src/sage/schemes/toric/divisor.py | 5 ++++- src/sage/schemes/toric/fano_variety.py | 3 ++- src/sage/schemes/toric/variety.py | 8 ++++++-- 12 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/sage/numerical/interactive_simplex_method.py b/src/sage/numerical/interactive_simplex_method.py index 4386e6f2e9e..de70f49839c 100644 --- a/src/sage/numerical/interactive_simplex_method.py +++ b/src/sage/numerical/interactive_simplex_method.py @@ -187,12 +187,9 @@ identity_matrix, matrix, random_matrix) -from sage.misc.all import (LatexExpr, - cached_function, - cached_method, - latex, - randint, - random) +from sage.misc.latex import LatexExpr, latex +from sage.misc.cachefunc import cached_function, cached_method +from sage.misc.prandom import randint, random from sage.misc.html import HtmlFragment from sage.misc.misc import get_main_globals from sage.modules.all import random_vector, vector diff --git a/src/sage/quadratic_forms/genera/genus.py b/src/sage/quadratic_forms/genera/genus.py index 3e9b04a936c..8abec816845 100644 --- a/src/sage/quadratic_forms/genera/genus.py +++ b/src/sage/quadratic_forms/genera/genus.py @@ -20,7 +20,8 @@ # **************************************************************************** from sage.misc.lazy_import import lazy_import -from sage.misc.all import prod, cached_method +from sage.misc.misc_c import prod +from sage.misc.cachefunc import cached_method from sage.arith.all import LCM, fundamental_discriminant from sage.matrix.matrix_space import MatrixSpace from sage.matrix.constructor import matrix diff --git a/src/sage/rings/polynomial/cyclotomic.pyx b/src/sage/rings/polynomial/cyclotomic.pyx index f9bd920b231..f868b9f2a31 100644 --- a/src/sage/rings/polynomial/cyclotomic.pyx +++ b/src/sage/rings/polynomial/cyclotomic.pyx @@ -34,7 +34,8 @@ from sage.structure.element cimport parent from sage.arith.all import factor from sage.rings.integer_ring import ZZ -from sage.misc.all import prod, subsets +from sage.misc.misc_c import prod +from sage.misc.misc import subsets from sage.rings.integer cimport Integer from sage.rings.rational cimport Rational from sage.libs.pari.all import pari diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index 5d34e62d04c..49e6bf448a9 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -247,7 +247,7 @@ from sage.interfaces.all import macaulay2 from sage.interfaces.singular import singular as singular_default, is_SingularElement, SingularElement from sage.interfaces.macaulay2 import macaulay2 as macaulay2_default, is_Macaulay2Element -from sage.misc.all import prod as mul +from sage.misc.misc_c import prod as mul from sage.misc.sage_eval import sage_eval diff --git a/src/sage/rings/polynomial/real_roots.pyx b/src/sage/rings/polynomial/real_roots.pyx index ccebbfba87f..e394d1601fe 100644 --- a/src/sage/rings/polynomial/real_roots.pyx +++ b/src/sage/rings/polynomial/real_roots.pyx @@ -144,7 +144,8 @@ from sage.modules.all import vector, FreeModule from sage.matrix.all import MatrixSpace from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.polynomial_ring import polygen -from sage.misc.all import numerator, denominator, prod +from sage.misc.functional import numerator, denominator +from sage.misc.misc_c import prod from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense from sage.modules.vector_integer_dense cimport Vector_integer_dense diff --git a/src/sage/schemes/affine/affine_space.py b/src/sage/schemes/affine/affine_space.py index 9562cdcf785..b2505942726 100644 --- a/src/sage/schemes/affine/affine_space.py +++ b/src/sage/schemes/affine/affine_space.py @@ -20,8 +20,8 @@ from sage.categories.fields import Fields _Fields = Fields() from sage.categories.number_fields import NumberFields -from sage.misc.all import (latex, - cartesian_product_iterator) +from sage.misc.latex import latex +from sage.misc.all import cartesian_product_iterator from sage.structure.category_object import normalize_names from sage.schemes.generic.scheme import AffineScheme from sage.schemes.generic.ambient_space import AmbientSpace diff --git a/src/sage/schemes/elliptic_curves/ell_tate_curve.py b/src/sage/schemes/elliptic_curves/ell_tate_curve.py index 533078f0808..53deed90f4f 100644 --- a/src/sage/schemes/elliptic_curves/ell_tate_curve.py +++ b/src/sage/schemes/elliptic_curves/ell_tate_curve.py @@ -51,7 +51,8 @@ from sage.modular.modform.constructor import EisensteinForms, CuspForms from sage.schemes.elliptic_curves.constructor import EllipticCurve from sage.functions.log import log -from sage.misc.all import denominator, prod +from sage.misc.functional import denominator +from sage.misc.misc_c import prod import sage.matrix.all as matrix diff --git a/src/sage/schemes/projective/projective_rational_point.py b/src/sage/schemes/projective/projective_rational_point.py index 6196eaa1021..f050d3764cb 100644 --- a/src/sage/schemes/projective/projective_rational_point.py +++ b/src/sage/schemes/projective/projective_rational_point.py @@ -59,7 +59,8 @@ 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.misc.all import cartesian_product_iterator, prod +from sage.misc.all import cartesian_product_iterator +from sage.misc.misc_c import prod from sage.misc.mrange import xmrange from sage.schemes.generic.scheme import is_Scheme from sage.parallel.ncpus import ncpus diff --git a/src/sage/schemes/projective/projective_space.py b/src/sage/schemes/projective/projective_space.py index 82763ef7344..78ef9e560bf 100644 --- a/src/sage/schemes/projective/projective_space.py +++ b/src/sage/schemes/projective/projective_space.py @@ -80,9 +80,9 @@ # **************************************************************************** from sage.arith.all import gcd, binomial, srange -from sage.rings.all import (PolynomialRing, - Integer, - ZZ) +from sage.rings.all import PolynomialRing +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ from sage.rings.ring import CommutativeRing from sage.rings.rational_field import is_RationalField @@ -94,8 +94,8 @@ from sage.categories.number_fields import NumberFields from sage.categories.homset import Hom from sage.categories.map import Map -from sage.misc.all import (latex, - prod) +from sage.misc.latex import latex +from sage.misc.misc_c import prod from sage.misc.all import cartesian_product_iterator from sage.misc.persist import register_unpickle_override diff --git a/src/sage/schemes/toric/divisor.py b/src/sage/schemes/toric/divisor.py index e5cd6cb05bd..16979be716c 100644 --- a/src/sage/schemes/toric/divisor.py +++ b/src/sage/schemes/toric/divisor.py @@ -172,7 +172,10 @@ from sage.geometry.toric_lattice_element import is_ToricLatticeElement from sage.topology.simplicial_complex import SimplicialComplex from sage.matrix.constructor import matrix -from sage.misc.all import cached_method, flatten, latex, prod +from sage.misc.cachefunc import cached_method +from sage.misc.flatten import flatten +from sage.misc.latex import latex +from sage.misc.misc_c import prod from sage.modules.free_module_element import vector from sage.modules.free_module import (FreeModule_ambient_field, FreeModule_ambient_pid) diff --git a/src/sage/schemes/toric/fano_variety.py b/src/sage/schemes/toric/fano_variety.py index 8935197298d..f35747ee5d3 100644 --- a/src/sage/schemes/toric/fano_variety.py +++ b/src/sage/schemes/toric/fano_variety.py @@ -136,7 +136,8 @@ import re from sage.geometry.all import Cone, FaceFan, Fan, LatticePolytope -from sage.misc.all import latex, prod +from sage.misc.latex import latex +from sage.misc.misc_c import prod from sage.rings.all import (PolynomialRing, QQ) from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing diff --git a/src/sage/schemes/toric/variety.py b/src/sage/schemes/toric/variety.py index 6286947d1f6..e9449737c6f 100644 --- a/src/sage/schemes/toric/variety.py +++ b/src/sage/schemes/toric/variety.py @@ -322,10 +322,14 @@ import sage.geometry.abc from sage.geometry.cone import Cone from sage.geometry.fan import Fan -from sage.misc.all import latex, prod, cached_method +from sage.misc.latex import latex +from sage.misc.misc_c import prod +from sage.misc.cachefunc import cached_method from sage.structure.unique_representation import UniqueRepresentation from sage.modules.free_module_element import vector -from sage.rings.all import PolynomialRing, ZZ, QQ +from sage.rings.all import PolynomialRing +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.rings.quotient_ring_element import QuotientRingElement from sage.rings.quotient_ring import QuotientRing_generic from sage.schemes.affine.affine_space import AffineSpace From d114096429564f6b8b821e16a6ffc4af97850657 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 6 Dec 2021 22:09:32 -0800 Subject: [PATCH 034/253] git grep -l 'misc.all import' | xargs sed -i.bak 's/misc.all import cartesian_product_iterator/misc.mrange import cartesian_product_iterator/' --- src/sage/rings/number_field/number_field.py | 2 +- src/sage/schemes/affine/affine_rational_point.py | 2 +- src/sage/schemes/affine/affine_space.py | 2 +- src/sage/schemes/elliptic_curves/ell_rational_field.py | 2 +- src/sage/schemes/elliptic_curves/height.py | 2 +- src/sage/schemes/projective/projective_rational_point.py | 2 +- src/sage/schemes/projective/projective_space.py | 2 +- src/sage/symbolic/relation.py | 4 ++-- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 561c575b0a6..1de13904dc7 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -5100,7 +5100,7 @@ def selmer_group_iterator(self, S, m, proof=True): """ KSgens, ords = self.selmer_generators(S=S, m=m, proof=proof, orders=True) one = self.one() - from sage.misc.all import cartesian_product_iterator + from sage.misc.mrange import cartesian_product_iterator for ev in cartesian_product_iterator([range(o) for o in ords]): yield prod([p ** e for p, e in zip(KSgens, ev)], one) diff --git a/src/sage/schemes/affine/affine_rational_point.py b/src/sage/schemes/affine/affine_rational_point.py index 513b5d67aa0..73a4c7d0ba6 100644 --- a/src/sage/schemes/affine/affine_rational_point.py +++ b/src/sage/schemes/affine/affine_rational_point.py @@ -53,7 +53,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.misc.all import cartesian_product_iterator +from sage.misc.mrange import cartesian_product_iterator from sage.schemes.generic.scheme import is_Scheme diff --git a/src/sage/schemes/affine/affine_space.py b/src/sage/schemes/affine/affine_space.py index b2505942726..f0654de0eb9 100644 --- a/src/sage/schemes/affine/affine_space.py +++ b/src/sage/schemes/affine/affine_space.py @@ -21,7 +21,7 @@ _Fields = Fields() from sage.categories.number_fields import NumberFields from sage.misc.latex import latex -from sage.misc.all import cartesian_product_iterator +from sage.misc.mrange import cartesian_product_iterator from sage.structure.category_object import normalize_names from sage.schemes.generic.scheme import AffineScheme from sage.schemes.generic.ambient_space import AmbientSpace diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index b0b674a0bde..221b4262344 100644 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -6579,7 +6579,7 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): return set(xs) #<------------------------------------------------------------------------- #End internal functions ############################################### - from sage.misc.all import cartesian_product_iterator + from sage.misc.mrange import cartesian_product_iterator E = self tors_points = E.torsion_points() diff --git a/src/sage/schemes/elliptic_curves/height.py b/src/sage/schemes/elliptic_curves/height.py index de9cbc670de..a4cdd111a95 100644 --- a/src/sage/schemes/elliptic_curves/height.py +++ b/src/sage/schemes/elliptic_curves/height.py @@ -36,7 +36,7 @@ from sage.rings.all import RR, RDF, RIF, CC, CDF, CIF from sage.misc.cachefunc import cached_method -from sage.misc.all import cartesian_product_iterator +from sage.misc.mrange import cartesian_product_iterator from sage.arith.all import lcm, factorial from sage.ext.fast_callable import fast_callable from sage.functions.log import log, exp diff --git a/src/sage/schemes/projective/projective_rational_point.py b/src/sage/schemes/projective/projective_rational_point.py index f050d3764cb..bc0b33e8dfb 100644 --- a/src/sage/schemes/projective/projective_rational_point.py +++ b/src/sage/schemes/projective/projective_rational_point.py @@ -59,7 +59,7 @@ 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.misc.all import cartesian_product_iterator +from sage.misc.mrange import cartesian_product_iterator from sage.misc.misc_c import prod from sage.misc.mrange import xmrange from sage.schemes.generic.scheme import is_Scheme diff --git a/src/sage/schemes/projective/projective_space.py b/src/sage/schemes/projective/projective_space.py index 78ef9e560bf..2da42665500 100644 --- a/src/sage/schemes/projective/projective_space.py +++ b/src/sage/schemes/projective/projective_space.py @@ -96,7 +96,7 @@ from sage.categories.map import Map from sage.misc.latex import latex from sage.misc.misc_c import prod -from sage.misc.all import cartesian_product_iterator +from sage.misc.mrange import cartesian_product_iterator from sage.misc.persist import register_unpickle_override from sage.structure.category_object import normalize_names diff --git a/src/sage/symbolic/relation.py b/src/sage/symbolic/relation.py index e07e50feea1..4801c05856e 100644 --- a/src/sage/symbolic/relation.py +++ b/src/sage/symbolic/relation.py @@ -1570,7 +1570,7 @@ def solve_mod(eqns, modulus, solution_dict=False): """ from sage.rings.all import Integer, Integers, crt_basis from sage.structure.element import Expression - from sage.misc.all import cartesian_product_iterator + from sage.misc.mrange import cartesian_product_iterator from sage.modules.free_module_element import vector from sage.matrix.constructor import matrix @@ -1686,7 +1686,7 @@ def _solve_mod_prime_power(eqns, p, m, vars): """ from sage.rings.all import Integers, PolynomialRing from sage.modules.free_module_element import vector - from sage.misc.all import cartesian_product_iterator + from sage.misc.mrange import cartesian_product_iterator mrunning = 1 ans = [] From 1ab9441f6023a5b6d20af6ab7150e66345b13816 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 6 Dec 2021 22:43:48 -0800 Subject: [PATCH 035/253] Remove remaining imports from sage.misc.all --- src/sage/databases/cremona.py | 2 +- src/sage/interfaces/gnuplot.py | 2 +- src/sage/lfunctions/lcalc.py | 2 +- src/sage/lfunctions/sympow.py | 2 +- src/sage/modular/modform/half_integral.py | 2 +- src/sage/numerical/backends/glpk_backend.pyx | 2 +- src/sage/rings/padics/relaxed_template.pxi | 2 +- src/sage/sandpiles/sandpile.py | 13 ++++++++++--- src/sage/schemes/curves/affine_curve.py | 2 +- src/sage/schemes/curves/projective_curve.py | 6 ++++-- .../schemes/elliptic_curves/ell_curve_isogeny.py | 2 +- src/sage/schemes/elliptic_curves/ell_egros.py | 2 +- src/sage/schemes/elliptic_curves/isogeny_class.py | 3 ++- src/sage/schemes/elliptic_curves/padic_lseries.py | 9 ++++----- src/sage/schemes/toric/chow_group.py | 6 ++++-- src/sage/symbolic/expression.pyx | 2 +- 16 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/sage/databases/cremona.py b/src/sage/databases/cremona.py index 8440a4811b1..6353ad7bbfe 100644 --- a/src/sage/databases/cremona.py +++ b/src/sage/databases/cremona.py @@ -51,7 +51,7 @@ import sage.schemes.elliptic_curves.constructor as elliptic from .sql_db import SQLDatabase, verify_column from sage.features.databases import DatabaseCremona -from sage.misc.all import walltime +from sage.misc.misc import walltime import re import string diff --git a/src/sage/interfaces/gnuplot.py b/src/sage/interfaces/gnuplot.py index b57967f433e..1757e616170 100644 --- a/src/sage/interfaces/gnuplot.py +++ b/src/sage/interfaces/gnuplot.py @@ -179,7 +179,7 @@ def plot3d_parametric(self, f='cos(u)*(3 + v*cos(u/2)), sin(u)*(3 + v*cos(u/2)), self(cmd) def interact(self, cmd): - from sage.misc.all import SAGE_TMP + from sage.misc.misc import SAGE_TMP file = os.path.join(SAGE_TMP, 'gnuplot') with open(file, 'w') as f: f.write(cmd + '\n pause -1 "Press return to continue (no further rotation possible)"') diff --git a/src/sage/lfunctions/lcalc.py b/src/sage/lfunctions/lcalc.py index aabbd47636f..939cfbbca72 100644 --- a/src/sage/lfunctions/lcalc.py +++ b/src/sage/lfunctions/lcalc.py @@ -30,7 +30,7 @@ import os from sage.structure.sage_object import SageObject -from sage.misc.all import pager +from sage.misc.pager import pager import sage.rings.all import sage.schemes.elliptic_curves.ell_generic diff --git a/src/sage/lfunctions/sympow.py b/src/sage/lfunctions/sympow.py index 7ba8b19df54..7af1940f62b 100644 --- a/src/sage/lfunctions/sympow.py +++ b/src/sage/lfunctions/sympow.py @@ -49,7 +49,7 @@ import os from sage.structure.sage_object import SageObject -from sage.misc.all import pager +from sage.misc.pager import pager from sage.misc.verbose import verbose import sage.rings.all diff --git a/src/sage/modular/modform/half_integral.py b/src/sage/modular/modform/half_integral.py index 0e945a0c4ef..94587840566 100644 --- a/src/sage/modular/modform/half_integral.py +++ b/src/sage/modular/modform/half_integral.py @@ -128,7 +128,7 @@ def half_integral_weight_modform_basis(chi, k, prec): B = C.basis() # This computation of S below -- of course --dominates the whole function. - #from sage.misc.all import cputime + #from sage.misc.misc import cputime #tm = cputime() #print "Computing basis..." S = [f.q_expansion(prec) for f in B] diff --git a/src/sage/numerical/backends/glpk_backend.pyx b/src/sage/numerical/backends/glpk_backend.pyx index 3a60b981b43..d93d90e97c8 100644 --- a/src/sage/numerical/backends/glpk_backend.pyx +++ b/src/sage/numerical/backends/glpk_backend.pyx @@ -2497,7 +2497,7 @@ cdef class GLPKBackend(GenericBackend): End of report """ - from sage.misc.all import SAGE_TMP + from sage.misc.misc import SAGE_TMP if filename is None: fname = SAGE_TMP + "/ranges.tmp" diff --git a/src/sage/rings/padics/relaxed_template.pxi b/src/sage/rings/padics/relaxed_template.pxi index 6c155e1c8a3..d9425c88682 100644 --- a/src/sage/rings/padics/relaxed_template.pxi +++ b/src/sage/rings/padics/relaxed_template.pxi @@ -2001,7 +2001,7 @@ cdef class RelaxedElement(pAdicGenericElement): :func:`dumps`, :func:`loads` """ tester = self._tester(**options) - from sage.misc.all import loads, dumps + from sage.misc.persist import loads, dumps if self._precbound >= maxordp: tester.assertEqual(loads(dumps(self)), self.at_precision_relative()) else: diff --git a/src/sage/sandpiles/sandpile.py b/src/sage/sandpiles/sandpile.py index f29d7395d7f..3776fc999b3 100644 --- a/src/sage/sandpiles/sandpile.py +++ b/src/sage/sandpiles/sandpile.py @@ -336,12 +336,19 @@ from sage.topology.simplicial_complex import SimplicialComplex from sage.interfaces.singular import singular from sage.matrix.constructor import matrix, identity_matrix -from sage.misc.all import prod, det, tmp_filename, exists, denominator +from sage.misc.functional import det, denominator +from sage.misc.misc import exists +from sage.misc.misc_c import prod +from sage.misc.temporary_file import tmp_filename from sage.arith.srange import xsrange from sage.modules.free_module_element import vector from sage.plot.colors import rainbow -from sage.arith.all import falling_factorial, lcm -from sage.rings.all import Integer, PolynomialRing, QQ, ZZ +from sage.arith.functions import lcm +from sage.arith.misc import falling_factorial +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.rational_field import QQ from sage.symbolic.constants import I, pi from sage.symbolic.ring import SR from sage.features.four_ti_2 import FourTi2Executable diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index 23312f06ed6..a0fdd7e0000 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -128,7 +128,7 @@ from sage.arith.misc import binomial from sage.interfaces.all import singular -from sage.misc.all import add +from builtins import sum as add from sage.categories.fields import Fields from sage.categories.finite_fields import FiniteFields diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 068ffb73146..79929177759 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -146,9 +146,11 @@ from sage.interfaces.all import singular from sage.matrix.constructor import matrix -from sage.misc.all import add, sage_eval +from builtins import sum as add +from sage.misc.sage_eval import sage_eval -from sage.rings.all import degree_lowest_rational_function, IntegerRing +from sage.rings.all import degree_lowest_rational_function +from sage.rings.integer_ring import IntegerRing from sage.rings.number_field.number_field import NumberField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.qqbar import (number_field_elements_from_algebraics, diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index 9783877f153..da10953408d 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -1860,7 +1860,7 @@ def __init_from_kernel_list(self, kernel_gens): # but it won't speed things up too much. kernel_set = Set([self.__E1(0)]) - from sage.misc.all import flatten + from sage.misc.flatten import flatten def all_multiples(itr, terminal): mult_list = [terminal] diff --git a/src/sage/schemes/elliptic_curves/ell_egros.py b/src/sage/schemes/elliptic_curves/ell_egros.py index bc782475f2e..d487235ab35 100644 --- a/src/sage/schemes/elliptic_curves/ell_egros.py +++ b/src/sage/schemes/elliptic_curves/ell_egros.py @@ -89,7 +89,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.misc.all import xmrange +from sage.misc.mrange import xmrange from sage.rings.rational_field import QQ from .constructor import EllipticCurve, EllipticCurve_from_j diff --git a/src/sage/schemes/elliptic_curves/isogeny_class.py b/src/sage/schemes/elliptic_curves/isogeny_class.py index 440792d5615..f137e39eb6c 100644 --- a/src/sage/schemes/elliptic_curves/isogeny_class.py +++ b/src/sage/schemes/elliptic_curves/isogeny_class.py @@ -30,7 +30,8 @@ import sage.databases.cremona from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.misc.all import flatten, cached_method +from sage.misc.flatten import flatten +from sage.misc.cachefunc import cached_method from sage.schemes.elliptic_curves.ell_field import EllipticCurve_field from sage.schemes.elliptic_curves.ell_number_field import EllipticCurve_number_field diff --git a/src/sage/schemes/elliptic_curves/padic_lseries.py b/src/sage/schemes/elliptic_curves/padic_lseries.py index d462d6c7151..4ee2bddbb17 100644 --- a/src/sage/schemes/elliptic_curves/padic_lseries.py +++ b/src/sage/schemes/elliptic_curves/padic_lseries.py @@ -68,14 +68,13 @@ from sage.rings.all import LaurentSeriesRing, PowerSeriesRing, PolynomialRing, Integers from sage.rings.integer import Integer -from sage.arith.all import valuation, binomial, kronecker_symbol, gcd, prime_divisors +from sage.arith.all import valuation, binomial, kronecker_symbol, gcd, prime_divisors, LCM from sage.structure.sage_object import SageObject from sage.structure.richcmp import richcmp_method, richcmp -from sage.misc.all import denominator +from sage.misc.functional import denominator from sage.misc.verbose import verbose, get_verbose -import sage.arith.all as arith from sage.modules.free_module_element import vector import sage.matrix.all as matrix @@ -1671,8 +1670,8 @@ def Dp_valued_height(self,prec=20): elog = Ehat.log(prec + Integer(3)) # we will have to do it properly with David Harvey's _multiply_point() - n = arith.LCM(E.tamagawa_numbers()) - n = arith.LCM(n, E.Np(p)) # allowed here because E has good reduction at p + n = LCM(E.tamagawa_numbers()) + n = LCM(n, E.Np(p)) # allowed here because E has good reduction at p def height(P,check=True): if P.is_finite_order(): diff --git a/src/sage/schemes/toric/chow_group.py b/src/sage/schemes/toric/chow_group.py index ea00dd42dd8..dde1ac5f600 100644 --- a/src/sage/schemes/toric/chow_group.py +++ b/src/sage/schemes/toric/chow_group.py @@ -119,14 +119,16 @@ # **************************************************************************** from __future__ import annotations -from sage.misc.all import flatten +from sage.misc.flatten import flatten from sage.misc.fast_methods import WithEqualityById from sage.modules.fg_pid.fgp_module import FGP_Module_class from sage.modules.fg_pid.fgp_element import FGP_Element from sage.modules.free_module import FreeModule from sage.structure.sage_object import SageObject from sage.structure.factory import UniqueFactory -from sage.rings.all import ZZ, QQ, Infinity +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.infinity import Infinity import sage.geometry.abc from sage.schemes.toric.variety import is_ToricVariety diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 843cfee7f4c..cb9a2e755e2 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -1467,7 +1467,7 @@ cdef class Expression(Expression_abc): MATHML version of the string pi + 2 """ - from sage.misc.all import mathml + from sage.misc.mathml import mathml try: obj = self.pyobject() except TypeError: From 1bab7ab183d30bf0db7ce0b6a9059fb713a8baa2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 8 Dec 2021 20:33:58 -0800 Subject: [PATCH 036/253] git grep -l 'libs[.]all import' | xargs sed -i.bak '/[Pp]ari/s/from sage.libs.all import/from sage.libs.pari.all import/' --- src/sage/combinat/combinat.py | 2 +- src/sage/combinat/partition.py | 2 +- src/sage/functions/special.py | 2 +- src/sage/modular/btquotients/btquotient.py | 2 +- .../polynomial/padics/polynomial_padic_capped_relative_dense.py | 2 +- src/sage/rings/polynomial/padics/polynomial_padic_flat.py | 2 +- src/sage/rings/polynomial/polynomial_element.pyx | 2 +- src/sage/rings/polynomial/polynomial_gf2x.pyx | 2 +- src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx | 2 +- src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx | 2 +- src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx | 2 +- src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx | 2 +- src/sage/rings/polynomial/polynomial_template.pxi | 2 +- src/sage/rings/polynomial/polynomial_zz_pex.pyx | 2 +- src/sage/rings/power_series_mpoly.pyx | 2 +- src/sage/rings/power_series_poly.pyx | 2 +- src/sage/schemes/elliptic_curves/period_lattice.py | 2 +- .../schemes/hyperelliptic_curves/hyperelliptic_finite_field.py | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index 8b24bf73aea..a533a3c952a 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -158,7 +158,7 @@ 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.libs.pari.all import pari from sage.misc.prandom import randint from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_function diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index c85dcf8b4d9..01308aa2a61 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -283,7 +283,7 @@ from copy import copy from itertools import accumulate -from sage.libs.all import pari +from sage.libs.pari.all import pari from sage.libs.flint.arith import number_of_partitions as flint_number_of_partitions from sage.arith.misc import multinomial diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index e507844219e..0d19deaeaa1 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -371,7 +371,7 @@ def elliptic_j(z, prec=53): z = CC(z) except ValueError: raise ValueError("elliptic_j only defined for complex arguments.") - from sage.libs.all import pari + from sage.libs.pari.all import pari return CC(pari(z).ellj()) #### elliptic integrals diff --git a/src/sage/modular/btquotients/btquotient.py b/src/sage/modular/btquotients/btquotient.py index 75ee74a49f0..19ff44d9ce8 100644 --- a/src/sage/modular/btquotients/btquotient.py +++ b/src/sage/modular/btquotients/btquotient.py @@ -57,7 +57,7 @@ from sage.algebras.quatalg.all import QuaternionAlgebra from sage.quadratic_forms.all import QuadraticForm from sage.graphs.all import Graph -from sage.libs.all import pari +from sage.libs.pari.all import pari from sage.interfaces.all import magma from sage.plot.colors import rainbow from sage.rings.number_field.all import NumberField 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 1fcfa993bca..6eac70126dc 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 @@ -20,7 +20,7 @@ import sage.rings.fraction_field_element as fraction_field_element import copy -from sage.libs.all import pari, pari_gen +from sage.libs.pari.all import pari, pari_gen from sage.libs.ntl.all import ZZX from sage.rings.infinity import infinity diff --git a/src/sage/rings/polynomial/padics/polynomial_padic_flat.py b/src/sage/rings/polynomial/padics/polynomial_padic_flat.py index ee106a1e09a..dc52258a268 100644 --- a/src/sage/rings/polynomial/padics/polynomial_padic_flat.py +++ b/src/sage/rings/polynomial/padics/polynomial_padic_flat.py @@ -11,7 +11,7 @@ from sage.rings.polynomial.polynomial_element import Polynomial_generic_dense, Polynomial from sage.rings.polynomial.padics.polynomial_padic import Polynomial_padic from sage.rings.infinity import infinity -from sage.libs.all import pari_gen +from sage.libs.pari.all import pari_gen import sage.rings.padics.misc diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 2edc2ab54ad..8f1604d9288 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -82,7 +82,7 @@ from sage.structure.richcmp cimport (richcmp, richcmp_item, rich_to_bool, rich_to_bool_sgn) from sage.interfaces.singular import singular as singular_default, is_SingularElement -from sage.libs.all import pari, pari_gen, PariError +from sage.libs.pari.all import pari, pari_gen, PariError cimport sage.rings.abc from sage.rings.real_mpfr import RealField, RR diff --git a/src/sage/rings/polynomial/polynomial_gf2x.pyx b/src/sage/rings/polynomial/polynomial_gf2x.pyx index 8149a3ba6e5..359d8a13539 100644 --- a/src/sage/rings/polynomial/polynomial_gf2x.pyx +++ b/src/sage/rings/polynomial/polynomial_gf2x.pyx @@ -26,7 +26,7 @@ include "sage/libs/ntl/ntl_GF2X_linkage.pxi" # and then the interface include "polynomial_template.pxi" -from sage.libs.all import pari +from sage.libs.pari.all import pari from sage.libs.m4ri cimport mzd_write_bit, mzd_read_bit from sage.matrix.matrix_mod2_dense cimport Matrix_mod2_dense diff --git a/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx b/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx index 75f61f37a46..2739582f5c5 100644 --- a/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx @@ -55,7 +55,7 @@ from sage.libs.ntl.ntl_ZZX cimport ntl_ZZX from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.libs.all import pari, pari_gen +from sage.libs.pari.all import pari, pari_gen from sage.structure.factorization import Factorization from sage.rings.fraction_field_element import FractionFieldElement diff --git a/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx b/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx index 160899b6d64..dd4e3eeaf22 100644 --- a/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx +++ b/src/sage/rings/polynomial/polynomial_integer_dense_ntl.pyx @@ -62,7 +62,7 @@ from sage.rings.integer cimport Integer from sage.rings.real_mpfr cimport RealNumber, RealField_class from sage.rings.real_mpfi cimport RealIntervalFieldElement -from sage.libs.all import pari, pari_gen +from sage.libs.pari.all import pari, pari_gen from sage.structure.factorization import Factorization from sage.structure.element import coerce_binop diff --git a/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx b/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx index 77f64bf3b99..6c9c903ec8c 100644 --- a/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx +++ b/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx @@ -38,7 +38,7 @@ from cysignals.signals cimport sig_on, sig_off from sage.rings.polynomial.polynomial_element cimport Polynomial, _dict_to_list -from sage.libs.all import pari, pari_gen +from sage.libs.pari.all import pari, pari_gen from sage.rings.integer cimport smallInteger diff --git a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx index e806ae2d228..d72a8076848 100644 --- a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx +++ b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx @@ -39,7 +39,7 @@ from sage.structure.element cimport parent from sage.structure.element import coerce_binop from sage.libs.mpfr cimport * -from sage.libs.all import pari_gen +from sage.libs.pari.all import pari_gen cdef class PolynomialRealDense(Polynomial): r""" diff --git a/src/sage/rings/polynomial/polynomial_template.pxi b/src/sage/rings/polynomial/polynomial_template.pxi index 551fc55dff8..6a9427cb585 100644 --- a/src/sage/rings/polynomial/polynomial_template.pxi +++ b/src/sage/rings/polynomial/polynomial_template.pxi @@ -20,7 +20,7 @@ from sage.structure.element import coerce_binop from sage.structure.richcmp cimport rich_to_bool from sage.rings.fraction_field_element import FractionFieldElement from sage.rings.integer cimport Integer -from sage.libs.all import pari_gen +from sage.libs.pari.all import pari_gen import operator diff --git a/src/sage/rings/polynomial/polynomial_zz_pex.pyx b/src/sage/rings/polynomial/polynomial_zz_pex.pyx index c9f2a309365..5db4b9d84d4 100644 --- a/src/sage/rings/polynomial/polynomial_zz_pex.pyx +++ b/src/sage/rings/polynomial/polynomial_zz_pex.pyx @@ -43,7 +43,7 @@ include "sage/libs/ntl/ntl_ZZ_pEX_linkage.pxi" # and then the interface include "polynomial_template.pxi" -from sage.libs.all import pari +from sage.libs.pari.all import pari from sage.libs.ntl.ntl_ZZ_pE cimport ntl_ZZ_pE cdef inline ZZ_pE_c_to_list(ZZ_pE_c x): diff --git a/src/sage/rings/power_series_mpoly.pyx b/src/sage/rings/power_series_mpoly.pyx index f4fda135c1e..2c5b5a7ec0e 100644 --- a/src/sage/rings/power_series_mpoly.pyx +++ b/src/sage/rings/power_series_mpoly.pyx @@ -3,7 +3,7 @@ from .power_series_ring_element cimport PowerSeries from sage.structure.element cimport Element, ModuleElement, RingElement from .infinity import infinity, is_Infinite -from sage.libs.all import PariError +from sage.libs.pari.all import PariError from .power_series_ring_element import is_PowerSeries from . import rational_field from .polynomial.multi_polynomial_ring_base import is_MPolynomialRing diff --git a/src/sage/rings/power_series_poly.pyx b/src/sage/rings/power_series_poly.pyx index b2be674256d..17c23bd3c2c 100644 --- a/src/sage/rings/power_series_poly.pyx +++ b/src/sage/rings/power_series_poly.pyx @@ -8,7 +8,7 @@ The class ``PowerSeries_poly`` provides additional methods for univariate power from .power_series_ring_element cimport PowerSeries from sage.structure.element cimport Element, ModuleElement, RingElement from .infinity import infinity, is_Infinite -from sage.libs.all import pari_gen, PariError +from sage.libs.pari.all import pari_gen, PariError cdef class PowerSeries_poly(PowerSeries): diff --git a/src/sage/schemes/elliptic_curves/period_lattice.py b/src/sage/schemes/elliptic_curves/period_lattice.py index 812aee93b21..071c4ef9dbb 100644 --- a/src/sage/schemes/elliptic_curves/period_lattice.py +++ b/src/sage/schemes/elliptic_curves/period_lattice.py @@ -108,7 +108,7 @@ from sage.schemes.elliptic_curves.constructor import EllipticCurve from sage.misc.cachefunc import cached_method from sage.structure.richcmp import richcmp_method, richcmp, richcmp_not_equal -from sage.libs.all import pari +from sage.libs.pari.all import pari class PeriodLattice(FreeModule_generic_pid): diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py index 445b22726f4..b3d227d5d0c 100644 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py @@ -56,7 +56,7 @@ from sage.misc.cachefunc import cached_method from sage.matrix.constructor import identity_matrix, matrix from sage.misc.functional import rank -from sage.libs.all import pari +from sage.libs.pari.all import pari from sage.schemes.curves.projective_curve import ProjectivePlaneCurve_finite_field From 46ad7a0a997cbeba11cc32c9bc1e195f54c64e4b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 8 Dec 2021 20:37:59 -0800 Subject: [PATCH 037/253] git grep -l 'libs[.]all import' | xargs sed -i.bak '/[Gg]ap/s/from sage.libs.all import/from sage.libs.gap.libgap import/' --- src/sage/combinat/root_system/weyl_group.py | 4 ++-- src/sage/groups/matrix_gps/pickling_overrides.py | 2 +- src/sage/libs/gap/test.py | 2 +- src/sage/libs/gap/test_long.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/root_system/weyl_group.py b/src/sage/combinat/root_system/weyl_group.py index f5b693f1313..8cc0fef437b 100644 --- a/src/sage/combinat/root_system/weyl_group.py +++ b/src/sage/combinat/root_system/weyl_group.py @@ -242,7 +242,7 @@ def __init__(self, domain, prefix): # FinitelyGeneratedMatrixGroup_gap takes plain matrices as input gens_matrix = [self.morphism_matrix(self.domain().simple_reflection(i)) for i in self.index_set()] - from sage.libs.all import libgap + from sage.libs.gap.libgap import libgap libgap_group = libgap.Group(gens_matrix) degree = ZZ(self.domain().dimension()) ring = self.domain().base_ring() @@ -1027,7 +1027,7 @@ def __init__(self, cartan_type, prefix): self._index_set_inverse = {ii: i for i,ii in enumerate(cartan_type.index_set())} self._reflection_representation = None self._prefix = prefix - #from sage.libs.all import libgap + #from sage.libs.gap.libgap import libgap Q = cartan_type.root_system().root_lattice() Phi = list(Q.positive_roots()) + [-x for x in Q.positive_roots()] p = [[Phi.index(x.weyl_action([i]))+1 for x in Phi] diff --git a/src/sage/groups/matrix_gps/pickling_overrides.py b/src/sage/groups/matrix_gps/pickling_overrides.py index 333bd4fe9bf..d8d68ffd22f 100644 --- a/src/sage/groups/matrix_gps/pickling_overrides.py +++ b/src/sage/groups/matrix_gps/pickling_overrides.py @@ -34,7 +34,7 @@ def __setstate__(self, state): matrix_gens = state['_gensG'] ring = state['_MatrixGroup_gap__R'] degree = state['_MatrixGroup_gap__n'] - from sage.libs.all import libgap + from sage.libs.gap.libgap import libgap libgap_group = libgap.Group(libgap(matrix_gens)) self.__init__(degree, ring, libgap_group) diff --git a/src/sage/libs/gap/test.py b/src/sage/libs/gap/test.py index 5f75ff3b16a..bee6f17ba84 100644 --- a/src/sage/libs/gap/test.py +++ b/src/sage/libs/gap/test.py @@ -2,7 +2,7 @@ Short tests for GAP """ -from sage.libs.all import libgap +from sage.libs.gap.libgap import libgap from sage.misc.temporary_file import tmp_filename diff --git a/src/sage/libs/gap/test_long.py b/src/sage/libs/gap/test_long.py index 33eb7c7eaf0..5a929ab4585 100644 --- a/src/sage/libs/gap/test_long.py +++ b/src/sage/libs/gap/test_long.py @@ -4,7 +4,7 @@ These stress test the garbage collection inside GAP """ -from sage.libs.all import libgap +from sage.libs.gap.libgap import libgap def test_loop_1(): From 9d5eea38c02186cb0af0442cd8cd64ea0f68636f Mon Sep 17 00:00:00 2001 From: Javier Honrubia Date: Thu, 9 Dec 2021 15:08:01 +0100 Subject: [PATCH 038/253] Pictures added to the examples --- src/sage/plot/line.py | 147 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 126 insertions(+), 21 deletions(-) diff --git a/src/sage/plot/line.py b/src/sage/plot/line.py index 9081181208e..dc701bc9e7b 100644 --- a/src/sage/plot/line.py +++ b/src/sage/plot/line.py @@ -2,7 +2,7 @@ Line Plots """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2006 Alex Clemesha , # William Stein , # 2008 Mike Hansen , @@ -17,11 +17,12 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.plot.primitive import GraphicPrimitive_xydata from sage.misc.decorators import options, rename_keyword from sage.plot.colors import to_mpl_color + class Line(GraphicPrimitive_xydata): """ Primitive class that initializes the line graphics type. @@ -73,19 +74,19 @@ def _allowed_options(self): ('thickness', 'How thick the line is.'), ('zorder', 'The layer level in which to draw')] """ - return {'alpha':'How transparent the line is.', - 'legend_color':'The color of the legend text.', - 'legend_label':'The label for this item in the legend.', - 'thickness':'How thick the line is.', - 'rgbcolor':'The color as an RGB tuple.', - 'hue':'The color given as a hue.', - 'linestyle':"The style of the line, which is one of '--' (dashed), '-.' (dash dot), '-' (solid), 'steps', ':' (dotted).", - 'marker':"the marker symbol (see documentation for line2d for details)", - 'markersize':'the size of the marker in points', - 'markeredgecolor':'the color of the marker edge', - 'markeredgewidth':'the size of the marker edge in points', - 'markerfacecolor':'the color of the marker face', - 'zorder':'The layer level in which to draw' + return {'alpha': 'How transparent the line is.', + 'legend_color': 'The color of the legend text.', + 'legend_label': 'The label for this item in the legend.', + 'thickness': 'How thick the line is.', + 'rgbcolor': 'The color as an RGB tuple.', + 'hue': 'The color given as a hue.', + 'linestyle': "The style of the line, which is one of '--' (dashed), '-.' (dash dot), '-' (solid), 'steps', ':' (dotted).", + 'marker': "the marker symbol (see documentation for line2d for details)", + 'markersize': 'the size of the marker in points', + 'markeredgecolor': 'the color of the marker edge', + 'markeredgewidth': 'the size of the marker edge in points', + 'markerfacecolor': 'the color of the marker face', + 'zorder': 'The layer level in which to draw' } def _plot3d_options(self, options=None): @@ -118,7 +119,7 @@ def _plot3d_options(self, options=None): del options['zorder'] if 'linestyle' in options: if options['linestyle'] not in ('-', 'solid'): - raise NotImplementedError("Invalid 3d line style: '%s'"% + raise NotImplementedError("Invalid 3d line style: '%s'" % (options['linestyle'])) del options['linestyle'] options_3d.update(GraphicPrimitive_xydata._plot3d_options(self, options)) @@ -134,6 +135,13 @@ def plot3d(self, z=0, **kwds): sage: F = EllipticCurve('37a').plot(thickness=5).plot3d(z=2) sage: E + F # long time (5s on sage.math, 2012) Graphics3d Object + + .. PLOT:: + + E = EllipticCurve('37a').plot(thickness=5).plot3d() + F = EllipticCurve('37a').plot(thickness=5).plot3d(z=2) + sphinx_plot(E+F) + """ from sage.plot.plot3d.shapes2 import line3d options = self._plot3d_options() @@ -150,7 +158,7 @@ def _repr_(self): sage: Line([-1,2,3,3], [17,4,0,2], {})._repr_() 'Line defined by 4 points' """ - return "Line defined by %s points"%len(self) + return "Line defined by %s points" % len(self) def __getitem__(self, i): """ @@ -265,6 +273,7 @@ def _render_on_subplot(self, subplot): return_type='short')) subplot.add_line(p) + def line(points, **kwds): """ Returns either a 2-dimensional or 3-dimensional line depending @@ -283,10 +292,20 @@ def line(points, **kwds): sage: line([(0,0), (1,1)]) Graphics object consisting of 1 graphics primitive + .. PLOT:: + + E = line([(0,0), (1,1)]) + sphinx_plot(E) + :: sage: line([(0,0,1), (1,1,1)]) Graphics3d Object + + .. PLOT:: + + E = line([(0,0,1), (1,1,1)]) + sphinx_plot(E) """ try: return line2d(points, **kwds) @@ -296,8 +315,8 @@ def line(points, **kwds): @rename_keyword(color='rgbcolor') -@options(alpha=1, rgbcolor=(0,0,1), thickness=1, legend_label=None, - legend_color=None, aspect_ratio ='automatic') +@options(alpha=1, rgbcolor=(0, 0, 1), thickness=1, legend_label=None, + legend_color=None, aspect_ratio='automatic') def line2d(points, **options): r""" Create the line through the given list of points. @@ -387,6 +406,10 @@ def line2d(points, **options): sage: line([(0,0),(1,1)], legend_label='line') Graphics object consisting of 1 graphics primitive + .. PLOT:: + + sphinx_plot(line([(0,0),(1,1)], legend_label='line')) + Lines with different colors in the legend text:: sage: p1 = line([(0,0),(1,1)], legend_label='line') @@ -394,6 +417,12 @@ def line2d(points, **options): sage: p1 + p2 Graphics object consisting of 2 graphics primitives + .. PLOT:: + + p1 = line([(0,0),(1,1)], legend_label='line') + p2 = line([(1,1),(2,4)], legend_label='squared', legend_color='red') + sphinx_plot(p1 + p2) + Extra options will get passed on to show(), as long as they are valid:: sage: line([(0,1), (3,4)], figsize=[10, 2]) @@ -405,6 +434,10 @@ def line2d(points, **options): sage: line([(1,2),(2,4),(3,4),(4,8),(4.5,32)],scale='loglog',base=2) Graphics object consisting of 1 graphics primitive + .. PLOT:: + + sphinx_plot(line([(1,2),(2,4),(3,4),(4,8),(4.5,32)],scale='loglog',base=2)) + Many more examples below! A blue conchoid of Nicomedes:: @@ -413,12 +446,23 @@ def line2d(points, **options): sage: line(L, rgbcolor=(1/4,1/8,3/4)) Graphics object consisting of 1 graphics primitive + .. PLOT:: + + L = [[1+5*cos(pi/2+pi*i/100), tan(pi/2+pi*i/100)*(1+5*cos(pi/2+pi*i/100))] for i in range(1,100)] + sphinx_plot(line(L, rgbcolor=(1/4,1/8,3/4))) + A line with 2 complex points:: - sage: i = CC.0 + sage: i = CC(0,1) sage: line([1+i, 2+3*i]) Graphics object consisting of 1 graphics primitive + .. PLOT:: + + i = CC(0,1) + o = line([1+i, 2+3*i]) + sphinx_plot(o) + A blue hypotrochoid (3 leaves):: sage: n = 4; h = 3; b = 2 @@ -426,6 +470,15 @@ def line2d(points, **options): sage: line(L, rgbcolor=(1/4,1/4,3/4)) Graphics object consisting of 1 graphics primitive + .. PLOT:: + + n = 4 + h = 3 + b = 2 + L = [[n*cos(pi*i/100)+h*cos((n/b)*pi*i/100),n*sin(pi*i/100)-h*sin((n/b)*pi*i/100)] for i in range(200)] + o = line(L, rgbcolor=(1/4,1/4,3/4)) + sphinx_plot(o) + A blue hypotrochoid (4 leaves):: sage: n = 6; h = 5; b = 2 @@ -433,18 +486,33 @@ def line2d(points, **options): sage: line(L, rgbcolor=(1/4,1/4,3/4)) Graphics object consisting of 1 graphics primitive + .. PLOT:: + + L = [[sin(pi*i/100)+sin(pi*i/50),-(1+cos(pi*i/100)+cos(pi*i/50))] for i in range(-100,101)] + sphinx_plot(line(L, rgbcolor=(1,1/4,1/2))) + A red limacon of Pascal:: sage: L = [[sin(pi*i/100)+sin(pi*i/50),-(1+cos(pi*i/100)+cos(pi*i/50))] for i in range(-100,101)] sage: line(L, rgbcolor=(1,1/4,1/2)) Graphics object consisting of 1 graphics primitive + .. PLOT:: + + L = [[sin(pi*i/100)+sin(pi*i/50),-(1+cos(pi*i/100)+cos(pi*i/50))] for i in range(-100,101)] + sphinx_plot(line(L, rgbcolor=(1,1/4,1/2))) + A light green trisectrix of Maclaurin:: sage: L = [[2*(1-4*cos(-pi/2+pi*i/100)^2),10*tan(-pi/2+pi*i/100)*(1-4*cos(-pi/2+pi*i/100)^2)] for i in range(1,100)] sage: line(L, rgbcolor=(1/4,1,1/8)) Graphics object consisting of 1 graphics primitive + .. PLOT:: + + L = [[2*(1-4*cos(-pi/2+pi*i/100)**2),10*tan(-pi/2+pi*i/100)*(1-4*cos(-pi/2+pi*i/100)**2)] for i in range(1,100)] + sphinx_plot(line(L, rgbcolor=(1/4,1,1/8))) + A green lemniscate of Bernoulli:: sage: cosines = [cos(-pi/2+pi*i/100) for i in range(201)] @@ -453,6 +521,13 @@ def line2d(points, **options): sage: line(L, rgbcolor=(1/4,3/4,1/8)) Graphics object consisting of 1 graphics primitive + .. PLOT:: + + cosines = [cos(-pi/2+pi*i/100) for i in range(201)] + v = [(1/c, tan(-pi/2+pi*i/100)) for i,c in enumerate(cosines) if c != 0] + L = [(a/(a**2+b**2), b/(a**2+b**2)) for a,b in v] + sphinx_plot(line(L, rgbcolor=(1/4,3/4,1/8))) + A red plot of the Jacobi elliptic function `\text{sn}(x,2)`, `-3 < x < 3`:: sage: L = [(i/100.0, real_part(jacobi('sn', i/100.0, 2.0))) for i in @@ -460,12 +535,21 @@ def line2d(points, **options): sage: line(L, rgbcolor=(3/4, 1/4, 1/8)) Graphics object consisting of 1 graphics primitive + .. PLOT:: + + L = [(i/100.0, real_part(jacobi('sn', i/100.0, 2.0))) for i in range(-300, 300, 30)] + sphinx_plot(line(L, rgbcolor=(3/4, 1/4, 1/8))) + A red plot of `J`-Bessel function `J_2(x)`, `0 < x < 10`:: sage: L = [(i/10.0, bessel_J(2,i/10.0)) for i in range(100)] sage: line(L, rgbcolor=(3/4,1/4,5/8)) Graphics object consisting of 1 graphics primitive + .. PLOT:: + + L = [(i/10.0, bessel_J(2,i/10.0)) for i in range(100)] + sphinx_plot(line(L, rgbcolor=(3/4,1/4,5/8))) A purple plot of the Riemann zeta function `\zeta(1/2 + it)`, `0 < t < 30`:: @@ -475,6 +559,13 @@ def line2d(points, **options): sage: line(L, rgbcolor=(3/4,1/2,5/8)) Graphics object consisting of 1 graphics primitive + .. PLOT:: + + i = CDF.gen() + v = [zeta(0.5 + n/10 * i) for n in range(300)] + L = [(z.real(), z.imag()) for z in v] + sphinx_plot(line(L, rgbcolor=(3/4,1/2,5/8))) + A purple plot of the Hasse-Weil `L`-function `L(E, 1 + it)`, `-1 < t < 10`:: sage: E = EllipticCurve('37a') @@ -483,6 +574,13 @@ def line2d(points, **options): sage: line(L, rgbcolor=(3/4,1/2,5/8)) Graphics object consisting of 1 graphics primitive + .. PLOT :: + + E = EllipticCurve('37a') + vals = E.lseries().values_along_line(1-I, 1+10*I, 100) # critical line + L = [(z[1].real(), z[1].imag()) for z in vals] + sphinx_plot(line(L, rgbcolor=(3/4,1/2,5/8))) + A red, blue, and green "cool cat":: sage: G = plot(-cos(x), -2, 2, thickness=5, rgbcolor=(0.5,1,0.5)) @@ -491,6 +589,13 @@ def line2d(points, **options): sage: G + P + Q # show the plot Graphics object consisting of 3 graphics primitives + .. PLOT:: + + G = plot(-cos(x), -2, 2, thickness=5, rgbcolor=(0.5,1,0.5)) + P = polygon([[1,2], [5,6], [5,0]], rgbcolor=(1,0,0)) + Q = polygon([(-x,y) for x,y in P[0]], rgbcolor=(0,0,1)) + sphinx_plot(G + P + Q) + TESTS: Check that :trac:`13690` is fixed. The legend label should have circles @@ -501,7 +606,7 @@ def line2d(points, **options): """ from sage.plot.all import Graphics from sage.plot.plot import xydata_from_point_list - points = list(points) # make sure points is a python list + points = list(points) # make sure points is a python list if not points: return Graphics() xdata, ydata = xydata_from_point_list(points) From c567b7101fc7e1a81e0bd017aa69178fa7ba4df8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Thu, 9 Dec 2021 18:02:06 +0100 Subject: [PATCH 039/253] adding feature pdftocairo from poppler --- src/sage/features/poppler.py | 58 ++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/sage/features/poppler.py diff --git a/src/sage/features/poppler.py b/src/sage/features/poppler.py new file mode 100644 index 00000000000..1b0379bc0d2 --- /dev/null +++ b/src/sage/features/poppler.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +r""" +Check for poppler features + +poppler-utils is a collection of tools built on Poppler's library API, to +manage PDF and extract contents: + + - ``pdfattach`` - add a new embedded file (attachment) to an existing PDF + - ``pdfdetach`` - extract embedded documents from a PDF + - ``pdffonts`` - lists the fonts used in a PDF + - ``pdfimages`` - extract all embedded images at native resolution from a PDF + - ``pdfinfo`` - list all information of a PDF + - ``pdfseparate`` - extract single pages from a PDF + - ``pdftocairo`` - convert single pages from a PDF to vector or bitmap formats using cairo + - ``pdftohtml`` - convert PDF to HTML format retaining formatting + - ``pdftoppm`` - convert a PDF page to a bitmap + - ``pdftops`` - convert PDF to printable PS format + - ``pdftotext`` - extract all text from PDF + - ``pdfunite`` - merges several PDF + +Currently we only check for the presence of ``pdftocairo``. +""" +# **************************************************************************** +# Copyright (C) 2021 Sebastien Labbe +# +# 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 . import Executable + +class pdftocairo(Executable): + r""" + A :class:`sage.features.Feature` describing the presence of + ``pdftocairo`` + + EXAMPLES:: + + sage: from sage.features.poppler import pdftocairo + sage: pdftocairo().is_present() # optional: pdftocairo + FeatureTestResult('pdftocairo', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.poppler import pdftocairo + sage: isinstance(pdftocairo(), pdftocairo) + True + """ + Executable.__init__(self, "pdftocairo", executable="pdftocairo", + url="https://poppler.freedesktop.org/") + +def all_features(): + return [pdftocairo()] From e8e4927b68ba5f762f4d1ce13525bff38b3ca2f0 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Thu, 9 Dec 2021 11:31:54 -0800 Subject: [PATCH 040/253] trac 32505: add a few examples using exterior algebras. make gen, gens aliases for generator, generators --- src/sage/modules/fp_graded/free_module.py | 10 ++++++++++ src/sage/modules/fp_graded/module.py | 23 ++++++++++++++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/sage/modules/fp_graded/free_module.py b/src/sage/modules/fp_graded/free_module.py index a5f2aa5d68d..2cdc696b243 100755 --- a/src/sage/modules/fp_graded/free_module.py +++ b/src/sage/modules/fp_graded/free_module.py @@ -292,6 +292,16 @@ class FreeGradedModule(CombinatorialFreeModule): TESTS:: sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: E. = ExteriorAlgebra(QQ) + sage: M = FreeGradedModule(E, (-1,3)) + sage: M + Finitely presented free left module on 2 generators over The exterior algebra of rank 3 over Rational Field + sage: M.generator_degrees() + (-1, 3) + sage: a, b = M.generators() + sage: (x*y*b).degree() + 5 + sage: A = SteenrodAlgebra(2) sage: FreeGradedModule(A, (-2,2,4)) Finitely presented free left module on 3 generators over mod 2 Steenrod algebra, milnor basis diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index 49d807d2e33..5872b0ee29a 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -87,13 +87,26 @@ class FPModule(Module, IndexedGenerators, UniqueRepresentation): - ``relations`` -- tuple of relations. A relation is a tuple of coefficients `(c_1, \ldots, c_n)`, ordered so that they - correspond to the module generators. + correspond to the module generators. That is, such a tuple + corresponds to the relation + + .. MATH:: + + c_1 g_1 + \ldots + c_n g_n = 0 + + if the generators are `(g_1, \ldots, g_n)`. EXAMPLES:: sage: from sage.modules.fp_graded.module import FPModule - sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) + sage: E. = ExteriorAlgebra(QQ) + sage: M = FPModule(E, [0, 1], [[x, 1]]) + sage: a, b = M.generators() + sage: x*a + b == 0 + True + + sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) sage: M = FPModule(A3, [0, 1], [[Sq(2), Sq(1)]]) sage: M.generators() [<1, 0>, <0, 1>] @@ -153,7 +166,7 @@ def __init__(self, algebra, generator_degrees, relations=()): sage: from sage.modules.fp_graded.module import FPModule sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) sage: M = FPModule(A3, [0, 1], [[Sq(2), Sq(1)]]) - sage: TestSuite(M).run() + sage: TestSuite(M).run(skip = "_test_elements") """ self._generator_degrees = generator_degrees self._relations = relations @@ -903,6 +916,8 @@ def generators(self): """ return [self.generator(i) for i in range(len(self.generator_degrees()))] + gens = generators + def generator(self, index): r""" @@ -923,6 +938,8 @@ def generator(self, index): """ return self(self._free_module().generator(index)) + gen = generator + def relations(self): r""" From a9b75174ce2ac5c78da1920db111a03ef5f71bea Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 9 Dec 2021 16:32:05 -0800 Subject: [PATCH 041/253] git grep -l 'interfaces.all import' | xargs sed -E -i.bak 's/interfaces[.]all import ([a-z][a-z]*)/interfaces.\1 import \1/' --- src/sage/coding/linear_code.py | 2 +- src/sage/groups/abelian_gps/abelian_group.py | 2 +- .../groups/abelian_gps/dual_abelian_group_element.py | 2 +- src/sage/groups/perm_gps/cubegroup.py | 2 +- src/sage/interfaces/magma.py | 2 +- src/sage/interfaces/singular.py | 2 +- src/sage/matrix/benchmark.py | 2 +- src/sage/matrix/matrix1.pyx | 2 +- src/sage/matrix/matrix_integer_dense_hnf.py | 4 ++-- src/sage/modular/btquotients/btquotient.py | 2 +- src/sage/modular/quatalg/brandt.py | 2 +- src/sage/rings/function_field/function_field.py | 2 +- src/sage/rings/integer.pyx | 4 ++-- .../rings/polynomial/multi_polynomial_libsingular.pyx | 2 +- src/sage/rings/polynomial/pbori/pbori.pyx | 2 +- .../rings/polynomial/polynomial_modn_dense_ntl.pyx | 2 +- .../rings/polynomial/polynomial_rational_flint.pyx | 6 +++--- .../rings/polynomial/polynomial_singular_interface.py | 2 +- src/sage/rings/polynomial/polynomial_template.pxi | 2 +- src/sage/schemes/affine/affine_subscheme.py | 2 +- src/sage/schemes/curves/affine_curve.py | 2 +- src/sage/schemes/curves/projective_curve.py | 2 +- src/sage/schemes/elliptic_curves/cm.py | 2 +- src/sage/schemes/elliptic_curves/ell_rational_field.py | 10 +++++----- src/sage/schemes/elliptic_curves/lseries_ell.py | 2 +- src/sage/schemes/hyperelliptic_curves/mestre.py | 2 +- src/sage/schemes/projective/projective_morphism.py | 2 +- 27 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index c335f04e1a9..7201f0bcdcb 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -209,7 +209,7 @@ class should inherit from this class. Also ``AbstractLinearCode`` should never from copy import copy from sage.cpython.string import bytes_to_str -from sage.interfaces.all import gap +from sage.interfaces.gap import gap from sage.categories.cartesian_product import cartesian_product from sage.categories.fields import Fields from sage.matrix.matrix_space import MatrixSpace diff --git a/src/sage/groups/abelian_gps/abelian_group.py b/src/sage/groups/abelian_gps/abelian_group.py index 1c9ce29e858..99f2a43b8dc 100644 --- a/src/sage/groups/abelian_gps/abelian_group.py +++ b/src/sage/groups/abelian_gps/abelian_group.py @@ -1658,7 +1658,7 @@ def __init__(self, ambient, gens, names="f", category=None): sage: G.subgroup([prod(g^k for g,k in zip(G.gens(),[1,-2,3,-4,5]))]) Multiplicative Abelian subgroup isomorphic to Z generated by {f0*f1^-2*f2^3*f3^-4*f4} """ - from sage.interfaces.all import gap + from sage.interfaces.gap import gap if not isinstance(ambient, AbelianGroup_class): raise TypeError("ambient (=%s) must be an abelian group."%ambient) if not isinstance(gens, tuple): diff --git a/src/sage/groups/abelian_gps/dual_abelian_group_element.py b/src/sage/groups/abelian_gps/dual_abelian_group_element.py index a4f2879fb3d..c7d5a5001f3 100644 --- a/src/sage/groups/abelian_gps/dual_abelian_group_element.py +++ b/src/sage/groups/abelian_gps/dual_abelian_group_element.py @@ -205,7 +205,7 @@ def word_problem(self, words, display=True): ## First convert the problem to one using AbelianGroups import copy from sage.groups.abelian_gps.abelian_group import AbelianGroup - from sage.interfaces.all import gap + from sage.interfaces.gap import gap M = self.parent() G = M.group() gens = M.variable_names() diff --git a/src/sage/groups/perm_gps/cubegroup.py b/src/sage/groups/perm_gps/cubegroup.py index 807cd92ad02..1ce49975a3f 100644 --- a/src/sage/groups/perm_gps/cubegroup.py +++ b/src/sage/groups/perm_gps/cubegroup.py @@ -99,7 +99,7 @@ from sage.structure.richcmp import richcmp, richcmp_method from sage.rings.real_double import RDF -from sage.interfaces.all import gap +from sage.interfaces.gap import gap from sage.groups.perm_gps.permgroup_element import PermutationGroupElement from sage.plot.polygon import polygon from sage.plot.text import text diff --git a/src/sage/interfaces/magma.py b/src/sage/interfaces/magma.py index 9aed0ea413d..c6a1d799351 100644 --- a/src/sage/interfaces/magma.py +++ b/src/sage/interfaces/magma.py @@ -2984,7 +2984,7 @@ def __init__(self, magma=None): 0 """ if magma is None: - from sage.interfaces.all import magma as magma_default + from sage.interfaces.magma import magma as magma_default magma = magma_default self.magma = magma diff --git a/src/sage/interfaces/singular.py b/src/sage/interfaces/singular.py index 023b9e3d42a..5a184d68846 100644 --- a/src/sage/interfaces/singular.py +++ b/src/sage/interfaces/singular.py @@ -2654,7 +2654,7 @@ def __init__(self, singular=None): it manually. """ if singular is None: - from sage.interfaces.all import singular as singular_default + from sage.interfaces.singular import singular as singular_default singular = singular_default self.singular = singular diff --git a/src/sage/matrix/benchmark.py b/src/sage/matrix/benchmark.py index 1ac40e3b6c1..5058798da1a 100644 --- a/src/sage/matrix/benchmark.py +++ b/src/sage/matrix/benchmark.py @@ -24,7 +24,7 @@ from sage.misc.misc import cputime from cysignals.alarm import AlarmInterrupt, alarm, cancel_alarm -from sage.interfaces.all import magma +from sage.interfaces.magma import magma verbose = False diff --git a/src/sage/matrix/matrix1.pyx b/src/sage/matrix/matrix1.pyx index 044fcb67029..0f241b7c6cb 100644 --- a/src/sage/matrix/matrix1.pyx +++ b/src/sage/matrix/matrix1.pyx @@ -421,7 +421,7 @@ cdef class Matrix(Matrix0): Tries to coerce this matrix to a singular matrix. """ if singular is None: - from sage.interfaces.all import singular as singular_default + from sage.interfaces.singular import singular as singular_default singular = singular_default try: self.base_ring()._singular_(singular) diff --git a/src/sage/matrix/matrix_integer_dense_hnf.py b/src/sage/matrix/matrix_integer_dense_hnf.py index 3796dd93451..e1ce64d5605 100644 --- a/src/sage/matrix/matrix_integer_dense_hnf.py +++ b/src/sage/matrix/matrix_integer_dense_hnf.py @@ -1206,7 +1206,7 @@ def benchmark_magma_hnf(nrange, bits=4): ('magma', 50, 32, ...), ('magma', 100, 32, ...), """ - from sage.interfaces.all import magma + from sage.interfaces.magma import magma b = 2**bits for n in nrange: a = magma('MatrixAlgebra(IntegerRing(),%s)![Random(%s,%s) : i in [1..%s]]' % (n, -b, b, n**2)) @@ -1256,7 +1256,7 @@ def sanity_checks(times=50, n=8, m=5, proof=True, stabilize=2, 0 1 2 3 4 (done) """ if check_using_magma: - from sage.interfaces.all import magma + from sage.interfaces.magma import magma def __do_check(v): """ diff --git a/src/sage/modular/btquotients/btquotient.py b/src/sage/modular/btquotients/btquotient.py index 75ee74a49f0..4291cdc0cab 100644 --- a/src/sage/modular/btquotients/btquotient.py +++ b/src/sage/modular/btquotients/btquotient.py @@ -58,7 +58,7 @@ from sage.quadratic_forms.all import QuadraticForm from sage.graphs.all import Graph from sage.libs.all import pari -from sage.interfaces.all import magma +from sage.interfaces.magma import magma from sage.plot.colors import rainbow from sage.rings.number_field.all import NumberField from sage.modular.arithgroup.all import Gamma0 diff --git a/src/sage/modular/quatalg/brandt.py b/src/sage/modular/quatalg/brandt.py index cad5e086785..f123eaaf16a 100644 --- a/src/sage/modular/quatalg/brandt.py +++ b/src/sage/modular/quatalg/brandt.py @@ -1646,7 +1646,7 @@ def benchmark_magma(levels, silent=False): ('magma', 97, 2, ...) """ ans = [] - from sage.interfaces.all import magma + from sage.interfaces.magma import magma for p, M in levels: t = magma.cputime() magma.eval('HeckeOperator(BrandtModule(%s, %s),2)' % (p, M)) diff --git a/src/sage/rings/function_field/function_field.py b/src/sage/rings/function_field/function_field.py index 9ab0c4de872..c0fd8296e52 100644 --- a/src/sage/rings/function_field/function_field.py +++ b/src/sage/rings/function_field/function_field.py @@ -224,7 +224,7 @@ # **************************************************************************** from sage.misc.cachefunc import cached_method -from sage.interfaces.all import singular +from sage.interfaces.singular import singular from sage.arith.all import lcm diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 9dad670c8df..d1220c864b7 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -3950,9 +3950,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sort=False, simplify=False) elif algorithm in ['kash', 'magma']: if algorithm == 'kash': - from sage.interfaces.all import kash as I + from sage.interfaces.kash import kash as I else: - from sage.interfaces.all import magma as I + from sage.interfaces.magma import magma as I str_res = I.eval('Factorization(%s)'%n) # The result looks like "[ , , ... ] str_res = str_res.replace(']', '').replace('[', '').replace('>', '').replace('<', '').split(',') diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index 5d34e62d04c..3fc086becfd 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -243,7 +243,7 @@ from sage.structure.richcmp cimport rich_to_bool, richcmp from sage.structure.factorization import Factorization from sage.structure.sequence import Sequence -from sage.interfaces.all import macaulay2 +from sage.interfaces.macaulay import macaulay2 from sage.interfaces.singular import singular as singular_default, is_SingularElement, SingularElement from sage.interfaces.macaulay2 import macaulay2 as macaulay2_default, is_Macaulay2Element diff --git a/src/sage/rings/polynomial/pbori/pbori.pyx b/src/sage/rings/polynomial/pbori/pbori.pyx index fafe1b30e72..38d5ac2084b 100644 --- a/src/sage/rings/polynomial/pbori/pbori.pyx +++ b/src/sage/rings/polynomial/pbori/pbori.pyx @@ -218,7 +218,7 @@ from sage.categories.action cimport Action from sage.monoids.monoid import Monoid_class from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.interfaces.all import singular as singular_default +from sage.interfaces.singular import singular as singular_default from sage.interfaces.singular import SingularElement order_dict = {"lp": pblp, diff --git a/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx b/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx index 77f64bf3b99..789345f8615 100644 --- a/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx +++ b/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx @@ -53,7 +53,7 @@ import sage.rings.polynomial.polynomial_ring from sage.rings.infinity import infinity from . import polynomial_singular_interface -from sage.interfaces.all import singular as singular_default +from sage.interfaces.singular import singular as singular_default from sage.structure.element import coerce_binop diff --git a/src/sage/rings/polynomial/polynomial_rational_flint.pyx b/src/sage/rings/polynomial/polynomial_rational_flint.pyx index 25d70431aa9..d2bfd5c9bfa 100644 --- a/src/sage/rings/polynomial/polynomial_rational_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_rational_flint.pyx @@ -38,7 +38,7 @@ from sage.libs.flint.fmpq cimport * from sage.libs.flint.fmpz_poly cimport * from sage.libs.flint.fmpq_poly cimport * -from sage.interfaces.all import singular as singular_default +from sage.interfaces.singular import singular as singular_default from cypari2.gen import Gen as pari_gen @@ -2192,7 +2192,7 @@ cdef class Polynomial_rational_flint(Polynomial): elif algorithm == 'kash': try: - from sage.interfaces.all import kash + from sage.interfaces.kash import kash kash.eval('X := PolynomialRing(RationalField()).1') s = self._repr(name='X') G = kash('Galois(%s)'%s) @@ -2217,7 +2217,7 @@ cdef class Polynomial_rational_flint(Polynomial): return TransitiveGroup(self.degree(), fgap.GaloisType()) elif algorithm == 'magma': - from sage.interfaces.all import magma + from sage.interfaces.magma import magma X = magma(self).GaloisGroup() try: n, d = X.TransitiveGroupIdentification(nvals=2) diff --git a/src/sage/rings/polynomial/polynomial_singular_interface.py b/src/sage/rings/polynomial/polynomial_singular_interface.py index c122bfd438d..be196c0086b 100644 --- a/src/sage/rings/polynomial/polynomial_singular_interface.py +++ b/src/sage/rings/polynomial/polynomial_singular_interface.py @@ -41,7 +41,7 @@ import sage.rings.abc import sage.rings.number_field as number_field -from sage.interfaces.all import singular +from sage.interfaces.singular import singular from sage.rings.rational_field import is_RationalField from sage.rings.function_field.function_field import RationalFunctionField from sage.rings.finite_rings.finite_field_base import is_FiniteField diff --git a/src/sage/rings/polynomial/polynomial_template.pxi b/src/sage/rings/polynomial/polynomial_template.pxi index 551fc55dff8..5a546020db2 100644 --- a/src/sage/rings/polynomial/polynomial_template.pxi +++ b/src/sage/rings/polynomial/polynomial_template.pxi @@ -24,7 +24,7 @@ from sage.libs.all import pari_gen import operator -from sage.interfaces.all import singular as singular_default +from sage.interfaces.singular import singular as singular_default def make_element(parent, args): return parent(*args) diff --git a/src/sage/schemes/affine/affine_subscheme.py b/src/sage/schemes/affine/affine_subscheme.py index 92b040b9631..9fd88f52896 100644 --- a/src/sage/schemes/affine/affine_subscheme.py +++ b/src/sage/schemes/affine/affine_subscheme.py @@ -21,7 +21,7 @@ # **************************************************************************** from sage.categories.fields import Fields -from sage.interfaces.all import singular +from sage.interfaces.singular import singular from sage.modules.free_module_element import vector from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index 23312f06ed6..4ba91613843 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -127,7 +127,7 @@ from sage.misc.cachefunc import cached_method from sage.arith.misc import binomial -from sage.interfaces.all import singular +from sage.interfaces.singular import singular from sage.misc.all import add from sage.categories.fields import Fields diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 068ffb73146..cce01fb546b 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -144,7 +144,7 @@ from sage.categories.number_fields import NumberFields from sage.categories.homset import Hom, End -from sage.interfaces.all import singular +from sage.interfaces.singular import singular from sage.matrix.constructor import matrix from sage.misc.all import add, sage_eval diff --git a/src/sage/schemes/elliptic_curves/cm.py b/src/sage/schemes/elliptic_curves/cm.py index e441ab51f1b..8137bbe6a19 100644 --- a/src/sage/schemes/elliptic_curves/cm.py +++ b/src/sage/schemes/elliptic_curves/cm.py @@ -33,7 +33,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.interfaces.all import magma +from sage.interfaces.magma import magma from sage.rings.all import (Integer, QQ, ZZ, diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index b0b674a0bde..62740ea7089 100644 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -93,7 +93,7 @@ from sage.libs.pari.all import pari from sage.functions.gamma import gamma_inc from math import sqrt -from sage.interfaces.all import gp +from sage.interfaces.gp import gp from sage.misc.cachefunc import cached_method from copy import copy @@ -471,7 +471,7 @@ def mwrank(self, options=''): Regulator = 95.98037... """ if not options: - from sage.interfaces.all import mwrank + from sage.interfaces.mwrank import mwrank else: from sage.interfaces.all import Mwrank mwrank = Mwrank(options=options) @@ -1544,7 +1544,7 @@ def analytic_rank(self, algorithm="pari", leading_coefficient=False): elif algorithm == 'magma': if leading_coefficient: raise NotImplementedError("Cannot compute leading coefficient using magma") - from sage.interfaces.all import magma + from sage.interfaces.magma import magma return rings.Integer(magma(self).AnalyticRank()) elif algorithm == 'zero_sum': if leading_coefficient: @@ -1970,7 +1970,7 @@ def three_selmer_rank(self, algorithm='UseSUnits'): sage: EllipticCurve('681b').three_selmer_rank(algorithm='Heuristic') # long time (10 seconds); optional - magma 2 """ - from sage.interfaces.all import magma + from sage.interfaces.magma import magma E = magma(self) return Integer(E.ThreeSelmerGroup(MethodForFinalStep = magma('"%s"'%algorithm)).Ngens()) @@ -3753,7 +3753,7 @@ def modular_degree(self, algorithm='sympow', M=1): from sage.lfunctions.all import sympow m = sympow.modular_degree(self) elif algorithm == 'magma': - from sage.interfaces.all import magma + from sage.interfaces.magma import magma m = rings.Integer(magma(self).ModularDegree()) else: raise ValueError("unknown algorithm %s"%algorithm) diff --git a/src/sage/schemes/elliptic_curves/lseries_ell.py b/src/sage/schemes/elliptic_curves/lseries_ell.py index 03af6f1fd30..4e8fa16994f 100644 --- a/src/sage/schemes/elliptic_curves/lseries_ell.py +++ b/src/sage/schemes/elliptic_curves/lseries_ell.py @@ -162,7 +162,7 @@ def dokchitser(self, prec=53, algorithm = 'pari' if algorithm == 'magma': - from sage.interfaces.all import magma + from sage.interfaces.magma import magma return magma(self.__E).LSeries(Precision=prec) if algorithm == 'pari': diff --git a/src/sage/schemes/hyperelliptic_curves/mestre.py b/src/sage/schemes/hyperelliptic_curves/mestre.py index 577888dc0c4..eb0b1b671eb 100644 --- a/src/sage/schemes/hyperelliptic_curves/mestre.py +++ b/src/sage/schemes/hyperelliptic_curves/mestre.py @@ -157,7 +157,7 @@ def HyperellipticCurve_from_invariants(i, reduced=True, precision=None, t = k['t'].gen() if algorithm == 'magma': - from sage.interfaces.all import magma + from sage.interfaces.magma import magma from sage.misc.sage_eval import sage_eval if MConic.has_rational_point(algorithm='magma'): parametrization = [l.replace('$.1', 't').replace('$.2', 'u') \ diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index e00e455843d..fc516739392 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -64,7 +64,7 @@ from sage.arith.all import gcd, lcm -from sage.interfaces.all import singular +from sage.interfaces.singular import singular from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_method From 607316f520d059c621fe081f1cece8d58cb4c989 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 9 Dec 2021 16:35:49 -0800 Subject: [PATCH 042/253] Remove remaining imports from sage.interfaces.all --- src/sage/rings/polynomial/multi_polynomial_ideal.py | 4 ++-- src/sage/schemes/elliptic_curves/ell_rational_field.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 70f21387412..aa3933bf579 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -232,8 +232,8 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.interfaces.all import (singular as singular_default, - magma as magma_default) +from sage.interfaces.singular import singular as singular_default +from sage.interfaces.magma import magma as magma_default from sage.interfaces.expect import StdOutContext diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index 62740ea7089..fefcee82307 100644 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -473,7 +473,7 @@ def mwrank(self, options=''): if not options: from sage.interfaces.mwrank import mwrank else: - from sage.interfaces.all import Mwrank + from sage.interfaces.mwrank import Mwrank mwrank = Mwrank(options=options) return mwrank(list(self.a_invariants())) From ded984f60dc7090448df317ec2b5104986ce1795 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 10 Dec 2021 10:11:18 +0900 Subject: [PATCH 043/253] Reviewer changes with misc tweaks and fixes. --- src/sage/modules/fp_graded/element.py | 38 +- src/sage/modules/fp_graded/free_element.py | 41 +- src/sage/modules/fp_graded/free_homspace.py | 53 ++- src/sage/modules/fp_graded/free_module.py | 223 ++++++----- src/sage/modules/fp_graded/free_morphism.py | 149 +++----- src/sage/modules/fp_graded/homspace.py | 103 ++--- src/sage/modules/fp_graded/module.py | 292 +++++++------- src/sage/modules/fp_graded/morphism.py | 401 ++++++++++---------- 8 files changed, 644 insertions(+), 656 deletions(-) diff --git a/src/sage/modules/fp_graded/element.py b/src/sage/modules/fp_graded/element.py index 3fae2d5fa51..72ca2e2f38e 100755 --- a/src/sage/modules/fp_graded/element.py +++ b/src/sage/modules/fp_graded/element.py @@ -66,10 +66,11 @@ def lift_to_free(self): @cached_method def degree(self): r""" - The degree of this element. + The degree of ``self``. - OUTPUT: The integer degree of this element, or raise an error - if this is the zero element. + OUTPUT: + + The integer degree of ``self`` or raise an error if the zero element. EXAMPLES:: @@ -126,7 +127,7 @@ def coefficients(self): def _repr_(self): r""" - Return a string representation of this element. + Return a string representation of ``self``. EXAMPLES:: @@ -152,9 +153,11 @@ def _lmul_(self, a): INPUT: - - ``a`` -- an element of the algebra this module is defined over. + - ``a`` -- an element of the algebra the parent module is defined over + + OUTPUT: - OUTPUT: the module element `a\cdot x` where `x` is this module element. + The module element `a \cdot x` where `x` is ``self``. EXAMPLES:: @@ -186,16 +189,18 @@ def _lmul_(self, a): def vector_presentation(self): r""" - A coordinate vector representing this module element when it is non-zero. + A coordinate vector representing ``self`` when it is non-zero. These are coordinates with respect to the basis chosen by :meth:`sage.modules.fp_graded.module.FPModule.basis_elements`. When the element is zero, it has no well defined degree, and this function returns ``None``. - OUTPUT: A vector of elements in the ground field of the algebra for - this module when this element is non-zero. Otherwise, the value - ``None``. + OUTPUT: + + A vector of elements in the ground field of the algebra for + this module when this element is non-zero. Otherwise, the + value ``None``. .. SEEALSO:: @@ -255,8 +260,10 @@ def __bool__(self): r""" Determine if this element is non-zero. - OUTPUT: The boolean value ``True`` if this element is non-zero, and ``False`` - otherwise. + OUTPUT: + + The boolean value ``True`` if this element is non-zero + and ``False`` otherwise. EXAMPLES:: @@ -309,8 +316,10 @@ def normalize(self): r""" A normalized form of ``self``. - OUTPUT: An instance of this element class representing the same - module element as this element. + OUTPUT: + + An instance representing the same module element as ``self`` in + normalized form. EXAMPLES:: @@ -336,3 +345,4 @@ def normalize(self): v = self.vector_presentation() return self.parent().element_from_coordinates(v, self.degree()) + diff --git a/src/sage/modules/fp_graded/free_element.py b/src/sage/modules/fp_graded/free_element.py index d3a23b812ce..c62cd15c03a 100755 --- a/src/sage/modules/fp_graded/free_element.py +++ b/src/sage/modules/fp_graded/free_element.py @@ -1,11 +1,6 @@ r""" Elements of finitely generated free graded left modules -This class implements construction and basic manipulation of -elements of the Sage parent -:class:`sage.modules.fp_graded.free_module.FreeModule`, which models -free graded left modules over connected algebras. - For an overview of the free module API, see :doc:`free_module`. AUTHORS: @@ -73,9 +68,11 @@ def coefficients(self): def degree(self): r""" - The degree of this element. + The degree of ``self``. + + OUTPUT: - OUTPUT: the integer degree of this element, or raise an error + The integer degree of this element, or raise an error if this is the zero element. EXAMPLES:: @@ -107,8 +104,7 @@ def degree(self): raise ValueError("the zero element does not have a well-defined degree") degrees = [] try: - for g, c in zip(self.parent().generator_degrees(), - self.coefficients()): + for g, c in zip(self.parent().generator_degrees(), self.coefficients()): if c: degrees.append(g + c.degree()) except ValueError: @@ -121,8 +117,8 @@ def degree(self): def lift_to_free(self): - """ - This returns the module itself. + r""" + Return ``self``. It is provided for compatibility with the method of the same name for :class:`sage.modules.fp_graded.module.FPModule`. @@ -143,7 +139,7 @@ def lift_to_free(self): def _repr_(self): r""" - Return a string representation of this element. + Return a string representation of ``self``. EXAMPLES:: @@ -173,9 +169,11 @@ def _lmul_(self, a): INPUT: - - ``a`` -- an element of the algebra this module is defined over. + - ``a`` -- an element of the algebra the parent module is defined over - OUTPUT: the module element `a\cdot x` where `x` is this module element. + OUTPUT: + + The module element `a \cdot x` where `x` is this module element. EXAMPLES:: @@ -207,14 +205,16 @@ def _lmul_(self, a): @cached_method def vector_presentation(self): r""" - A coordinate vector representing this module element when it is non-zero. + A coordinate vector representing ``self`` when it is non-zero. These are coordinates with respect to the basis chosen by :meth:`sage.modules.fp_graded.free_module.FreeGradedModule.basis_elements`. When the element is zero, it has no well defined degree, and this function returns ``None``. - OUTPUT: A vector of elements in the ground field of the algebra for + OUTPUT: + + A vector of elements in the ground field of the algebra for this module when this element is non-zero. Otherwise, the value ``None``. @@ -265,8 +265,9 @@ def vector_presentation(self): if self.is_zero(): return None - bas_gen = self.parent().basis_elements(self.degree()) - base_vec = self.parent().vector_presentation(self.degree()) + P = self.parent() + bas_gen = P.basis_elements(self.degree()) + base_vec = P.vector_presentation(self.degree()) base_dict = dict(zip(bas_gen, base_vec.basis())) @@ -275,7 +276,9 @@ def vector_presentation(self): vector = base_vec.zero() for summand_index, algebra_element in sparse_coeffs: + g = P.generator(summand_index) for scalar_coefficient, monomial in zip(algebra_element.coefficients(), algebra_element.monomials()): - vector += scalar_coefficient*base_dict[monomial*self.parent().generator(summand_index)] + vector += scalar_coefficient * base_dict[monomial * g] return vector + diff --git a/src/sage/modules/fp_graded/free_homspace.py b/src/sage/modules/fp_graded/free_homspace.py index 83913bba351..69fc03ca242 100755 --- a/src/sage/modules/fp_graded/free_homspace.py +++ b/src/sage/modules/fp_graded/free_homspace.py @@ -1,20 +1,16 @@ r""" The set of homomorphisms of finitely generated free graded left modules -This class implements methods for construction and basic manipulation -of homsets of finitely generated free graded left modules over a -connected graded `k`-algebra, where `k` is a field. - For an overview of the free module API, see :doc:`free_module`. -TESTS:: +EXAMPLES:: sage: from sage.modules.fp_graded.free_module import FreeGradedModule - sage: from sage.misc.sage_unittest import TestSuite sage: A = SteenrodAlgebra(2) sage: F1 = FreeGradedModule(A, (1,3)) sage: F2 = FreeGradedModule(A, (2,3)) - sage: homset = Hom(F1, F2); homset + sage: homset = Hom(F1, F2) + sage: homset Set of Morphisms from Finitely presented free left module on 2 generators ... sage: homset([F2((Sq(1), 1)), F2((0, Sq(2)))]) Module homomorphism of degree 2 defined by sending the generators @@ -33,7 +29,7 @@ """ #***************************************************************************** -# Copyright (C) 2011 Robert R. Bruner and +# Copyright (C) 2021 Robert R. Bruner and # Michael J. Catanzaro # # This program is free software: you can redistribute it and/or modify @@ -48,6 +44,9 @@ class FreeGradedModuleHomspace(Homset): + """ + Homspace between two free graded modules. + """ # In the category framework, Elements of the class FPModule are of the # class FPElement, see # http://doc.sagemath.org/html/en/thematic_tutorials/coercion_and_categories.html#implementing-the-category-framework-for-the-elements @@ -57,20 +56,21 @@ class FreeGradedModuleHomspace(Homset): def _element_constructor_(self, values): r""" - Construct any element of this homset. + Construct an element of ``self``. - This function is used internally by the ()-method when creating + This function is used internally by the call method when creating homomorphisms. INPUT: - - ``values`` -- A tuple of values (i.e. elements of the - codomain for this homset) corresponding bijectively to the generators - of the domain of this homset, or the zero integer constant. + - ``values`` -- a tuple of values (i.e. elements of the + codomain for this homset) corresponding bijectively to the generators + of the domain of this homset, or the zero integer constant + + OUTPUT: - OUTPUT: An instance of the morphism class. The returned morphism is - defined by mapping the module generators in the domain to the given - values. + An instance of the morphism class. The returned morphism is defined + by mapping the module generators in the domain to the given values. EXAMPLES:: @@ -88,7 +88,7 @@ def _element_constructor_(self, values): [, <0, Sq(3)>] sage: H(0) - The trivial homomorphism. + The trivial homomorphism """ from .free_morphism import FreeGradedModuleMorphism if isinstance(values, FreeGradedModuleMorphism): @@ -101,9 +101,7 @@ def _element_constructor_(self, values): def _an_element_(self): r""" - Return a morphism belonging to this homspace. - - OUTPUT: A morphism in this homspace. + Return a morphism belonging to ``self``. EXAMPLES:: @@ -113,7 +111,7 @@ def _an_element_(self): sage: L = FreeGradedModule(A2, (2,3)) sage: H = Hom(F, L) sage: H._an_element_() - The trivial homomorphism. + The trivial homomorphism """ return self.zero() @@ -121,10 +119,7 @@ def _an_element_(self): @cached_method def zero(self): r""" - Return the trivial morphism of this homspace. - - OUTPUT: The morphism evaluating to the zero element for any element in - the domain. + Return the trivial morphism of ``self``. EXAMPLES:: @@ -134,16 +129,14 @@ def zero(self): sage: L = FreeGradedModule(A2, (2,3)) sage: H = Hom(F, L) sage: H.zero() - The trivial homomorphism. + The trivial homomorphism """ return self.element_class(self, self.codomain().zero()) def identity(self): r""" - Return the identity morphism, if this is an endomorphism set. - - OUTPUT: The identity endomorphism. + Return the identity morphism, if ``self`` is an endomorphism set. EXAMPLES:: @@ -152,7 +145,7 @@ def identity(self): sage: L = FreeGradedModule(A2, (2,3)) sage: H = Hom(L, L) sage: H.identity() - The identity homomorphism. + The identity homomorphism TESTS:: diff --git a/src/sage/modules/fp_graded/free_module.py b/src/sage/modules/fp_graded/free_module.py index 2cdc696b243..84f4cf4b8af 100755 --- a/src/sage/modules/fp_graded/free_module.py +++ b/src/sage/modules/fp_graded/free_module.py @@ -1,13 +1,5 @@ r""" -Finitely generated free graded left modules over connected graded algebras. - -This class implements methods for construction and basic manipulation -of finitely generated free graded modules over connected graded -algebras with a given graded basis. - -========== -User guide -========== +Finitely generated free graded left modules over connected graded algebras Let `p` be a prime number. The mod `p` Steenrod algebra `A_p` is a connected algebra over the finite field of `p` elements. All modules @@ -16,16 +8,19 @@ sage: A = SteenrodAlgebra(p=2) -The constructor of the module class takes as arguments the algebra -over which the module is defined and an ordered tuple of degrees for -the generators:: +However, the current implementation can use any connected graded algebra +that has a graded basis where each graded part is finite dimensional. + +A free module is defined by the graded algebra and an ordered tuple +of degrees for the generators:: sage: from sage.modules.fp_graded.free_module import FreeGradedModule - sage: M = FreeGradedModule(algebra=A, generator_degrees=(0,1)); M - Finitely presented free left module on 2 generators over mod 2 Steenrod algebra, milnor basis + sage: M = FreeGradedModule(algebra=A, generator_degrees=(0,1)) + sage: M + Finitely presented free left module on 2 generators over + mod 2 Steenrod algebra, milnor basis -The resulting free module will have generators in the degrees given to its -constructor:: +The resulting free module will have generators in the degrees as specified:: sage: M.generator_degrees() (0, 1) @@ -37,7 +32,6 @@ sage: M.connectivity() 0 ---------------- Module elements --------------- @@ -64,16 +58,15 @@ sage: M.generators() [<1, 0>, <0, 1>] -Producing elements from a given set of coefficients is possible using the -module class ()-method:: +Producing elements from a given set of coefficients is possible as usual:: - sage: coeffs=[Sq(5), Sq(1,1)] + sage: coeffs = [Sq(5), Sq(1,1)] sage: x = M(coeffs); x The module action produces new elements:: - sage: Sq(2)*x + sage: Sq(2) * x Each non-zero element has a well-defined degree:: @@ -81,7 +74,7 @@ sage: x.degree() 5 -But the zero element has not:: +However the zero element does not:: sage: zero = M.zero(); zero 0 @@ -133,7 +126,7 @@ sage: x_ == x True --------------------- + Module homomorphisms -------------------- @@ -146,7 +139,12 @@ sage: M = FreeGradedModule(A, (0,1)) sage: N = FreeGradedModule(A, (2,)) sage: homspace = Hom(M, N); homspace - Set of Morphisms from Finitely presented free left module on 2 generators over mod 2 Steenrod algebra, milnor basis to Finitely presented free left module on 1 generator over mod 2 Steenrod algebra, milnor basis in Category of finite dimensional graded modules with basis over mod 2 Steenrod algebra, milnor basis + Set of Morphisms from Finitely presented free left module on 2 generators + over mod 2 Steenrod algebra, milnor basis + to Finitely presented free left module on 1 generator + over mod 2 Steenrod algebra, milnor basis + in Category of finite dimensional graded modules with basis + over mod 2 Steenrod algebra, milnor basis Just as module elements, homomorphisms are created using the ()-method of the homspace object. The only argument is a list of module elements in the @@ -168,12 +166,12 @@ Convenience methods exist for creating the trivial morphism:: sage: homspace.zero() - The trivial homomorphism. + The trivial homomorphism as well as the identity endomorphism:: sage: Hom(M, M).identity() - The identity homomorphism. + The identity homomorphism Homomorphisms can be evaluated on elements of the domain module:: @@ -221,7 +219,7 @@ Finally, additive inverses exist:: sage: f - f - The trivial homomorphism. + The trivial homomorphism The restriction of a homomorphism to the vector space of `n`-dimensional module elements is a linear transformation:: @@ -284,10 +282,10 @@ class FreeGradedModule(CombinatorialFreeModule): INPUT: - ``algebra`` -- the graded connected algebra over which the module is - defined. This algebra must be equipped with a graded basis. + defined; this algebra must be equipped with a graded basis - ``generator_degrees`` -- tuple of integers defining the number - of generators of the module, and their degrees. + of generators of the module, and their degrees TESTS:: @@ -295,7 +293,8 @@ class FreeGradedModule(CombinatorialFreeModule): sage: E. = ExteriorAlgebra(QQ) sage: M = FreeGradedModule(E, (-1,3)) sage: M - Finitely presented free left module on 2 generators over The exterior algebra of rank 3 over Rational Field + Finitely presented free left module on 2 generators over + The exterior algebra of rank 3 over Rational Field sage: M.generator_degrees() (-1, 3) sage: a, b = M.generators() @@ -304,16 +303,14 @@ class FreeGradedModule(CombinatorialFreeModule): sage: A = SteenrodAlgebra(2) sage: FreeGradedModule(A, (-2,2,4)) - Finitely presented free left module on 3 generators over mod 2 Steenrod algebra, milnor basis + Finitely presented free left module on 3 generators over + mod 2 Steenrod algebra, milnor basis """ def __init__(self, algebra, generator_degrees): r""" Create a finitely generated free graded module over a connected graded algebra. - OUTPUT: The finitely generated free graded module on generators with - degrees given by ``generator_degrees``. - TESTS:: sage: from sage.modules.fp_graded.free_module import FreeGradedModule @@ -329,11 +326,12 @@ def __init__(self, algebra, generator_degrees): raise ValueError('the ground ring of the algebra must be a field') # Call the base class constructor. + cat = GradedModules(algebra).WithBasis().FiniteDimensional() CombinatorialFreeModule.__init__(self, algebra, basis_keys=keys, - element_class=FreeGradedModuleElement, - category=GradedModules(algebra).WithBasis().FiniteDimensional()) + category=cat) + Element = FreeGradedModuleElement def generator_degrees(self): r""" @@ -375,9 +373,11 @@ def is_trivial(self): def connectivity(self): r""" - The connectivity of this module. + The connectivity of ``self``. + + OUTPUT: - OUTPUT: An integer equal to the minimal degree of all the generators, if + An integer equal to the minimal degree of all the generators, if this module is non-trivial. Otherwise, `+\infty`. EXAMPLES:: @@ -401,20 +401,19 @@ def connectivity(self): def _element_constructor_(self, coefficients): r""" - Construct any element of the module. - - This function is used internally by the ()-method when creating - module elements, and should not be called by the user explicitly. + Construct any element of ``self``. INPUT: - - ``coefficients`` -- A tuple of coefficient (i.e. elements of the - algebra for this module), an element of FreeGradedModule, or the zero integer - constant. + - ``coefficients`` -- a tuple of coefficient (i.e. elements of the + algebra for this module), an element of FreeGradedModule, or the + zero integer constant + + OUTPUT: - OUTPUT: An instance of the element class with coefficients from - ``coefficients``, the element ``coefficients`` if it already was an - element, or the zero module element. + An instance of the element class with coefficients from + ``coefficients``, the element ``coefficients`` if it already + was an element, or the zero module element. EXAMPLES:: @@ -433,26 +432,27 @@ def _element_constructor_(self, coefficients): """ if isinstance(coefficients, self.element_class): return coefficients - elif not coefficients: + if not coefficients: return self.zero() - else: - B = self.basis() - return sum(c*B[b] for (c,b) in zip(coefficients, self._generator_keys)) + + B = self.basis() + return sum(c * B[b] for (c,b) in zip(coefficients, self._generator_keys)) def an_element(self, n=None): r""" - Return an element of the module. + Return an element of ``self``. - This function chooses deterministically an element of the module in the - given degree. + This function chooses deterministically an element of the module + in the given degree. INPUT: - - ``n`` -- the degree of the element to construct. If the default - value ``None`` is given, a degree will be chosen by the function. + - ``n`` -- (optional) the degree of the element to construct + + OUTPUT: - OUTPUT: An element of the given degree. + An element (of the given degree if specified). EXAMPLES:: @@ -491,7 +491,7 @@ def an_element(self, n=None): def _repr_(self): r""" - Construct a string representation of the module. + Construct a string representation of ``self``. TESTS:: @@ -509,19 +509,24 @@ def _repr_(self): @cached_method def basis_elements(self, n): r""" - A basis for the vector space of degree ``n`` module elements. - This returns a basis as a vector space over the base field, - not a basis as a free module over the algebra. + Return a basis for the vector space of degree ``n`` module elements. + + .. NOTE:: + + This returns a basis as a vector space over the base field, + not a basis as a free module over the algebra. INPUT: - - ``n`` -- an integer. + - ``n`` -- an integer + + OUTPUT: - OUTPUT: A sequence of homogeneous module elements of degree ``n`` - which is a basis for the vector space of all degree ``n`` module - elements. + A sequence of homogeneous module elements of degree ``n``, which + is a basis for the vector space of all degree ``n`` module elements. .. SEEALSO:: + :meth:`vector_presentation`, :meth:`element_from_coordinates` EXAMPLES:: @@ -557,12 +562,15 @@ def element_from_coordinates(self, coordinates, n): INPUT: - - ``coordinates`` -- a sequence of elements of the ground field. - - ``n`` -- an integer. + - ``coordinates`` -- a sequence of elements of the ground field + - ``n`` -- an integer + + OUTPUT: - OUTPUT: A module element of degree ``n``. + A module element of degree ``n``. .. SEEALSO:: + :meth:`vector_presentation`, and :meth:`basis_elements`. EXAMPLES:: @@ -583,8 +591,8 @@ def element_from_coordinates(self, coordinates, n): basis_elements = self.basis_elements(n) if len(coordinates) != len(basis_elements): - raise ValueError('the given coordinate vector has incorrect length: %d. ' - 'It should have length %d' % (len(coordinates), len(basis_elements))) + raise ValueError('the given coordinate vector has incorrect length (%d); ' + 'it should have length %d' % (len(coordinates), len(basis_elements))) # Adding the condition `if c != 0` improved performance dramatically in this # real life example: @@ -601,15 +609,16 @@ def element_from_coordinates(self, coordinates, n): # and the total running time of the entire computation dropped from # 57 to 21 seconds by adding the optimization. # - element = sum([c*element for c, element in zip(coordinates, basis_elements) if c != 0]) - if element == 0: + element = sum(c*element for c, element in zip(coordinates, basis_elements) if c) + + if not element: # The previous sum was over the empty list, yielding the integer # 0 as a result, rather than a module element. # Fix this by returning the zero element. return self.zero() - else: - # The sum defining element is of the correct type, so return it. - return element + + # The sum defining element is of the correct type, so return it. + return element def __getitem__(self, n): @@ -628,6 +637,7 @@ def __getitem__(self, n): 4 .. SEEALSO:: + This function is an alias for :meth:`vector_presentation`. """ return self.vector_presentation(n) @@ -636,11 +646,12 @@ def __getitem__(self, n): @cached_method def vector_presentation(self, n): r""" - A vector space over the ground field of the module algebra, - isomorphic to the degree ``n`` elements of this module. + Return a vector space over the ground field of the module algebra + isomorphic to the degree ``n`` elements of ``self``. - Let `\mathcal{k}` be the ground field of the algebra over this module is defined, - and let `M_n` be the vector space of module elements of degree ``n``. + Let `\mathcal{k}` be the ground field of the algebra over this module + is defined, and let `M_n` be the vector space of module elements of + degree ``n``. The return value of this function is the vector space `\mathcal{k}^{r}` where `r = dim(M_n)`. @@ -651,13 +662,16 @@ def vector_presentation(self, n): INPUT: - - ``n`` -- an integer degree. + - ``n`` -- an integer degree - OUTPUT: A vector space over the ground field of the algebra over which - this module is defined, isomorphic to the vector space of module + OUTPUT: + + A vector space over the ground field of the algebra over which + ``self`` is defined, isomorphic to the vector space of module elements of degree ``n``. .. SEEALSO:: + :meth:`basis_elements`, :meth:`element_from_coordinates` EXAMPLES:: @@ -680,8 +694,6 @@ def generator(self, index): r""" Return the module generator with the given index. - OUTPUT: An instance of the element class of this parent. - EXAMPLES:: sage: from sage.modules.fp_graded.free_module import * @@ -697,8 +709,8 @@ def generator(self, index): try: return self.monomial(self._generator_keys[index]) except IndexError: - raise ValueError('the parent module has generators in the index '\ - 'range [0, %s]; generator %s does not exist' %\ + raise ValueError('the parent module has generators in the index ' + 'range [0, %s]; generator %s does not exist' % (len(self.generator_degrees()) - 1, index)) @@ -706,9 +718,6 @@ def generators(self): r""" Return all the module generators. - OUTPUT: A list consisting instances of the element class of this - parent. - EXAMPLES:: sage: from sage.modules.fp_graded.free_module import * @@ -723,8 +732,8 @@ def generators(self): def _Hom_(self, Y, category): r""" The internal hook used by the free function - :meth:`sage.categories.homset.hom.Hom` to create homsets involving this - parent. + :meth:`sage.categories.homset.hom.Hom` to create homsets + involving ``self``. TESTS:: @@ -732,7 +741,12 @@ def _Hom_(self, Y, category): sage: A = SteenrodAlgebra(2) sage: M = FreeGradedModule(A, (0,1)) sage: M._Hom_(M, category=None) - Set of Morphisms from Finitely presented free left module on 2 generators over mod 2 Steenrod algebra, milnor basis to Finitely presented free left module on 2 generators over mod 2 Steenrod algebra, milnor basis in Category of finite dimensional graded modules with basis over mod 2 Steenrod algebra, milnor basis + Set of Morphisms from Finitely presented free left module on 2 generators + over mod 2 Steenrod algebra, milnor basis + to Finitely presented free left module on 2 generators + over mod 2 Steenrod algebra, milnor basis + in Category of finite dimensional graded modules with basis + over mod 2 Steenrod algebra, milnor basis """ from .free_homspace import FreeGradedModuleHomspace return FreeGradedModuleHomspace(self, Y, category) @@ -740,13 +754,15 @@ def _Hom_(self, Y, category): def suspension(self, t): r""" - Suspend the module by the given integer degree. + Suspend ``self`` by the given degree ``t``. INPUT: - - ``t`` -- An integer. + - ``t`` -- an integer - OUTPUT: A module which is isomorphic to this module by a shift + OUTPUT: + + A module which is isomorphic to this module by a shift of degrees by the integer ``t``. EXAMPLES:: @@ -765,9 +781,11 @@ def suspension(self, t): def to_fp_module(self): """ - Create a finitely presented module from this free module. + Create a finitely presented module from ``self``. + + OUTPUT: - OUTPUT: the finitely presented module having same set of generators + The finitely presented module having same set of generators as this module, no relations. EXAMPLES:: @@ -776,10 +794,11 @@ def to_fp_module(self): sage: A = SteenrodAlgebra(2) sage: F = FreeGradedModule(A, (-2,2,4)) sage: F.to_fp_module() - Finitely presented left module on 3 generators and 0 relations over mod 2 Steenrod algebra, milnor basis + Finitely presented left module on 3 generators and 0 relations over + mod 2 Steenrod algebra, milnor basis """ from .module import FPModule return FPModule(algebra=self.base_ring(), - generator_degrees=self.generator_degrees(), - relations=()) - + generator_degrees=self.generator_degrees(), + relations=()) + diff --git a/src/sage/modules/fp_graded/free_morphism.py b/src/sage/modules/fp_graded/free_morphism.py index adbcd3b6e11..8ead453daf3 100755 --- a/src/sage/modules/fp_graded/free_morphism.py +++ b/src/sage/modules/fp_graded/free_morphism.py @@ -1,12 +1,6 @@ r""" Homomorphisms of finitely generated free graded left modules -This class implements construction and basic manipulation of elements -of the Sage parent -:class:`sage.modules.fp_graded.free_homspace.FreeGradedModuleHomspace`, -which models homomorphisms of free graded left modules over connected -algebras. - For an overview of the free module API, see :doc:`free_module`. AUTHORS: @@ -29,8 +23,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from __future__ import absolute_import - from inspect import isfunction from sage.categories.homset import Hom @@ -43,11 +35,11 @@ class FreeGradedModuleMorphism(Morphism): INPUT: - - ``parent`` -- A homspace in the category of finitely generated free - modules. + - ``parent`` -- a homspace in the category of finitely generated free + modules - - ``values`` -- A list of elements in the codomain. Each element - corresponds (by their ordering) to a module generator in the domain. + - ``values`` -- a list of elements in the codomain; each element + corresponds (by their ordering) to a module generator in the domain EXAMPLES:: @@ -82,10 +74,7 @@ class FreeGradedModuleMorphism(Morphism): def __init__(self, parent, values): r""" - Create a homomorphism between finitely generated free graded modules. - - OUTPUT: A module homomorphism defined by sending each - generator to its corresponding value. + Initialize ``self``. TESTS:: @@ -102,7 +91,6 @@ def __init__(self, parent, values): if not isinstance(parent, FreeGradedModuleHomspace): raise TypeError('the parent (%s) must be a f.p. free module homset' % parent) - # Get the values. C = parent.codomain() D = parent.domain() @@ -115,8 +103,8 @@ def __init__(self, parent, values): # Check the homomorphism is well defined. if len(D.generator_degrees()) != len(_values): - raise ValueError('the number of values must equal the number of '\ - 'generators in the domain. Invalid argument: %s' % _values) + raise ValueError('the number of values must equal the number of ' + 'generators in the domain; invalid argument: %s' % _values) # Compute the degree. if all(v.is_zero() for v in _values): @@ -142,9 +130,11 @@ def __init__(self, parent, values): def degree(self): r""" - The degree of this homomorphism. + The degree of ``self``. - OUTPUT: The degree of this homomorphism. Raise an error if this is + OUTPUT: + + The degree of this homomorphism. Raise an error if this is the trivial homomorphism. EXAMPLES:: @@ -173,10 +163,12 @@ def degree(self): def values(self): r""" - The values under this homomorphism corresponding to the generators of + The values under ``self`` corresponding to the generators of the domain module. - OUTPUT: A sequence of elements of the codomain module. + OUTPUT: + + A sequence of elements of the codomain module. EXAMPLES:: @@ -198,18 +190,6 @@ def _richcmp_(self, other, op): r""" Compare this homomorphism to the given homomorphism. - INPUT: - - - ``other`` -- An instance of this class. - - - ``op`` -- An integer specifying the comparison operation to be - carried out: If ``op`` == 2, then return ``True`` if and only if the - homomorphisms are equal. If ``op`` == 3, then return ``True `` if - and only if the homomorphisms are not equal. Otherwise, - return ``False``. - - OUTPUT: A boolean. - EXAMPLES:: sage: from sage.modules.fp_graded.free_module import FreeGradedModule @@ -223,7 +203,6 @@ def _richcmp_(self, other, op): sage: f._richcmp_(f, op=3) False """ - try: same = (self - other).is_zero() except ValueError: @@ -242,19 +221,15 @@ def _richcmp_(self, other, op): def _add_(self, g): r""" - The pointwise sum of this and the given homomorphism. + The pointwise sum of `self`` and ``g``. - Pointwise addition of two homomorphisms `f` and `g` with the same domain - and codomain is given by the formula `(f+g)(x) = f(x) + g(x)` for - every `x` in the domain of `f`. + Pointwise addition of two homomorphisms `f` and `g` with the same + domain and codomain is given by the formula `(f+g)(x) = f(x) + g(x)` + for every `x` in the domain of `f`. INPUT: - - ``g`` -- A homomorphism with the same domain and codomain as this - homomorphism. - - OUTPUT: The pointwise sum homomorphism of this and the given - homomorphism. + - ``g`` -- a homomorphism with the same domain and codomain as ``self`` EXAMPLES:: @@ -290,11 +265,9 @@ def _add_(self, g): def _neg_(self): r""" - The additive inverse of this homomorphism with respect to the group + The additive inverse of ``self`` with respect to the group structure given by pointwise sum. - OUTPUT: An instance of this class. - EXAMPLES:: sage: from sage.modules.fp_graded.free_module import FreeGradedModule @@ -316,9 +289,7 @@ def _neg_(self): def _sub_(self, g): r""" - The pointwise difference between this and the given homomorphism. - - OUTPUT: An instance of this class. + The pointwise difference between ``self`` and ``g``. EXAMPLES:: @@ -331,7 +302,7 @@ def _sub_(self, g): sage: values2 = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] sage: g = homspace(values2) sage: f - g - The trivial homomorphism. + The trivial homomorphism """ return self + (-g) @@ -340,11 +311,7 @@ def _sub_(self, g): # "multiplication" by morphisms from different homsets. def __mul__(self, g): r""" - The composition of the given homomorphism ``g``, followed by this - homomorphism. - - OUTPUT: A homomorphism from the domain of this homomorphism, into the - codomain of the homomorphism ``g``. + The composition of ``g`` followed by ``self``. EXAMPLES:: @@ -386,9 +353,11 @@ def __mul__(self, g): def is_zero(self): r""" - Decide if this homomomorphism is trivial. + Decide if ``self`` is trivial. + + OUTPUT: - OUTPUT: The boolean value ``True`` if this homomorphism is trivial, and + The boolean value ``True`` if this homomorphism is trivial, and ``False`` otherwise. EXAMPLES:: @@ -406,13 +375,17 @@ def is_zero(self): """ return all(v.is_zero() for v in self.values()) + __bool__ = is_zero + def is_identity(self): r""" - Decide if this homomomorphism is the identity endomorphism. + Return if ``self`` is the identity endomorphism. + + OUTPUT: - OUTPUT: The boolean value ``True`` if this homomorphism is the - identity, and ``False`` otherwise. + The boolean value ``True`` if this homomorphism is the identity + and ``False`` otherwise. EXAMPLES:: @@ -425,15 +398,12 @@ def is_identity(self): sage: f.is_identity() False sage: id = Hom(M, M)(M.generators()); id - The identity homomorphism. + The identity homomorphism sage: id.is_identity() True """ - if self.parent().is_endomorphism_set(): - return self.parent().identity() == self - else: - return False - + return (self.parent().is_endomorphism_set() and + self.parent().identity() == self) def __call__(self, x): r""" @@ -441,9 +411,11 @@ def __call__(self, x): INPUT: - - ``x`` -- An element of the domain of this morphism. + - ``x`` -- an element of the domain of this morphism + + OUTPUT: - OUTPUT: The module element of the codomain which is the value of ``x`` + The module element of the codomain which is the value of ``x`` under this homomorphism. EXAMPLES:: @@ -462,15 +434,15 @@ def __call__(self, x): if x.parent() != self.domain(): raise ValueError('cannot evaluate morphism on element not in the domain') - value = sum([c*v for c, v in zip( - x.dense_coefficient_list(), self.values())], self.codomain()(0)) + value = sum((c * v for c, v in zip(x.dense_coefficient_list(), self.values())), + self.codomain().zero()) return value def _repr_(self): r""" - A string representation of this homomorphism. + A string representation of ``self``. EXAMPLES:: @@ -481,18 +453,19 @@ def _repr_(self): sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] sage: Hom(M, N)(values)._repr_() - 'Module homomorphism of degree 7 defined by sending the generators\n [<1, 0>, <0, 1>]\nto\n [, ]' + 'Module homomorphism of degree 7 defined by sending the generators\n + [<1, 0>, <0, 1>]\nto\n [, ]' sage: Hom(M, N).zero()._repr_() - 'The trivial homomorphism.' + 'The trivial homomorphism' sage: Hom(M, M).identity()._repr_() - 'The identity homomorphism.' + 'The identity homomorphism' """ if self.is_zero(): - return "The trivial homomorphism." + return "The trivial homomorphism" elif self.is_identity(): - return "The identity homomorphism." + return "The identity homomorphism" else: r = "Module homomorphism of degree {} defined by sending the generators\n {}\nto\n {}" return r.format(self.degree(), self.domain().generators(), self.values()) @@ -500,8 +473,7 @@ def _repr_(self): def vector_presentation(self, n): r""" - The restriction of this homomorphism to the domain module elements of - degree ``n``. + The restriction of ``self`` to the domain module elements of degree ``n``. The restriction of a non-zero module homomorphism to the vector space of module elements of degree `n` is a linear function into the vector space @@ -514,9 +486,11 @@ def vector_presentation(self, n): INPUT: - - ``n`` -- An integer degree. + - ``n`` -- an integer degree - OUTPUT: A linear function of finite dimensional vector spaces over the + OUTPUT: + + A linear function of finite dimensional vector spaces over the ground field of the algebra for this module. The domain is isomorphic to the vector space of domain elements of degree ``n`` of this free module, via the choice of basis given by @@ -579,10 +553,11 @@ def vector_presentation(self, n): def to_fp_module(self): r""" - Create a finitely presented module from this morphism. + Create a finitely presented module from ``self``. + + OUTPUT: - OUTPUT: The finitely presented module having presentation - equal to this morphism. + The finitely presented module with presentation equal to ``self``. EXAMPLES:: @@ -593,7 +568,8 @@ def to_fp_module(self): sage: v = F2([Sq(2)]) sage: pres = Hom(F1, F2)([v]) sage: M = pres.to_fp_module(); M - Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis + Finitely presented left module on 1 generator and 1 relation over + mod 2 Steenrod algebra, milnor basis sage: M.generator_degrees() (0,) sage: M.relations() @@ -603,3 +579,4 @@ def to_fp_module(self): return FPModule(algebra=self.base_ring(), generator_degrees=self.codomain().generator_degrees(), relations=tuple([r.dense_coefficient_list() for r in self.values()])) + diff --git a/src/sage/modules/fp_graded/homspace.py b/src/sage/modules/fp_graded/homspace.py index 002fee86db5..c271fe0a9a1 100755 --- a/src/sage/modules/fp_graded/homspace.py +++ b/src/sage/modules/fp_graded/homspace.py @@ -5,9 +5,6 @@ manipulation of homsets of finitely presented graded modules over a connected graded `k`-algebra, where `k` is a field. -.. NOTE:: This class is intended for private use by - :class:`sage.modules.fp_steenrod.fpa_homspace.FPA_ModuleHomspace`. - TESTS:: sage: from sage.modules.fp_graded.module import FPModule @@ -72,16 +69,18 @@ class FPModuleHomspace(Homset): def _element_constructor_(self, values): r""" - Constructs a morphism contained in this homset. + Construct a morphism contained in ``self``. - This function is not part of the public API, but is used by :meth:Hom - method to create morphisms. + This function is not part of the public API, but is used by + :meth:`Hom` method to create morphisms. INPUT: - - ``values`` -- An iterable of FPElements of the codomain. + - ``values`` -- an iterable of FPElements of the codomain + + OUTPUT: - OUTPUT: A module homomorphism in this homspace sending the generators + A module homomorphism in this homspace sending the generators of the domain module to the given values. EXAMPLES:: @@ -97,7 +96,7 @@ def _element_constructor_(self, values): sage: f = homset._element_constructor_([v1, v2]) Rather than calling ``_element_constructor_`` explicitly, one - can call it implicitly, using the ``call`` syntax:: + should call it implicitly using the syntax:: sage: f = homset([v1, v2]); f Module homomorphism of degree 2 defined by sending the generators @@ -114,7 +113,7 @@ def _element_constructor_(self, values): And there is a convenient way of making the trivial homomorphism:: sage: z = homset(0); z - The trivial homomorphism. + The trivial homomorphism """ if isinstance(values, self.element_class): return values @@ -126,13 +125,15 @@ def _element_constructor_(self, values): def an_element(self, n=0): r""" - Create a homomorphism belonging to this homset. + Create a homomorphism belonging to ``self``. INPUT: - - ``n`` -- an integer degree. (optional, default: 0) + - ``n`` -- (default: 0) an integer degree + + OUTPUT: - OUTPUT: A module homomorphism of degree ``n``. + A module homomorphism of degree ``n``. EXAMPLES:: @@ -171,9 +172,11 @@ def basis_elements(self, n): INPUT: - - ``n`` -- an integer degree. + - ``n`` -- an integer degree - OUTPUT: A basis for the set of all module homomorphisms of degree ``n``. + OUTPUT: + + A basis for the set of all module homomorphisms of degree ``n``. EXAMPLES:: @@ -196,7 +199,7 @@ def basis_elements(self, n): def zero(self): r""" - Create the trivial homomorphism in this homset. + Create the trivial homomorphism in ``self``. EXAMPLES:: @@ -206,20 +209,20 @@ def zero(self): sage: L = FPModule(A2, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]) sage: z = Hom(F, L).zero(); z - The trivial homomorphism. + The trivial homomorphism sage: z(F.an_element(5)) 0 - sage: z(F.an_element(23)) 0 """ - return self.element_class(self, [self.codomain().zero() for g in self.domain().generator_degrees()]) + ngens = len(self.domain().generator_degrees()) + return self.element_class(self, [self.codomain().zero()] * ngens) def identity(self): r""" - Create the identity homomorphism. + Create The identity homomorphism EXAMPLES:: @@ -228,7 +231,7 @@ def identity(self): sage: L = FPModule(A2, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]) sage: id = Hom(L, L).identity(); id - The identity homomorphism. + The identity homomorphism sage: e = L.an_element(5) sage: e == id(e) @@ -253,19 +256,21 @@ def _basis_elements(self, n, basis): r""" Compute a basis for the vector space of degree ``n`` homomorphisms. - This function is private and used by :meth:`basis_elements` and + This function is private for use by :meth:`basis_elements` and :meth:`an_element`. INPUT: - - ``n`` -- an integer degree. - - ``basis`` -- boolean to decide if a basis should be returned, or just - a single homomorphism. + - ``n`` -- an integer degree + - ``basis`` -- boolean; decide if a basis should be returned or just + a single homomorphism + + OUTPUT: - OUTPUT: A basis for the set of all module homomorphisms of degree ``n`` - if ``basis`` is True. Otherwise a single element is returned. In the - latter case, this homomorphism is non-trivial if the vector space of all - homomorphisms is non-trivial. + A basis for the set of all module homomorphisms of degree ``n`` + if ``basis`` is ``True``. Otherwise a single element is returned. + In the latter case, this homomorphism is non-trivial if the vector + space of all homomorphisms is non-trivial. TESTS:: @@ -302,9 +307,9 @@ def _basis_elements(self, n, basis): [] Hom(FPA_Module([0], A, [[Sq(1)]]), FPA_Module([-2], A, [[Sq(1)]])).an_element(0) - The trivial homomorphism. + The trivial homomorphism - Test corner cases involving trivial modules: + Test corner cases involving trivial modules:: sage: F = FPModule(A, [0]) # A module without relations. sage: Z0 = FPModule(A, []) # A trivial module. @@ -313,7 +318,7 @@ def _basis_elements(self, n, basis): Hom(FPA_Module([-1], A), F)._basis_elements(0, basis=True) [] Hom(FPA_Module([-1], A), F)._basis_elements(0, basis=False) - The trivial homomorphism. + The trivial homomorphism sage: from itertools import product sage: for D,C in product([(F, 'Free'), (Hko, 'Hko'), (Z0, 'Trivial'), (Z1, 'Trivial with redundant generator')], repeat=2): @@ -353,17 +358,17 @@ def _basis_elements(self, n, basis): []] Hom(Free, Trivial): basis==False: - The trivial homomorphism. + The trivial homomorphism basis==True: [] Hom(Free, Trivial with redundant generator): basis==False: - The trivial homomorphism. + The trivial homomorphism basis==True: [] Hom(Hko, Free): basis==False: - The trivial homomorphism. + The trivial homomorphism basis==True: [] Hom(Hko, Hko): @@ -379,56 +384,56 @@ def _basis_elements(self, n, basis): []] Hom(Hko, Trivial): basis==False: - The trivial homomorphism. + The trivial homomorphism basis==True: [] Hom(Hko, Trivial with redundant generator): basis==False: - The trivial homomorphism. + The trivial homomorphism basis==True: [] Hom(Trivial, Free): basis==False: - The trivial homomorphism. + The trivial homomorphism basis==True: [] Hom(Trivial, Hko): basis==False: - The trivial homomorphism. + The trivial homomorphism basis==True: [] Hom(Trivial, Trivial): basis==False: - The trivial homomorphism. + The trivial homomorphism basis==True: [] Hom(Trivial, Trivial with redundant generator): basis==False: - The trivial homomorphism. + The trivial homomorphism basis==True: [] Hom(Trivial with redundant generator, Free): basis==False: - The trivial homomorphism. + The trivial homomorphism basis==True: [] Hom(Trivial with redundant generator, Hko): basis==False: - The trivial homomorphism. + The trivial homomorphism basis==True: [] Hom(Trivial with redundant generator, Trivial): basis==False: - The trivial homomorphism. + The trivial homomorphism basis==True: [] Hom(Trivial with redundant generator, Trivial with redundant generator): basis==False: - The trivial homomorphism. + The trivial homomorphism basis==True: [] """ - from .morphism import _CreateRelationsMatrix + from .morphism import _create_relations_matrix M = self.domain() N = self.codomain() @@ -443,7 +448,7 @@ def _trivial_case(): return [] else: # Since the vector space of homomorphisms is trivial, it contains - # only the trivial homomorphism. + # only The trivial homomorphism return self.zero() # Deal with the trivial cases first. Note that this covers the case @@ -473,7 +478,7 @@ def _trivial_case(): # case above. target_degs = [r.degree() + n for r in M.relations()] - block_matrix, R = _CreateRelationsMatrix( + block_matrix, R = _create_relations_matrix( N, [r.coefficients() for r in M.relations()], source_degs, target_degs) ker = R.right_kernel() @@ -494,7 +499,7 @@ def _trivial_case(): # If the code above found a non-trivial homomorphism and ``basis==False``, # it will have terminated by now. - if len(res) == 0: + if not res: return _trivial_case() else: return res diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index 5872b0ee29a..5c9bd2119bd 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -1,25 +1,8 @@ r""" Finitely presented graded modules -This class implements methods for construction and basic manipulation -of finitely presented graded modules over connected graded algebras -with a given graded basis. - -.. NOTE:: This class was designed for use by - :class:`sage.modules.fp_graded.fpa_module.FPA_Module`. - As a consequence, all tests and examples consider modules over the - the Steenrod algebra (or a finite sub-Hopf algebra of it). - - However, this class does not assume that the algebra is the Steenrod - algebra and could be a starting point for developers wanting to extend - Sage further. - -============== -Implementation -============== - Let `R` be a connected graded algebra. A finitely presented module over `R` -is isomorphic to the cokernel of an `R`-linear homomorphism `f:F_1 \to F_0` +is isomorphic to the cokernel of an `R`-linear homomorphism `f: F_1 \to F_0` of finitely generated free modules: The generators of `F_0` corresponds to the generators of the module, and the generators of `F_1` corresponds to its relations, via the map `f`. @@ -31,8 +14,8 @@ This package was designed with homological algebra in mind, and its API focuses on maps rather than objects. A good example of this is the kernel function :meth:`sage.modules.fp_graded.morphism.FPModuleMorphism.kernel` -which computes the kernel of a homomorphism `f: M\to N`. Its return value is -not an instance of the module class, but rather an injective homomorphism +which computes the kernel of a homomorphism `f: M\to N`. Its return value +is not an instance of the module class, but rather an injective homomorphism `i: K\to M` with the property that `\operatorname{im}(i) = \ker(f)`. AUTHORS: @@ -81,20 +64,20 @@ class FPModule(Module, IndexedGenerators, UniqueRepresentation): INPUT: - ``algebra`` -- the graded connected algebra over which the module is - defined. This algebra must be equipped with a graded basis. + defined; this algebra must be equipped with a graded basis - - ``generator_degrees`` -- tuple of integer degrees. + - ``generator_degrees`` -- tuple of integer degrees - - ``relations`` -- tuple of relations. A relation is a tuple of + - ``relations`` -- tuple of relations; a relation is a tuple of coefficients `(c_1, \ldots, c_n)`, ordered so that they - correspond to the module generators. That is, such a tuple + correspond to the module generators, that is, such a tuple corresponds to the relation .. MATH:: c_1 g_1 + \ldots + c_n g_n = 0 - if the generators are `(g_1, \ldots, g_n)`. + if the generators are `(g_1, \ldots, g_n)` EXAMPLES:: @@ -128,45 +111,30 @@ def __classcall_private__(cls, algebra, generator_degrees, relations=()): r""" Normalize input to ensure a unique representation. - INPUT: - - - ``generator_degrees`` -- an iterable of integer degrees. - - - ``algebra`` -- the connected graded algebra over which the module is defined. - - - ``relations`` -- an iterable of relations. A relation is a tuple of - coefficients `(c_1, \ldots, c_n)` corresponding to the module - generators. - - OUTPUT: The finitely presented module with presentation given by - the ``generator_degrees`` and ``relations``. - TESTS:: sage: from sage.modules.fp_graded.module import FPModule sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) sage: FPModule(A3, [0, 1], [[Sq(2), Sq(1)]]) - Finitely presented left module on 2 generators and 1 relation over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] + Finitely presented left module on 2 generators and 1 relation over + sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] """ return super(FPModule, cls).__classcall__(cls, - algebra=algebra, - generator_degrees=tuple(generator_degrees), - relations=tuple([tuple([algebra(x) for x in r]) for r in relations])) + algebra=algebra, + generator_degrees=tuple(generator_degrees), + relations=tuple([tuple([algebra(x) for x in r]) for r in relations])) def __init__(self, algebra, generator_degrees, relations=()): r""" Create a finitely presented module over a connected graded algebra. - OUTPUT: The finitely presented module over ``algebra`` with - presentation given by ``generator_degrees`` and ``relations``. - TESTS:: sage: from sage.modules.fp_graded.module import FPModule sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) sage: M = FPModule(A3, [0, 1], [[Sq(2), Sq(1)]]) - sage: TestSuite(M).run(skip = "_test_elements") + sage: TestSuite(M).run() """ self._generator_degrees = generator_degrees self._relations = relations @@ -176,29 +144,25 @@ def __init__(self, algebra, generator_degrees, relations=()): self._generator_keys = keys # The free module on the generators of the module. - generatorModule = FreeGradedModule(algebra, - generator_degrees) + generator_module = FreeGradedModule(algebra, generator_degrees) # Use the coefficients given for the relations and make module elements # from them. Filter out the zero elements, as they are redundant. - rels = [v for v in [generatorModule(r) for r in relations] if not v.is_zero()] + rels = [v for v in [generator_module(r) for r in relations] if not v.is_zero()] # The free module for the relations of the module. - relationsModule = FreeGradedModule(algebra, - tuple([r.degree() for r in rels])) + relations_module = FreeGradedModule(algebra, + tuple([r.degree() for r in rels])) # The module we want to model is the cokernel of the # following morphism. - self.j = Hom(relationsModule, generatorModule)(rels) + self.j = Hom(relations_module, generator_module)(rels) # Call the base class constructors. cat = GradedModules(algebra).WithBasis().FinitelyPresented() IndexedGenerators.__init__(self, keys) Module.__init__(self, algebra, category=cat) - Parent.__init__(self, base=algebra, category=cat) - - - element_class = FPElement + Element = FPElement def _free_module(self): """ @@ -225,7 +189,7 @@ def from_free_module(cls, free_module): INPUT: - - ``free_module`` -- a finitely generated free module. + - ``free_module`` -- a finitely generated free module OUTPUT: the finitely presented module having same set of generators as ``free_module``, and no relations. @@ -237,7 +201,8 @@ def from_free_module(cls, free_module): sage: A = SteenrodAlgebra(2) sage: F = FreeGradedModule(A, (-2,2,4)) sage: FPModule.from_free_module(F) - Finitely presented left module on 3 generators and 0 relations over mod 2 Steenrod algebra, milnor basis + Finitely presented left module on 3 generators and 0 relations over + mod 2 Steenrod algebra, milnor basis """ return cls(algebra=free_module.base_ring(), generator_degrees=free_module.generator_degrees(), @@ -252,7 +217,7 @@ def from_free_module_morphism(cls, morphism): INPUT: - - ``morphism`` -- a morphism between finitely generated free modules. + - ``morphism`` -- a morphism between finitely generated free modules OUTPUT: @@ -269,7 +234,8 @@ def from_free_module_morphism(cls, morphism): sage: v = F2([Sq(2)]) sage: pres = Hom(F1, F2)([v]) sage: M = FPModule.from_free_module_morphism(pres); M - Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis + Finitely presented left module on 1 generator and 1 relation over + mod 2 Steenrod algebra, milnor basis sage: M.generator_degrees() (0,) sage: M.relations() @@ -286,24 +252,28 @@ def change_ring(self, algebra): INPUT: - - ``algebra`` -- a connected graded algebra. + - ``algebra`` -- a connected graded algebra + + OUTPUT: - OUTPUT: The finitely presented module over ``algebra`` defined with the - exact same number of generators of the same degrees and relations as - this module. + The finitely presented module over ``algebra`` defined with the + exact same number of generators of the same degrees and relations + as ``self``. EXAMPLES:: sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) - sage: A2 = SteenrodAlgebra(2,profile=(3,2,1)) + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) sage: M = FPModule(A, [0,1], [[Sq(2), Sq(1)]]) - sage: M_ = M.change_ring(A2); M_ - Finitely presented left module on 2 generators and 1 relation over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + sage: N = M.change_ring(A2); N + Finitely presented left module on 2 generators and 1 relation over + sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + + Changing back yields the original module:: - sage: # Changing back yields the original module. - sage: M_.change_ring(A) is M + sage: N.change_ring(A) is M True """ # self.relations() consists of module elements. We need to extra the coefficients. @@ -333,7 +303,9 @@ def _from_dict(self, d, coerce=False, remove_zeros=True): Construct an element of ``self`` from an ``{index: coefficient}`` dictionary. - INPUT: ``d``, a dictionary + INPUT: + + - ``d`` -- a dictionary This code is taken from the method of the same name for ``sage.combinat.free_module.FreeModule``. @@ -393,18 +365,20 @@ def monomial(self): def _element_constructor_(self, x): r""" - Construct any element of this module. + Construct any element of ``self``. This function is used internally by the ()-method when creating module elements, and should not be called by the user explicitly. INPUT: - - ``x`` -- A tuple of coefficients, an element of FPModule, or the - zero integer constant. + - ``x`` -- a tuple of coefficients, an element of FPModule, or the + zero integer constant + + OUTPUT: - OUTPUT: An instance of the element class with coefficients from ``x``, - the element ``x`` if it already was an element, or the zero element. + An instance of the element class with coefficients from ``x``, the + element ``x`` if it already was an element, or the zero element. EXAMPLES:: @@ -450,18 +424,21 @@ def _element_constructor_(self, x): def _repr_(self): r""" - Construct a string representation of the module. + Construct a string representation of ``self``. EXAMPLES:: sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) sage: M = FPModule(A, [0,2,4], [[Sq(4),Sq(2),0]]); M - Finitely presented left module on 3 generators and 1 relation over mod 2 Steenrod algebra, milnor basis + Finitely presented left module on 3 generators and 1 relation over + mod 2 Steenrod algebra, milnor basis sage: N = FPModule(A, [0,1], [[Sq(2),Sq(1)], [Sq(2)*Sq(1),Sq(2)]]); N - Finitely presented left module on 2 generators and 2 relations over mod 2 Steenrod algebra, milnor basis + Finitely presented left module on 2 generators and 2 relations over + mod 2 Steenrod algebra, milnor basis sage: F = FPModule(A, [2]); F - Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis + Finitely presented left module on 1 generator and 0 relations over + mod 2 Steenrod algebra, milnor basis """ return "Finitely presented left module on %s generator%s and %s relation%s over %s"\ %(len(self._free_module().generator_degrees()), "" if len(self._free_module().generator_degrees()) == 1 else "s", @@ -471,7 +448,7 @@ def _repr_(self): def connectivity(self): r""" - The connectivity of this module. + The connectivity of ``self``. Since a finitely presented module over a connected algebra is in particular bounded below, the connectivity is an integer when the @@ -516,8 +493,7 @@ def connectivity(self): # We must check that the generator(s) in the free generator module are # not hit by relations, since we are not guaranteed that the # presentation we have is minimal. - X = [x for x in self.generator_degrees()] - X.sort() + X = sorted(x for x in self.generator_degrees()) previous = None for k in X: @@ -609,15 +585,16 @@ def an_element(self, n=None): r""" An element of this module. - This function chooses deterministically an element, i.e the output + This function chooses deterministically an element, i.e. the output depends only on the module and its input ``n``. INPUT: - - ``n`` -- The degree of the element to construct. If the default - value ``None`` is given, a degree will be chosen by the function. + - ``n`` -- (optional) the degree of the element to construct + + OUTPUT: - OUTPUT: A module element of the given degree. + A module element of the given degree. EXAMPLES:: @@ -650,12 +627,13 @@ def basis_elements(self, n, verbose=False): INPUT: - - ``n`` -- an integer. + - ``n`` -- an integer + - ``verbose`` -- (default: ``False``) a boolean to control if log + messages should be emitted - - ``verbose`` -- A boolean to control if log messages should be emitted. - (optional, default: ``False``) + OUTPUT: - OUTPUT: A list of homogeneous module elements of degree ``n`` which is + A list of homogeneous module elements of degree ``n`` which is a basis for the vector space of all degree ``n`` module elements. .. SEEALSO:: @@ -693,8 +671,8 @@ def basis_elements(self, n, verbose=False): sage: Z1.basis_elements(n=10) [] """ - return [self.element_from_coordinates(x, n) for\ - x in self.vector_presentation(n, verbose).basis()] + return [self.element_from_coordinates(x, n) for + x in self.vector_presentation(n, verbose).basis()] @cached_method @@ -708,11 +686,13 @@ def element_from_coordinates(self, coordinates, n): INPUT: - - ``coordinates`` -- a vector of coordinates. + - ``coordinates`` -- a vector of coordinates + + - ``n`` -- the degree of the element to construct - - ``n`` -- the degree of the element to construct. + OUTPUT: - OUTPUT: A module element of degree ``n`` having the given coordinates + A module element of degree ``n`` having the given coordinates with respect to the basis returned by :meth:`basis_elements`. EXAMPLES:: @@ -736,7 +716,7 @@ def element_from_coordinates(self, coordinates, n): sage: M.element_from_coordinates((0,1,0,0), 12) Traceback (most recent call last): ... - ValueError: the given coordinate vector has incorrect length: 4. It should have length 3 + ValueError: the given coordinate vector has incorrect length (4); it should have length 3 .. SEEALSO:: @@ -745,8 +725,8 @@ def element_from_coordinates(self, coordinates, n): M_n = self.vector_presentation(n) if len(coordinates) != M_n.dimension(): - raise ValueError('the given coordinate vector has incorrect length: %d. ' - 'It should have length %d' % (len(coordinates), M_n.dimension())) + raise ValueError('the given coordinate vector has incorrect length (%d); ' + 'it should have length %d' % (len(coordinates), M_n.dimension())) free_element = self._free_module().element_from_coordinates( M_n.lift(coordinates), n) @@ -760,9 +740,11 @@ def __getitem__(self, n): INPUT: - - ``n`` -- an integer. + - ``n`` -- an integer + + OUTPUT: - OUTPUT: A list of homogeneous module elements of degree ``n`` which is + A list of homogeneous module elements of degree ``n`` which is a basis for the vector space of all degree ``n`` module elements. EXAMPLES:: @@ -789,9 +771,11 @@ def vector_presentation(self, n, verbose=False): INPUT: - - ``n`` -- The degree of the presentation. + - ``n`` -- the degree of the presentation + + OUTPUT: - OUTPUT: A vector space. + A vector space. .. SEEALSO:: @@ -829,7 +813,6 @@ def vector_presentation(self, n, verbose=False): iteration_count = 0 for relation in self.j.values(): - if relation.is_zero(): continue @@ -855,8 +838,8 @@ def vector_presentation(self, n, verbose=False): def _Hom_(self, Y, category): r""" The internal hook used by the free function - :meth:`sage.categories.homset.hom.Hom` to create homsets involving - this parent class. + :meth:`sage.categories.homset.hom.Hom` to create homsets + involving ``self``. TESTS:: @@ -879,7 +862,7 @@ def _Hom_(self, Y, category): def generator_degrees(self): r""" - The degrees of the generators for this module. + The degrees of the generators for ``self``. EXAMPLES:: @@ -895,7 +878,7 @@ def generator_degrees(self): def generators(self): r""" - The generators of this module. + The generators of ``self``. EXAMPLES:: @@ -921,7 +904,7 @@ def generators(self): def generator(self, index): r""" - The module generator with the given index. + Return the module generator with the given index. EXAMPLES:: @@ -943,7 +926,7 @@ def generator(self, index): def relations(self): r""" - The relations of this module. + Return the relations of ``self``. EXAMPLES:: @@ -967,7 +950,7 @@ def relations(self): def relation(self, index): r""" - The module relation of the given index. + Return the module relation of the given index. EXAMPLES:: @@ -982,9 +965,12 @@ def relation(self, index): def min_presentation(self, top_dim=None, verbose=False): r""" - A minimal presentation of this module. + A minimal presentation of ``self``. + + OUTPUT: - OUTPUT: An isomorphism `M \to self`, where `M` has minimal presentation. + An isomorphism `M \to S`, where `M` has minimal presentation + and `S` is ``self``. EXAMPLES:: @@ -1023,13 +1009,15 @@ def min_presentation(self, top_dim=None, verbose=False): def suspension(self, t): r""" - The suspension of this module by the given degree. + The suspension of ``self`` by degree ``t``. INPUT: - - ``t`` -- An integer degree by which the module is suspended. + - ``t`` -- an integer degree by which the module is suspended + + OUTPUT: - OUTPUT: A module which is identical to this module by a shift of + A module which is identical to this module by a shift of degrees by the integer ``t``. EXAMPLES:: @@ -1058,21 +1046,22 @@ def suspension(self, t): sage: Q.generator_degrees() (2, 3) """ - return FPModule( - algebra=self.base_ring(), - generator_degrees=tuple([g + t for g in self.generator_degrees()]), - relations=self._relations) + return FPModule(algebra=self.base_ring(), + generator_degrees=tuple([g + t for g in self.generator_degrees()]), + relations=self._relations) def submodule(self, spanning_elements): r""" - The submodule of this module spanned by the given elements. + Return the submodule of ``self`` spanned by the given elements. INPUT: - - ``spanning_elements`` - An iterable of elements of this module. + - ``spanning_elements`` -- an iterable of elements - OUTPUT: The inclusion of the submodule into this module. + OUTPUT: + + The inclusion of the submodule into this module. EXAMPLES:: @@ -1104,23 +1093,31 @@ def resolution(self, k, top_dim=None, verbose=False): INPUT: - - ``k`` -- An non-negative integer. + - ``k`` -- an non-negative integer + + - ``verbose`` -- (default: ``False``) a boolean to control if + log messages should be emitted + + OUTPUT: - - ``verbose`` -- A boolean to control if log messages should be emitted. - (optional, default: ``False``) + A list of homomorphisms `[\epsilon, f_1, \ldots, f_k]` such that - OUTPUT: A list of homomorphisms `[\epsilon, f_1, \ldots, f_k]` such that + .. MATH:: - `f_i: F_i \to F_{i-1}` for `1, )] sage: for i in range(len(res)-1): - ....: if not (res[i]*res[i+1]).is_zero(): - ....: print('The result is not a complex.') + ....: assert (res[i]*res[i+1]).is_zero(), 'the result is not a complex' """ def _print_progress(i, k): if verbose: @@ -1174,22 +1173,22 @@ def _print_progress(i, k): if k < 0: raise ValueError('the length of the resolution must be non-negative') - complex = [] + ret_complex = [] # Epsilon: F_0 -> M F_0 = FPModule.from_free_module(self._free_module()) epsilon = Hom(F_0, self)(tuple(self.generators())) - complex.append(epsilon) + ret_complex.append(epsilon) if k == 0: - return complex + return ret_complex # f_1: F_1 -> F_0 _print_progress(1, k) F_1 = FPModule.from_free_module(self.j.domain()) pres = Hom(F_1, F_0)(tuple([ F_0(x.coefficients()) for x in self.j.values() ])) - complex.append(pres) + ret_complex.append(pres) from .morphism import FPModuleMorphism @@ -1197,12 +1196,9 @@ def _print_progress(i, k): for i in range(2, k+1): _print_progress(i, k) - f = complex[i-1] - complex.append( - FPModuleMorphism._resolve_kernel( - f, - top_dim=top_dim, - verbose=verbose)) + f = ret_complex[i-1] + ret_complex.append(FPModuleMorphism._resolve_kernel(f, top_dim=top_dim, + verbose=verbose)) - return complex + return ret_complex diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py index 31bcfd841b3..5c84c44e847 100755 --- a/src/sage/modules/fp_graded/morphism.py +++ b/src/sage/modules/fp_graded/morphism.py @@ -1,14 +1,6 @@ r""" Homomorphisms of finitely presented graded modules -This class implements construction and basic manipulation of elements of the -Sage parent :class:`sage.modules.fp_graded.homspace.FPModuleHomspace`, -which models homomorphisms of finitely presented graded modules over connected -algebras. - -.. NOTE:: This class is intended for private use by its derived class - :class:`sage.modules.fp_steenrod.fpa_morphism.FPA_ModuleMorphism`. - AUTHORS: - Robert R. Bruner, Michael J. Catanzaro (2012): Initial version. @@ -29,19 +21,13 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from __future__ import absolute_import -from __future__ import print_function - -import sys - -from sage.categories.homset import End -from sage.categories.homset import Hom +from sage.categories.homset import End, Hom from sage.categories.morphism import Morphism from sage.misc.cachefunc import cached_method from sage.rings.infinity import PlusInfinity -def _CreateRelationsMatrix(module, relations, source_degs, target_degs): +def _create_relations_matrix(module, relations, source_degs, target_degs): r""" The action by the given relations can be written as multiplication by the matrix `R = (r_{ij})_{i,j}` where each entry is an algebra element and @@ -54,17 +40,17 @@ def _CreateRelationsMatrix(module, relations, source_degs, target_degs): INPUT: - - ``module`` -- The module where the relations acts. - - ``relations`` -- A list of lists of algebra coefficients defining the - matrix `R`. - - ``source_degs`` -- A list of integer degrees. Its length should be - equal to the number of columns of `R`. - - ``target_degs`` -- A list of integer degrees. Its length should be - equal to the number of rows of `R`. + - ``module`` -- the module where the relations acts + - ``relations`` -- a list of lists of algebra coefficients defining the + matrix `R` + - ``source_degs`` -- a list of integer degrees; its length should be + equal to the number of columns of `R` + - ``target_degs`` -- a list of integer degrees; its length should be + equal to the number of rows of `R` - Furthermore must the degrees given by the input satisfy the following: + Furthermore must the degrees given by the input satisfy the following:: - `\text{source_degs[j]} + \deg(r_{i,j}) = \text{target_degs[i]}` + source_degs[j] + deg(r[i,j]) = target_degs[i] for all `i, j`. @@ -80,9 +66,9 @@ def _CreateRelationsMatrix(module, relations, source_degs, target_degs): TESTS:: sage: from sage.modules.fp_graded.module import FPModule - sage: from sage.modules.fp_graded.morphism import _CreateRelationsMatrix + sage: from sage.modules.fp_graded.morphism import _create_relations_matrix sage: A = SteenrodAlgebra(p=2) - sage: blocks, R = _CreateRelationsMatrix(FPModule(A, [0]), [[Sq(2)]], [4], [6]) + sage: blocks, R = _create_relations_matrix(FPModule(A, [0]), [[Sq(2)]], [4], [6]) sage: blocks [[Vector space morphism represented by the matrix: @@ -106,7 +92,7 @@ def _CreateRelationsMatrix(module, relations, source_degs, target_degs): """ from sage.matrix.constructor import matrix - if len(relations) == 0: + if not relations: raise ValueError('no relations given, can not build matrix') # Create the block matrix of linear transformations. @@ -142,8 +128,8 @@ def _CreateRelationsMatrix(module, relations, source_degs, target_degs): # Create a matrix from the matrix of linear transformations. entries = [] - for j in range(len(block_matrix[0])): - for n in range(block_matrix[0][j].domain().dimension()): + for j, block in enumerate(block_matrix[0]): + for n in range(block.domain().dimension()): column = [] for i in range(len(block_matrix)): lin_trans = block_matrix[i][j] @@ -159,14 +145,9 @@ class FPModuleMorphism(Morphism): INPUT: - - ``parent`` -- A homspace of finitely presented graded modules. - - ``values`` -- A list of elements in the codomain. Each element - corresponds to a module generator in the domain. - - .. NOTE:: Never use this constructor explicitly, but rather the parent's - call method, or this class' __call__ method. The reason for this - is that the dynamic type of the element class changes as a - consequence of the category system. + - ``parent`` -- a homspace of finitely presented graded modules + - ``values`` -- a list of elements in the codomain; each element + corresponds to a module generator in the domain TESTS:: @@ -195,7 +176,9 @@ def __init__(self, parent, values): r""" Create a homomorphism between finitely presented graded modules. - OUTPUT: A module homomorphism defined by sending the generator + OUTPUT: + + A module homomorphism defined by sending the generator with index `i` to the corresponding element in ``values``. TESTS:: @@ -213,7 +196,8 @@ def __init__(self, parent, values): if not isinstance(parent, FPModuleHomspace): raise TypeError('parent (=%s) must be a fp module hom space' % parent) - self.free_morphism = Hom(parent.domain().j.codomain(), parent.codomain().j.codomain())([v.lift_to_free() for v in values]) + Homspace = Hom(parent.domain().j.codomain(), parent.codomain().j.codomain()) + self.free_morphism = Homspace([v.lift_to_free() for v in values]) self._values = values # Call the base class constructor. @@ -229,13 +213,11 @@ def __init__(self, parent, values): def change_ring(self, algebra): r""" - Change the base ring of this module homomorphism. + Change the base ring of ``self``. INPUT: - - ``algebra`` -- a graded algebra. - - OUTPUT: An instance of this class. + - ``algebra`` -- a graded algebra EXAMPLES:: @@ -268,9 +250,11 @@ def change_ring(self, algebra): def degree(self): r""" - The degree of this homomorphism. + The degree of ``self``. + + OUTPUT: - OUTPUT: The integer degree of this homomorphism. + The integer degree of ``self``. EXAMPLES:: @@ -312,10 +296,11 @@ def degree(self): def values(self): r""" - The values under this homomorphism of the module generators of the - domain module. + The values under ``self`` of the module generators of the domain module. - OUTPUT: A sequence of module elements of the codomain. + OUTPUT: + + A sequence of module elements of the codomain. EXAMPLES:: @@ -339,22 +324,7 @@ def values(self): def _richcmp_(self, other, op): r""" - Compare this homomorphism to the given homomorphism. - - Implementation of this function allows Sage to make sense of the == - operator for instances of this class. - - INPUT: - - - ``other`` -- An instance of this class. - - - ``op`` -- An integer specifying the comparison operation to be - carried out: If ``op`` == 2, then return ``True`` if and only if the - homomorphisms are equal. If ``op`` == 3, then return ``True `` if - and only if the homomorphisms are not equal. Otherwise, - return ``False``. - - OUTPUT: A boolean. + Compare ``self`` to ``other``. EXAMPLES:: @@ -388,7 +358,7 @@ def _richcmp_(self, other, op): def __add__(self, g): r""" - The pointwise sum of this and the given homomorphism. + The pointwise sum of ``self`` and ``g``. Pointwise addition of two homomorphisms `f` and `g` with the same domain and codomain is given by the formula `(f+g)(x) = f(x) + g(x)` for @@ -396,8 +366,7 @@ def __add__(self, g): INPUT: - - ``g`` -- A homomorphism with the same domain and codomain as this - homomorphism. + - ``g`` -- a homomorphism with the same domain and codomain as ``self`` EXAMPLES:: @@ -432,7 +401,7 @@ def __add__(self, g): def __neg__(self): r""" - The additive inverse of this homomorphism with respect to the group + The additive inverse of ``self`` with respect to the group structure given by pointwise sum. EXAMPLES:: @@ -457,7 +426,7 @@ def __neg__(self): def __sub__(self, g): r""" - The difference between this and the given homomorphism, with + The difference between ``self`` and ``g`` with respect to the group structure given by pointwise sum. EXAMPLES:: @@ -487,8 +456,7 @@ def __sub__(self, g): def __mul__(self, g): r""" - The composition of the given homomorphism ``g``, followed by this - homomorphisms. + The composition of ``g`` followed by ``self``. EXAMPLES:: @@ -527,10 +495,11 @@ def __mul__(self, g): @cached_method def is_zero(self): r""" - Decide if this homomomorphism is the zero homomorphism. + Decide if ``self`` is the zero homomorphism. - OUTPUT: The boolean value ``True`` if this homomorphism is trivial, and - ``False`` otherwise. + OUTPUT: + + The boolean value ``True`` if ``self`` is trivial and ``False`` otherwise. EXAMPLES:: @@ -547,13 +516,15 @@ def is_zero(self): sage: (f-f).is_zero() True """ - return all([x.is_zero() for x in self._values]) + return all(x.is_zero() for x in self._values) + + __bool__ = is_zero @cached_method def is_identity(self): r""" - Decide if this homomomorphism is the identity endomorphism. + Decide if ``self`` is the identity endomorphism. EXAMPLES:: @@ -568,15 +539,13 @@ def is_identity(self): False sage: id = Hom(M, M)(M.generators()); id - The identity homomorphism. + The identity homomorphism sage: id.is_identity() True """ - if self.parent().is_endomorphism_set(): - return self.parent().identity() == self - else: - return False + return (self.parent().is_endomorphism_set() and + self.parent().identity() == self) def __call__(self, x): @@ -585,9 +554,11 @@ def __call__(self, x): INPUT: - - ``x`` - An element of the domain of the homomorphism. + - ``x`` -- an element of the domain of the homomorphism - OUTPUT: The module element of the codomain which is the value of ``x`` + OUTPUT: + + The module element of the codomain which is the value of ``x`` under this homomorphism. EXAMPLES:: @@ -614,7 +585,7 @@ def __call__(self, x): def _repr_(self): r""" - A string representation of this homomorphism. + A string representation of ``self``. EXAMPLES:: @@ -624,16 +595,17 @@ def _repr_(self): sage: N = FPModule(A, [2], [[Sq(4)]]) sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] sage: Hom(M, N)(values)._repr_() - 'Module homomorphism of degree 7 defined by sending the generators\n [<1, 0>, <0, 1>]\nto\n [, ]' + 'Module homomorphism of degree 7 defined by sending the generators\n + [<1, 0>, <0, 1>]\nto\n [, ]' sage: Hom(M, N).zero()._repr_() - 'The trivial homomorphism.' + 'The trivial homomorphism' sage: Hom(M, M).identity()._repr_() - 'The identity homomorphism.' + 'The identity homomorphism' """ if self.is_zero(): - return "The trivial homomorphism." + return "The trivial homomorphism" elif self.is_identity(): - return "The identity homomorphism." + return "The identity homomorphism" else: return "Module homomorphism of degree %d defined by sending "\ "the generators\n %s\nto\n %s" % (self.degree(), self.domain().generators(), self._values) @@ -642,8 +614,7 @@ def _repr_(self): @cached_method def vector_presentation(self, n): r""" - The restriction of this homomorphism to the domain module elements of - degree ``n``. + The restriction of ``self`` to the domain module elements of degree ``n``. The restriction of a non-zero module homomorphism to the vectorspace of module elements of degree `n` is a linear function into the vectorspace @@ -656,9 +627,11 @@ def vector_presentation(self, n): INPUT: - - ``n`` -- An integer degree. + - ``n`` -- an integer degree + + OUTPUT: - OUTPUT: A linear function of finite dimensional vectorspaces over the + A linear function of finite dimensional vector spaces over the ground field of the algebra for this module. The domain is isomorphic to the vectorspace of domain elements of degree ``n`` of this free module, via the choice of basis given by @@ -741,20 +714,22 @@ def vector_presentation(self, n): values = [self(e) for e in self.domain().basis_elements(n)] - return Hom(D_n, C_n)([ - C_n.zero() if e.is_zero() else e.vector_presentation() for e in values]) + return Hom(D_n, C_n)([C_n.zero() if e.is_zero() else e.vector_presentation() + for e in values]) def solve(self, x): r""" - Find an element in the inverse image of the given element. + Find an element in the inverse image of ``x``. INPUT: - - ``x`` -- An element of the codomain of this morphism. + - ``x`` -- an element of the codomain of this morphism + + OUTPUT: - OUTPUT: An element of the domain which maps to ``x`` under this - morphism, or ``None`` if ``x`` was not in the image of this morphism. + An element of the domain which maps to ``x`` under this morphism + or ``None`` if ``x`` was not in the image of this morphism. EXAMPLES:: @@ -770,7 +745,8 @@ def solve(self, x): sage: y == f(x) True - Trying to lift an element which is not in the image results in a ``None`` value:: + Trying to lift an element which is not in the image results + in a ``None`` value:: sage: z = f.solve(Sq(1)*N.generator(0)) sage: z is None @@ -815,13 +791,13 @@ def lift(self, f, verbose=False): INPUT: - - ``f`` -- A homomorphism with codomain equal to the codomain of this - homomorphism. - - ``verbose`` -- A boolean to enable progress messages. (optional, - default: ``False``) + - ``f`` -- a homomorphism with codomain equal to the codomain of ``self`` + - ``verbose`` -- boolean (default: ``False``); enable progress messages - OUTPUT: A homomorphism `g` with the property that this homomorphism - equals `f\circ g`. If no lift exist, ``None`` is returned. + OUTPUT: + + A homomorphism `g` with the property that ``self`` equals `f \circ g`. + If no lift exist, ``None`` is returned. ALGORITHM: @@ -836,7 +812,9 @@ def lift(self, f, verbose=False): Let `k \in \ker(f)` solve the matrix equation: - `R\cdot k = R\cdot x`. + .. MATH:: + + R \cdot k = R \cdot x. Define a module homomorphism by sending the generators of `L` to `x_1 - k_1, \ldots, x_N - k_N`. This is well defined, and is also a @@ -875,7 +853,7 @@ def lift(self, f, verbose=False): sage: # We can construct a splitting of `q` manually: sage: split = Hom(HZ,A_plus_HZ)([A_plus_HZ.generator(1)]) sage: q*split - The identity homomorphism. + The identity homomorphism sage: # Thus, lifting the identity homomorphism over `q` should be possible: sage: id = Hom(HZ,HZ).identity() sage: j = id.lift(q); j @@ -884,7 +862,7 @@ def lift(self, f, verbose=False): to [<0, 1>] sage: q*j - The identity homomorphism. + The identity homomorphism Lifting over the inclusion of the image sub module:: @@ -898,14 +876,15 @@ def lift(self, f, verbose=False): to [<1>] - When a lift cannot be found, the ``None`` value is returned. By setting the - verbose argument to ``True``, an explanation of why the lifting failed will - be displayed:: + When a lift cannot be found, the ``None`` value is returned. By + setting the verbose argument to ``True``, an explanation of why + the lifting failed will be displayed:: sage: F2 = FPModule(A, [0,0]) sage: non_surjection = Hom(F2, F2)([F2([1, 0]), F2([0, 0])]) sage: lift = Hom(F2, F2).identity().lift(non_surjection, verbose=True) - The generators of the domain of this homomorphism do not map into the image of the homomorphism we are lifting over. + The generators of the domain of this homomorphism do not map into + the image of the homomorphism we are lifting over. sage: lift is None True @@ -916,23 +895,26 @@ def lift(self, f, verbose=False): sage: # The trivial map often involved in corner cases.. sage: trivial_map = Hom(FPModule(A, [0]), FPModule(A, [])).zero() sage: trivial_map.lift(trivial_map) - The trivial homomorphism. + The trivial homomorphism sage: F = FPModule(A, [0]) sage: HZ = FPModule(A, [0], relations=[[Sq(1)]]) sage: f = Hom(F,HZ)(HZ.generators()) sage: split = Hom(HZ, HZ).identity().lift(f, verbose=True) - The homomorphism cannot be lifted in any way such that the relations of the domain are respected: matrix equation has no solutions + The homomorphism cannot be lifted in any way such that the relations + of the domain are respected: matrix equation has no solutions sage: split is None True sage: Hom(F, F).identity().lift(f, verbose=true) Traceback (most recent call last): ... - ValueError: the codomains of this homomorphism and the homomorphism we are lifting over are different + ValueError: the codomains of this homomorphism and the homomorphism + we are lifting over are different sage: f.lift(Hom(HZ, HZ).zero(), verbose=True) - This homomorphism cannot lift over a trivial homomorphism since it is non-trivial. + This homomorphism cannot lift over a trivial homomorphism since + it is non-trivial. sage: Ap = SteenrodAlgebra(p=2, profile=(2,2,2,1)) sage: Hko = FPModule(Ap, [0], [[Sq(2)], [Sq(1)]]) @@ -976,8 +958,8 @@ def lift(self, f, verbose=False): # It is an error to call this function with incompatible arguments. if not f.codomain() is N: - raise ValueError('the codomains of this homomorphism and the homomorphism '\ - 'we are lifting over are different') + raise ValueError('the codomains of this homomorphism and the homomorphism ' + 'we are lifting over are different') # The trivial map lifts over any other map. if self.is_zero(): @@ -986,7 +968,8 @@ def lift(self, f, verbose=False): # A non-trivial map never lifts over the trivial map. if f.is_zero(): if verbose: - print('This homomorphism cannot lift over a trivial homomorphism since it is non-trivial.') + print('This homomorphism cannot lift over a trivial homomorphism' + ' since it is non-trivial.') return None xs = [f.solve(self(g)) for g in L.generators()] @@ -995,7 +978,7 @@ def lift(self, f, verbose=False): # hope finding a lift. if None in xs: if verbose: - print('The generators of the domain of this homomorphism do '\ + print('The generators of the domain of this homomorphism do ' 'not map into the image of the homomorphism we are lifting over.') return None @@ -1040,7 +1023,7 @@ def lift(self, f, verbose=False): if all_zero: return Hom(L, M)(xs) - block_matrix, R = _CreateRelationsMatrix( + block_matrix, R = _create_relations_matrix( K, [r.coefficients() for r in L.relations()], source_degs, target_degs) try: @@ -1077,16 +1060,17 @@ def lift(self, f, verbose=False): def split(self, verbose=False): r""" - A split of this homomorphism. + Return a split of ``self``. INPUT: - - ``verbose`` -- A boolean to enable progress messages. (optional, - default: ``False``) + - ``verbose`` -- boolean (default: ``False``); enable progress messages - OUTPUT: A homomorphism with the property that the composite - homomorphism `self \circ f = id` is the identity homomorphism. If no - such split exist, ``None`` is returned. + OUTPUT: + + A homomorphism with the property that the composite homomorphism + `S \circ f = id`, where `S` is ``self``, is The identity homomorphism + If no such split exist, ``None`` is returned. EXAMPLES:: @@ -1102,7 +1086,7 @@ def split(self, verbose=False): [<0, 1>] sage: # Verify that `s` is a splitting: sage: p*s - The identity homomorphism. + The identity homomorphism TESTS:: @@ -1110,10 +1094,12 @@ def split(self, verbose=False): sage: N = FPModule(A, [0], [[Sq(1)]]) sage: p = Hom(F, N)([N.generator(0)]) sage: p.split(verbose=True) is None - The homomorphism cannot be lifted in any way such that the relations of the domain are respected: matrix equation has no solutions + The homomorphism cannot be lifted in any way such that the relations + of the domain are respected: matrix equation has no solutions True .. SEEALSO:: + :meth:`lift` """ id = End(self.codomain()).identity() @@ -1122,8 +1108,8 @@ def split(self, verbose=False): def homology(self, f, top_dim=None, verbose=False): r""" - Compute the sub-quotient module `H(self, f) = \ker(self)/\operatorname{im}(f)`, in - a range of degrees. + Compute the sub-quotient module `H(self, f) = + \ker(self)/\operatorname{im}(f)` in a range of degrees. For a pair of composable morphisms `f: M\to N` and `g: N \to Q` of finitely presented modules, the homology module is a finitely @@ -1131,23 +1117,21 @@ def homology(self, f, top_dim=None, verbose=False): INPUT: - - ``f`` -- A homomorphism with codomain equal to the domain of this - homomorphism, and image contained in the kernel of this homomorphism. + - ``f`` -- a homomorphism with codomain equal to the domain of ``self`` + and image contained in the kernel of this homomorphism + - ``top_dim`` -- integer (optional); used by this function to stop the + computation at the given degree + - ``verbose`` -- boolean (default: ``False``) enable progress messages - - ``top_dim`` -- An integer used by this function to stop the - computation at the given degree, or the value ``None`` if no termination - should be enforced. (optional, default: ``None``) + OUTPUT: - - ``verbose`` -- A boolean to enable progress messages. (optional, - default: ``False``) - - OUTPUT: A quotient homomorphism `\ker(self) \to H`, where `H` is - isomorphic to `H(self, f)` in degrees less than or equal to ``top_dim``. + A quotient homomorphism `\ker(self) \to H`, where `H` is isomorphic + to `H(self, f)` in degrees less than or equal to ``top_dim``. .. NOTE:: - If the algebra for this module is finite, then no ``top_dim`` - needs to be specified in order to ensure that this function terminates. + If the algebra for this module is finite, then no ``top_dim`` needs + to be specified in order to ensure that this function terminates. EXAMPLES:: @@ -1160,7 +1144,8 @@ def homology(self, f, top_dim=None, verbose=False): sage: g = Hom(F, M)([A.Sq(4)*A.Sq(1,2)*M.generator(0)]) sage: ho = f.homology(g) sage: ho.codomain() - Finitely presented left module on 1 generator and 5 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Finitely presented left module on 1 generator and 5 relations over + sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] sage: ho.codomain().is_trivial() False """ @@ -1168,8 +1153,8 @@ def homology(self, f, top_dim=None, verbose=False): f_ = f.lift(k) if f_ is None: raise ValueError('the image of the given homomorphism is not contained ' - 'in the kernel of this homomorphism. The homology is ' - 'therefore not defined for this pair of maps') + 'in the kernel of this homomorphism; the homology is ' + 'therefore not defined for this pair of maps') return f_.cokernel() @@ -1180,10 +1165,11 @@ def suspension(self, t): INPUT: - - ``t`` -- An integer by which the morphism is suspended. + - ``t`` -- an integer by which the morphism is suspended - OUTPUT: The morphism which is the suspension of this morphism by the - degree ``t``. + OUTPUT: + + The morphism which is the suspension of ``self`` by the degree ``t``. EXAMPLES:: @@ -1219,17 +1205,19 @@ def suspension(self, t): """ if t == 0: return self - else: - D = self.domain().suspension(t) - C = self.codomain().suspension(t) - return Hom(D, C)([C(x.lift_to_free().dense_coefficient_list()) for x in self._values]) + + D = self.domain().suspension(t) + C = self.codomain().suspension(t) + return Hom(D, C)([C(x.lift_to_free().dense_coefficient_list()) for x in self._values]) def cokernel(self): r""" - Compute the cokernel of this homomorphism. + Compute the cokernel of ``self``. + + OUTPUT: - OUTPUT: The natural projection from the codomain of this homomorphism + The natural projection from the codomain of this homomorphism to its cokernel. EXAMPLES:: @@ -1264,18 +1252,17 @@ def cokernel(self): def kernel(self, top_dim=None, verbose=False): r""" - Compute the kernel of this homomorphism. + Compute the kernel of ``self``. INPUT: - - ``top_dim`` -- An integer used by this function to stop the - computation at the given degree, or the value ``None`` if no - termination should be enforced. (optional, default: ``None``) + - ``top_dim`` -- integer (optional); used by this function to stop the + computation at the given degree + - ``verbose`` -- boolean (default: ``False``) enable progress messages - - ``verbose`` -- A boolean to enable progress messages. (optional, - default: ``False``) + OUTPUT: - OUTPUT: A homomorphism into `\ker(self)` which is an isomorphism in + A homomorphism into `\ker(self)` which is an isomorphism in degrees less than or equal to ``top_dim``. .. NOTE:: @@ -1304,9 +1291,11 @@ def kernel(self, top_dim=None, verbose=False): sage: K = f.kernel(verbose=True, top_dim=17) 1. Computing the generators of the kernel presentation: - Resolving the kernel in the range of dimensions [0, 17]: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17. + Resolving the kernel in the range of dimensions [0, 17]: + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17. 2. Computing the relations of the kernel presentation: - Resolving the kernel in the range of dimensions [7, 17]: 7 8 9 10 11 12 13 14 15 16 17. + Resolving the kernel in the range of dimensions [7, 17]: + 7 8 9 10 11 12 13 14 15 16 17. sage: K.domain().generators() [<1>] @@ -1339,19 +1328,18 @@ def kernel(self, top_dim=None, verbose=False): def image(self, top_dim=None, verbose=False): r""" - Compute the image of this homomorphism. + Compute the image of ``self``. INPUT: - - ``top_dim`` -- An integer used by this function to stop the - computation at the given degree, or the value ``None`` if no - termination should be enforced. (optional, default: ``None``) + - ``top_dim`` -- integer (optional); used by this function to stop the + computation at the given degree + - ``verbose`` -- boolean (default: ``False``) enable progress messages - - ``verbose`` -- A boolean to enable progress messages. (optional, - default: ``False``) + OUTPUT: - OUTPUT: A homomorphism into `\operatorname{im}(self)` which is an - isomorphism in degrees less than or equal to ``top_dim``. + A homomorphism into `\operatorname{im}(self)` that is an + isomorphism in degrees less than or equal to ``top_dim`` .. NOTE:: @@ -1379,9 +1367,11 @@ def image(self, top_dim=None, verbose=False): sage: f = H([F2([1]), F2([0])]) sage: K = f.image(verbose=True, top_dim=17) 1. Computing the generators of the image presentation: - Resolving the image in the range of dimensions [0, 17]: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17. + Resolving the image in the range of dimensions [0, 17]: + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17. 2. Computing the relations of the image presentation: - Resolving the kernel in the range of dimensions [0, 17]: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17. + Resolving the kernel in the range of dimensions [0, 17]: + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17. sage: K.is_injective() # long time True @@ -1410,16 +1400,13 @@ def image(self, top_dim=None, verbose=False): def is_injective(self, top_dim=None, verbose=False): r""" - Return ``True`` if and only if this homomorphism has a trivial kernel. + Return ``True`` if and only if ``self`` has a trivial kernel. INPUT: - - ``top_dim`` -- An integer used by this function to stop the - computation at the given degree, or the value ``None`` if no termination - should be enforced. (optional, default: ``None``) - - - ``verbose`` -- A boolean to enable progress messages. (optional, - default: ``False``) + - ``top_dim`` -- integer (optional); used by this function to stop the + computation at the given degree + - ``verbose`` -- boolean (default: ``False``) enable progress messages EXAMPLES:: @@ -1446,7 +1433,7 @@ def is_injective(self, top_dim=None, verbose=False): def is_surjective(self): r""" - Return ``True`` if and only if this homomorphism has a trivial cokernel. + Return ``True`` if and only if ``self`` has a trivial cokernel. EXAMPLES:: @@ -1470,21 +1457,19 @@ def is_surjective(self): def _resolve_kernel(self, top_dim=None, verbose=False): r""" - Resolve the kernel of this homomorphism by a free module. + Resolve the kernel of ``self`` by a free module. INPUT: - - ``top_dim`` -- An integer used by this function to stop the - computation at the given degree, or the value ``None`` if no termination - should be enforced. (optional, default: ``None``) + - ``top_dim`` -- integer (optional); used by this function to stop the + computation at the given degree + - ``verbose`` -- boolean (default: ``False``) enable progress messages - - ``verbose`` -- A boolean to enable progress messages. (optional, - default: ``False``) + OUTPUT: - OUTPUT: A homomorphism `j: F \rightarrow D` where `D` is the domain of - this homomorphism, `F` is free and such that - `\ker(self) = \operatorname{im}(j)` in all degrees less than or equal - to ``top_dim``. + A homomorphism `j: F \rightarrow D` where `D` is the domain of ``self``, + where `F` is free and such that `\ker(self) = \operatorname{im}(j)` + in all degrees less than or equal to ``top_dim``. .. NOTE:: @@ -1563,7 +1548,6 @@ def _resolve_kernel(self, top_dim=None, verbose=False): if verbose: print(' %d' % n, end='') - sys.stdout.flush() # We have taken care of the case when self is zero, so the # vector presentation exists. @@ -1609,19 +1593,18 @@ def _resolve_kernel(self, top_dim=None, verbose=False): def _resolve_image(self, top_dim=None, verbose=False): r""" - Resolve the image of this homomorphism by a free module. + Resolve the image of ``self`` by a free module. INPUT: - - ``top_dim`` -- An integer used by this function to stop the - computation at the given degree, or the value ``None`` if no termination - should be enforced. (optional, default: ``None``) + - ``top_dim`` -- integer (optional); used by this function to stop the + computation at the given degree + - ``verbose`` -- boolean (default: ``False``) enable progress messages - - ``verbose`` -- A boolean to enable progress messages. (optional, - default: ``False``) + OUTPUT: - OUTPUT: A homomorphism `j: F \rightarrow C` where `C` is the codomain - of this homomorphism, `F` is free, and + A homomorphism `j: F \rightarrow C` where `C` is the codomain + of ``self``, where `F` is free, and `\operatorname{im}(self) = \operatorname{im}(j)` in all degrees less than or equal to ``top_dim``. @@ -1701,7 +1684,6 @@ def _resolve_image(self, top_dim=None, verbose=False): if verbose: print(' %d' % n, end='') - sys.stdout.flush() self_n = self.vector_presentation(n - self_degree) image_n = self_n.image() @@ -1746,10 +1728,12 @@ def _resolve_image(self, top_dim=None, verbose=False): def to_fp_module(self): r""" - Create a finitely presented module from this morphism. + Create a finitely presented module from ``self``. + + OUTPUT: - OUTPUT: The finitely presented module having presentation - equal to this morphism, as long as the domain and codomain are free. + The finitely presented module having presentation equal to ``self`` + as long as the domain and codomain are free. EXAMPLES:: @@ -1760,7 +1744,8 @@ def to_fp_module(self): sage: v = F2([Sq(2)]) sage: pres = Hom(F1, F2)([v]) sage: M = pres.to_fp_module(); M - Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis + Finitely presented left module on 1 generator and 1 relation over + mod 2 Steenrod algebra, milnor basis sage: M.generator_degrees() (0,) sage: M.relations() From 8dfde967a69b17155c8c14e0555fe0ea2ade12b3 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Thu, 9 Dec 2021 19:53:22 -0800 Subject: [PATCH 044/253] trac 32505: delete _repr_ for elements and instead use _repr_term --- src/sage/modules/fp_graded/element.py | 62 ++----- src/sage/modules/fp_graded/free_element.py | 60 ++---- src/sage/modules/fp_graded/free_homspace.py | 12 +- src/sage/modules/fp_graded/free_module.py | 193 ++++++++++++++------ src/sage/modules/fp_graded/free_morphism.py | 28 +-- src/sage/modules/fp_graded/homspace.py | 96 +++++----- src/sage/modules/fp_graded/module.py | 139 +++++++------- src/sage/modules/fp_graded/morphism.py | 112 ++++++------ 8 files changed, 376 insertions(+), 326 deletions(-) diff --git a/src/sage/modules/fp_graded/element.py b/src/sage/modules/fp_graded/element.py index 72ca2e2f38e..f5eabaa5b44 100755 --- a/src/sage/modules/fp_graded/element.py +++ b/src/sage/modules/fp_graded/element.py @@ -38,7 +38,7 @@ class FPElement(IndexedFreeModuleElement): sage: from sage.modules.fp_graded.module import FPModule sage: FPModule(SteenrodAlgebra(2), [0])([Sq(2)]) - + Sq(2)*g_{0} """ def lift_to_free(self): r""" @@ -51,11 +51,11 @@ def lift_to_free(self): sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) sage: x = M([Sq(1), 1]) sage: x - + Sq(1)*g_{0} + g_{1} sage: x.parent() Finitely presented left module on 2 generators and 1 relation over mod 2 Steenrod algebra, milnor basis sage: x.lift_to_free() - + Sq(1)*g_{0} + g_{1} sage: x.lift_to_free().parent() Finitely presented free left module on 2 generators over mod 2 Steenrod algebra, milnor basis """ @@ -79,7 +79,7 @@ def degree(self): sage: x = M.an_element(7) sage: x - + Sq(0,0,1)*g_{0} + Sq(3,1)*g_{1} sage: x.degree() 7 @@ -125,28 +125,6 @@ def coefficients(self): return [self[i] for i in sorted(self.parent().basis().keys())] - def _repr_(self): - r""" - Return a string representation of ``self``. - - EXAMPLES:: - - sage: from sage.modules.fp_graded.module import FPModule - sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) - sage: [M.an_element(n) for n in range(1,10)] - [, - , - , - , - , - , - , - , - ] - """ - return self.lift_to_free()._repr_() - - def _lmul_(self, a): r""" Act by left multiplication on this element by ``a``. @@ -165,24 +143,24 @@ def _lmul_(self, a): sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) sage: M = FPModule(A2, [0,3], [[Sq(2)*Sq(4), Sq(3)]]) sage: A2.Sq(2)*M.generator(1) - <0, Sq(2)> + Sq(2)*g_{3} sage: A2.Sq(2)*(A2.Sq(1)*A2.Sq(2)*M.generator(0) + M.generator(1)) - + Sq(2,1)*g_{0} + Sq(2)*g_{3} TESTS:: sage: elements = [M.an_element(n) for n in range(1,10)] sage: a = A2.Sq(3) sage: [a*x for x in elements] - [, + [Sq(1,1)*g_{0}, 0, - , - <0, Sq(1,1)>, + Sq(3,1)*g_{0} + Sq(3)*g_{3}, + Sq(1,1)*g_{3}, 0, - , - , - , - <0, Sq(3,2)>] + Sq(3,2)*g_{0} + Sq(3,1)*g_{3}, + Sq(3,0,1)*g_{0} + Sq(7)*g_{3}, + Sq(1,1,1)*g_{0} + Sq(5,1)*g_{3}, + Sq(3,2)*g_{3}] """ return self.parent()(a*self.lift_to_free()) @@ -212,7 +190,7 @@ def vector_presentation(self): sage: from sage.modules.fp_graded.module import FPModule sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) - sage: M = FPModule(A2, (0,1)) + sage: M. = FPModule(A2, (0,1)) sage: x = M.an_element(7) sage: v = x.vector_presentation(); v @@ -232,7 +210,7 @@ def vector_presentation(self): sage: basis = M.basis_elements(7) sage: x_ = sum( [c*b for (c,b) in zip(v, basis)] ); x_ - + Sq(0,0,1)*m0 + Sq(3,1)*m1 sage: x == x_ True @@ -298,7 +276,7 @@ def __eq__(self, other): sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) sage: x = M([Sq(1), 1]) sage: x - + Sq(1)*g_{0} + g_{1} sage: x == x True sage: x == M.zero() @@ -324,17 +302,17 @@ def normalize(self): EXAMPLES:: sage: from sage.modules.fp_graded.module import FPModule - sage: M = FPModule(SteenrodAlgebra(2), [0,2,4], [[Sq(4),Sq(2),0]]) + sage: M. = FPModule(SteenrodAlgebra(2), [0,2,4], [[Sq(4),Sq(2),0]]) sage: m = M((Sq(6), 0, Sq(2))); m - + Sq(6)*a0 + Sq(2)*c4 sage: m.normalize() - + Sq(6)*a0 + Sq(2)*c4 sage: m == m.normalize() True sage: n = M((Sq(4), Sq(2), 0)); n - + Sq(4)*a0 + Sq(2)*b2 sage: n.normalize() 0 sage: n == n.normalize() diff --git a/src/sage/modules/fp_graded/free_element.py b/src/sage/modules/fp_graded/free_element.py index c62cd15c03a..7019becd9b3 100755 --- a/src/sage/modules/fp_graded/free_element.py +++ b/src/sage/modules/fp_graded/free_element.py @@ -40,13 +40,13 @@ class FreeGradedModuleElement(IndexedFreeModuleElement): 0 sage: M([1, 0]) - <1, 0> + g_{0} sage: M([0, 1]) - <0, 1> + g_{1} sage: M([Sq(1), 1]) - + Sq(1)*g_{0} + g_{1} """ def coefficients(self): @@ -57,9 +57,9 @@ def coefficients(self): sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: A = SteenrodAlgebra() - sage: M = FreeGradedModule(SteenrodAlgebra(2), (0, 1)) + sage: M. = FreeGradedModule(SteenrodAlgebra(2), (0, 1)) sage: x = M.an_element(7); x - + Sq(0,0,1)*Y + Sq(3,1)*Z sage: x.coefficients() [Sq(0,0,1), Sq(3,1)] """ @@ -81,7 +81,7 @@ def degree(self): sage: A = SteenrodAlgebra(2) sage: M = FreeGradedModule(A, (0,1)) sage: x = M.an_element(7); x - + Sq(0,0,1)*g_{0} + Sq(3,1)*g_{1} sage: x.degree() 7 @@ -137,32 +137,6 @@ def lift_to_free(self): return self - def _repr_(self): - r""" - Return a string representation of ``self``. - - EXAMPLES:: - - sage: from sage.modules.fp_graded.free_module import FreeGradedModule - sage: A = SteenrodAlgebra(2) - sage: M = FreeGradedModule(A, (0,1)) - sage: [M.an_element(n) for n in range(1,10)] - [, - , - , - , - , - , - , - , - ] - """ - if self: - return '<%s>' % ', '.join(['%s' % c for c in self.coefficients()]) - else: - return '0' - - def _lmul_(self, a): r""" Act by left multiplication on this element by ``a``. @@ -179,26 +153,26 @@ def _lmul_(self, a): sage: from sage.modules.fp_graded.free_module import * sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) - sage: M = FreeGradedModule(A2, (0,0,3)) + sage: M. = FreeGradedModule(A2, (0,0,3)) sage: A2.Sq(2)*M.generator(1) - <0, Sq(2), 0> + Sq(2)*y0 sage: A2.Sq(2)*(A2.Sq(1)*A2.Sq(2)*M.generator(1) + M.generator(2)) - <0, Sq(2,1), Sq(2)> + Sq(2,1)*y0 + Sq(2)*z3 TESTS:: sage: elements = [M.an_element(n) for n in range(1,10)] sage: a = A2.Sq(3) sage: [a*x for x in elements] - [, + [Sq(1,1)*x0 + Sq(1,1)*y0, 0, - , - <0, 0, Sq(1,1)>, + Sq(3,1)*x0 + Sq(3,1)*y0 + Sq(3)*z3, + Sq(1,1)*z3, 0, - , - , - , - <0, 0, Sq(3,2)>] + Sq(3,2)*x0 + Sq(3,2)*y0 + Sq(3,1)*z3, + Sq(3,0,1)*x0 + Sq(3,0,1)*y0 + Sq(7)*z3, + Sq(1,1,1)*x0 + Sq(1,1,1)*y0 + Sq(5,1)*z3, + Sq(3,2)*z3] """ return self.parent()((a*c for c in self.coefficients())) @@ -247,7 +221,7 @@ def vector_presentation(self): sage: basis = M.basis_elements(7) sage: x_ = sum( [c*b for (c,b) in zip(v, basis)] ); x_ - + Sq(0,0,1)*g_{0} + Sq(3,1)*g_{1} sage: x == x_ True diff --git a/src/sage/modules/fp_graded/free_homspace.py b/src/sage/modules/fp_graded/free_homspace.py index 69fc03ca242..5524a3b2197 100755 --- a/src/sage/modules/fp_graded/free_homspace.py +++ b/src/sage/modules/fp_graded/free_homspace.py @@ -7,16 +7,16 @@ sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: A = SteenrodAlgebra(2) - sage: F1 = FreeGradedModule(A, (1,3)) - sage: F2 = FreeGradedModule(A, (2,3)) + sage: F1 = FreeGradedModule(A, (1,3), names='g') + sage: F2 = FreeGradedModule(A, (2,3), names='h') sage: homset = Hom(F1, F2) sage: homset Set of Morphisms from Finitely presented free left module on 2 generators ... sage: homset([F2((Sq(1), 1)), F2((0, Sq(2)))]) Module homomorphism of degree 2 defined by sending the generators - [<1, 0>, <0, 1>] + [g_{1}, g_{3}] to - [, <0, Sq(2)>] + [Sq(1)*h_{2} + h_{3}, Sq(2)*h_{3}] sage: TestSuite(homset).run() AUTHORS: @@ -83,9 +83,9 @@ def _element_constructor_(self, values): sage: values = (A2.Sq(4)*L.generator(0), A2.Sq(3)*L.generator(1)) sage: f = H(values); f Module homomorphism of degree 5 defined by sending the generators - [<1, 0>, <0, 1>] + [g_{1}, g_{3}] to - [, <0, Sq(3)>] + [Sq(4)*g_{2}, Sq(3)*g_{5}] sage: H(0) The trivial homomorphism diff --git a/src/sage/modules/fp_graded/free_module.py b/src/sage/modules/fp_graded/free_module.py index 84f4cf4b8af..899e78c4dde 100755 --- a/src/sage/modules/fp_graded/free_module.py +++ b/src/sage/modules/fp_graded/free_module.py @@ -48,26 +48,26 @@ Module elements are displayed by their algebra coefficients:: sage: M.an_element(n=5) - + Sq(2,1)*g_{0} + Sq(4)*g_{1} sage: M.an_element(n=15) - + Sq(0,0,0,1)*g_{0} + Sq(1,2,1)*g_{1} The generators are themselves elements of the module:: sage: M.generators() - [<1, 0>, <0, 1>] + [g_{0}, g_{1}] Producing elements from a given set of coefficients is possible as usual:: sage: coeffs = [Sq(5), Sq(1,1)] sage: x = M(coeffs); x - + Sq(5)*g_{0} + Sq(1,1)*g_{1} The module action produces new elements:: sage: Sq(2) * x - + (Sq(4,1)+Sq(7))*g_{0} + Sq(3,1)*g_{1} Each non-zero element has a well-defined degree:: @@ -86,9 +86,9 @@ Any two elements can be added as long as they are in the same degree:: sage: y = M.an_element(5); y - + Sq(2,1)*g_{0} + Sq(4)*g_{1} sage: x + y - + (Sq(2,1)+Sq(5))*g_{0} + (Sq(1,1)+Sq(4))*g_{1} or when at least one of them is zero:: @@ -105,7 +105,7 @@ computed:: sage: M.basis_elements(5) - [, , <0, Sq(1,1)>, <0, Sq(4)>] + [Sq(2,1)*g_{0}, Sq(5)*g_{0}, Sq(1,1)*g_{1}, Sq(4)*g_{1}] together with a corresponding vector space presentation:: @@ -122,7 +122,7 @@ sage: x_ = M.element_from_coordinates((0,1,1,0), 5) sage: x_ - + Sq(5)*g_{0} + Sq(1,1)*g_{1} sage: x_ == x True @@ -137,7 +137,7 @@ such homomorphisms using the free function ``Hom``:: sage: M = FreeGradedModule(A, (0,1)) - sage: N = FreeGradedModule(A, (2,)) + sage: N. = FreeGradedModule(A, (2,)) sage: homspace = Hom(M, N); homspace Set of Morphisms from Finitely presented free left module on 2 generators over mod 2 Steenrod algebra, milnor basis @@ -150,8 +150,7 @@ of the homspace object. The only argument is a list of module elements in the codomain, corresponding to the module generators of the domain:: - sage: g = N([1]) # the generator of the codomain module. - sage: values = [Sq(2)*g, Sq(2)*Sq(1)*g] + sage: values = [Sq(2)*c2, Sq(2)*Sq(1)*c2] sage: f = homspace(values) The resulting homomorphism is the one sending the `i`-th generator of the @@ -159,9 +158,9 @@ sage: f Module homomorphism of degree 4 defined by sending the generators - [<1, 0>, <0, 1>] + [g_{0}, g_{1}] to - [, ] + [Sq(2)*c2, (Sq(0,1)+Sq(3))*c2] Convenience methods exist for creating the trivial morphism:: @@ -176,10 +175,10 @@ Homomorphisms can be evaluated on elements of the domain module:: sage: v1 = f(Sq(7)*M.generator(0)); v1 - + Sq(3,2)*c2 sage: v2 = f(Sq(17)*M.generator(1)); v2 - + (Sq(11,3)+Sq(13,0,1)+Sq(17,1))*c2 and they respect the module action:: @@ -204,12 +203,12 @@ Any two homomorphisms can be added as long as they are of the same degree:: - sage: f2 = homspace([Sq(2)*g, Sq(3)*g]) + sage: f2 = homspace([Sq(2)*c2, Sq(3)*c2]) sage: f + f2 Module homomorphism of degree 4 defined by sending the generators - [<1, 0>, <0, 1>] + [g_{0}, g_{1}] to - [0, ] + [0, Sq(0,1)*c2] or when at least one of them is zero:: @@ -287,7 +286,19 @@ class FreeGradedModule(CombinatorialFreeModule): - ``generator_degrees`` -- tuple of integers defining the number of generators of the module, and their degrees - TESTS:: + - ``names`` -- optional, the names of the generators. If ``names`` + is a comma-separated string like ``'a, b, c'``, then those will + be the names. Otherwise, for example if ``names`` is ``abc``, + then the names will be ``abc_{d,i}``. + + By default, if all generators are in distinct degrees, then the + ``names`` of the generators will have the form ``g_{d}`` where + ``d`` is the degree of the generator. If the degrees are not + distinct, then the generators will be callsed ``g_{d,i}`` where + ``d`` is the degree and ``i` is its index in the list of + generators in that degree. + + EXAMPLES:: sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: E. = ExteriorAlgebra(QQ) @@ -301,12 +312,28 @@ class FreeGradedModule(CombinatorialFreeModule): sage: (x*y*b).degree() 5 + ``names`` of generators:: + + sage: M.generators() + [g_{-1}, g_{3}] + sage: FreeGradedModule(E, (0, 0, 2)).generators() + [g_{0,0}, g_{0,1}, g_{2,0}] + sage: FreeGradedModule(E, (0, 0, 2), names='x, y, z').generators() + [x, y, z] + sage: FreeGradedModule(E, (0, 0, 2), names='xyz').generators() + [xyz_{0,0}, xyz_{0,1}, xyz_{2,0}] + + ``names`` can also be defined implicitly using Sage's ``M.<...>`` syntax:: + sage: A = SteenrodAlgebra(2) - sage: FreeGradedModule(A, (-2,2,4)) + sage: M. = FreeGradedModule(A, (-2,2,4)) + sage: M Finitely presented free left module on 3 generators over mod 2 Steenrod algebra, milnor basis + sage: M.gens() + (x, y, z) """ - def __init__(self, algebra, generator_degrees): + def __init__(self, algebra, generator_degrees, names=None): r""" Create a finitely generated free graded module over a connected graded algebra. @@ -322,6 +349,34 @@ def __init__(self, algebra, generator_degrees): keys = list(enumerate(generator_degrees)) self._generator_keys = keys + degs_and_indices = [] + degs_so_far = {} + for i in generator_degrees: + try: + idx = degs_so_far[i] + 1 + degs_so_far[i] += 1 + except KeyError: + idx = 0 + degs_so_far[i] = 0 + degs_and_indices.append((i, idx)) + if not degs_so_far or max(degs_so_far.values()) == 0: + degs_and_indices = [str(i[0]) for i in degs_and_indices] + else: + degs_and_indices = ['{},{}'.format(i[0],i[1]) for i in degs_and_indices] + + if names is None: + names = tuple('g_{{{}}}'.format(s) for s in degs_and_indices) + elif isinstance(names, str): + if names.find(',') == -1: + names = tuple('{}_{{{}}}'.format(names, s) for s in degs_and_indices) + else: + names = tuple(s.strip() for s in names.split(',')) + else: + names = tuple(names) + self._names = names + + self._names_dict = dict(zip(keys, degs_and_indices)) + if not algebra.base_ring().is_field(): raise ValueError('the ground ring of the algebra must be a field') @@ -343,7 +398,7 @@ def generator_degrees(self): EXAMPLES:: - sage: from sage.modules.fp_graded.free_module import * + sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: A = SteenrodAlgebra(2) sage: M = FreeGradedModule(A, (-2,2,4)) sage: M.generator_degrees() @@ -361,7 +416,7 @@ def is_trivial(self): EXAMPLES:: - sage: from sage.modules.fp_graded.free_module import * + sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: A = SteenrodAlgebra(2) sage: FreeGradedModule(A, (-2,2,4)).is_trivial() False @@ -382,7 +437,7 @@ def connectivity(self): EXAMPLES:: - sage: from sage.modules.fp_graded.free_module import * + sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: A = SteenrodAlgebra(2) sage: M = FreeGradedModule(A, (-2,2,4)) sage: M.connectivity() @@ -417,15 +472,15 @@ def _element_constructor_(self, coefficients): EXAMPLES:: - sage: from sage.modules.fp_graded.free_module import * + sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: A = SteenrodAlgebra(2) - sage: M = FreeGradedModule(A, (0,2,4)) + sage: M. = FreeGradedModule(A, (0,2,4)) sage: zero = M(0); zero 0 sage: e = M((Sq(4), Sq(2), 1)); e - + Sq(4)*a + Sq(2)*b + c sage: e is M(e) True @@ -456,11 +511,11 @@ def an_element(self, n=None): EXAMPLES:: - sage: from sage.modules.fp_graded.free_module import * + sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: A = SteenrodAlgebra(2) sage: M = FreeGradedModule(A, (0,2,4)) sage: M.an_element(172) - + Sq(0,0,2,0,1,0,1)*g_{0} + Sq(0,4,0,0,1,0,1)*g_{2} + Sq(7,1,0,0,1,0,1)*g_{4} Zero is the only element in the trivial module:: @@ -495,7 +550,7 @@ def _repr_(self): TESTS:: - sage: from sage.modules.fp_graded.free_module import * + sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: A = SteenrodAlgebra(2) sage: M = FreeGradedModule(A, (0,2,4)) sage: M._repr_() @@ -506,6 +561,30 @@ def _repr_(self): self.base_ring()) + def _repr_term(self, m): + """ + Return a string representing the generator indexed by ``m``. + + INPUT: + + - ``m`` -- a key corresponding to a generator. This will be a + pair ``(idx, deg)`` where ``deg`` is the generator's degree + and ``idx`` is its index in the list of all generators. + + TESTS:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (0,2,4)) + sage: M._repr_term((1,2)) + 'g_{2}' + sage: M. = FreeGradedModule(A, (0,2,4)) + sage: M._repr_term((1,2)) + 'b' + """ + return self._names[m[0]] + + @cached_method def basis_elements(self, n): r""" @@ -531,19 +610,19 @@ def basis_elements(self, n): EXAMPLES:: - sage: from sage.modules.fp_graded.free_module import * + sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: A = SteenrodAlgebra(2) - sage: M = FreeGradedModule(A, (0,2,4)) + sage: M. = FreeGradedModule(A, (0,2,4)) sage: M.basis_elements(8) - [, - , - , - , - <0, Sq(0,2), 0>, - <0, Sq(3,1), 0>, - <0, Sq(6), 0>, - <0, 0, Sq(1,1)>, - <0, 0, Sq(4)>] + [Sq(1,0,1)*m0, + Sq(2,2)*m0, + Sq(5,1)*m0, + Sq(8)*m0, + Sq(0,2)*m2, + Sq(3,1)*m2, + Sq(6)*m2, + Sq(1,1)*m4, + Sq(4)*m4] """ basis_n = [] for i, generator_degree in enumerate(self.generator_degrees()): @@ -575,11 +654,11 @@ def element_from_coordinates(self, coordinates, n): EXAMPLES:: - sage: from sage.modules.fp_graded.free_module import * + sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: A = SteenrodAlgebra(2) sage: M = FreeGradedModule(A, (0,1)) sage: x = M.element_from_coordinates((0,1,0,1), 5); x - + Sq(5)*g_{0} + Sq(4)*g_{1} sage: basis = M.basis_elements(5) sage: y = 0*basis[0] + 1*basis[1] + 0*basis[2] + 1*basis[3] sage: x == y @@ -628,7 +707,7 @@ def __getitem__(self, n): EXAMPLES:: - sage: from sage.modules.fp_graded.free_module import * + sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: A = SteenrodAlgebra(2) sage: M = FreeGradedModule(A, (0,2,4)) sage: V = M[4]; V @@ -676,13 +755,13 @@ def vector_presentation(self, n): EXAMPLES:: - sage: from sage.modules.fp_graded.free_module import * + sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: A1 = SteenrodAlgebra(2, profile=[2,1]) - sage: M = FreeGradedModule(A1, (0,)) + sage: M. = FreeGradedModule(A1, (0,)) sage: M.vector_presentation(3) Vector space of dimension 2 over Finite Field of size 2 sage: M.basis_elements(3) - [, ] + [Sq(0,1)*x, Sq(3)*x] sage: [M.vector_presentation(i).dimension() for i in range(-2, 9)] [0, 0, 1, 1, 1, 2, 1, 1, 1, 0, 0] """ @@ -696,15 +775,15 @@ def generator(self, index): EXAMPLES:: - sage: from sage.modules.fp_graded.free_module import * + sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: A = SteenrodAlgebra(2) sage: M = FreeGradedModule(A, (0,2,4)) sage: M.generator(0) - <1, 0, 0> + g_{0} sage: M.generator(1) - <0, 1, 0> + g_{2} sage: M.generator(2) - <0, 0, 1> + g_{4} """ try: return self.monomial(self._generator_keys[index]) @@ -713,6 +792,8 @@ def generator(self, index): 'range [0, %s]; generator %s does not exist' % (len(self.generator_degrees()) - 1, index)) + gen = generator + def generators(self): r""" @@ -720,11 +801,11 @@ def generators(self): EXAMPLES:: - sage: from sage.modules.fp_graded.free_module import * + sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: A = SteenrodAlgebra(2) - sage: M = FreeGradedModule(A, (0,1)) + sage: M = FreeGradedModule(A, (-2,1)) sage: M.generators() - [<1, 0>, <0, 1>] + [g_{-2}, g_{1}] """ return [self.generator(i) for i in range(len(self.generator_degrees()))] @@ -767,7 +848,7 @@ def suspension(self, t): EXAMPLES:: - sage: from sage.modules.fp_graded.free_module import * + sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: A = SteenrodAlgebra(2) sage: M = FreeGradedModule(A, (0,2,4)) sage: M.suspension(4).generator_degrees() diff --git a/src/sage/modules/fp_graded/free_morphism.py b/src/sage/modules/fp_graded/free_morphism.py index 8ead453daf3..71121deea02 100755 --- a/src/sage/modules/fp_graded/free_morphism.py +++ b/src/sage/modules/fp_graded/free_morphism.py @@ -45,18 +45,18 @@ class FreeGradedModuleMorphism(Morphism): sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: A = SteenrodAlgebra(2) - sage: F1 = FreeGradedModule(A, (4,5)) - sage: F2 = FreeGradedModule(A, (3,4)) - sage: F3 = FreeGradedModule(A, (2,3)) + sage: F1 = FreeGradedModule(A, (4,5), names='b') + sage: F2 = FreeGradedModule(A, (3,4), names='c') + sage: F3 = FreeGradedModule(A, (2,3), names='d') sage: H1 = Hom(F1, F2) sage: H2 = Hom(F2, F3) sage: f = H1( ( F2((Sq(4), 0)), F2((0, Sq(4))) ) ) sage: g = H2( ( F3((Sq(2), 0)), F3((Sq(3), Sq(2))) ) ) sage: g*f Module homomorphism of degree 4 defined by sending the generators - [<1, 0>, <0, 1>] + [b_{4}, b_{5}] to - [, ] + [(Sq(0,2)+Sq(3,1)+Sq(6))*d_{2}, (Sq(1,2)+Sq(7))*d_{2} + (Sq(0,2)+Sq(3,1)+Sq(6))*d_{3}] TESTS:: @@ -179,7 +179,7 @@ def values(self): sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] sage: f = homspace(values) sage: f.values() - [, ] + [Sq(5)*g_{2}, Sq(3,1)*g_{2}] sage: homspace.zero().values() [0, 0] """ @@ -278,9 +278,9 @@ def _neg_(self): sage: f = homspace(values) sage: f_inverse = -f; f_inverse Module homomorphism of degree 7 defined by sending the generators - [<1, 0>, <0, 1>] + [g_{0}, g_{1}] to - [, ] + [Sq(5)*g_{2}, Sq(3,1)*g_{2}] sage: (f + f_inverse).is_zero() True """ @@ -325,9 +325,9 @@ def __mul__(self, g): sage: g = Hom(N, M)(values2) sage: fg = f * g; fg Module homomorphism of degree 7 defined by sending the generators - [<1>] + [g_{2}] to - [] + [(Sq(4,1)+Sq(7))*g_{2}] sage: fg.is_endomorphism() True @@ -427,9 +427,9 @@ def __call__(self, x): sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] sage: f = Hom(M, N)(values) sage: f.__call__(M.generator(0)) - + Sq(5)*g_{2} sage: f.__call__(M.generator(1)) - + Sq(3,1)*g_{2} """ if x.parent() != self.domain(): raise ValueError('cannot evaluate morphism on element not in the domain') @@ -454,7 +454,7 @@ def _repr_(self): sage: Hom(M, N)(values)._repr_() 'Module homomorphism of degree 7 defined by sending the generators\n - [<1, 0>, <0, 1>]\nto\n [, ]' + [g_{0}, g_{1}]\nto\n [Sq(5)*g_{2}, Sq(3,1)*g_{2}]' sage: Hom(M, N).zero()._repr_() 'The trivial homomorphism' @@ -573,7 +573,7 @@ def to_fp_module(self): sage: M.generator_degrees() (0,) sage: M.relations() - [] + [Sq(2)*g_{0}] """ from .module import FPModule return FPModule(algebra=self.base_ring(), diff --git a/src/sage/modules/fp_graded/homspace.py b/src/sage/modules/fp_graded/homspace.py index c271fe0a9a1..fe755660e5c 100755 --- a/src/sage/modules/fp_graded/homspace.py +++ b/src/sage/modules/fp_graded/homspace.py @@ -10,25 +10,25 @@ sage: from sage.modules.fp_graded.module import FPModule sage: from sage.misc.sage_unittest import TestSuite sage: A = SteenrodAlgebra(2, profile=(3,2,1)) - sage: F = FPModule(A, [1,3]) - sage: L = FPModule(A, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]) + sage: F = FPModule(A, [1,3], names='c') + sage: L = FPModule(A, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]], names='h') sage: homset = Hom(F, L); homset Set of Morphisms from Finitely presented left module on 2 generators ... sage: homset.an_element() Module homomorphism of degree 0 defined by sending the generators - [<1, 0>, <0, 1>] + [c_{1}, c_{3}] to - [0, ] + [0, Sq(1)*h_{2}] sage: homset([L((A.Sq(1), 1)), L((0, A.Sq(2)))]) Module homomorphism of degree 2 defined by sending the generators - [<1, 0>, <0, 1>] + [c_{1}, c_{3}] to - [, <0, Sq(2)>] + [Sq(1)*h_{2} + h_{3}, Sq(2)*h_{3}] sage: Hom(F, L) ([L((A.Sq(1), 1)), L((0, A.Sq(2)))]).kernel() Module homomorphism of degree 0 defined by sending the generators - [<1, 0>, <0, 1>] + [g_{3}, g_{4}] to - (<0, 1>, ) + (c_{3}, Sq(0,1)*c_{1}) AUTHORS: @@ -100,9 +100,9 @@ def _element_constructor_(self, values): sage: f = homset([v1, v2]); f Module homomorphism of degree 2 defined by sending the generators - [<1, 0>, <0, 1>] + [g_{1}, g_{3}] to - [, <0, Sq(2)>] + [Sq(1)*g_{2} + g_{3}, Sq(2)*g_{3}] One can construct a homomorphism from another homomorhism:: @@ -143,25 +143,25 @@ def an_element(self, n=0): sage: Hom(HZ, HZ).an_element(3) Module homomorphism of degree 3 defined by sending the generators - [<1>] + [g_{0}] to - [] + [Sq(0,1)*g_{0}] TESTS:: sage: K = FPModule(A, [0, 0], [[Sq(2), 0]]) # Using a zero coefficient in the relations. sage: Hom(K, K).an_element(4) Module homomorphism of degree 4 defined by sending the generators - [<1, 0>, <0, 1>] + [g_{0,0}, g_{0,1}] to - [0, ] + [0, Sq(4)*g_{0,0}] sage: K = FPModule(A, [0, 0], [[Sq(2), 0], [0,0], [Sq(4), Sq(2)*Sq(2)]]) sage: Hom(K, K).an_element(n=3) Module homomorphism of degree 3 defined by sending the generators - [<1, 0>, <0, 1>] + [g_{0,0}, g_{0,1}] to - [0, ] + [0, Sq(0,1)*g_{0,0}] """ return self._basis_elements(n, basis=False) @@ -186,13 +186,13 @@ def basis_elements(self, n): sage: Hom(Hko, Hko).basis_elements(21) [Module homomorphism of degree 21 defined by sending the generators - [<1>] + [g_{0}] to - [], + [(Sq(0,0,3)+Sq(0,2,0,1))*g_{0}], Module homomorphism of degree 21 defined by sending the generators - [<1>] + [g_{0}] to - []] + [Sq(8,2,1)*g_{0}]] """ return self._basis_elements(n, basis=True) @@ -279,32 +279,32 @@ def _basis_elements(self, n, basis): sage: Hko = FPModule(A, [0], relations=[[Sq(2)], [Sq(1)]]) sage: Hom(Hko, Hko)._basis_elements(21, basis=True) [Module homomorphism of degree 21 defined by sending the generators - [<1>] + [g_{0}] to - [], + [(Sq(0,0,3)+Sq(0,2,0,1))*g_{0}], Module homomorphism of degree 21 defined by sending the generators - [<1>] + [g_{0}] to - []] + [Sq(8,2,1)*g_{0}]] sage: Hom(Hko, Hko)._basis_elements(21, basis=False) Module homomorphism of degree 21 defined by sending the generators - [<1>] + [g_{0}] to - [] + [(Sq(0,0,3)+Sq(0,2,0,1))*g_{0}] sage: F = FPModule(A, [0]) sage: Hom(F, Hko)._basis_elements(21, basis=False) Module homomorphism of degree 21 defined by sending the generators - [<1>] + [g_{0}] to - [] + [Sq(0,2,0,1)*g_{0}] sage: Hom(F, Hko)._basis_elements(21, basis=False) Module homomorphism of degree 21 defined by sending the generators - [<1>] + [g_{0}] to - [] + [Sq(0,2,0,1)*g_{0}] Hom(FPA_Module([0], A, [[Sq(1)]]), FPA_Module([-2], A, [[Sq(1)]])).an_element(0) The trivial homomorphism @@ -328,34 +328,34 @@ def _basis_elements(self, n, basis): Hom(Free, Free): basis==False: Module homomorphism of degree 7 defined by sending the generators - [<1>] + [g_{0}] to - [] + [Sq(0,0,1)*g_{0}] basis==True: [Module homomorphism of degree 7 defined by sending the generators - [<1>] + [g_{0}] to - [], Module homomorphism of degree 7 defined by sending the generators - [<1>] + [Sq(0,0,1)*g_{0}], Module homomorphism of degree 7 defined by sending the generators + [g_{0}] to - [], Module homomorphism of degree 7 defined by sending the generators - [<1>] + [Sq(1,2)*g_{0}], Module homomorphism of degree 7 defined by sending the generators + [g_{0}] to - [], Module homomorphism of degree 7 defined by sending the generators - [<1>] + [Sq(4,1)*g_{0}], Module homomorphism of degree 7 defined by sending the generators + [g_{0}] to - []] + [Sq(7)*g_{0}]] Hom(Free, Hko): basis==False: Module homomorphism of degree 7 defined by sending the generators - [<1>] + [g_{0}] to - [] + [Sq(0,0,1)*g_{0}] basis==True: [Module homomorphism of degree 7 defined by sending the generators - [<1>] + [g_{0}] to - []] + [Sq(0,0,1)*g_{0}]] Hom(Free, Trivial): basis==False: The trivial homomorphism @@ -374,14 +374,14 @@ def _basis_elements(self, n, basis): Hom(Hko, Hko): basis==False: Module homomorphism of degree 7 defined by sending the generators - [<1>] + [g_{0}] to - [] + [Sq(0,0,1)*g_{0}] basis==True: [Module homomorphism of degree 7 defined by sending the generators - [<1>] + [g_{0}] to - []] + [Sq(0,0,1)*g_{0}]] Hom(Hko, Trivial): basis==False: The trivial homomorphism diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index 5c9bd2119bd..b542e161b73 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -88,13 +88,15 @@ class FPModule(Module, IndexedGenerators, UniqueRepresentation): sage: a, b = M.generators() sage: x*a + b == 0 True + sage: (x*a + b).normalize() + 0 sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) sage: M = FPModule(A3, [0, 1], [[Sq(2), Sq(1)]]) sage: M.generators() - [<1, 0>, <0, 1>] + [g_{0}, g_{1}] sage: M.relations() - [] + [Sq(2)*g_{0} + Sq(1)*g_{1}] sage: M.is_trivial() False @@ -107,7 +109,7 @@ class FPModule(Module, IndexedGenerators, UniqueRepresentation): True """ @staticmethod - def __classcall_private__(cls, algebra, generator_degrees, relations=()): + def __classcall_private__(cls, algebra, generator_degrees, relations=(), names=None): r""" Normalize input to ensure a unique representation. @@ -122,10 +124,10 @@ def __classcall_private__(cls, algebra, generator_degrees, relations=()): return super(FPModule, cls).__classcall__(cls, algebra=algebra, generator_degrees=tuple(generator_degrees), - relations=tuple([tuple([algebra(x) for x in r]) for r in relations])) + relations=tuple([tuple([algebra(x) for x in r]) for r in relations]), + names=names) - - def __init__(self, algebra, generator_degrees, relations=()): + def __init__(self, algebra, generator_degrees, relations=(), names=None): r""" Create a finitely presented module over a connected graded algebra. @@ -144,7 +146,7 @@ def __init__(self, algebra, generator_degrees, relations=()): self._generator_keys = keys # The free module on the generators of the module. - generator_module = FreeGradedModule(algebra, generator_degrees) + generator_module = FreeGradedModule(algebra, generator_degrees, names) # Use the coefficients given for the relations and make module elements # from them. Filter out the zero elements, as they are redundant. rels = [v for v in [generator_module(r) for r in relations] if not v.is_zero()] @@ -172,12 +174,12 @@ def _free_module(self): sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra() - sage: M = FPModule(A, [0, 1], [[Sq(2), Sq(1)]]) + sage: M. = FPModule(A, [0, 1], [[Sq(2), Sq(1)]]) sage: M.generators() - [<1, 0>, <0, 1>] + [x, y] sage: F = M._free_module() sage: F.generators() - [<1, 0>, <0, 1>] + [x, y] """ return self.j.codomain() @@ -239,7 +241,7 @@ def from_free_module_morphism(cls, morphism): sage: M.generator_degrees() (0,) sage: M.relations() - [] + [Sq(2)*g_{0}] """ return cls(algebra=morphism.base_ring(), generator_degrees=morphism.codomain().generator_degrees(), @@ -334,9 +336,9 @@ def _monomial(self, index): sage: from sage.modules.fp_graded.module import FPModule sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) sage: M._monomial((0,0)) - <1, 0> + g_{0} sage: M._monomial((1,1)) - <0, 1> + g_{1} """ return self._from_dict({index: self.base_ring().one()}, remove_zeros=False) @@ -354,9 +356,9 @@ def monomial(self): sage: from sage.modules.fp_graded.module import FPModule sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) sage: M.monomial((0,0)) - <1, 0> + g_{0} sage: M.monomial((1,1)) - <0, 1> + g_{1} """ # Should use a real Map, as soon as combinatorial_classes are enumerated sets, and therefore parents from sage.categories.poor_man_map import PoorManMap @@ -384,11 +386,11 @@ def _element_constructor_(self, x): sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) - sage: M = FPModule(A, [0,2,4], [[Sq(4), Sq(2), 0]]) + sage: M. = FPModule(A, [0,2,4], [[Sq(4), Sq(2), 0]]) sage: # Creating an element from coefficients: sage: e = M((Sq(6), 0, Sq(2))); e - + Sq(6)*a0 + Sq(2)*a4 sage: e in M True @@ -400,7 +402,7 @@ def _element_constructor_(self, x): sage: # Creating an element from another element returns a reference to itself: sage: M(e) - + Sq(6)*a0 + Sq(2)*a4 sage: e is M(e) True """ @@ -446,6 +448,21 @@ def _repr_(self): self.base_ring()) + def _repr_term(self, m): + """ + Return a string representing the generator indexed by ``m``. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FPModule + sage: A = SteenrodAlgebra(2) + sage: M = FPModule(A, [0,2,4], [[Sq(4),Sq(2),0]]) + sage: M._repr_term((2,4)) + 'g_{4}' + """ + return self._free_module()._repr_term(m) + + def connectivity(self): r""" The connectivity of ``self``. @@ -603,16 +620,16 @@ def an_element(self, n=None): sage: M = FPModule(A2, [0,2,4], [[0, Sq(5), Sq(3)], [Sq(7), 0, Sq(2)*Sq(1)]]) sage: [M.an_element(i) for i in range(10)] - [<1, 0, 0>, - , - , - , - , - , - , - , - , - ] + [g_{0}, + Sq(1)*g_{0}, + Sq(2)*g_{0} + g_{2}, + Sq(0,1)*g_{0} + Sq(1)*g_{2}, + Sq(1,1)*g_{0} + Sq(2)*g_{2} + g_{4}, + Sq(2,1)*g_{0} + Sq(0,1)*g_{2} + Sq(1)*g_{4}, + Sq(0,2)*g_{0} + Sq(1,1)*g_{2} + Sq(2)*g_{4}, + Sq(0,0,1)*g_{0} + Sq(2,1)*g_{2} + Sq(0,1)*g_{4}, + Sq(1,0,1)*g_{0} + Sq(6)*g_{2} + Sq(1,1)*g_{4}, + Sq(2,0,1)*g_{0} + Sq(4,1)*g_{2} + Sq(2,1)*g_{4}] """ a_free_element = self._free_module().an_element(n) return self(a_free_element) @@ -644,22 +661,22 @@ def basis_elements(self, n, verbose=False): sage: from sage.modules.fp_graded.module import FPModule sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) - sage: M = FPModule(A2, [0,2], [[Sq(4), Sq(2)], [0, Sq(6)]]) + sage: M. = FPModule(A2, [0,2], [[Sq(4), Sq(2)], [0, Sq(6)]]) sage: M.basis_elements(4) - [, ] + [Sq(1,1)*m0, Sq(4)*m0] sage: M.basis_elements(5) - [, , <0, Sq(0,1)>] + [Sq(2,1)*m0, Sq(5)*m0, Sq(0,1)*m2] sage: M.basis_elements(25) [] sage: M.basis_elements(0) - [<1, 0>] + [m0] sage: M.basis_elements(2) - [, <0, 1>] + [Sq(2)*m0, m2] TESTS:: @@ -704,7 +721,7 @@ def element_from_coordinates(self, coordinates, n): sage: M.vector_presentation(12).dimension() 3 sage: x = M.element_from_coordinates((0,1,0), 12); x - + Sq(0,4)*g_{0} Applying the inverse function brings us back to the coordinate form:: @@ -754,7 +771,7 @@ def __getitem__(self, n): sage: M = FPModule(A, [0,2,4], [[Sq(4),Sq(2),0]]) sage: M[4] - [, , <0, 0, 1>] + [Sq(1,1)*g_{0}, Sq(4)*g_{0}, g_{4}] .. SEEALSO:: @@ -885,13 +902,13 @@ def generators(self): sage: from sage.modules.fp_graded.module import FPModule sage: A4 = SteenrodAlgebra(2, profile=(4,3,2,1)) - sage: M = FPModule(A4, [0,2,3]) + sage: M = FPModule(A4, [0,0,2,3]) sage: M.generators() - [<1, 0, 0>, <0, 1, 0>, <0, 0, 1>] + [g_{0,0}, g_{0,1}, g_{2,0}, g_{3,0}] - sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]]) + sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]], names='h') sage: N.generators() - [<1, 0>, <0, 1>] + [h_{0}, h_{1}] sage: Z = FPModule(A4, []) sage: Z.generators() @@ -913,11 +930,11 @@ def generator(self, index): sage: M = FPModule(A4, [0,2,3]) sage: M.generator(0) - <1, 0, 0> + g_{0} - sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]]) + sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]], names='h') sage: N.generator(1) - <0, 1> + h_{1} """ return self(self._free_module().generator(index)) @@ -939,7 +956,7 @@ def relations(self): sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]]) sage: N.relations() - [] + [Sq(2)*g_{0} + Sq(1)*g_{1}] sage: Z = FPModule(A4, []) sage: Z.relations() @@ -958,7 +975,7 @@ def relation(self, index): sage: A4 = SteenrodAlgebra(2, profile=(4,3,2,1)) sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]]) sage: N.relation(0) - + Sq(2)*g_{0} + Sq(1)*g_{1} """ return self.j.values()[index] @@ -991,9 +1008,9 @@ def min_presentation(self, top_dim=None, verbose=False): sage: # There are more relations in M than in M_min: sage: M.relations() - [, <0, Sq(2)>, ] + [Sq(2)*g_{0} + Sq(1)*g_{1}, Sq(2)*g_{1}, Sq(3)*g_{0}] sage: M_min.relations() - [, <0, Sq(2)>] + [Sq(2)*g_{0} + Sq(1)*g_{1}, Sq(2)*g_{1}] TESTS:: @@ -1031,14 +1048,14 @@ def suspension(self, t): sage: X.generator_degrees() (4,) sage: X.relations() - [] + [Sq(1)*g_{4}] sage: M = FPModule(A, [2,3], [[Sq(2), Sq(1)], [0, Sq(2)]]) sage: Q = M.suspension(1) sage: Q.generator_degrees() (3, 4) sage: Q.relations() - [, <0, Sq(2)>] + [Sq(2)*g_{3} + Sq(1)*g_{4}, Sq(2)*g_{4}] sage: Q = M.suspension(-3) sage: Q.generator_degrees() (-1, 0) @@ -1077,7 +1094,7 @@ def submodule(self, spanning_elements): sage: i.domain().generator_degrees() (0,) sage: i.domain().relations() - [] + [Sq(3)*g_{0}] """ # Create the free graded module on the set of spanning elements. degs = [x.degree() for x in spanning_elements] @@ -1126,9 +1143,9 @@ def resolution(self, k, top_dim=None, verbose=False): sage: M = FPModule(A2, [0,1], [[Sq(2), Sq(1)]]) sage: M.resolution(0) [Module homomorphism of degree 0 defined by sending the generators - [<1, 0>, <0, 1>] + [g_{0}, g_{1}] to - (<1, 0>, <0, 1>)] + (g_{0}, g_{1})] sage: res = M.resolution(4, verbose=True) Computing f_1 (1/4) Computing f_2 (2/4) @@ -1144,25 +1161,25 @@ def resolution(self, k, top_dim=None, verbose=False): 5 sage: res [Module homomorphism of degree 0 defined by sending the generators - [<1, 0>, <0, 1>] + [g_{0}, g_{1}] to - (<1, 0>, <0, 1>), + (g_{0}, g_{1}), Module homomorphism of degree 0 defined by sending the generators - [<1>] + [g_{2}] to - (,), + (Sq(2)*g_{0} + Sq(1)*g_{1},), Module homomorphism of degree 0 defined by sending the generators - [<1>] + [g_{8}] to - (,), + (Sq(3,1)*g_{2},), Module homomorphism of degree 0 defined by sending the generators - [<1, 0>, <0, 1>] + [g_{9}, g_{10}] to - (, ), + (Sq(1)*g_{8}, Sq(2)*g_{8}), Module homomorphism of degree 0 defined by sending the generators - [<1, 0>, <0, 1>] + [g_{10}, g_{12}] to - (, )] + (Sq(1)*g_{9}, Sq(0,1)*g_{9} + Sq(2)*g_{10})] sage: for i in range(len(res)-1): ....: assert (res[i]*res[i+1]).is_zero(), 'the result is not a complex' """ diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py index 5c84c44e847..28c110b7d96 100755 --- a/src/sage/modules/fp_graded/morphism.py +++ b/src/sage/modules/fp_graded/morphism.py @@ -170,7 +170,7 @@ class FPModuleMorphism(Morphism): sage: w = Hom(Q, F)( (F((1, 0)), F((0, 1))) ) Traceback (most recent call last): ... - ValueError: relation is not sent to zero + ValueError: relation Sq(6)*g_{2} + Sq(5)*g_{3} is not sent to zero """ def __init__(self, parent, values): r""" @@ -229,9 +229,9 @@ def change_ring(self, algebra): sage: f = Hom(M,N)([A2.Sq(3)*N.generator(0)]); f Module homomorphism of degree 3 defined by sending the generators - [<1>] + [g_{0}] to - [] + [Sq(3)*g_{0}] sage: f.base_ring() sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] @@ -314,7 +314,7 @@ def values(self): sage: f = homspace(values) sage: f.values() - [, ] + [Sq(5)*g_{2}, Sq(3,1)*g_{2}] sage: homspace.zero().values() [0, 0] @@ -415,9 +415,9 @@ def __neg__(self): sage: f = homspace(values) sage: f_inverse = f.__neg__(); f_inverse Module homomorphism of degree 7 defined by sending the generators - [<1, 0>, <0, 1>] + [g_{0}, g_{1}] to - [, ] + [Sq(5)*g_{2}, Sq(3,1)*g_{2}] sage: (f + f_inverse).is_zero() True """ @@ -439,17 +439,17 @@ def __sub__(self, g): sage: g = Hom(M, N)( [Sq(0,1)*N.generator(0)] ) sage: f.__sub__(g) Module homomorphism of degree 3 defined by sending the generators - [<1>] + [g_{0}] to - [] + [(Sq(0,1)+Sq(3))*g_{0}] sage: f = Hom(M, N)( [Sq(4)*N.generator(0)] ) # the zero map sage: g = Hom(M, N)( [Sq(1,1)*N.generator(0)] ) sage: f.__sub__(g) Module homomorphism of degree 4 defined by sending the generators - [<1>] + [g_{0}] to - [] + [Sq(1,1)*g_{0}] """ return self.__add__(g.__neg__()) @@ -468,9 +468,9 @@ def __mul__(self, g): sage: g = Hom(N, M)( [Sq(2,2)*M.generator(0)] ) sage: fg = f.__mul__(g); fg Module homomorphism of degree 10 defined by sending the generators - [<1>] + [g_{0}] to - [] + [(Sq(0,1,1)+Sq(1,3)+Sq(3,0,1))*g_{0}] sage: fg.is_endomorphism() True @@ -572,10 +572,10 @@ def __call__(self, x): sage: f = Hom(M, N)(values) sage: f.__call__(M.generator(0)) - + Sq(5)*g_{2} sage: f.__call__(M.generator(1)) - + Sq(3,1)*g_{2} """ if x.parent() != self.domain(): raise ValueError('cannot evaluate morphism on element not in domain') @@ -596,7 +596,7 @@ def _repr_(self): sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] sage: Hom(M, N)(values)._repr_() 'Module homomorphism of degree 7 defined by sending the generators\n - [<1, 0>, <0, 1>]\nto\n [, ]' + [g_{0}, g_{1}]\nto\n [Sq(5)*g_{2}, Sq(3,1)*g_{2}]' sage: Hom(M, N).zero()._repr_() 'The trivial homomorphism' sage: Hom(M, M).identity()._repr_() @@ -739,9 +739,9 @@ def solve(self, x): sage: N = FPModule(A, [0], [[Sq(2,2)]]) sage: f = Hom(M, N)( [Sq(2)*N.generator(0)] ) sage: y = Sq(1,1)*N.generator(0); y - + Sq(1,1)*g_{0} sage: x = f.solve(y); x - + Sq(2)*g_{0} sage: y == f(x) True @@ -841,9 +841,9 @@ def lift(self, f, verbose=False): True sage: f_ Module homomorphism of degree 1 defined by sending the generators - [<1>] + [g_{0}] to - [] + [Sq(1)*g_{0}] A split projection:: @@ -858,9 +858,9 @@ def lift(self, f, verbose=False): sage: id = Hom(HZ,HZ).identity() sage: j = id.lift(q); j Module homomorphism of degree 0 defined by sending the generators - [<1>] + [g_{0}] to - [<0, 1>] + [g_{0,1}] sage: q*j The identity homomorphism @@ -872,9 +872,9 @@ def lift(self, f, verbose=False): sage: im = f.image(top_dim=10) sage: f.lift(im) Module homomorphism of degree 2 defined by sending the generators - [<1>] + [g_{0}] to - [<1>] + [g_{2}] When a lift cannot be found, the ``None`` value is returned. By setting the verbose argument to ``True``, an explanation of why @@ -924,9 +924,9 @@ def lift(self, f, verbose=False): sage: k = f.kernel() # long time sage: f.lift(k) # long time Module homomorphism of degree 21 defined by sending the generators - [<1>] + [g_{0}] to - [<0, Sq(1), 0>] + [Sq(1)*g_{20}] Corner cases involving trivial maps:: @@ -1081,9 +1081,9 @@ def split(self, verbose=False): sage: p = Hom(M, N)([N.generator(0), N.generator(0)]) sage: s = p.split(); s Module homomorphism of degree 0 defined by sending the generators - [<1>] + [g_{0}] to - [<0, 1>] + [g_{0,1}] sage: # Verify that `s` is a splitting: sage: p*s The identity homomorphism @@ -1180,22 +1180,22 @@ def suspension(self, t): sage: f = Hom(F1, F2)( ( F2([Sq(4)]), F2([Sq(5)]) ) ); f Module homomorphism of degree 5 defined by sending the generators - [<1, 0>, <0, 1>] + [g_{4}, g_{5}] to - (, ) + (Sq(4)*g_{5}, Sq(5)*g_{5}) sage: e1 = F1([1, 0]) sage: e2 = F1([0, 1]) sage: f(e1) - + Sq(4)*g_{5} sage: f(e2) - + Sq(5)*g_{5} sage: sf = f.suspension(4); sf Module homomorphism of degree 5 defined by sending the generators - [<1, 0>, <0, 1>] + [g_{8}, g_{9}] to - [, ] + [Sq(4)*g_{9}, Sq(5)*g_{9}] sage: sf.domain() is f.domain().suspension(4) True @@ -1230,9 +1230,9 @@ def cokernel(self): sage: r = Hom(F, M)([A1.Sq(1)*M.generator(0)]) sage: co = r.cokernel(); co Module homomorphism of degree 0 defined by sending the generators - [<1>] + [g_{0}] to - [<1>] + [g_{0}] sage: co.domain().is_trivial() False @@ -1280,9 +1280,9 @@ def kernel(self, top_dim=None, verbose=False): sage: H([L((A3.Sq(1), 1)), L((0, A3.Sq(2)))]).kernel() # long time Module homomorphism of degree 0 defined by sending the generators - [<1, 0>, <0, 1>] + [g_{3}, g_{4}] to - (<0, 1>, ) + (g_{3}, Sq(0,1)*g_{1}) sage: M = FPModule(A3, [0,7], [[Sq(1), 0], [Sq(2), 0], [Sq(4), 0], [Sq(8), Sq(1)], [0, Sq(7)], [0, Sq(0,1,1)+Sq(4,2)]]) sage: F2 = FPModule(A3, [0], [[Sq(1)], [Sq(2)], [Sq(4)], [Sq(8)], [Sq(15)]]) @@ -1298,18 +1298,18 @@ def kernel(self, top_dim=None, verbose=False): 7 8 9 10 11 12 13 14 15 16 17. sage: K.domain().generators() - [<1>] + [g_{7}] sage: K.domain().relations() - [, - , - , - ] + [(Sq(0,1)+Sq(3))*g_{7}, + (Sq(0,0,1)+Sq(1,2)+Sq(4,1))*g_{7}, + Sq(9)*g_{7}, + (Sq(0,1,1)+Sq(4,2))*g_{7}] sage: K Module homomorphism of degree 0 defined by sending the generators - [<1>] + [g_{7}] to - (<0, 1>,) + (g_{7},) """ if verbose: print('1. Computing the generators of the kernel presentation:') @@ -1357,9 +1357,9 @@ def image(self, top_dim=None, verbose=False): sage: H([L((A3.Sq(1), 1)), L((0, A3.Sq(2)))]).image() # long time Module homomorphism of degree 0 defined by sending the generators - [<1>] + [g_{3}] to - (,) + (Sq(1)*g_{2} + g_{3},) sage: M = FPModule(A3, [0,7], [[Sq(1), 0], [Sq(2), 0], [Sq(4), 0], [Sq(8), Sq(1)], [0, Sq(7)], [0, Sq(0,1,1)+Sq(4,2)]]) sage: F2 = FPModule(A3, [0], [[Sq(1)], [Sq(2)], [Sq(4)], [Sq(8)], [Sq(15)]]) @@ -1378,7 +1378,7 @@ def image(self, top_dim=None, verbose=False): sage: K.domain().generator_degrees() (0,) sage: K.domain().relations() - [, , , ] + [Sq(1)*g_{0}, Sq(2)*g_{0}, Sq(4)*g_{0}, Sq(8)*g_{0}] sage: K.domain().is_trivial() False @@ -1489,15 +1489,15 @@ def _resolve_kernel(self, top_dim=None, verbose=False): ValueError: a top dimension must be specified for this calculation to terminate sage: f._resolve_kernel(top_dim=20) Module homomorphism of degree 0 defined by sending the generators - [<1, 0, 0>, <0, 1, 0>, <0, 0, 1>] + [g_{0,0}, g_{3,0}, g_{3,1}] to - (<0, 1>, , ) + (g_{0,1}, Sq(0,1)*g_{0,0}, Sq(3)*g_{0,0}) sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) sage: f.change_ring(A3)._resolve_kernel() # long time Module homomorphism of degree 0 defined by sending the generators - [<1, 0, 0>, <0, 1, 0>, <0, 0, 1>] + [g_{0,0}, g_{3,0}, g_{3,1}] to - (<0, 1>, , ) + (g_{0,1}, Sq(0,1)*g_{0,0}, Sq(3)*g_{0,0}) """ # Let # @@ -1626,15 +1626,15 @@ def _resolve_image(self, top_dim=None, verbose=False): ValueError: a top dimension must be specified for this calculation to terminate sage: f._resolve_image(top_dim=20) Module homomorphism of degree 0 defined by sending the generators - [<1>] + [g_{2}] to - (,) + (Sq(2)*g_{0,0},) sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) sage: f.change_ring(A3)._resolve_image() # long time Module homomorphism of degree 0 defined by sending the generators - [<1>] + [g_{2}] to - (,) + (Sq(2)*g_{0,0},) """ # Let # @@ -1749,7 +1749,7 @@ def to_fp_module(self): sage: M.generator_degrees() (0,) sage: M.relations() - [] + [Sq(2)*g_{0}] sage: F3 = FPModule(A, (0,), [[Sq(4)]]) sage: pres = Hom(F1, F3)([v]) From a12a8380fa33f8fb08c9c8b0cf9214c5a123861c Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Thu, 9 Dec 2021 20:05:01 -0800 Subject: [PATCH 045/253] trac 32505: rename kernel() to kernel_morphism() and similar for cokernel and submodule. --- src/sage/modules/fp_graded/homspace.py | 2 +- src/sage/modules/fp_graded/module.py | 9 +++++---- src/sage/modules/fp_graded/morphism.py | 20 ++++++++++---------- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/sage/modules/fp_graded/homspace.py b/src/sage/modules/fp_graded/homspace.py index fe755660e5c..28ae792ae77 100755 --- a/src/sage/modules/fp_graded/homspace.py +++ b/src/sage/modules/fp_graded/homspace.py @@ -24,7 +24,7 @@ [c_{1}, c_{3}] to [Sq(1)*h_{2} + h_{3}, Sq(2)*h_{3}] - sage: Hom(F, L) ([L((A.Sq(1), 1)), L((0, A.Sq(2)))]).kernel() + sage: Hom(F, L) ([L((A.Sq(1), 1)), L((0, A.Sq(2)))]).kernel_morphism() Module homomorphism of degree 0 defined by sending the generators [g_{3}, g_{4}] to diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index b542e161b73..85e61d70a2a 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -13,7 +13,7 @@ This package was designed with homological algebra in mind, and its API focuses on maps rather than objects. A good example of this is the kernel -function :meth:`sage.modules.fp_graded.morphism.FPModuleMorphism.kernel` +function :meth:`sage.modules.fp_graded.morphism.FPModuleMorphism.kernel_morphism` which computes the kernel of a homomorphism `f: M\to N`. Its return value is not an instance of the module class, but rather an injective homomorphism `i: K\to M` with the property that `\operatorname{im}(i) = \ker(f)`. @@ -1068,9 +1068,10 @@ def suspension(self, t): relations=self._relations) - def submodule(self, spanning_elements): + def submodule_inclusion(self, spanning_elements): r""" - Return the submodule of ``self`` spanned by the given elements. + Return the inclusion morphism of the submodule of ``self`` spanned + by the given elements. INPUT: @@ -1086,7 +1087,7 @@ def submodule(self, spanning_elements): sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) sage: M = FPModule(A2, [0,1], [[Sq(2),Sq(1)]]) - sage: i = M.submodule([M.generator(0)]) + sage: i = M.submodule_inclusion([M.generator(0)]) sage: i.codomain() is M True sage: i.is_injective() diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py index 28c110b7d96..287ef0a0d49 100755 --- a/src/sage/modules/fp_graded/morphism.py +++ b/src/sage/modules/fp_graded/morphism.py @@ -921,7 +921,7 @@ def lift(self, f, verbose=False): sage: f = Hom(Hko, Hko)([(Ap.Sq(0,0,3) + Ap.Sq(0,2,0,1))*Hko.generator(0)]) sage: f*f == 0 True - sage: k = f.kernel() # long time + sage: k = f.kernel_morphism() # long time sage: f.lift(k) # long time Module homomorphism of degree 21 defined by sending the generators [g_{0}] @@ -991,7 +991,7 @@ def lift(self, f, verbose=False): # Compute the kernel of f. The equations we will solve will live in # this submodule. - iK = f.kernel(top_dim=max([r.degree() + lift_deg for r in L.relations()])) + iK = f.kernel_morphism(top_dim=max([r.degree() + lift_deg for r in L.relations()])) source_degs = [g.degree() + lift_deg for g in L.generators()] target_degs = [r.degree() + lift_deg for r in L.relations()] @@ -1149,14 +1149,14 @@ def homology(self, f, top_dim=None, verbose=False): sage: ho.codomain().is_trivial() False """ - k = self.kernel(top_dim, verbose) + k = self.kernel_morphism(top_dim, verbose) f_ = f.lift(k) if f_ is None: raise ValueError('the image of the given homomorphism is not contained ' 'in the kernel of this homomorphism; the homology is ' 'therefore not defined for this pair of maps') - return f_.cokernel() + return f_.cokernel_morphism() def suspension(self, t): @@ -1211,7 +1211,7 @@ def suspension(self, t): return Hom(D, C)([C(x.lift_to_free().dense_coefficient_list()) for x in self._values]) - def cokernel(self): + def cokernel_morphism(self): r""" Compute the cokernel of ``self``. @@ -1228,7 +1228,7 @@ def cokernel(self): sage: F = FPModule(A1, [0]) sage: r = Hom(F, M)([A1.Sq(1)*M.generator(0)]) - sage: co = r.cokernel(); co + sage: co = r.cokernel_morphism(); co Module homomorphism of degree 0 defined by sending the generators [g_{0}] to @@ -1250,7 +1250,7 @@ def cokernel(self): return projection - def kernel(self, top_dim=None, verbose=False): + def kernel_morphism(self, top_dim=None, verbose=False): r""" Compute the kernel of ``self``. @@ -1278,7 +1278,7 @@ def kernel(self, top_dim=None, verbose=False): sage: L = FPModule(A3, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]); sage: H = Hom(F, L); - sage: H([L((A3.Sq(1), 1)), L((0, A3.Sq(2)))]).kernel() # long time + sage: H([L((A3.Sq(1), 1)), L((0, A3.Sq(2)))]).kernel_morphism() # long time Module homomorphism of degree 0 defined by sending the generators [g_{3}, g_{4}] to @@ -1289,7 +1289,7 @@ def kernel(self, top_dim=None, verbose=False): sage: H = Hom(M, F2) sage: f = H([F2([1]), F2([0])]) - sage: K = f.kernel(verbose=True, top_dim=17) + sage: K = f.kernel_morphism(verbose=True, top_dim=17) 1. Computing the generators of the kernel presentation: Resolving the kernel in the range of dimensions [0, 17]: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17. @@ -1452,7 +1452,7 @@ def is_surjective(self): True """ - return self.cokernel().is_zero() + return self.cokernel_morphism().is_zero() def _resolve_kernel(self, top_dim=None, verbose=False): From 8529b6c0be23120ac6f087a5d9c04b805fdf008a Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Thu, 9 Dec 2021 20:10:42 -0800 Subject: [PATCH 046/253] trac 32505: add _latex_term --- src/sage/modules/fp_graded/free_module.py | 5 +++++ src/sage/modules/fp_graded/module.py | 15 +++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/sage/modules/fp_graded/free_module.py b/src/sage/modules/fp_graded/free_module.py index 899e78c4dde..91a223ce1ab 100755 --- a/src/sage/modules/fp_graded/free_module.py +++ b/src/sage/modules/fp_graded/free_module.py @@ -364,6 +364,8 @@ def __init__(self, algebra, generator_degrees, names=None): else: degs_and_indices = ['{},{}'.format(i[0],i[1]) for i in degs_and_indices] + # _latex_term is defined to be the same as _repr_term, so the + # names should be valid LaTeX. if names is None: names = tuple('g_{{{}}}'.format(s) for s in degs_and_indices) elif isinstance(names, str): @@ -585,6 +587,9 @@ def _repr_term(self, m): return self._names[m[0]] + _latex_term = _repr_term + + @cached_method def basis_elements(self, n): r""" diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index 85e61d70a2a..fec1b1986a5 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -463,6 +463,21 @@ def _repr_term(self, m): return self._free_module()._repr_term(m) + def _latex_term(self, m): + """ + Return a LaTeX representing the generator indexed by ``m``. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FPModule + sage: A = SteenrodAlgebra(2) + sage: M = FPModule(A, [0,2,4], [[Sq(4),Sq(2),0]]) + sage: M._latex_term((2,4)) + 'g_{4}' + """ + return self._free_module()._latex_term(m) + + def connectivity(self): r""" The connectivity of ``self``. From 8e54829b2c315f9fd9bd696b82eef78c33510f09 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Thu, 9 Dec 2021 20:45:52 -0800 Subject: [PATCH 047/253] trac 32505: typos --- src/sage/modules/fp_graded/free_module.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/modules/fp_graded/free_module.py b/src/sage/modules/fp_graded/free_module.py index 91a223ce1ab..a389d271da6 100755 --- a/src/sage/modules/fp_graded/free_module.py +++ b/src/sage/modules/fp_graded/free_module.py @@ -294,8 +294,8 @@ class FreeGradedModule(CombinatorialFreeModule): By default, if all generators are in distinct degrees, then the ``names`` of the generators will have the form ``g_{d}`` where ``d`` is the degree of the generator. If the degrees are not - distinct, then the generators will be callsed ``g_{d,i}`` where - ``d`` is the degree and ``i` is its index in the list of + distinct, then the generators will be called ``g_{d,i}`` where + ``d`` is the degree and ``i`` is its index in the list of generators in that degree. EXAMPLES:: From 5b854ac7f0da3e6a813fc449647d263f6e971c33 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Fri, 10 Dec 2021 11:25:54 +0100 Subject: [PATCH 048/253] move facet adjacency matrix to combinatorial polyhedron --- src/sage/geometry/polyhedron/base3.py | 51 +++++-------------- .../combinatorial_polyhedron/base.pyx | 45 ++++++++++++++++ 2 files changed, 57 insertions(+), 39 deletions(-) diff --git a/src/sage/geometry/polyhedron/base3.py b/src/sage/geometry/polyhedron/base3.py index d090bd16b82..dbc939af876 100644 --- a/src/sage/geometry/polyhedron/base3.py +++ b/src/sage/geometry/polyhedron/base3.py @@ -967,7 +967,7 @@ def vertex_adjacency_matrix(self): @cached_method def facet_adjacency_matrix(self): """ - Return the adjacency matrix for the facets and hyperplanes. + Return the adjacency matrix for the facets. EXAMPLES:: @@ -979,6 +979,13 @@ def facet_adjacency_matrix(self): [1 1 1 0 1] [1 1 1 1 0] + sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)]) + sage: p.facet_adjacency_matrix() + [0 1 1] + [1 0 1] + [1 1 0] + + The facet adjacency matrix has base ring integers. This way one can express various counting questions:: @@ -992,52 +999,18 @@ def facet_adjacency_matrix(self): Check that :trac:`28828` is fixed:: - sage: s4.facet_adjacency_matrix().is_immutable() - True - """ - return self._facet_adjacency_matrix() - - def _facet_adjacency_matrix(self): - """ - Compute the facet adjacency matrix in case it has not been - computed during initialization. - - EXAMPLES:: - - sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)]) - sage: p._facet_adjacency_matrix() - [0 1 1] - [1 0 1] - [1 1 0] + sage: s4.facet_adjacency_matrix().is_immutable() + True Checks that :trac:`22455` is fixed:: sage: s = polytopes.simplex(2) - sage: s._facet_adjacency_matrix() + sage: s.facet_adjacency_matrix() [0 1 1] [1 0 1] [1 1 0] - """ - # TODO: This implementation computes the whole face lattice, - # which is much more information than necessary. - M = matrix(ZZ, self.n_facets(), self.n_facets(), 0) - codim = self.ambient_dim()-self.dim() - - def set_adjacent(h1, h2): - if h1 is h2: - return - i = h1.index() - codim - j = h2.index() - codim - M[i, j] = 1 - M[j, i] = 1 - - for face in self.faces(self.dim()-2): - Hrep = face.ambient_Hrepresentation() - assert(len(Hrep) == codim+2) - set_adjacent(Hrep[-2], Hrep[-1]) - M.set_immutable() - return M + return self.combinatorial_polyhedron().facet_adjacency_matrix() def a_maximal_chain(self): r""" diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index ff697423d46..a6f71826223 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -1432,6 +1432,51 @@ cdef class CombinatorialPolyhedron(SageObject): return tuple((facet_one(i), facet_two(i)) for i in range(n_ridges)) + @cached_method + def facet_adjacency_matrix(self): + """ + Return the binary matrix of facet adjacencies. + + .. SEEALSO:: + + :meth:`~sage.geometry.polyhedron.base.Polyhedron_base.vertex_adjacency_matrix`. + + EXAMPLES:: + + sage: P = polytopes.cube() + sage: C = P.combinatorial_polyhedron() + sage: C.facet_adjacency_matrix() + [0 1 1 0 1 1] + [1 0 1 1 1 0] + [1 1 0 1 0 1] + [0 1 1 0 1 1] + [1 1 0 1 0 1] + [1 0 1 1 1 0] + + TESTS:: + + sage: CombinatorialPolyhedron(-1).facet_adjacency_matrix() + [] + sage: CombinatorialPolyhedron(0).facet_adjacency_matrix() + [] + sage: polytopes.cube().facet_adjacency_matrix().is_immutable() + True + """ + from sage.rings.integer_ring import ZZ + from sage.matrix.constructor import matrix + cdef Matrix_integer_dense adjacency_matrix = matrix( + ZZ, self.n_facets(), self.n_facets(), 0) + cdef size_t i, a, b + + self._compute_ridges(-1) + for i in range(self._n_ridges): + a = self._get_edge(self._ridges, i, 0) + b = self._get_edge(self._ridges, i, 1) + adjacency_matrix.set_unsafe_si(a, b, 1) + adjacency_matrix.set_unsafe_si(b, a, 1) + adjacency_matrix.set_immutable() + return adjacency_matrix + def facet_graph(self, names=True): r""" Return the facet graph. From 80666d41cd192cded8e7dac66d9caeb25296d63d Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Fri, 10 Dec 2021 12:47:58 +0100 Subject: [PATCH 049/253] move is_prism and is_bipyramid to combinatorial polyhedron --- src/sage/geometry/polyhedron/base3.py | 157 ++------------- .../combinatorial_polyhedron/base.pyx | 179 ++++++++++++++++++ 2 files changed, 199 insertions(+), 137 deletions(-) diff --git a/src/sage/geometry/polyhedron/base3.py b/src/sage/geometry/polyhedron/base3.py index d090bd16b82..6426980693c 100644 --- a/src/sage/geometry/polyhedron/base3.py +++ b/src/sage/geometry/polyhedron/base3.py @@ -1303,13 +1303,13 @@ def is_bipyramid(self, certificate=False): sage: P.is_bipyramid() True sage: P.is_bipyramid(certificate=True) - (True, [A vertex at (-1, 0, 0), A vertex at (1, 0, 0)]) + (True, [A vertex at (1, 0, 0), A vertex at (-1, 0, 0)]) sage: Q = polytopes.cyclic_polytope(3,7) sage: Q.is_bipyramid() False sage: R = Q.bipyramid() sage: R.is_bipyramid(certificate=True) - (True, [A vertex at (-1, 3, 13, 63), A vertex at (1, 3, 13, 63)]) + (True, [A vertex at (1, 3, 13, 63), A vertex at (-1, 3, 13, 63)]) TESTS:: @@ -1326,72 +1326,11 @@ def is_bipyramid(self, certificate=False): Traceback (most recent call last): ... ValueError: polyhedron has to be compact - - ALGORITHM: - - Assume all faces of a polyhedron to be given as lists of vertices. - - A polytope is a bipyramid with apexes `v`, `w` if and only if for each - proper face `v \in F` there exists a face `G` with - `G \setminus \{w\} = F \setminus \{v\}` - and vice versa (for each proper face - `w \in F` there exists ...). - - To check this property it suffices to check for all facets of the polyhedron. """ if not self.is_compact(): raise ValueError("polyhedron has to be compact") - from sage.misc.functional import is_odd - n_verts = self.n_vertices() - n_facets = self.n_facets() - if is_odd(n_facets): - if certificate: - return (False, None) - return False - - IM = self.incidence_matrix() - if self.n_equations(): - # Remove equations from the incidence matrix, - # such that this is the vertex-facet incidences matrix. - I1 = IM.transpose() - I2 = I1[[i for i in range(self.n_Hrepresentation()) - if not self.Hrepresentation()[i].is_equation()]] - IM = I2.transpose() - - facets_incidences = [set(column.nonzero_positions()) for column in IM.columns()] - verts_incidences = dict() - for i in range(n_verts): - v_i = set(IM.row(i).nonzero_positions()) - if len(v_i) == n_facets/2: - verts_incidences[i] = v_i - - # Find two vertices ``vert1`` and ``vert2`` such that one of them - # lies on exactly half of the facets, and the other one lies on - # exactly the other half. - from itertools import combinations - for index1, index2 in combinations(verts_incidences, 2): - vert1_incidences = verts_incidences[index1] - vert2_incidences = verts_incidences[index2] - vert1and2 = vert1_incidences.union(vert2_incidences) - if len(vert1and2) == n_facets: - # We have found two candidates for apexes. - # Remove from each facet ``index1`` resp. ``index2``. - test_facets = set(frozenset(facet_inc.difference({index1, index2})) - for facet_inc in facets_incidences) - if len(test_facets) == n_facets/2: - # For each `F` containing `index1` there is - # `G` containing `index2` such that - # `F \setminus \{index1\} = G \setminus \{index2\} - # and vice versa. - if certificate: - V = self.vertices() - return (True, [V[index1], V[index2]]) - return True - - if certificate: - return (False, None) - return False + return self.combinatorial_polyhedron().is_bipyramid(certificate) def is_prism(self, certificate=False): """ @@ -1422,36 +1361,36 @@ def is_prism(self, certificate=False): True sage: P.is_prism(certificate=True) (True, - [[A vertex at (1, -1, -1), - A vertex at (1, 1, -1), + [(A vertex at (1, -1, -1), + A vertex at (1, -1, 1), + A vertex at (-1, -1, 1), + A vertex at (-1, -1, -1)), + (A vertex at (1, 1, -1), A vertex at (1, 1, 1), - A vertex at (1, -1, 1)], - [A vertex at (-1, -1, 1), - A vertex at (-1, -1, -1), A vertex at (-1, 1, -1), - A vertex at (-1, 1, 1)]]) + A vertex at (-1, 1, 1))]) sage: Q = polytopes.cyclic_polytope(3,8) sage: Q.is_prism() False sage: R = Q.prism() sage: R.is_prism(certificate=True) (True, - [[A vertex at (1, 6, 36, 216), - A vertex at (1, 0, 0, 0), - A vertex at (1, 7, 49, 343), - A vertex at (1, 5, 25, 125), - A vertex at (1, 1, 1, 1), - A vertex at (1, 2, 4, 8), - A vertex at (1, 4, 16, 64), - A vertex at (1, 3, 9, 27)], - [A vertex at (0, 3, 9, 27), + [(A vertex at (0, 3, 9, 27), A vertex at (0, 6, 36, 216), A vertex at (0, 0, 0, 0), A vertex at (0, 7, 49, 343), A vertex at (0, 5, 25, 125), A vertex at (0, 1, 1, 1), A vertex at (0, 2, 4, 8), - A vertex at (0, 4, 16, 64)]]) + A vertex at (0, 4, 16, 64)), + (A vertex at (1, 6, 36, 216), + A vertex at (1, 0, 0, 0), + A vertex at (1, 7, 49, 343), + A vertex at (1, 5, 25, 125), + A vertex at (1, 1, 1, 1), + A vertex at (1, 2, 4, 8), + A vertex at (1, 4, 16, 64), + A vertex at (1, 3, 9, 27))]) TESTS:: @@ -1468,67 +1407,11 @@ def is_prism(self, certificate=False): Traceback (most recent call last): ... NotImplementedError: polyhedron has to be compact - - ALGORITHM: - - See :meth:`Polyhedron_base.is_bipyramid`. """ if not self.is_compact(): raise NotImplementedError("polyhedron has to be compact") - from sage.misc.functional import is_odd - n_verts = self.n_vertices() - n_facets = self.n_facets() - if is_odd(n_verts): - if certificate: - return (False, None) - return False - - IM = self.incidence_matrix() - if self.n_equations(): - # Remove equations from the incidence matrix, - # such that this is the vertex-facet incidences matrix. - I1 = IM.transpose() - I2 = I1[[i for i in range(self.n_Hrepresentation()) - if not self.Hrepresentation()[i].is_equation()]] - IM = I2.transpose() - - verts_incidences = [set(row.nonzero_positions()) for row in IM.rows()] - facets_incidences = dict() - for j in range(n_facets): - F_j = set(IM.column(j).nonzero_positions()) - if len(F_j) == n_verts/2: - facets_incidences[j] = F_j - - # Find two vertices ``facet1`` and ``facet2`` such that one of them - # contains exactly half of the vertices, and the other one contains - # exactly the other half. - from itertools import combinations - for index1, index2 in combinations(facets_incidences, 2): - facet1_incidences = facets_incidences[index1] - facet2_incidences = facets_incidences[index2] - facet1and2 = facet1_incidences.union(facet2_incidences) - if len(facet1and2) == n_verts: - # We have found two candidates for base faces. - # Remove from each vertex ``index1`` resp. ``index2``. - test_verts = set(frozenset(vert_inc.difference({index1, index2})) - for vert_inc in verts_incidences) - if len(test_verts) == n_verts/2: - # For each vertex containing `index1` there is - # another one contained in `index2` - # and vice versa. - # Other than `index1` and `index2` both are contained in - # exactly the same facets. - if certificate: - V = self.vertices() - facet1_vertices = [V[i] for i in facet1_incidences] - facet2_vertices = [V[i] for i in facet2_incidences] - return (True, [facet1_vertices, facet2_vertices]) - return True - - if certificate: - return (False, None) - return False + return self.combinatorial_polyhedron().is_prism(certificate) def is_lawrence_polytope(self): """ diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index ff697423d46..4a1b35e429a 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -2335,6 +2335,185 @@ cdef class CombinatorialPolyhedron(SageObject): return (False, None) return False + @cached_method + def is_bipyramid(self, certificate=False): + r""" + Test whether the polytope is a bipyramid over some other polytope. + + INPUT: + + - ``certificate`` -- boolean (default: ``False``); specifies whether + to return a vertex of the polytope which is the apex of a pyramid, + if found + + INPUT: + + - ``certificate`` -- boolean (default: ``False``); specifies whether + to return two vertices of the polytope which are the apices of a + bipyramid, if found + + OUTPUT: + + If ``certificate`` is ``True``, returns a tuple containing: + + 1. Boolean. + 2. ``None`` or a tuple containing: + a. The first apex. + b. The second apex. + + If ``certificate`` is ``False`` returns a boolean. + + EXAMPLES:: + + sage: C = polytopes.hypercube(4).combinatorial_polyhedron() + sage: C.is_bipyramid() + False + sage: C.is_bipyramid(certificate=True) + (False, None) + sage: C = polytopes.cross_polytope(4).combinatorial_polyhedron() + sage: C.is_bipyramid() + True + sage: C.is_bipyramid(certificate=True) + (True, [A vertex at (1, 0, 0, 0), A vertex at (-1, 0, 0, 0)]) + + For unbounded polyhedra, an error is raised:: + + sage: C = CombinatorialPolyhedron([[0,1], [0,2]], far_face=[1,2], unbounded=True) + sage: C.is_pyramid() + Traceback (most recent call last): + ... + ValueError: polyhedron has to be compact + + TESTS:: + + sage: CombinatorialPolyhedron(-1).is_bipyramid() + False + sage: CombinatorialPolyhedron(-1).is_bipyramid(True) + (False, None) + sage: C = polytopes.cross_polytope(1) + sage: C.is_bipyramid() + True + sage: C.is_bipyramid(True) + (True, [A vertex at (1), A vertex at (-1)]) + + Check that bug analog to :trac:`30292` is avoided:: + + sage: Polyhedron([[0, 1, 0], [0, 0, 1], [0, -1, -1], [1, 0, 0], [-1, 0, 0]]).is_bipyramid(certificate=True) + (True, [A vertex at (1, 0, 0), A vertex at (-1, 0, 0)]) + + ALGORITHM: + + Assume all faces of a polyhedron to be given as lists of vertices. + + A polytope is a bipyramid with apexes `v`, `w` if and only if for each + proper face `v \in F` there exists a face `G` with + `G \setminus \{w\} = F \setminus \{v\}` + and vice versa (for each proper face + `w \in F` there exists ...). + + To check this property it suffices to check for all facets of the polyhedron. + """ + if not self.is_compact(): + raise ValueError("polyhedron has to be compact") + + n_facets = self.n_facets() + if n_facets % 2 or self.dim() < 1: + if certificate: + return (False, None) + return False + + facets_incidences = [set(f) for f in self.facets(names=False)] + verts_incidences = dict() + for v in self.face_iter(0): + verts_incidences[v.ambient_V_indices()[0]] = set(v.ambient_H_indices(add_equations=False)) + + # Find two vertices ``vert1`` and ``vert2`` such that one of them + # lies on exactly half of the facets, and the other one lies on + # exactly the other half. + from itertools import combinations + for index1, index2 in combinations(verts_incidences, 2): + vert1_incidences = verts_incidences[index1] + vert2_incidences = verts_incidences[index2] + vert1and2 = vert1_incidences.union(vert2_incidences) + if len(vert1and2) == n_facets: + # We have found two candidates for apexes. + # Remove from each facet ``index1`` resp. ``index2``. + test_facets = set(frozenset(facet_inc.difference({index1, index2})) + for facet_inc in facets_incidences) + if len(test_facets) == n_facets/2: + # For each `F` containing `index1` there is + # `G` containing `index2` such that + # `F \setminus \{index1\} = G \setminus \{index2\} + # and vice versa. + if certificate: + V = self.vertices() + return (True, [V[index1], V[index2]]) + return True + + if certificate: + return (False, None) + return False + + @cached_method + def is_prism(self, certificate=False): + r""" + Test whether the polytope is a prism of some polytope. + + INPUT: + + - ``certificate`` -- boolean (default: ``False``); specifies whether + to return two facets of the polytope which are the bases of a prism, + if found + + OUTPUT: + + If ``certificate`` is ``True``, returns a tuple containing: + + 1. Boolean. + 2. ``None`` or a tuple containing: + a. List of the vertices of the first base facet. + b. List of the vertices of the second base facet. + + If ``certificate`` is ``False`` returns a boolean. + + TESTS:: + + sage: CombinatorialPolyhedron(-1).is_prism() + False + sage: CombinatorialPolyhedron(1).is_prism() + False + sage: C = polytopes.cross_polytope(3).prism().combinatorial_polyhedron() + sage: C.is_prism(certificate=True) + (True, + [(A vertex at (0, 0, 1, 0), + A vertex at (0, 1, 0, 0), + A vertex at (0, 0, 0, -1), + A vertex at (0, 0, -1, 0), + A vertex at (0, -1, 0, 0), + A vertex at (0, 0, 0, 1)), + (A vertex at (1, 1, 0, 0), + A vertex at (1, 0, 0, -1), + A vertex at (1, 0, -1, 0), + A vertex at (1, -1, 0, 0), + A vertex at (1, 0, 0, 1), + A vertex at (1, 0, 1, 0))]) + sage: C = CombinatorialPolyhedron([[0,1], [0,2]], far_face=[1,2], unbounded=True) + sage: C.is_prism() + Traceback (most recent call last): + ... + ValueError: self must be bounded + """ + if not certificate: + return self.dual().is_bipyramid() + + val, cert = self.dual().is_bipyramid(True) + if val: + facets = self.facets() + return (True, [facets[cert[0]], facets[cert[1]]]) + + return (False, None) + + def join_of_Vrep(self, *indices): r""" Return the smallest face containing all Vrepresentatives indicated by the indices. From c0ebfa19ac01c5b2d8ac76eb34136eacc8f3d89e Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Fri, 10 Dec 2021 10:32:54 -0800 Subject: [PATCH 050/253] trac 32505: rename kernel_morphism to kernel_inclusion, cokernel_morphism -> cokernel_projection --- src/sage/modules/fp_graded/homspace.py | 2 +- src/sage/modules/fp_graded/module.py | 2 +- src/sage/modules/fp_graded/morphism.py | 22 +++++++++++----------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/sage/modules/fp_graded/homspace.py b/src/sage/modules/fp_graded/homspace.py index 28ae792ae77..b59f65a5ff9 100755 --- a/src/sage/modules/fp_graded/homspace.py +++ b/src/sage/modules/fp_graded/homspace.py @@ -24,7 +24,7 @@ [c_{1}, c_{3}] to [Sq(1)*h_{2} + h_{3}, Sq(2)*h_{3}] - sage: Hom(F, L) ([L((A.Sq(1), 1)), L((0, A.Sq(2)))]).kernel_morphism() + sage: Hom(F, L) ([L((A.Sq(1), 1)), L((0, A.Sq(2)))]).kernel_inclusion() Module homomorphism of degree 0 defined by sending the generators [g_{3}, g_{4}] to diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index fec1b1986a5..c267b27e8c7 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -13,7 +13,7 @@ This package was designed with homological algebra in mind, and its API focuses on maps rather than objects. A good example of this is the kernel -function :meth:`sage.modules.fp_graded.morphism.FPModuleMorphism.kernel_morphism` +function :meth:`sage.modules.fp_graded.morphism.FPModuleMorphism.kernel_inclusion` which computes the kernel of a homomorphism `f: M\to N`. Its return value is not an instance of the module class, but rather an injective homomorphism `i: K\to M` with the property that `\operatorname{im}(i) = \ker(f)`. diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py index 287ef0a0d49..9cca16a3e86 100755 --- a/src/sage/modules/fp_graded/morphism.py +++ b/src/sage/modules/fp_graded/morphism.py @@ -921,7 +921,7 @@ def lift(self, f, verbose=False): sage: f = Hom(Hko, Hko)([(Ap.Sq(0,0,3) + Ap.Sq(0,2,0,1))*Hko.generator(0)]) sage: f*f == 0 True - sage: k = f.kernel_morphism() # long time + sage: k = f.kernel_inclusion() # long time sage: f.lift(k) # long time Module homomorphism of degree 21 defined by sending the generators [g_{0}] @@ -991,7 +991,7 @@ def lift(self, f, verbose=False): # Compute the kernel of f. The equations we will solve will live in # this submodule. - iK = f.kernel_morphism(top_dim=max([r.degree() + lift_deg for r in L.relations()])) + iK = f.kernel_inclusion(top_dim=max([r.degree() + lift_deg for r in L.relations()])) source_degs = [g.degree() + lift_deg for g in L.generators()] target_degs = [r.degree() + lift_deg for r in L.relations()] @@ -1149,14 +1149,14 @@ def homology(self, f, top_dim=None, verbose=False): sage: ho.codomain().is_trivial() False """ - k = self.kernel_morphism(top_dim, verbose) + k = self.kernel_inclusion(top_dim, verbose) f_ = f.lift(k) if f_ is None: raise ValueError('the image of the given homomorphism is not contained ' 'in the kernel of this homomorphism; the homology is ' 'therefore not defined for this pair of maps') - return f_.cokernel_morphism() + return f_.cokernel_projection() def suspension(self, t): @@ -1211,9 +1211,9 @@ def suspension(self, t): return Hom(D, C)([C(x.lift_to_free().dense_coefficient_list()) for x in self._values]) - def cokernel_morphism(self): + def cokernel_projection(self): r""" - Compute the cokernel of ``self``. + Compute the map to the cokernel of ``self``. OUTPUT: @@ -1228,7 +1228,7 @@ def cokernel_morphism(self): sage: F = FPModule(A1, [0]) sage: r = Hom(F, M)([A1.Sq(1)*M.generator(0)]) - sage: co = r.cokernel_morphism(); co + sage: co = r.cokernel_projection(); co Module homomorphism of degree 0 defined by sending the generators [g_{0}] to @@ -1250,7 +1250,7 @@ def cokernel_morphism(self): return projection - def kernel_morphism(self, top_dim=None, verbose=False): + def kernel_inclusion(self, top_dim=None, verbose=False): r""" Compute the kernel of ``self``. @@ -1278,7 +1278,7 @@ def kernel_morphism(self, top_dim=None, verbose=False): sage: L = FPModule(A3, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]); sage: H = Hom(F, L); - sage: H([L((A3.Sq(1), 1)), L((0, A3.Sq(2)))]).kernel_morphism() # long time + sage: H([L((A3.Sq(1), 1)), L((0, A3.Sq(2)))]).kernel_inclusion() # long time Module homomorphism of degree 0 defined by sending the generators [g_{3}, g_{4}] to @@ -1289,7 +1289,7 @@ def kernel_morphism(self, top_dim=None, verbose=False): sage: H = Hom(M, F2) sage: f = H([F2([1]), F2([0])]) - sage: K = f.kernel_morphism(verbose=True, top_dim=17) + sage: K = f.kernel_inclusion(verbose=True, top_dim=17) 1. Computing the generators of the kernel presentation: Resolving the kernel in the range of dimensions [0, 17]: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17. @@ -1452,7 +1452,7 @@ def is_surjective(self): True """ - return self.cokernel_morphism().is_zero() + return self.cokernel_projection().is_zero() def _resolve_kernel(self, top_dim=None, verbose=False): From db79c13f71ab358d0d403db0903b57253110b53c Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Fri, 10 Dec 2021 11:12:09 -0800 Subject: [PATCH 051/253] trac 32505: comments about submodules --- src/sage/modules/fp_graded/module.py | 7 +++++++ src/sage/modules/fp_graded/morphism.py | 16 ++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index c267b27e8c7..55bcf580955 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -1096,6 +1096,13 @@ def submodule_inclusion(self, spanning_elements): The inclusion of the submodule into this module. + Because a submodule of a finitely presented module need not be + finitely presented, this method will only work if the + underlying algebra is finite-dimensional. Indeed, the current + implementation only works if the algebra has a ``top_class`` + method, which gets used in + :meth:`sage.modules.fp_graded.morphism._resolve_kernel`. + EXAMPLES:: sage: from sage.modules.fp_graded.module import FPModule diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py index 9cca16a3e86..60511b34588 100755 --- a/src/sage/modules/fp_graded/morphism.py +++ b/src/sage/modules/fp_graded/morphism.py @@ -1473,8 +1473,10 @@ def _resolve_kernel(self, top_dim=None, verbose=False): .. NOTE:: - If the algebra for this module is finite, then no ``top_dim`` - needs to be specified in order to ensure that this function terminates. + If the algebra for this module is finite and has a + ``top_class`` method, then no ``top_dim`` needs to be + specified in order to ensure that this function + terminates. TESTS:: @@ -1528,8 +1530,14 @@ def _resolve_kernel(self, top_dim=None, verbose=False): print ('The domain of the morphism is trivial, so there is nothing to resolve.') return j - limit = PlusInfinity() if not self.base_ring().is_finite() else\ - (self.base_ring().top_class().degree() + max(self.domain().generator_degrees())) + # TODO: + # + # Handle algebras which are finite dimensional but which have + # no top_class method, for example exterior algebras. + if not self.base_ring().dimension() < PlusInfinity(): + limit = PlusInfinity() + else: + limit = (self.base_ring().top_class().degree() + max(self.domain().generator_degrees())) if not top_dim is None: limit = min(top_dim, limit) From 2e9b692503d169c9e4f5fa0ee0c84ca5b7b6a863 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Fri, 10 Dec 2021 20:07:45 -0800 Subject: [PATCH 052/253] trac 32505: fix some comparisons to None --- src/sage/modules/fp_graded/module.py | 4 ++-- src/sage/modules/fp_graded/morphism.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index 55bcf580955..5214ed33fa8 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -529,7 +529,7 @@ def connectivity(self): previous = None for k in X: - if previous != None and k == previous: + if previous is not None and k == previous: continue if not self.j.vector_presentation(k - self.j._degree).is_surjective(): return k @@ -858,7 +858,7 @@ def vector_presentation(self, n, verbose=False): # assert: isinstance(FreeElement, relation) v = (a*relation).vector_presentation() - if not v is None: + if v is not None: spanning_set.append(v) R_n = F_n.subspace(spanning_set) diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py index 60511b34588..66f90dc926a 100755 --- a/src/sage/modules/fp_graded/morphism.py +++ b/src/sage/modules/fp_graded/morphism.py @@ -1539,7 +1539,7 @@ def _resolve_kernel(self, top_dim=None, verbose=False): else: limit = (self.base_ring().top_class().degree() + max(self.domain().generator_degrees())) - if not top_dim is None: + if top_dim is not None: limit = min(top_dim, limit) if limit == PlusInfinity(): @@ -1676,7 +1676,7 @@ def _resolve_image(self, top_dim=None, verbose=False): limit = PlusInfinity() if not self.base_ring().is_finite() else\ (self.base_ring().top_class().degree() + max(degree_values)) - if not top_dim is None: + if top_dim is not None: limit = min(top_dim, limit) if limit == PlusInfinity(): From ca99e34bf1bde1a08cda1ab0404c5881951e0ddc Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Mon, 13 Dec 2021 08:31:11 +0100 Subject: [PATCH 053/253] fix random failure in number_field_element.pyx --- src/sage/rings/number_field/number_field_element.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/number_field/number_field_element.pyx b/src/sage/rings/number_field/number_field_element.pyx index 89242c9fe24..cf6352cbe45 100644 --- a/src/sage/rings/number_field/number_field_element.pyx +++ b/src/sage/rings/number_field/number_field_element.pyx @@ -4415,7 +4415,7 @@ cdef class NumberFieldElement(FieldElement): sage: K. = CyclotomicField(8) sage: K(1).descend_mod_power(QQ,2) [1, 2, -1, -2] - sage: a = 17*K.random_element()^2 + sage: a = 17 * K._random_nonzero_element()^2 sage: a.descend_mod_power(QQ,2) [17, 34, -17, -34] """ From 34de48b29ad48e0890bbc409e3e04e0a1b19bb64 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Tue, 14 Dec 2021 08:38:37 +0100 Subject: [PATCH 054/253] docs --- .../modules/free_quadratic_module_integer_symmetric.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index ac8d990fa71..a6943afac36 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -1380,7 +1380,7 @@ def quadratic_form(self): r""" Return the quadratic form given by `q(x)=(x,x)`. - Examples:: + EXAMPLES:: sage: L = IntegralLattice("A2") sage: q = L.quadratic_form() @@ -1396,7 +1396,7 @@ def minimum(self): r""" Return the minimum of this lattice. - .. Math:: + .. MATH:: \min\{x^2 | x \in L\setminus \{0\}\} @@ -1422,11 +1422,10 @@ def maximum(self): r""" Return the maximum of this lattice. - .. Math:: + .. MATH:: \max\{x^2 | x \in L\setminus \{0\}\} - EXAMPLES:: sage: L = IntegralLattice('A2') From c3bf4b88715dba4a2419e398cd30884b7f3f5fff Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Tue, 14 Dec 2021 21:10:22 -0800 Subject: [PATCH 055/253] trac 32505: add free_graded_module method to GradedAlgebrasWithBasis --- .../categories/graded_algebras_with_basis.py | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/sage/categories/graded_algebras_with_basis.py b/src/sage/categories/graded_algebras_with_basis.py index e7ae68328e2..8af922cd31b 100644 --- a/src/sage/categories/graded_algebras_with_basis.py +++ b/src/sage/categories/graded_algebras_with_basis.py @@ -84,6 +84,45 @@ def graded_algebra(self): # Also, ``projection`` could be overridden by, well, a # projection. + def free_graded_module(self, generator_degrees, names=None): + """ + Create a finitely generated free graded module over ``self`` + + This is only implemented when the ground ring is a field. + + INPUTS: + + - ``generator_degrees`` -- tuple of integers defining the + number of generators of the module, and their degrees + + - ``names`` -- optional, the names of the generators. If + ``names`` is a comma-separated string like ``'a, b, + c'``, then those will be the names. Otherwise, for + example if ``names`` is ``abc``, then the names will be + ``abc_{d,i}``. + + By default, if all generators are in distinct degrees, + then the ``names`` of the generators will have the form + ``g_{d}`` where ``d`` is the degree of the generator. If + the degrees are not distinct, then the generators will be + called ``g_{d,i}`` where ``d`` is the degree and ``i`` is + its index in the list of generators in that degree. + + See :mod:`sage.modules.fp_graded.free_module` for more + examples and details. + + EXAMPLES:: + + sage: Q = QuadraticForm(QQ, 3, [1,2,3,4,5,6]) + sage: Cl = CliffordAlgebra(Q) + sage: M = Cl.free_graded_module((0, 2, 3)) + sage: M.gens() + (g_{0}, g_{2}, g_{3}) + """ + from sage.modules.fp_graded.free_module import FreeGradedModule + return FreeGradedModule(self, generator_degrees, names) + + class ElementMethods: pass From c3f6bcbfbf315cfaf2f1759d1136b2dbe7204487 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 16 Dec 2021 09:53:10 -0800 Subject: [PATCH 056/253] src/sage/misc/namespace_package.py (is_package_or_sage_namespace_package_dir): New --- src/sage/misc/namespace_package.py | 45 ++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/sage/misc/namespace_package.py b/src/sage/misc/namespace_package.py index 75d9f1d8dcc..ff7283a33dd 100644 --- a/src/sage/misc/namespace_package.py +++ b/src/sage/misc/namespace_package.py @@ -2,6 +2,7 @@ Utility functions for namespace packages in Sage """ from importlib import import_module +import os, glob def install_doc(package, doc): """ @@ -18,3 +19,47 @@ def install_doc(package, doc): pkg = import_module(package) pkg.__doc__ = doc # enable sage.package? pkg.getdoc = lambda: doc # enable help(sage.package) + + +def is_package_or_sage_namespace_package_dir(path): + """ + Return whether ``path`` is a directory that contains a Python package. + + Ordinary Python packages are recognized by the presence of `__init__.py`. + + Implicit namespace packages (PEP 420) are only recognized if they + follow the conventions of the Sage library, i.e., the directory contains + a file ``all.py`` or a file matching the pattern ``all__*.py`` + such as ``all__sagemath_categories.py``. + + EXAMPLES: + + :mod:`sage.cpython` is an ordinary package:: + + sage: from sage.misc.namespace_package import is_package_or_sage_namespace_package_dir + sage: d = os.path.dirname(sage.cpython.__file__); d + '.../sage/cpython' + sage: is_package_or_sage_namespace_package_dir(d) + True + + :mod:`sage` is designated to become an implicit namespace package:: + + sage: d = os.path.dirname(sage.env.__file__); d + '.../sage' + sage: is_package_or_sage_namespace_package_dir(d) + True + + Not a package:: + + sage: d = os.path.join(os.path.dirname(sage.symbolic.__file__), 'ginac'); d + '.../sage/symbolic/ginac' + sage: is_package_or_sage_namespace_package_dir(d) + False + """ + if os.path.exists(os.path.join(path, '__init__.py')): # ordinary package + return True + if os.path.exists(os.path.join(path, 'all.py')): # complete namespace package + return True + for _ in glob.iglob(os.path.join(path, 'all__*.py')): + return True # partial namespace package + return False From ab23a145ba3961925f6e4b73eb45ea71f3708020 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 16 Dec 2021 10:46:22 -0800 Subject: [PATCH 057/253] src/sage/doctest/sources.py: Use is_package_or_sage_namespace_package_dir --- src/sage/doctest/sources.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/doctest/sources.py b/src/sage/doctest/sources.py index f60c275af74..cc3d89c62c5 100644 --- a/src/sage/doctest/sources.py +++ b/src/sage/doctest/sources.py @@ -24,10 +24,10 @@ import re import random import doctest -from Cython.Utils import is_package_dir from sage.cpython.string import bytes_to_str from sage.repl.load import load from sage.misc.lazy_attribute import lazy_attribute +from sage.misc.namespace_package import is_package_or_sage_namespace_package_dir from .parsing import SageDocTestParser from .util import NestedName from sage.structure.dynamic_class import dynamic_class @@ -100,8 +100,8 @@ def get_basename(path): root = path[:len(sp)] else: # If this file is in some python package we can see how deep - # it goes by the presence of __init__.py files. - while os.path.exists(os.path.join(root, '__init__.py')): + # it goes. + while is_package_or_sage_namespace_package_dir(root): root = os.path.dirname(root) fully_qualified_path = os.path.splitext(path[len(root) + 1:])[0] if os.path.split(path)[1] == '__init__.py': @@ -648,11 +648,13 @@ def basename(self): @lazy_attribute def in_lib(self): """ - Whether this file is part of a package (i.e. is in a directory - containing an ``__init__.py`` file). + Whether this file is to be treated as a module in a Python package. Such files aren't loaded before running tests. + This uses :func:`~sage.misc.namespace_package.is_package_or_sage_namespace_package_dir` + but can be overridden via :class:`~sage.doctest.control.DocTestDefaults`. + EXAMPLES:: sage: from sage.doctest.control import DocTestDefaults @@ -677,10 +679,8 @@ def in_lib(self): sage: FDS.in_lib True """ - # We need an explicit bool() because is_package_dir() returns - # 1/None instead of True/False. return bool(self.options.force_lib or - is_package_dir(os.path.dirname(self.path))) + is_package_or_sage_namespace_package_dir(os.path.dirname(self.path))) def create_doctests(self, namespace): r""" From 0f05856b4efadc29ae22b4d7ae2ad604413a7afe Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 16 Dec 2021 11:09:19 -0800 Subject: [PATCH 058/253] src/sage/doctest/sources.py: Remove unnecessary conversion to bool --- src/sage/doctest/sources.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/doctest/sources.py b/src/sage/doctest/sources.py index cc3d89c62c5..a33817dd062 100644 --- a/src/sage/doctest/sources.py +++ b/src/sage/doctest/sources.py @@ -679,8 +679,8 @@ def in_lib(self): sage: FDS.in_lib True """ - return bool(self.options.force_lib or - is_package_or_sage_namespace_package_dir(os.path.dirname(self.path))) + return (self.options.force_lib + or is_package_or_sage_namespace_package_dir(os.path.dirname(self.path))) def create_doctests(self, namespace): r""" From d8aa37c1998193670f894f1d54aac65663761ea4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 16 Dec 2021 11:11:50 -0800 Subject: [PATCH 059/253] src/sage/misc/namespace_package.py: In doctests, use 'directory' instead of the single-letter variable name --- src/sage/misc/namespace_package.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/misc/namespace_package.py b/src/sage/misc/namespace_package.py index ff7283a33dd..fd1bb9eeaa3 100644 --- a/src/sage/misc/namespace_package.py +++ b/src/sage/misc/namespace_package.py @@ -37,23 +37,23 @@ def is_package_or_sage_namespace_package_dir(path): :mod:`sage.cpython` is an ordinary package:: sage: from sage.misc.namespace_package import is_package_or_sage_namespace_package_dir - sage: d = os.path.dirname(sage.cpython.__file__); d + sage: directory = os.path.dirname(sage.cpython.__file__); directory '.../sage/cpython' - sage: is_package_or_sage_namespace_package_dir(d) + sage: is_package_or_sage_namespace_package_dir(directory) True :mod:`sage` is designated to become an implicit namespace package:: - sage: d = os.path.dirname(sage.env.__file__); d + sage: directory = os.path.dirname(sage.env.__file__); directory '.../sage' - sage: is_package_or_sage_namespace_package_dir(d) + sage: is_package_or_sage_namespace_package_dir(directory) True Not a package:: - sage: d = os.path.join(os.path.dirname(sage.symbolic.__file__), 'ginac'); d + sage: directory = os.path.join(os.path.dirname(sage.symbolic.__file__), 'ginac'); directory '.../sage/symbolic/ginac' - sage: is_package_or_sage_namespace_package_dir(d) + sage: is_package_or_sage_namespace_package_dir(directory) False """ if os.path.exists(os.path.join(path, '__init__.py')): # ordinary package From 19e93f0f60f5d5e900d04561a187be82318921bb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 16 Dec 2021 13:59:42 -0800 Subject: [PATCH 060/253] is_package_or_sage_namespace_package_dir: Make directories with __init__.pxd package directories --- src/sage/misc/namespace_package.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/sage/misc/namespace_package.py b/src/sage/misc/namespace_package.py index fd1bb9eeaa3..73bab836bc9 100644 --- a/src/sage/misc/namespace_package.py +++ b/src/sage/misc/namespace_package.py @@ -42,6 +42,14 @@ def is_package_or_sage_namespace_package_dir(path): sage: is_package_or_sage_namespace_package_dir(directory) True + :mod:`sage.libs.mpfr` only has an ``__init__.pxd`` file, but we consider + it a package directory for consistency with Cython:: + + sage: directory = os.path.join(os.path.dirname(sage.libs.all.__file__), 'mpfr'); directory + '.../sage/libs/mpfr' + sage: is_package_or_sage_namespace_package_dir(directory) + True + :mod:`sage` is designated to become an implicit namespace package:: sage: directory = os.path.dirname(sage.env.__file__); directory @@ -56,10 +64,12 @@ def is_package_or_sage_namespace_package_dir(path): sage: is_package_or_sage_namespace_package_dir(directory) False """ - if os.path.exists(os.path.join(path, '__init__.py')): # ordinary package + if os.path.exists(os.path.join(path, '__init__.py')): # ordinary package + return True + if os.path.exists(os.path.join(path, '__init__.pxd')): # for consistency with Cython return True - if os.path.exists(os.path.join(path, 'all.py')): # complete namespace package + if os.path.exists(os.path.join(path, 'all.py')): # complete namespace package return True for _ in glob.iglob(os.path.join(path, 'all__*.py')): - return True # partial namespace package + return True # partial namespace package return False From 5808f3d6b4241590adbc95925aa84c50535d9e65 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 16 Dec 2021 21:13:22 -0800 Subject: [PATCH 061/253] src/sage/misc/package_dir.py: New file for is_package_or_sage_namespace_package_dir --- src/sage/doctest/sources.py | 4 +-- src/sage/misc/namespace_package.py | 55 ---------------------------- src/sage/misc/package_dir.py | 57 ++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 57 deletions(-) create mode 100644 src/sage/misc/package_dir.py diff --git a/src/sage/doctest/sources.py b/src/sage/doctest/sources.py index a33817dd062..31fc5f84e80 100644 --- a/src/sage/doctest/sources.py +++ b/src/sage/doctest/sources.py @@ -27,7 +27,7 @@ from sage.cpython.string import bytes_to_str from sage.repl.load import load from sage.misc.lazy_attribute import lazy_attribute -from sage.misc.namespace_package import is_package_or_sage_namespace_package_dir +from sage.misc.package_dir import is_package_or_sage_namespace_package_dir from .parsing import SageDocTestParser from .util import NestedName from sage.structure.dynamic_class import dynamic_class @@ -652,7 +652,7 @@ def in_lib(self): Such files aren't loaded before running tests. - This uses :func:`~sage.misc.namespace_package.is_package_or_sage_namespace_package_dir` + This uses :func:`~sage.misc.package_dir.is_package_or_sage_namespace_package_dir` but can be overridden via :class:`~sage.doctest.control.DocTestDefaults`. EXAMPLES:: diff --git a/src/sage/misc/namespace_package.py b/src/sage/misc/namespace_package.py index 73bab836bc9..75d9f1d8dcc 100644 --- a/src/sage/misc/namespace_package.py +++ b/src/sage/misc/namespace_package.py @@ -2,7 +2,6 @@ Utility functions for namespace packages in Sage """ from importlib import import_module -import os, glob def install_doc(package, doc): """ @@ -19,57 +18,3 @@ def install_doc(package, doc): pkg = import_module(package) pkg.__doc__ = doc # enable sage.package? pkg.getdoc = lambda: doc # enable help(sage.package) - - -def is_package_or_sage_namespace_package_dir(path): - """ - Return whether ``path`` is a directory that contains a Python package. - - Ordinary Python packages are recognized by the presence of `__init__.py`. - - Implicit namespace packages (PEP 420) are only recognized if they - follow the conventions of the Sage library, i.e., the directory contains - a file ``all.py`` or a file matching the pattern ``all__*.py`` - such as ``all__sagemath_categories.py``. - - EXAMPLES: - - :mod:`sage.cpython` is an ordinary package:: - - sage: from sage.misc.namespace_package import is_package_or_sage_namespace_package_dir - sage: directory = os.path.dirname(sage.cpython.__file__); directory - '.../sage/cpython' - sage: is_package_or_sage_namespace_package_dir(directory) - True - - :mod:`sage.libs.mpfr` only has an ``__init__.pxd`` file, but we consider - it a package directory for consistency with Cython:: - - sage: directory = os.path.join(os.path.dirname(sage.libs.all.__file__), 'mpfr'); directory - '.../sage/libs/mpfr' - sage: is_package_or_sage_namespace_package_dir(directory) - True - - :mod:`sage` is designated to become an implicit namespace package:: - - sage: directory = os.path.dirname(sage.env.__file__); directory - '.../sage' - sage: is_package_or_sage_namespace_package_dir(directory) - True - - Not a package:: - - sage: directory = os.path.join(os.path.dirname(sage.symbolic.__file__), 'ginac'); directory - '.../sage/symbolic/ginac' - sage: is_package_or_sage_namespace_package_dir(directory) - False - """ - if os.path.exists(os.path.join(path, '__init__.py')): # ordinary package - return True - if os.path.exists(os.path.join(path, '__init__.pxd')): # for consistency with Cython - return True - if os.path.exists(os.path.join(path, 'all.py')): # complete namespace package - return True - for _ in glob.iglob(os.path.join(path, 'all__*.py')): - return True # partial namespace package - return False diff --git a/src/sage/misc/package_dir.py b/src/sage/misc/package_dir.py new file mode 100644 index 00000000000..11f83a06f73 --- /dev/null +++ b/src/sage/misc/package_dir.py @@ -0,0 +1,57 @@ +""" +Recognizing package directories +""" +import os, glob + +def is_package_or_sage_namespace_package_dir(path): + """ + Return whether ``path`` is a directory that contains a Python package. + + Ordinary Python packages are recognized by the presence of `__init__.py`. + + Implicit namespace packages (PEP 420) are only recognized if they + follow the conventions of the Sage library, i.e., the directory contains + a file ``all.py`` or a file matching the pattern ``all__*.py`` + such as ``all__sagemath_categories.py``. + + EXAMPLES: + + :mod:`sage.cpython` is an ordinary package:: + + sage: from sage.misc.package_dir import is_package_or_sage_namespace_package_dir + sage: directory = os.path.dirname(sage.cpython.__file__); directory + '.../sage/cpython' + sage: is_package_or_sage_namespace_package_dir(directory) + True + + :mod:`sage.libs.mpfr` only has an ``__init__.pxd`` file, but we consider + it a package directory for consistency with Cython:: + + sage: directory = os.path.join(os.path.dirname(sage.libs.all.__file__), 'mpfr'); directory + '.../sage/libs/mpfr' + sage: is_package_or_sage_namespace_package_dir(directory) + True + + :mod:`sage` is designated to become an implicit namespace package:: + + sage: directory = os.path.dirname(sage.env.__file__); directory + '.../sage' + sage: is_package_or_sage_namespace_package_dir(directory) + True + + Not a package:: + + sage: directory = os.path.join(os.path.dirname(sage.symbolic.__file__), 'ginac'); directory + '.../sage/symbolic/ginac' + sage: is_package_or_sage_namespace_package_dir(directory) + False + """ + if os.path.exists(os.path.join(path, '__init__.py')): # ordinary package + return True + if os.path.exists(os.path.join(path, '__init__.pxd')): # for consistency with Cython + return True + if os.path.exists(os.path.join(path, 'all.py')): # complete namespace package + return True + for _ in glob.iglob(os.path.join(path, 'all__*.py')): + return True # partial namespace package + return False From 6a56bb5ec65aef7a1b8c7d5a6914c0fb27a5f07c Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Fri, 17 Dec 2021 15:52:27 +0100 Subject: [PATCH 062/253] fix unstable doctest in continued_fraction_gosper --- src/sage/rings/continued_fraction_gosper.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/continued_fraction_gosper.py b/src/sage/rings/continued_fraction_gosper.py index 7ec7a6cd1ab..c36dfd99501 100644 --- a/src/sage/rings/continued_fraction_gosper.py +++ b/src/sage/rings/continued_fraction_gosper.py @@ -106,9 +106,11 @@ def __iter__(self): sage: c = Integer(randint(-100,100)); d = Integer(randint(-100,100)); sage: from sage.rings.continued_fraction_gosper import gosper_iterator sage: ig = iter(gosper_iterator(a,b,c,d,continued_fraction(pi))); icf = iter(continued_fraction((a*pi+b)/(c*pi+d))); - sage: lg = [next(ig) for _ in range(10)]; lcf = [next(icf) for _ in range(10)]; - sage: lg == lcf - True + sage: for i in range(10): + ....: try: + ....: assert next(ig) == next(icf) + ....: except StopIteration: + ....: pass """ return self @@ -123,7 +125,10 @@ def __next__(self): sage: from sage.rings.continued_fraction_gosper import gosper_iterator sage: ig = iter(gosper_iterator(a,b,c,d,continued_fraction(pi))); icf = iter(continued_fraction((a*pi+b)/(c*pi+d))); sage: for i in range(10): - ....: assert next(ig) == next(icf) + ....: try: + ....: assert next(ig) == next(icf) + ....: except StopIteration: + ....: pass """ while True: if self.currently_read >= self.input_preperiod_length: From ae80b6d963d28e762e9398010a33c4a0a273d0d3 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Sat, 18 Dec 2021 10:44:19 +0100 Subject: [PATCH 063/253] slightly improve doctests --- src/sage/rings/continued_fraction_gosper.py | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/sage/rings/continued_fraction_gosper.py b/src/sage/rings/continued_fraction_gosper.py index c36dfd99501..07b2dcc852b 100644 --- a/src/sage/rings/continued_fraction_gosper.py +++ b/src/sage/rings/continued_fraction_gosper.py @@ -102,15 +102,15 @@ def __iter__(self): TESTS:: - sage: a = Integer(randint(-100,100)); b = Integer(randint(-100,100)); - sage: c = Integer(randint(-100,100)); d = Integer(randint(-100,100)); sage: from sage.rings.continued_fraction_gosper import gosper_iterator - sage: ig = iter(gosper_iterator(a,b,c,d,continued_fraction(pi))); icf = iter(continued_fraction((a*pi+b)/(c*pi+d))); + sage: a, b, c, d = (Integer(randint(-100,100)) for _ in range(4)) + sage: ig = iter(gosper_iterator(a, b, c, d, continued_fraction(pi))) + sage: icf = iter(continued_fraction((a*pi + b) / (c*pi + d))); sage: for i in range(10): ....: try: ....: assert next(ig) == next(icf) ....: except StopIteration: - ....: pass + ....: break """ return self @@ -120,15 +120,10 @@ def __next__(self): TESTS:: - sage: a = Integer(randint(-100,100)); b = Integer(randint(-100,100)); - sage: c = Integer(randint(-100,100)); d = Integer(randint(-100,100)); sage: from sage.rings.continued_fraction_gosper import gosper_iterator - sage: ig = iter(gosper_iterator(a,b,c,d,continued_fraction(pi))); icf = iter(continued_fraction((a*pi+b)/(c*pi+d))); - sage: for i in range(10): - ....: try: - ....: assert next(ig) == next(icf) - ....: except StopIteration: - ....: pass + sage: it = gosper_iterator(1, 0, 0, 1, continued_fraction(pi)) + sage: list(next(it) for _ in range(10)) + [3, 7, 15, 1, 292, 1, 1, 1, 2, 1] """ while True: if self.currently_read >= self.input_preperiod_length: From 2a8072b0896c4ec5381557cb53de54ad5b0b74ac Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 19 Dec 2021 19:47:59 -0800 Subject: [PATCH 064/253] build/pkgs/setuptools: Update to 59.8.0 --- build/pkgs/setuptools/checksums.ini | 6 +++--- build/pkgs/setuptools/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/setuptools/checksums.ini b/build/pkgs/setuptools/checksums.ini index d9290d04ffb..0282c2adea8 100644 --- a/build/pkgs/setuptools/checksums.ini +++ b/build/pkgs/setuptools/checksums.ini @@ -1,5 +1,5 @@ tarball=setuptools-VERSION.tar.gz -sha1=cd4e5d1f7c47f86354fc89d040d869cde244da3b -md5=79b36f59270a6f2e45d6a9a0c6dc68c1 -cksum=430889097 +sha1=52826ae4c3e5b57e8ee31ed7fedcd2fd087cb751 +md5=675f2089d970bf0bbfc3f49c80e4c7c3 +cksum=424370034 upstream_url=https://pypi.io/packages/source/s/setuptools/setuptools-VERSION.tar.gz diff --git a/build/pkgs/setuptools/package-version.txt b/build/pkgs/setuptools/package-version.txt index aec1257e4c0..130aeff8195 100644 --- a/build/pkgs/setuptools/package-version.txt +++ b/build/pkgs/setuptools/package-version.txt @@ -1 +1 @@ -59.2.0 +59.8.0 From 62a73ecfb66379f56e227f888cbf87c25b0d77eb Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Wed, 15 Dec 2021 15:58:07 +0800 Subject: [PATCH 065/253] make BinaryQF.solve_integer() work for square discriminants --- src/sage/quadratic_forms/binary_qf.py | 42 +++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/sage/quadratic_forms/binary_qf.py b/src/sage/quadratic_forms/binary_qf.py index 6f54b0c074d..61b43c4ada6 100755 --- a/src/sage/quadratic_forms/binary_qf.py +++ b/src/sage/quadratic_forms/binary_qf.py @@ -1497,11 +1497,53 @@ def solve_integer(self, n): sage: xy = Q.solve_integer(n) sage: xy is None or Q(*xy) == n True + + Test for square discriminants specifically (:trac:`33026`):: + + sage: n = randrange(-10^3, 10^3) + sage: Q = BinaryQF([n, randrange(-10^3, 10^3), 0][::(-1)**randrange(2)]) + sage: U = random_matrix(ZZ, 2, 2, 'unimodular') + sage: U.rescale_row(0, choice((+1,-1))); assert U.det() in (+1,-1) + sage: Q = Q.matrix_action_right(U) + sage: Q.discriminant().is_square() + True + sage: xy = Q.solve_integer(n) + sage: Q(*xy) == n + True """ n = ZZ(n) + if self.is_negative_definite(): # not supported by PARI return (-self).solve_integer(-n) + if self.is_reducible(): # square discriminant; not supported by PARI + if self._a: + # https://math.stackexchange.com/a/980075 + w = self.discriminant().sqrt() + r = (-self._b + (w if w != self._b else -w)) / (2*self._a) + p,q = r.as_integer_ratio() + g,u,v = p.xgcd(q) + M = Matrix(ZZ, [[v,p],[-u,q]]) + elif self._c: + M = Matrix(ZZ, [[0,1],[1,0]]) + else: + M = Matrix(ZZ, [[1,0],[0,1]]) + assert M.is_unit() + Q = self.matrix_action_right(M) + assert not Q._c + + # at this point, Q = a*x^2 + b*x*y + if not n: + return tuple(M.columns()[1]) + for x in n.divisors(): + try: + y = ZZ((n//x - Q._a*x) / Q._b) + except TypeError: + continue + return tuple(row[0]*x + row[1]*y for row in M.rows()) + + return None + flag = 2 # single solution, possibly imprimitive sol = self.__pari__().qfbsolve(n, flag) return tuple(map(ZZ, sol)) if sol else None From a92d27c9ee0d53e2a6d78adeee46bc42c45a9356 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Dec 2021 11:24:52 -0800 Subject: [PATCH 066/253] sage --package update[-latest]: Add option --commit --- build/sage_bootstrap/app.py | 22 ++++++++++++++++++---- build/sage_bootstrap/cmdline.py | 10 ++++++++-- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/build/sage_bootstrap/app.py b/build/sage_bootstrap/app.py index ca1f8aa6078..53ba7298537 100644 --- a/build/sage_bootstrap/app.py +++ b/build/sage_bootstrap/app.py @@ -114,7 +114,17 @@ def apropos(self, incorrect_name): print('There is no package similar to {0}'.format(incorrect_name)) print('You can find further packages at http://files.sagemath.org/spkg/') - def update(self, package_name, new_version, url=None): + def commit(self, package_name, message=None): + """ + Commit the changes to the Sage source tree for the given package + """ + import os + package = Package(package_name) + if message is None: + message = 'build/pkgs/{0}: Update to {1}'.format(package_name, package.version) + os.system('git commit -m "{0}" {1}'.format(message, package.path)) + + def update(self, package_name, new_version, url=None, commit=False): """ Update a package. This modifies the Sage sources. @@ -126,8 +136,10 @@ def update(self, package_name, new_version, url=None): log.debug('Downloading %s', url) update.download_upstream(url) update.fix_checksum() + if commit: + self.commit(package_name) - def update_latest(self, package_name): + def update_latest(self, package_name, commit=False): """ Update a package to the latest version. This modifies the Sage sources. """ @@ -138,8 +150,10 @@ def update_latest(self, package_name): return else: pypi.update(Package(package_name)) + if commit: + self.commit(package_name) - def update_latest_cls(self, package_name_or_class): + def update_latest_cls(self, package_name_or_class, commit=False): exclude = [ 'cypari' # Name conflict ] @@ -152,7 +166,7 @@ def update_latest_cls(self, package_name_or_class): log.debug('skipping %s because of pypi name collision', package_name) continue try: - self.update_latest(package_name) + self.update_latest(package_name, commit=commit) except PyPiError as e: log.warn('updating %s failed: %s', package_name, e) diff --git a/build/sage_bootstrap/cmdline.py b/build/sage_bootstrap/cmdline.py index 4408b00e9d7..fe4760119e5 100644 --- a/build/sage_bootstrap/cmdline.py +++ b/build/sage_bootstrap/cmdline.py @@ -237,6 +237,9 @@ def make_parser(): 'new_version', type=str, help='New version') parser_update.add_argument( '--url', type=str, default=None, help='Download URL') + parser_update.add_argument( + '--commit', action="store_true", + help='Whether to run "git commit"') parser_update_latest = subparsers.add_parser( 'update-latest', epilog=epilog_update_latest, @@ -244,6 +247,9 @@ def make_parser(): help='Update a package to the latest version. This modifies the Sage sources.') parser_update_latest.add_argument( 'package_name', type=str, help='Package name (:all: for all packages)') + parser_update_latest.add_argument( + '--commit', action="store_true", + help='Whether to run "git commit"') parser_download = subparsers.add_parser( 'download', epilog=epilog_download, @@ -329,9 +335,9 @@ def run(): elif args.subcommand == 'apropos': app.apropos(args.incorrect_name) elif args.subcommand == 'update': - app.update(args.package_name, args.new_version, url=args.url) + app.update(args.package_name, args.new_version, url=args.url, commit=args.commit) elif args.subcommand == 'update-latest': - app.update_latest_cls(args.package_name) + app.update_latest_cls(args.package_name, commit=args.commit) elif args.subcommand == 'download': app.download_cls(args.package_name, allow_upstream=args.allow_upstream, From 385f2ed6e39065eae2b65a51366f67105e7328ad Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Dec 2021 11:29:31 -0800 Subject: [PATCH 067/253] build/pkgs/prometheus_client: Update to 0.12.0 --- build/pkgs/prometheus_client/checksums.ini | 6 +++--- build/pkgs/prometheus_client/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/prometheus_client/checksums.ini b/build/pkgs/prometheus_client/checksums.ini index f71a7d69f25..aaa1f105b0b 100644 --- a/build/pkgs/prometheus_client/checksums.ini +++ b/build/pkgs/prometheus_client/checksums.ini @@ -1,5 +1,5 @@ tarball=prometheus_client-VERSION.tar.gz -sha1=3d8077107a06a2ec413c64afaf8ca9a7124b283e -md5=eeb8c4ebac21508e1bb420d6fd90fa95 -cksum=144951026 +sha1=78932e768ad69d5ffe1f12abb41c51554ef12eb8 +md5=4439c954aa7bc68b15915c6360967851 +cksum=4269644267 upstream_url=https://pypi.io/packages/source/p/prometheus-client/prometheus_client-VERSION.tar.gz diff --git a/build/pkgs/prometheus_client/package-version.txt b/build/pkgs/prometheus_client/package-version.txt index d9df1bbc0c7..ac454c6a1fc 100644 --- a/build/pkgs/prometheus_client/package-version.txt +++ b/build/pkgs/prometheus_client/package-version.txt @@ -1 +1 @@ -0.11.0 +0.12.0 From c7c4d25f4598bd615b255d1ed4855278baa24700 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Dec 2021 11:30:01 -0800 Subject: [PATCH 068/253] build/pkgs/gmpy2: Update to 2.1.1 --- build/pkgs/gmpy2/checksums.ini | 6 +++--- build/pkgs/gmpy2/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/gmpy2/checksums.ini b/build/pkgs/gmpy2/checksums.ini index 7072505cb52..d17df675312 100644 --- a/build/pkgs/gmpy2/checksums.ini +++ b/build/pkgs/gmpy2/checksums.ini @@ -1,5 +1,5 @@ tarball=gmpy2-VERSION.tar.gz -sha1=6564cfd78f552a8db82136c10b19aa7465856865 -md5=a1555e0d7ca28b3a49c9a81aa06e2bb6 -cksum=2826987588 +sha1=fcb929ab9a44d96bfb47b7ed411cc2f048b484b2 +md5=877d324e676b162053772affda5c0de7 +cksum=2408333571 upstream_url=https://pypi.io/packages/source/g/gmpy2/gmpy2-VERSION.tar.gz diff --git a/build/pkgs/gmpy2/package-version.txt b/build/pkgs/gmpy2/package-version.txt index 0c271bcf956..3e3c2f1e5ed 100644 --- a/build/pkgs/gmpy2/package-version.txt +++ b/build/pkgs/gmpy2/package-version.txt @@ -1 +1 @@ -2.1.0rc1 +2.1.1 From 1576c5afa16a58d98ed6759c48aa6eb72aa6f0d1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Dec 2021 11:30:11 -0800 Subject: [PATCH 069/253] build/pkgs/distlib: Update to 0.3.4 --- build/pkgs/distlib/checksums.ini | 6 +++--- build/pkgs/distlib/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/distlib/checksums.ini b/build/pkgs/distlib/checksums.ini index 6a01aedfbb5..9c739a93823 100644 --- a/build/pkgs/distlib/checksums.ini +++ b/build/pkgs/distlib/checksums.ini @@ -1,5 +1,5 @@ tarball=distlib-VERSION.zip -sha1=47db238631902dbd0fbf730ca303438eaecbb0c8 -md5=442dc114d7e59deec1c727b8a27d7e7c -cksum=4135782264 +sha1=e7927ebc964676c17d466ed6a345222c34167a85 +md5=c886b7d99b4085c5d960e7435dcbd397 +cksum=10374426 upstream_url=https://pypi.io/packages/source/d/distlib/distlib-VERSION.zip diff --git a/build/pkgs/distlib/package-version.txt b/build/pkgs/distlib/package-version.txt index 1c09c74e221..42045acae20 100644 --- a/build/pkgs/distlib/package-version.txt +++ b/build/pkgs/distlib/package-version.txt @@ -1 +1 @@ -0.3.3 +0.3.4 From da943f202b3cf177340678658cb25fc6392c31a9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Dec 2021 11:30:20 -0800 Subject: [PATCH 070/253] build/pkgs/debugpy: Update to 1.5.1 --- build/pkgs/debugpy/checksums.ini | 6 +++--- build/pkgs/debugpy/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/debugpy/checksums.ini b/build/pkgs/debugpy/checksums.ini index 0cf6031093b..4f00cc11258 100644 --- a/build/pkgs/debugpy/checksums.ini +++ b/build/pkgs/debugpy/checksums.ini @@ -1,5 +1,5 @@ tarball=debugpy-VERSION.zip -sha1=c0162bd8d68a43702eea2591c67624fd5b4aa87b -md5=0c1103c7234b1f547eb705aff150ab31 -cksum=676752698 +sha1=169efd648ce0903c30cd300f8040136ec0ee16cc +md5=7c8ef4f136c9bcf501e80a12b8e21ac1 +cksum=422456395 upstream_url=https://pypi.io/packages/source/d/debugpy/debugpy-VERSION.zip diff --git a/build/pkgs/debugpy/package-version.txt b/build/pkgs/debugpy/package-version.txt index 347f5833ee6..26ca594609a 100644 --- a/build/pkgs/debugpy/package-version.txt +++ b/build/pkgs/debugpy/package-version.txt @@ -1 +1 @@ -1.4.1 +1.5.1 From 4a66496dec099e01d8be103c0dc3a7647cfa9586 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Dec 2021 11:30:29 -0800 Subject: [PATCH 071/253] build/pkgs/defusedxml: Update to 0.7.1 --- build/pkgs/defusedxml/checksums.ini | 6 +++--- build/pkgs/defusedxml/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/defusedxml/checksums.ini b/build/pkgs/defusedxml/checksums.ini index cbabc3b2b9d..a774cca051e 100644 --- a/build/pkgs/defusedxml/checksums.ini +++ b/build/pkgs/defusedxml/checksums.ini @@ -1,4 +1,4 @@ tarball=defusedxml-VERSION.tar.gz -sha1=0bba33cc1e6d59f8fc71ceb8d12ad951072ad122 -md5=a59741f675c4cba649de40a99f732897 -cksum=2504737728 +sha1=37667af1dc1357eb96b005c4f408ad5292d77b9f +md5=a50e7f21aa60a741efe6b1b658dfb3f8 +cksum=3442371004 diff --git a/build/pkgs/defusedxml/package-version.txt b/build/pkgs/defusedxml/package-version.txt index a918a2aa18d..39e898a4f95 100644 --- a/build/pkgs/defusedxml/package-version.txt +++ b/build/pkgs/defusedxml/package-version.txt @@ -1 +1 @@ -0.6.0 +0.7.1 From dfa52f5f8be62e8a3ec9edc8b15ba9d36deb0891 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Dec 2021 11:32:27 -0800 Subject: [PATCH 072/253] build/pkgs/decorator: Update to 5.0.9, add upstream_url --- build/pkgs/decorator/checksums.ini | 7 ++++--- build/pkgs/decorator/dependencies | 1 - build/pkgs/decorator/package-version.txt | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/pkgs/decorator/checksums.ini b/build/pkgs/decorator/checksums.ini index 5d6c11b1022..d7abe4363b8 100644 --- a/build/pkgs/decorator/checksums.ini +++ b/build/pkgs/decorator/checksums.ini @@ -1,4 +1,5 @@ tarball=decorator-VERSION.tar.gz -sha1=24d4560ff3e89a6cec068d323383577343c086fb -md5=d83c624cce93e6bdfab144821b526e1d -cksum=1324765948 +sha1=4035760ce781a93181eeb3f8a36435eb799ceb76 +md5=a90526e45e7a30cf2710d6467f403e03 +cksum=1796541525 +upstream_url=https://pypi.io/packages/source/d/decorator/decorator-VERSION.tar.gz diff --git a/build/pkgs/decorator/dependencies b/build/pkgs/decorator/dependencies index 15df0c4d6d8..0738c2d7777 100644 --- a/build/pkgs/decorator/dependencies +++ b/build/pkgs/decorator/dependencies @@ -2,4 +2,3 @@ $(PYTHON) | $(PYTHON_TOOLCHAIN) ---------- 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/decorator/package-version.txt b/build/pkgs/decorator/package-version.txt index 1d068c6ec6a..bb09d45b574 100644 --- a/build/pkgs/decorator/package-version.txt +++ b/build/pkgs/decorator/package-version.txt @@ -1 +1 @@ -4.4.2 +5.0.9 From bcc1193304d76175ad06c28f34cf303eb1b5f4ea Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Dec 2021 11:33:07 -0800 Subject: [PATCH 073/253] build/pkgs/jsonschema: Update to 4.3.2 --- build/pkgs/jsonschema/checksums.ini | 6 +++--- build/pkgs/jsonschema/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/jsonschema/checksums.ini b/build/pkgs/jsonschema/checksums.ini index 76250d4ae36..9c88c7bee89 100644 --- a/build/pkgs/jsonschema/checksums.ini +++ b/build/pkgs/jsonschema/checksums.ini @@ -1,5 +1,5 @@ tarball=jsonschema-VERSION.tar.gz -sha1=fbca135887b3c79e7f08fff6a34fef053746151b -md5=f1a0b5011f05a02a8dee1070cd10a26d -cksum=3852093817 +sha1=f804244e37c3f8f1c587ed6aee8f1f6a851f90f5 +md5=87cf45f980c9b48e040c0c5897e574c4 +cksum=1105743845 upstream_url=https://pypi.io/packages/source/j/jsonschema/jsonschema-VERSION.tar.gz diff --git a/build/pkgs/jsonschema/package-version.txt b/build/pkgs/jsonschema/package-version.txt index 944880fa15e..cc2fbe89b6c 100644 --- a/build/pkgs/jsonschema/package-version.txt +++ b/build/pkgs/jsonschema/package-version.txt @@ -1 +1 @@ -3.2.0 +4.3.2 From fd42526a5436ef63c16d2af6fe076774d3153cd7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Dec 2021 11:33:19 -0800 Subject: [PATCH 074/253] build/pkgs/nest_asyncio: Update to 1.5.4 --- build/pkgs/nest_asyncio/checksums.ini | 6 +++--- build/pkgs/nest_asyncio/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/nest_asyncio/checksums.ini b/build/pkgs/nest_asyncio/checksums.ini index 6f6094e9330..d46939ec9cb 100644 --- a/build/pkgs/nest_asyncio/checksums.ini +++ b/build/pkgs/nest_asyncio/checksums.ini @@ -1,5 +1,5 @@ tarball=nest_asyncio-VERSION.tar.gz -sha1=7ef28133a6703242618104a92263a867957b98d8 -md5=6271f5e4181736c2e711657ef1eae915 -cksum=1746231914 +sha1=a139466f747bcd3324b8e080e00fc443603e8fa6 +md5=a97d6622335d35563baeabb87afb758f +cksum=2526839264 upstream_url=https://pypi.io/packages/source/n/nest_asyncio/nest_asyncio-VERSION.tar.gz diff --git a/build/pkgs/nest_asyncio/package-version.txt b/build/pkgs/nest_asyncio/package-version.txt index 26ca594609a..94fe62c2740 100644 --- a/build/pkgs/nest_asyncio/package-version.txt +++ b/build/pkgs/nest_asyncio/package-version.txt @@ -1 +1 @@ -1.5.1 +1.5.4 From f3e0fe6e45f44330d96f7e9da2a90c73a2de8fda Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Dec 2021 11:33:28 -0800 Subject: [PATCH 075/253] build/pkgs/packaging: Update to 21.3 --- build/pkgs/packaging/checksums.ini | 6 +++--- build/pkgs/packaging/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/packaging/checksums.ini b/build/pkgs/packaging/checksums.ini index e68006c5b1b..c8c315c78c8 100644 --- a/build/pkgs/packaging/checksums.ini +++ b/build/pkgs/packaging/checksums.ini @@ -1,5 +1,5 @@ tarball=packaging-VERSION.tar.gz -sha1=6ba3b8ff3ee43d1d4c0b658241f4fd6036ee7c78 -md5=240ba5823ed31051a1254e74c9d18d55 -cksum=3836397838 +sha1=b8caff3bec760723db6af4092c68075e22bdb769 +md5=e713c1939f294fd729af4a7be40dd141 +cksum=2539089468 upstream_url=https://pypi.io/packages/source/p/packaging/packaging-VERSION.tar.gz diff --git a/build/pkgs/packaging/package-version.txt b/build/pkgs/packaging/package-version.txt index 5f39e914469..8e5954eb6f3 100644 --- a/build/pkgs/packaging/package-version.txt +++ b/build/pkgs/packaging/package-version.txt @@ -1 +1 @@ -21.0 +21.3 From c836c8e77652f6f10cf68a2e6de52aa1516512d1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Dec 2021 11:33:36 -0800 Subject: [PATCH 076/253] build/pkgs/pycparser: Update to 2.21 --- build/pkgs/pycparser/checksums.ini | 6 +++--- build/pkgs/pycparser/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/pycparser/checksums.ini b/build/pkgs/pycparser/checksums.ini index 885d94acf9d..c4eb97e2c59 100644 --- a/build/pkgs/pycparser/checksums.ini +++ b/build/pkgs/pycparser/checksums.ini @@ -1,5 +1,5 @@ tarball=pycparser-VERSION.tar.gz -sha1=0ae93d89b69fab48af3a407a2f8663bcea270c3d -md5=b8f88de737db8c346ee8d31c07c7a25a -cksum=3289554032 +sha1=359c718c6ece361047f61846b9fa4ea0239576dc +md5=48f7d743bf018f7bb2ffc5fb976d1492 +cksum=1065143416 upstream_url=https://pypi.io/packages/source/p/pycparser/pycparser-VERSION.tar.gz diff --git a/build/pkgs/pycparser/package-version.txt b/build/pkgs/pycparser/package-version.txt index a4b5a6f4a49..2ef40bd8c62 100644 --- a/build/pkgs/pycparser/package-version.txt +++ b/build/pkgs/pycparser/package-version.txt @@ -1 +1 @@ -2.20 +2.21 From dc094ecaf49e28ebede401ac56a95b4cec4d4cdc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 19 Dec 2021 20:24:32 -0800 Subject: [PATCH 077/253] build/pkgs/scipy: Update to 1.7.3 --- build/pkgs/scipy/checksums.ini | 6 +++--- build/pkgs/scipy/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/scipy/checksums.ini b/build/pkgs/scipy/checksums.ini index 152e882c0dc..9db6d5aab7d 100644 --- a/build/pkgs/scipy/checksums.ini +++ b/build/pkgs/scipy/checksums.ini @@ -1,5 +1,5 @@ tarball=scipy-VERSION.tar.gz -sha1=4c117a55ad57110c03e05973add84e2e6db28c18 -md5=9ba02f72fbdc922644ddb9ce5501c37e -cksum=3061904604 +sha1=4667454b1ee5195b8c104a68e15ab7f9aa0570fd +md5=daae4fedcd479738e54fd7035445be89 +cksum=2230241814 upstream_url=https://pypi.io/packages/source/s/scipy/scipy-VERSION.tar.gz diff --git a/build/pkgs/scipy/package-version.txt b/build/pkgs/scipy/package-version.txt index f8a696c8dc5..661e7aeadf3 100644 --- a/build/pkgs/scipy/package-version.txt +++ b/build/pkgs/scipy/package-version.txt @@ -1 +1 @@ -1.7.2 +1.7.3 From 2b77fae57aa370e62c56b148cf0e586787739892 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Dec 2021 17:05:55 -0800 Subject: [PATCH 078/253] build/pkgs/defusedxml/checksums.ini: Add upstream_url --- build/pkgs/defusedxml/checksums.ini | 1 + build/pkgs/defusedxml/dependencies | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/defusedxml/checksums.ini b/build/pkgs/defusedxml/checksums.ini index a774cca051e..c2cf328d5b2 100644 --- a/build/pkgs/defusedxml/checksums.ini +++ b/build/pkgs/defusedxml/checksums.ini @@ -2,3 +2,4 @@ tarball=defusedxml-VERSION.tar.gz sha1=37667af1dc1357eb96b005c4f408ad5292d77b9f md5=a50e7f21aa60a741efe6b1b658dfb3f8 cksum=3442371004 +upstream_url=https://pypi.io/packages/source/d/defusedxml/defusedxml-VERSION.tar.gz diff --git a/build/pkgs/defusedxml/dependencies b/build/pkgs/defusedxml/dependencies index 15df0c4d6d8..0738c2d7777 100644 --- a/build/pkgs/defusedxml/dependencies +++ b/build/pkgs/defusedxml/dependencies @@ -2,4 +2,3 @@ $(PYTHON) | $(PYTHON_TOOLCHAIN) ---------- 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. From e442cfcb56450a3a21c14d5e3ad0852ddfb88949 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 25 Dec 2021 20:52:20 -0800 Subject: [PATCH 079/253] build/pkgs/pillow: Update to 8.4.0 --- build/pkgs/pillow/checksums.ini | 6 +++--- build/pkgs/pillow/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/pillow/checksums.ini b/build/pkgs/pillow/checksums.ini index 7adfee1aca6..71d2e392acf 100644 --- a/build/pkgs/pillow/checksums.ini +++ b/build/pkgs/pillow/checksums.ini @@ -1,5 +1,5 @@ tarball=Pillow-VERSION.tar.gz -sha1=2c972f30581da0c58edb1e2bed420c2b8f6fd216 -md5=14ce2c5d19369e335c331c8f529ecf87 -cksum=976804255 +sha1=ca8d057aec64ccd0804044bc71c17921afbe2e4e +md5=7a1eb5a250c7ccbd549a89e16404f09f +cksum=555919456 upstream_url=https://pypi.io/packages/source/p/pillow/Pillow-VERSION.tar.gz diff --git a/build/pkgs/pillow/package-version.txt b/build/pkgs/pillow/package-version.txt index 6b409d977b8..a2f28f43be3 100644 --- a/build/pkgs/pillow/package-version.txt +++ b/build/pkgs/pillow/package-version.txt @@ -1 +1 @@ -8.1.2 +8.4.0 From 824056fcc7d81e031f8964cd00c5258db726bfa3 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Thu, 30 Dec 2021 00:45:44 +0800 Subject: [PATCH 080/253] use .divides and // instead of try-except and / and ZZ --- src/sage/quadratic_forms/binary_qf.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sage/quadratic_forms/binary_qf.py b/src/sage/quadratic_forms/binary_qf.py index 61b43c4ada6..85b4427e59f 100755 --- a/src/sage/quadratic_forms/binary_qf.py +++ b/src/sage/quadratic_forms/binary_qf.py @@ -1536,11 +1536,10 @@ def solve_integer(self, n): if not n: return tuple(M.columns()[1]) for x in n.divisors(): - try: - y = ZZ((n//x - Q._a*x) / Q._b) - except TypeError: - continue - return tuple(row[0]*x + row[1]*y for row in M.rows()) + y_num = n // x - Q._a * x + if Q._b.divides(y_num): + y = y_num // Q._b + return tuple(row[0]*x + row[1]*y for row in M.rows()) return None From 7820aaaba5ea8a4a840d451b5ee3ea7f8d25a3f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 29 Dec 2021 18:21:16 +0100 Subject: [PATCH 081/253] more details in Dyck words --- src/sage/combinat/dyck_word.py | 49 +++++++++++++--------------------- 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/src/sage/combinat/dyck_word.py b/src/sage/combinat/dyck_word.py index c8ad21d1c25..99b69f5ec9c 100644 --- a/src/sage/combinat/dyck_word.py +++ b/src/sage/combinat/dyck_word.py @@ -552,9 +552,9 @@ def _repr_lattice(self, type=None, labelling=None, underpath=True) -> str: row += "__"*(alst[-i-2]-alst[-i-1])+"| " + "x "*(n-c-2-i) + " ."*i + labels[-1] + "\n" labels.pop() if underpath: - row += "|" + labels[-1] + " ."*(n-1) + "\n" + row += "|" + labels[-1] + " ." * (n - 1) + "\n" else: - row += "| "+" ."*(n-1) + labels[-1] + "\n" + row += "| " + " ." * (n - 1) + labels[-1] + "\n" return row else: raise ValueError("The given type (=%s) is not valid." % type) @@ -629,7 +629,7 @@ def to_path_string(self, unicode=False) -> str: """ if unicode: import unicodedata - space = u' ' + space = ' ' up = unicodedata.lookup('BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT') down = unicodedata.lookup('BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT') else: @@ -1129,7 +1129,7 @@ def associated_parenthesis(self, pos) -> int | None: height -= 1 return pos - def ascent_prime_decomposition(self) -> list: + def ascent_prime_decomposition(self) -> list[DyckWord]: r""" Decompose this Dyck word into a sequence of ascents and prime Dyck paths. @@ -1183,7 +1183,7 @@ def ascent_prime_decomposition(self) -> list: result.append(DyckWord([open_symbol] * up)) # type:ignore return result - def catalan_factorization(self) -> list: + def catalan_factorization(self) -> list[DyckWord]: r""" Decompose this Dyck word into a sequence of complete Dyck words. @@ -1401,7 +1401,7 @@ def number_of_double_rises(self) -> int: """ return len(self.positions_of_double_rises()) - def returns_to_zero(self) -> list: + def returns_to_zero(self) -> list[int]: r""" Return a list of positions where ``self`` has height `0`, excluding the position `0`. @@ -1428,7 +1428,7 @@ def returns_to_zero(self) -> list: points.append(i + 1) return points - def touch_points(self) -> list: + def touch_points(self) -> list[int]: r""" Return the abscissae (or, equivalently, ordinates) of the points where the Dyck path corresponding to ``self`` (comprising @@ -1577,7 +1577,7 @@ def to_standard_tableau(self): from sage.combinat.tableau import StandardTableau return StandardTableau([x for x in [open_positions, close_positions] if x]) - def to_tamari_sorting_tuple(self) -> list: + def to_tamari_sorting_tuple(self) -> list[int]: """ Convert a Dyck word to a Tamari sorting tuple. @@ -1600,7 +1600,7 @@ def to_tamari_sorting_tuple(self) -> list: sage: DyckWord([1, 1, 0, 1, 0, 0]).to_tamari_sorting_tuple() [2, 0, 0] - .. SEEALSO:: :meth:`to_Catalan_code` + .. SEEALSO:: :meth:`~DyckWord_complete.to_Catalan_code` """ position = 0 resu = [-i - 1 for i in range(len(self) // 2)] @@ -1923,7 +1923,7 @@ def number_of_parking_functions(self) -> int: 6 """ from sage.arith.all import multinomial - return multinomial(list(self.rise_composition())) + return multinomial(self.rise_composition()) def list_parking_functions(self): r""" @@ -2295,7 +2295,7 @@ def to_noncrossing_partition(self, bijection=None): from [Stu2008]_, see also the method :meth:`to_noncrossing_permutation`. Thanks to Mathieu Dutour for describing the bijection. See also - :func:`~DyckWords.from_noncrossing_partition`. + :func:`~CompleteDyckWords.from_noncrossing_partition`. EXAMPLES:: @@ -2718,14 +2718,14 @@ def reverse(self) -> DyckWord: sage: DyckWord([]).reverse() [] """ - list = [] + alist = [] for i in range(len(self)): if self[i] == open_symbol: - list.append(close_symbol) + alist.append(close_symbol) else: - list.append(open_symbol) - list.reverse() - return DyckWord(list) # type:ignore + alist.append(open_symbol) + alist.reverse() + return DyckWord(alist) # type:ignore def first_return_decomposition(self) -> tuple: r""" @@ -2923,16 +2923,7 @@ def area(self) -> int: sage: DyckWord([1,0,1,0,1,0,1,0]).area() 0 """ - above = 0 - diagonal = 0 - a = 0 - for move in self: - if move == open_symbol: - above += 1 - elif move == close_symbol: - diagonal += 1 - a += above - diagonal - return a + return sum(self._area_sequence_iter()) def bounce_path(self) -> DyckWord: r""" @@ -3811,7 +3802,7 @@ def from_area_sequence(self, code) -> DyckWord: See :meth:`~DyckWord.to_area_sequence` for a definition of the area sequence of a Dyck word. - .. SEEALSO:: :meth:`~DyckWord.area`, :meth:`~DyckWord.to_area_sequence`. + .. SEEALSO:: :meth:`~DyckWord_complete.area`, :meth:`~DyckWord.to_area_sequence`. INPUT: @@ -3845,15 +3836,13 @@ def from_noncrossing_partition(self, ncp) -> DyckWord: r""" Convert a noncrossing partition ``ncp`` to a Dyck word. - TESTS:: + EXAMPLES:: sage: DyckWord(noncrossing_partition=[[1,2]]) # indirect doctest [1, 1, 0, 0] sage: DyckWord(noncrossing_partition=[[1],[2]]) [1, 0, 1, 0] - :: - sage: dws = DyckWords(5).list() sage: ncps = [x.to_noncrossing_partition() for x in dws] sage: dws2 = [DyckWord(noncrossing_partition=x) for x in ncps] From 584d121fbf3b109e84517746ea191e0af9202075 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 29 Dec 2021 10:40:54 -0800 Subject: [PATCH 082/253] src/sage/rings/polynomial/multi_polynomial_libsingular.pyx: Fix import --- src/sage/rings/polynomial/multi_polynomial_libsingular.pyx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index 397553341de..7e957d0d257 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -243,7 +243,6 @@ from sage.structure.richcmp cimport rich_to_bool, richcmp from sage.structure.factorization import Factorization from sage.structure.sequence import Sequence -from sage.interfaces.macaulay import macaulay2 from sage.interfaces.singular import singular as singular_default, is_SingularElement, SingularElement from sage.interfaces.macaulay2 import macaulay2 as macaulay2_default, is_Macaulay2Element From d48cc0fec4e9a5aa527a618af964fc95ed6bf999 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 29 Dec 2021 11:15:12 -0800 Subject: [PATCH 083/253] src/tox.ini (relint): Exclude editor temp files etc. --- src/tox.ini | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/tox.ini b/src/tox.ini index eb5f55064db..40b3f04f3f5 100644 --- a/src/tox.ini +++ b/src/tox.ini @@ -100,7 +100,13 @@ description = # The patterns are in .relint.yml deps = relint whitelist_externals = find -commands = find {posargs:{toxinidir}/sage/} -exec relint -c {toxinidir}/.relint.yml \{\} + +commands = find {posargs:{toxinidir}/sage/} \ + -name "*.png" -prune -o -name "*.png" -prune -o -name "*.jpg" -prune -o -name "*.JPG" -prune -o -name "*.inv" -prune -o \ + -name "*.dia" -prune -o -name "*.pdf" -prune -o -name "*.ico" -prune -o -name "*#*" -prune -o -name "*~*" -prune -o \ + -name "*.bak" -prune -o -name "*.orig" -prune -o -name "*.log" -prune -o -name "*.sobj" -prune -o -name "*.tar" -prune -o \ + -name "*.gz" -prune -o -name "*.pyc" -prune -o -name "*.o" -prune -o -name "*.sws" -prune -o -name "*.so" -prune -o \ + -name "*.a" -prune -o -name ".DS_Store" -prune -o \ + -exec relint -c {toxinidir}/.relint.yml \{\} + [testenv:codespell] description = From 4efced8d0946bda02b2c944ba51dc1f74ba28523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20Leli=C3=A8vre?= Date: Thu, 30 Dec 2021 04:01:07 +0100 Subject: [PATCH 084/253] 33096: src/tox.ini: cleanup relint and codespell skips --- src/tox.ini | 46 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/src/tox.ini b/src/tox.ini index 40b3f04f3f5..9b18ac08211 100644 --- a/src/tox.ini +++ b/src/tox.ini @@ -101,11 +101,35 @@ description = deps = relint whitelist_externals = find commands = find {posargs:{toxinidir}/sage/} \ - -name "*.png" -prune -o -name "*.png" -prune -o -name "*.jpg" -prune -o -name "*.JPG" -prune -o -name "*.inv" -prune -o \ - -name "*.dia" -prune -o -name "*.pdf" -prune -o -name "*.ico" -prune -o -name "*#*" -prune -o -name "*~*" -prune -o \ - -name "*.bak" -prune -o -name "*.orig" -prune -o -name "*.log" -prune -o -name "*.sobj" -prune -o -name "*.tar" -prune -o \ - -name "*.gz" -prune -o -name "*.pyc" -prune -o -name "*.o" -prune -o -name "*.sws" -prune -o -name "*.so" -prune -o \ - -name "*.a" -prune -o -name ".DS_Store" -prune -o \ + -name "*#*" -prune -o \ + -name "*.a" -prune -o \ + -name "*.bak" -prune -o \ + -name "*.bz2" -prune -o \ + -name "*.dia" -prune -o \ + -name "*.gz" -prune -o \ + -name "*.ico" -prune -o \ + -name "*.inv" -prune -o \ + -name "*.JPEG" -prune -o \ + -name "*.jpeg" -prune -o \ + -name "*.JPG" -prune -o \ + -name "*.jpg" -prune -o \ + -name "*.log" -prune -o \ + -name "*.o" -prune -o \ + -name "*.orig" -prune -o \ + -name "*.PDF" -prune -o \ + -name "*.pdf" -prune -o \ + -name "*.PNG" -prune -o \ + -name "*.png" -prune -o \ + -name "*.pyc" -prune -o \ + -name "*.so" -prune -o \ + -name "*.sobj" -prune -o \ + -name "*.sws" -prune -o \ + -name "*.tar" -prune -o \ + -name "*.tgz" -prune -o \ + -name "*.xz" -prune -o \ + -name "*.zip" -prune -o \ + -name "*~*" -prune -o \ + -name ".DS_Store" -prune -o \ -exec relint -c {toxinidir}/.relint.yml \{\} + [testenv:codespell] @@ -114,10 +138,14 @@ description = # https://pypi.org/project/codespell/ deps = codespell commands = codespell \ - --skip="*.png,*.jpg,*.JPG,*.inv,*.dia,*.pdf,*.ico,*#*,*~*,*.bak,*.orig,*.log,*.sobj,*.tar,*.gz,*.pyc,*.o,*.sws,*.so,*.a,.DS_Store" \ - --skip="doc/ca,doc/de,doc/es,doc/hu,doc/ja,doc/ru,doc/fr,doc/it,doc/pt,doc/tr" \ - --skip="src/doc/ca,src/doc/de,src/doc/es,src/doc/hu,src/doc/ja,src/doc/ru,src/doc/fr,src/doc/it,src/doc/pt,src/doc/tr" \ - --skip=".git,.tox,worktree*,dist,upstream,logs,local,cythonized,scripts-3,autom4te.cache,tmp,lib.*,*.egg-info" \ + --skip="*#*,*.a,*.bak,*.bz2,*.dia,*.gz,*.ico,*.inv,*.JPEG,*.jpeg" \ + --skip="*.JPG,*.jpg,*.log,*.o,*.orig,*.PDF,*.pdf,*.PNG,*.png,*.pyc" \ + --skip="*.so,*.sobj,*.sws,*.tar,*.tgz,*.xz,*.zip,*~*,.DS_Store" \ + --skip="doc/ca,doc/de,doc/es,doc/fr,doc/hu,doc/it,doc/ja,doc/pt,doc/ru,doc/tr" \ + --skip="src/doc/ca,src/doc/de,src/doc/es,src/doc/fr,src/doc/hu" \ + --skip="src/doc/it,src/doc/ja,src/doc/pt,src/doc/ru,src/doc/tr" \ + --skip=".git,.tox,autom4te.cache,cythonized,dist,lib.*,local" \ + --skip="logs,scripts-3,tmp,upstream,worktree*,*.egg-info" \ --dictionary=- \ --dictionary={toxinidir}/.codespell-dictionary.txt \ --ignore-words={toxinidir}/.codespell-ignore.txt \ From 5e8a2a34074a40ad2194290f83e11737ee1f8a6f Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Thu, 30 Dec 2021 20:16:22 +0800 Subject: [PATCH 085/253] add doctest; style tweak --- src/sage/quadratic_forms/binary_qf.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/sage/quadratic_forms/binary_qf.py b/src/sage/quadratic_forms/binary_qf.py index 85b4427e59f..bcae6f6b441 100755 --- a/src/sage/quadratic_forms/binary_qf.py +++ b/src/sage/quadratic_forms/binary_qf.py @@ -1503,13 +1503,20 @@ def solve_integer(self, n): sage: n = randrange(-10^3, 10^3) sage: Q = BinaryQF([n, randrange(-10^3, 10^3), 0][::(-1)**randrange(2)]) sage: U = random_matrix(ZZ, 2, 2, 'unimodular') - sage: U.rescale_row(0, choice((+1,-1))); assert U.det() in (+1,-1) + sage: U.rescale_row(0, choice((+1,-1))) + sage: assert U.det() in (+1,-1) sage: Q = Q.matrix_action_right(U) sage: Q.discriminant().is_square() True sage: xy = Q.solve_integer(n) sage: Q(*xy) == n True + + Also test the `n=0` special case separately:: + + sage: xy = Q.solve_integer(0) + sage: Q(*xy) + 0 """ n = ZZ(n) From a3b730b9d64cef48408ab83643bab5c7046caffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Wed, 29 Dec 2021 10:24:08 -0300 Subject: [PATCH 086/253] void linux: packages that can be used from system --- build/pkgs/_prereq/distros/void.txt | 7 ++++--- build/pkgs/brial/distros/void.txt | 1 + build/pkgs/cddlib/distros/void.txt | 1 + build/pkgs/cliquer/distros/void.txt | 1 + build/pkgs/fflas_ffpack/distros/void.txt | 1 + build/pkgs/flintqs/distros/void.txt | 1 + build/pkgs/fplll/distros/void.txt | 1 + build/pkgs/gfan/distros/void.txt | 1 + build/pkgs/givaro/distros/void.txt | 1 + build/pkgs/gmp/distros/void.txt | 1 + build/pkgs/graphviz/distros/void.txt | 1 + build/pkgs/igraph/distros/void.txt | 1 + build/pkgs/iml/distros/void.txt | 1 + build/pkgs/lcalc/distros/void.txt | 1 + build/pkgs/libbraiding/distros/void.txt | 1 + build/pkgs/libhomfly/distros/void.txt | 1 + build/pkgs/libnauty/distros/void.txt | 1 + build/pkgs/linbox/distros/void.txt | 1 + build/pkgs/lrcalc/distros/void.txt | 1 + build/pkgs/m4ri/distros/void.txt | 1 + build/pkgs/m4rie/distros/void.txt | 1 + build/pkgs/maxima/distros/void.txt | 2 +- build/pkgs/mpfi/distros/void.txt | 1 + build/pkgs/nauty/distros/void.txt | 1 + build/pkgs/palp/distros/void.txt | 1 + build/pkgs/pari/distros/void.txt | 5 +++-- build/pkgs/pari_elldata/distros/void.txt | 3 ++- build/pkgs/pari_galpol/distros/void.txt | 3 ++- build/pkgs/pari_nftables/distros/void.txt | 1 + build/pkgs/pari_seadata_small/distros/void.txt | 2 ++ build/pkgs/pdf2svg/distros/void.txt | 1 - build/pkgs/perl_cpan_polymake_prereq/distros/void.txt | 7 +++++++ build/pkgs/pkgconfig/distros/void.txt | 1 + build/pkgs/planarity/distros/void.txt | 1 + build/pkgs/primecount/distros/void.txt | 1 + build/pkgs/primesieve/distros/void.txt | 1 + build/pkgs/qhull/distros/void.txt | 1 + build/pkgs/rw/distros/void.txt | 1 + build/pkgs/singular/distros/void.txt | 1 + build/pkgs/suitesparse/distros/void.txt | 1 + build/pkgs/symmetrica/distros/void.txt | 1 + build/pkgs/sympow/distros/void.txt | 1 + build/pkgs/tachyon/distros/void.txt | 1 + build/pkgs/zn_poly/distros/void.txt | 1 + 44 files changed, 57 insertions(+), 9 deletions(-) create mode 100644 build/pkgs/brial/distros/void.txt create mode 100644 build/pkgs/cddlib/distros/void.txt create mode 100644 build/pkgs/cliquer/distros/void.txt create mode 100644 build/pkgs/fflas_ffpack/distros/void.txt create mode 100644 build/pkgs/flintqs/distros/void.txt create mode 100644 build/pkgs/fplll/distros/void.txt create mode 100644 build/pkgs/gfan/distros/void.txt create mode 100644 build/pkgs/givaro/distros/void.txt create mode 100644 build/pkgs/igraph/distros/void.txt create mode 100644 build/pkgs/iml/distros/void.txt create mode 100644 build/pkgs/lcalc/distros/void.txt create mode 100644 build/pkgs/libbraiding/distros/void.txt create mode 100644 build/pkgs/libhomfly/distros/void.txt create mode 100644 build/pkgs/libnauty/distros/void.txt create mode 100644 build/pkgs/linbox/distros/void.txt create mode 100644 build/pkgs/lrcalc/distros/void.txt create mode 100644 build/pkgs/m4ri/distros/void.txt create mode 100644 build/pkgs/m4rie/distros/void.txt create mode 100644 build/pkgs/mpfi/distros/void.txt create mode 100644 build/pkgs/nauty/distros/void.txt create mode 100644 build/pkgs/palp/distros/void.txt create mode 100644 build/pkgs/pari_nftables/distros/void.txt create mode 100644 build/pkgs/pari_seadata_small/distros/void.txt delete mode 100644 build/pkgs/pdf2svg/distros/void.txt create mode 100644 build/pkgs/perl_cpan_polymake_prereq/distros/void.txt create mode 100644 build/pkgs/pkgconfig/distros/void.txt create mode 100644 build/pkgs/planarity/distros/void.txt create mode 100644 build/pkgs/primecount/distros/void.txt create mode 100644 build/pkgs/primesieve/distros/void.txt create mode 100644 build/pkgs/rw/distros/void.txt create mode 100644 build/pkgs/singular/distros/void.txt create mode 100644 build/pkgs/suitesparse/distros/void.txt create mode 100644 build/pkgs/symmetrica/distros/void.txt create mode 100644 build/pkgs/sympow/distros/void.txt create mode 100644 build/pkgs/tachyon/distros/void.txt create mode 100644 build/pkgs/zn_poly/distros/void.txt diff --git a/build/pkgs/_prereq/distros/void.txt b/build/pkgs/_prereq/distros/void.txt index a2e7644840f..da5cd5330ee 100644 --- a/build/pkgs/_prereq/distros/void.txt +++ b/build/pkgs/_prereq/distros/void.txt @@ -1,10 +1,11 @@ +bc binutils -make +gcc +libgomp-devel m4 +make perl pkg-config python3 tar -bc -gcc which diff --git a/build/pkgs/brial/distros/void.txt b/build/pkgs/brial/distros/void.txt new file mode 100644 index 00000000000..f28d17cd914 --- /dev/null +++ b/build/pkgs/brial/distros/void.txt @@ -0,0 +1 @@ +brial-devel diff --git a/build/pkgs/cddlib/distros/void.txt b/build/pkgs/cddlib/distros/void.txt new file mode 100644 index 00000000000..32b52a21aec --- /dev/null +++ b/build/pkgs/cddlib/distros/void.txt @@ -0,0 +1 @@ +cddlib-devel diff --git a/build/pkgs/cliquer/distros/void.txt b/build/pkgs/cliquer/distros/void.txt new file mode 100644 index 00000000000..9b5325ee797 --- /dev/null +++ b/build/pkgs/cliquer/distros/void.txt @@ -0,0 +1 @@ +cliquer-devel diff --git a/build/pkgs/fflas_ffpack/distros/void.txt b/build/pkgs/fflas_ffpack/distros/void.txt new file mode 100644 index 00000000000..683f84a42ca --- /dev/null +++ b/build/pkgs/fflas_ffpack/distros/void.txt @@ -0,0 +1 @@ +fflas-ffpack diff --git a/build/pkgs/flintqs/distros/void.txt b/build/pkgs/flintqs/distros/void.txt new file mode 100644 index 00000000000..dcc1f9f725f --- /dev/null +++ b/build/pkgs/flintqs/distros/void.txt @@ -0,0 +1 @@ +FlintQS diff --git a/build/pkgs/fplll/distros/void.txt b/build/pkgs/fplll/distros/void.txt new file mode 100644 index 00000000000..f9eb6f7462c --- /dev/null +++ b/build/pkgs/fplll/distros/void.txt @@ -0,0 +1 @@ +fplll-devel diff --git a/build/pkgs/gfan/distros/void.txt b/build/pkgs/gfan/distros/void.txt new file mode 100644 index 00000000000..30698c7bd41 --- /dev/null +++ b/build/pkgs/gfan/distros/void.txt @@ -0,0 +1 @@ +gfan diff --git a/build/pkgs/givaro/distros/void.txt b/build/pkgs/givaro/distros/void.txt new file mode 100644 index 00000000000..9540863331f --- /dev/null +++ b/build/pkgs/givaro/distros/void.txt @@ -0,0 +1 @@ +givaro-devel diff --git a/build/pkgs/gmp/distros/void.txt b/build/pkgs/gmp/distros/void.txt index e6ec1a0e220..f18386ec77b 100644 --- a/build/pkgs/gmp/distros/void.txt +++ b/build/pkgs/gmp/distros/void.txt @@ -1 +1,2 @@ +gmp-devel gmpxx-devel diff --git a/build/pkgs/graphviz/distros/void.txt b/build/pkgs/graphviz/distros/void.txt index 4d95609306f..e14ca4ce8cc 100644 --- a/build/pkgs/graphviz/distros/void.txt +++ b/build/pkgs/graphviz/distros/void.txt @@ -1 +1,2 @@ graphviz +graphviz-devel diff --git a/build/pkgs/igraph/distros/void.txt b/build/pkgs/igraph/distros/void.txt new file mode 100644 index 00000000000..f0bff4a2bc4 --- /dev/null +++ b/build/pkgs/igraph/distros/void.txt @@ -0,0 +1 @@ +igraph-devel diff --git a/build/pkgs/iml/distros/void.txt b/build/pkgs/iml/distros/void.txt new file mode 100644 index 00000000000..56644ed0c93 --- /dev/null +++ b/build/pkgs/iml/distros/void.txt @@ -0,0 +1 @@ +iml-devel diff --git a/build/pkgs/lcalc/distros/void.txt b/build/pkgs/lcalc/distros/void.txt new file mode 100644 index 00000000000..90481575b47 --- /dev/null +++ b/build/pkgs/lcalc/distros/void.txt @@ -0,0 +1 @@ +lcalc-devel diff --git a/build/pkgs/libbraiding/distros/void.txt b/build/pkgs/libbraiding/distros/void.txt new file mode 100644 index 00000000000..b7873e1b3c6 --- /dev/null +++ b/build/pkgs/libbraiding/distros/void.txt @@ -0,0 +1 @@ +libbraiding-devel diff --git a/build/pkgs/libhomfly/distros/void.txt b/build/pkgs/libhomfly/distros/void.txt new file mode 100644 index 00000000000..48f7e49dc2a --- /dev/null +++ b/build/pkgs/libhomfly/distros/void.txt @@ -0,0 +1 @@ +libhomfly-devel diff --git a/build/pkgs/libnauty/distros/void.txt b/build/pkgs/libnauty/distros/void.txt new file mode 100644 index 00000000000..6ddbfe67f4e --- /dev/null +++ b/build/pkgs/libnauty/distros/void.txt @@ -0,0 +1 @@ +nauty-devel diff --git a/build/pkgs/linbox/distros/void.txt b/build/pkgs/linbox/distros/void.txt new file mode 100644 index 00000000000..e0fb5eb3ccc --- /dev/null +++ b/build/pkgs/linbox/distros/void.txt @@ -0,0 +1 @@ +linbox-devel diff --git a/build/pkgs/lrcalc/distros/void.txt b/build/pkgs/lrcalc/distros/void.txt new file mode 100644 index 00000000000..9807c3a2d3b --- /dev/null +++ b/build/pkgs/lrcalc/distros/void.txt @@ -0,0 +1 @@ +lrcalc-devel diff --git a/build/pkgs/m4ri/distros/void.txt b/build/pkgs/m4ri/distros/void.txt new file mode 100644 index 00000000000..7630ec6eace --- /dev/null +++ b/build/pkgs/m4ri/distros/void.txt @@ -0,0 +1 @@ +m4ri-devel diff --git a/build/pkgs/m4rie/distros/void.txt b/build/pkgs/m4rie/distros/void.txt new file mode 100644 index 00000000000..b4c3e366c49 --- /dev/null +++ b/build/pkgs/m4rie/distros/void.txt @@ -0,0 +1 @@ +m4rie-devel diff --git a/build/pkgs/maxima/distros/void.txt b/build/pkgs/maxima/distros/void.txt index f5fe3fdc6cb..6400290f44d 100644 --- a/build/pkgs/maxima/distros/void.txt +++ b/build/pkgs/maxima/distros/void.txt @@ -1 +1 @@ -maxima +maxima-ecl diff --git a/build/pkgs/mpfi/distros/void.txt b/build/pkgs/mpfi/distros/void.txt new file mode 100644 index 00000000000..b3c032626fa --- /dev/null +++ b/build/pkgs/mpfi/distros/void.txt @@ -0,0 +1 @@ +mpfi-devel diff --git a/build/pkgs/nauty/distros/void.txt b/build/pkgs/nauty/distros/void.txt new file mode 100644 index 00000000000..21c67b1e856 --- /dev/null +++ b/build/pkgs/nauty/distros/void.txt @@ -0,0 +1 @@ +nauty diff --git a/build/pkgs/palp/distros/void.txt b/build/pkgs/palp/distros/void.txt new file mode 100644 index 00000000000..f037baef346 --- /dev/null +++ b/build/pkgs/palp/distros/void.txt @@ -0,0 +1 @@ +palp diff --git a/build/pkgs/pari/distros/void.txt b/build/pkgs/pari/distros/void.txt index 0a6a6eb2969..fc7f100d58c 100644 --- a/build/pkgs/pari/distros/void.txt +++ b/build/pkgs/pari/distros/void.txt @@ -1,6 +1,7 @@ pari pari-devel -pari-elldata +pari-elldata-small pari-galdata -pari-galpol +pari-galpol-small +#pari-seadata-small pari-seadata diff --git a/build/pkgs/pari_elldata/distros/void.txt b/build/pkgs/pari_elldata/distros/void.txt index 540f0b1ab86..edcd26c7769 100644 --- a/build/pkgs/pari_elldata/distros/void.txt +++ b/build/pkgs/pari_elldata/distros/void.txt @@ -1 +1,2 @@ -pari-elldata +# pari-elldata +pari-elldata-small diff --git a/build/pkgs/pari_galpol/distros/void.txt b/build/pkgs/pari_galpol/distros/void.txt index e3b41380f41..8de86cb71e6 100644 --- a/build/pkgs/pari_galpol/distros/void.txt +++ b/build/pkgs/pari_galpol/distros/void.txt @@ -1 +1,2 @@ -pari-galpol +#pari-galpol +pari-galpol-small diff --git a/build/pkgs/pari_nftables/distros/void.txt b/build/pkgs/pari_nftables/distros/void.txt new file mode 100644 index 00000000000..a9f2eb4a474 --- /dev/null +++ b/build/pkgs/pari_nftables/distros/void.txt @@ -0,0 +1 @@ +pari-nftables diff --git a/build/pkgs/pari_seadata_small/distros/void.txt b/build/pkgs/pari_seadata_small/distros/void.txt new file mode 100644 index 00000000000..ddd556ef902 --- /dev/null +++ b/build/pkgs/pari_seadata_small/distros/void.txt @@ -0,0 +1,2 @@ +#pari-seadata-small +pari-seadata diff --git a/build/pkgs/pdf2svg/distros/void.txt b/build/pkgs/pdf2svg/distros/void.txt deleted file mode 100644 index 52c66a99cbf..00000000000 --- a/build/pkgs/pdf2svg/distros/void.txt +++ /dev/null @@ -1 +0,0 @@ -pdf2svg diff --git a/build/pkgs/perl_cpan_polymake_prereq/distros/void.txt b/build/pkgs/perl_cpan_polymake_prereq/distros/void.txt new file mode 100644 index 00000000000..bf56b8bfe7e --- /dev/null +++ b/build/pkgs/perl_cpan_polymake_prereq/distros/void.txt @@ -0,0 +1,7 @@ +perl-File-Slurp +perl-JSON +perl-SVG +perl-Term-ReadKey +perl-XML-LibXML +perl-XML-LibXSLT +perl-XML-Writer diff --git a/build/pkgs/pkgconfig/distros/void.txt b/build/pkgs/pkgconfig/distros/void.txt new file mode 100644 index 00000000000..38e5106dd74 --- /dev/null +++ b/build/pkgs/pkgconfig/distros/void.txt @@ -0,0 +1 @@ +python3-pkgconfig diff --git a/build/pkgs/planarity/distros/void.txt b/build/pkgs/planarity/distros/void.txt new file mode 100644 index 00000000000..7b88e76947d --- /dev/null +++ b/build/pkgs/planarity/distros/void.txt @@ -0,0 +1 @@ +planarity-devel diff --git a/build/pkgs/primecount/distros/void.txt b/build/pkgs/primecount/distros/void.txt new file mode 100644 index 00000000000..b67cc7d852c --- /dev/null +++ b/build/pkgs/primecount/distros/void.txt @@ -0,0 +1 @@ +primecount-devel diff --git a/build/pkgs/primesieve/distros/void.txt b/build/pkgs/primesieve/distros/void.txt new file mode 100644 index 00000000000..b0fb14ce4f8 --- /dev/null +++ b/build/pkgs/primesieve/distros/void.txt @@ -0,0 +1 @@ +primesieve-devel diff --git a/build/pkgs/qhull/distros/void.txt b/build/pkgs/qhull/distros/void.txt index 95d316779cf..f053195b191 100644 --- a/build/pkgs/qhull/distros/void.txt +++ b/build/pkgs/qhull/distros/void.txt @@ -1 +1,2 @@ qhull +libqhull-devel diff --git a/build/pkgs/rw/distros/void.txt b/build/pkgs/rw/distros/void.txt new file mode 100644 index 00000000000..85b77be4262 --- /dev/null +++ b/build/pkgs/rw/distros/void.txt @@ -0,0 +1 @@ +rankwidth-devel diff --git a/build/pkgs/singular/distros/void.txt b/build/pkgs/singular/distros/void.txt new file mode 100644 index 00000000000..5f0dc01955f --- /dev/null +++ b/build/pkgs/singular/distros/void.txt @@ -0,0 +1 @@ +singular diff --git a/build/pkgs/suitesparse/distros/void.txt b/build/pkgs/suitesparse/distros/void.txt new file mode 100644 index 00000000000..1f94b0a3bdc --- /dev/null +++ b/build/pkgs/suitesparse/distros/void.txt @@ -0,0 +1 @@ +SuiteSparse-devel diff --git a/build/pkgs/symmetrica/distros/void.txt b/build/pkgs/symmetrica/distros/void.txt new file mode 100644 index 00000000000..8a4c52ca90e --- /dev/null +++ b/build/pkgs/symmetrica/distros/void.txt @@ -0,0 +1 @@ +symmetrica-devel diff --git a/build/pkgs/sympow/distros/void.txt b/build/pkgs/sympow/distros/void.txt new file mode 100644 index 00000000000..a2ae7a8a59c --- /dev/null +++ b/build/pkgs/sympow/distros/void.txt @@ -0,0 +1 @@ +sympow diff --git a/build/pkgs/tachyon/distros/void.txt b/build/pkgs/tachyon/distros/void.txt new file mode 100644 index 00000000000..39e8fd61a2d --- /dev/null +++ b/build/pkgs/tachyon/distros/void.txt @@ -0,0 +1 @@ +tachyon diff --git a/build/pkgs/zn_poly/distros/void.txt b/build/pkgs/zn_poly/distros/void.txt new file mode 100644 index 00000000000..5ff8997d672 --- /dev/null +++ b/build/pkgs/zn_poly/distros/void.txt @@ -0,0 +1 @@ +zn_poly From cf12322bf968679da1c2df1889053240a607f6a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Wed, 29 Dec 2021 11:14:12 -0300 Subject: [PATCH 087/253] void linux: add python3 packages for #29665 --- build/pkgs/alabaster/distros/void.txt | 1 + build/pkgs/argcomplete/distros/void.txt | 1 + build/pkgs/argon2_cffi/distros/void.txt | 1 + build/pkgs/attrs/distros/void.txt | 1 + build/pkgs/babel/distros/void.txt | 1 + build/pkgs/backcall/distros/void.txt | 1 + build/pkgs/beniget/distros/void.txt | 1 + build/pkgs/bleach/distros/void.txt | 1 + build/pkgs/certifi/distros/void.txt | 1 + build/pkgs/cffi/distros/void.txt | 1 + build/pkgs/charset_normalizer/distros/void.txt | 1 + build/pkgs/cycler/distros/void.txt | 1 + build/pkgs/dateutil/distros/void.txt | 1 + build/pkgs/decorator/distros/void.txt | 1 + build/pkgs/defusedxml/distros/void.txt | 1 + build/pkgs/docutils/distros/void.txt | 1 + build/pkgs/entrypoints/distros/void.txt | 1 + build/pkgs/flit_core/distros/void.txt | 1 + build/pkgs/gast/distros/void.txt | 1 + build/pkgs/html5lib/distros/void.txt | 1 + build/pkgs/idna/distros/void.txt | 1 + build/pkgs/imagesize/distros/void.txt | 1 + build/pkgs/importlib_metadata/distros/void.txt | 1 + build/pkgs/ipykernel/distros/void.txt | 1 + build/pkgs/ipython/distros/void.txt | 1 + build/pkgs/ipython_genutils/distros/void.txt | 1 + build/pkgs/ipywidgets/distros/void.txt | 1 + build/pkgs/jedi/distros/void.txt | 1 + build/pkgs/jinja2/distros/void.txt | 1 + build/pkgs/jsonschema/distros/void.txt | 1 + build/pkgs/jupyter_client/distros/void.txt | 1 + build/pkgs/jupyter_core/distros/void.txt | 1 + build/pkgs/jupyterlab_pygments/distros/void.txt | 1 + build/pkgs/kiwisolver/distros/void.txt | 1 + build/pkgs/markupsafe/distros/void.txt | 1 + build/pkgs/matplotlib/distros/void.txt | 1 + build/pkgs/matplotlib_inline/distros/void.txt | 1 + build/pkgs/mistune/distros/void.txt | 1 + build/pkgs/mpmath/distros/void.txt | 1 + build/pkgs/nbclient/distros/void.txt | 1 + build/pkgs/nbconvert/distros/void.txt | 1 + build/pkgs/nbformat/distros/void.txt | 1 + build/pkgs/nest_asyncio/distros/void.txt | 1 + build/pkgs/networkx/distros/void.txt | 1 + build/pkgs/notebook/distros/void.txt | 1 + build/pkgs/numpy/distros/void.txt | 1 + build/pkgs/packaging/distros/void.txt | 1 + build/pkgs/pandocfilters/distros/void.txt | 1 + build/pkgs/parso/distros/void.txt | 1 + build/pkgs/pexpect/distros/void.txt | 1 + build/pkgs/pickleshare/distros/void.txt | 1 + build/pkgs/pillow/distros/void.txt | 1 + build/pkgs/pip/distros/void.txt | 1 + build/pkgs/pluggy/distros/void.txt | 1 + build/pkgs/ply/distros/void.txt | 1 + build/pkgs/prometheus_client/distros/void.txt | 1 + build/pkgs/prompt_toolkit/distros/void.txt | 1 + build/pkgs/ptyprocess/distros/void.txt | 1 + build/pkgs/py/distros/void.txt | 1 + build/pkgs/pybind11/distros/void.txt | 1 + build/pkgs/pycparser/distros/void.txt | 1 + build/pkgs/pygments/distros/void.txt | 1 + build/pkgs/pyparsing/distros/void.txt | 1 + build/pkgs/pyrsistent/distros/void.txt | 1 + build/pkgs/pythran/distros/void.txt | 1 + build/pkgs/pytz/distros/void.txt | 1 + build/pkgs/pyzmq/distros/void.txt | 1 + build/pkgs/requests/distros/void.txt | 1 + build/pkgs/scipy/distros/void.txt | 1 + build/pkgs/send2trash/distros/void.txt | 1 + build/pkgs/setuptools/distros/void.txt | 1 + build/pkgs/setuptools_scm/distros/void.txt | 1 + build/pkgs/simplegeneric/distros/void.txt | 1 + build/pkgs/six/distros/void.txt | 1 + build/pkgs/snowballstemmer/distros/void.txt | 1 + build/pkgs/sphinx/distros/void.txt | 1 + build/pkgs/sphinxcontrib_applehelp/distros/void.txt | 1 + build/pkgs/sphinxcontrib_devhelp/distros/void.txt | 1 + build/pkgs/sphinxcontrib_htmlhelp/distros/void.txt | 1 + build/pkgs/sphinxcontrib_jsmath/distros/void.txt | 1 + build/pkgs/sphinxcontrib_qthelp/distros/void.txt | 1 + build/pkgs/sphinxcontrib_serializinghtml/distros/void.txt | 1 + build/pkgs/sympy/distros/void.txt | 1 + build/pkgs/terminado/distros/void.txt | 1 + build/pkgs/testpath/distros/void.txt | 1 + build/pkgs/texttable/distros/void.txt | 1 + build/pkgs/toml/distros/void.txt | 1 + build/pkgs/tomli/distros/void.txt | 1 + build/pkgs/tornado/distros/void.txt | 1 + build/pkgs/traitlets/distros/void.txt | 1 + build/pkgs/typing_extensions/distros/void.txt | 1 + build/pkgs/tzlocal/distros/void.txt | 1 + build/pkgs/urllib3/distros/void.txt | 1 + build/pkgs/wcwidth/distros/void.txt | 1 + build/pkgs/webencodings/distros/void.txt | 1 + build/pkgs/wheel/distros/void.txt | 1 + build/pkgs/zipp/distros/void.txt | 1 + 97 files changed, 97 insertions(+) create mode 100644 build/pkgs/alabaster/distros/void.txt create mode 100644 build/pkgs/argcomplete/distros/void.txt create mode 100644 build/pkgs/argon2_cffi/distros/void.txt create mode 100644 build/pkgs/attrs/distros/void.txt create mode 100644 build/pkgs/babel/distros/void.txt create mode 100644 build/pkgs/backcall/distros/void.txt create mode 100644 build/pkgs/beniget/distros/void.txt create mode 100644 build/pkgs/bleach/distros/void.txt create mode 100644 build/pkgs/certifi/distros/void.txt create mode 100644 build/pkgs/cffi/distros/void.txt create mode 100644 build/pkgs/charset_normalizer/distros/void.txt create mode 100644 build/pkgs/cycler/distros/void.txt create mode 100644 build/pkgs/dateutil/distros/void.txt create mode 100644 build/pkgs/decorator/distros/void.txt create mode 100644 build/pkgs/defusedxml/distros/void.txt create mode 100644 build/pkgs/docutils/distros/void.txt create mode 100644 build/pkgs/entrypoints/distros/void.txt create mode 100644 build/pkgs/flit_core/distros/void.txt create mode 100644 build/pkgs/gast/distros/void.txt create mode 100644 build/pkgs/html5lib/distros/void.txt create mode 100644 build/pkgs/idna/distros/void.txt create mode 100644 build/pkgs/imagesize/distros/void.txt create mode 100644 build/pkgs/importlib_metadata/distros/void.txt create mode 100644 build/pkgs/ipykernel/distros/void.txt create mode 100644 build/pkgs/ipython/distros/void.txt create mode 100644 build/pkgs/ipython_genutils/distros/void.txt create mode 100644 build/pkgs/ipywidgets/distros/void.txt create mode 100644 build/pkgs/jedi/distros/void.txt create mode 100644 build/pkgs/jinja2/distros/void.txt create mode 100644 build/pkgs/jsonschema/distros/void.txt create mode 100644 build/pkgs/jupyter_client/distros/void.txt create mode 100644 build/pkgs/jupyter_core/distros/void.txt create mode 100644 build/pkgs/jupyterlab_pygments/distros/void.txt create mode 100644 build/pkgs/kiwisolver/distros/void.txt create mode 100644 build/pkgs/markupsafe/distros/void.txt create mode 100644 build/pkgs/matplotlib/distros/void.txt create mode 100644 build/pkgs/matplotlib_inline/distros/void.txt create mode 100644 build/pkgs/mistune/distros/void.txt create mode 100644 build/pkgs/mpmath/distros/void.txt create mode 100644 build/pkgs/nbclient/distros/void.txt create mode 100644 build/pkgs/nbconvert/distros/void.txt create mode 100644 build/pkgs/nbformat/distros/void.txt create mode 100644 build/pkgs/nest_asyncio/distros/void.txt create mode 100644 build/pkgs/networkx/distros/void.txt create mode 100644 build/pkgs/notebook/distros/void.txt create mode 100644 build/pkgs/numpy/distros/void.txt create mode 100644 build/pkgs/packaging/distros/void.txt create mode 100644 build/pkgs/pandocfilters/distros/void.txt create mode 100644 build/pkgs/parso/distros/void.txt create mode 100644 build/pkgs/pexpect/distros/void.txt create mode 100644 build/pkgs/pickleshare/distros/void.txt create mode 100644 build/pkgs/pillow/distros/void.txt create mode 100644 build/pkgs/pip/distros/void.txt create mode 100644 build/pkgs/pluggy/distros/void.txt create mode 100644 build/pkgs/ply/distros/void.txt create mode 100644 build/pkgs/prometheus_client/distros/void.txt create mode 100644 build/pkgs/prompt_toolkit/distros/void.txt create mode 100644 build/pkgs/ptyprocess/distros/void.txt create mode 100644 build/pkgs/py/distros/void.txt create mode 100644 build/pkgs/pybind11/distros/void.txt create mode 100644 build/pkgs/pycparser/distros/void.txt create mode 100644 build/pkgs/pygments/distros/void.txt create mode 100644 build/pkgs/pyparsing/distros/void.txt create mode 100644 build/pkgs/pyrsistent/distros/void.txt create mode 100644 build/pkgs/pythran/distros/void.txt create mode 100644 build/pkgs/pytz/distros/void.txt create mode 100644 build/pkgs/pyzmq/distros/void.txt create mode 100644 build/pkgs/requests/distros/void.txt create mode 100644 build/pkgs/scipy/distros/void.txt create mode 100644 build/pkgs/send2trash/distros/void.txt create mode 100644 build/pkgs/setuptools/distros/void.txt create mode 100644 build/pkgs/setuptools_scm/distros/void.txt create mode 100644 build/pkgs/simplegeneric/distros/void.txt create mode 100644 build/pkgs/six/distros/void.txt create mode 100644 build/pkgs/snowballstemmer/distros/void.txt create mode 100644 build/pkgs/sphinx/distros/void.txt create mode 100644 build/pkgs/sphinxcontrib_applehelp/distros/void.txt create mode 100644 build/pkgs/sphinxcontrib_devhelp/distros/void.txt create mode 100644 build/pkgs/sphinxcontrib_htmlhelp/distros/void.txt create mode 100644 build/pkgs/sphinxcontrib_jsmath/distros/void.txt create mode 100644 build/pkgs/sphinxcontrib_qthelp/distros/void.txt create mode 100644 build/pkgs/sphinxcontrib_serializinghtml/distros/void.txt create mode 100644 build/pkgs/sympy/distros/void.txt create mode 100644 build/pkgs/terminado/distros/void.txt create mode 100644 build/pkgs/testpath/distros/void.txt create mode 100644 build/pkgs/texttable/distros/void.txt create mode 100644 build/pkgs/toml/distros/void.txt create mode 100644 build/pkgs/tomli/distros/void.txt create mode 100644 build/pkgs/tornado/distros/void.txt create mode 100644 build/pkgs/traitlets/distros/void.txt create mode 100644 build/pkgs/typing_extensions/distros/void.txt create mode 100644 build/pkgs/tzlocal/distros/void.txt create mode 100644 build/pkgs/urllib3/distros/void.txt create mode 100644 build/pkgs/wcwidth/distros/void.txt create mode 100644 build/pkgs/webencodings/distros/void.txt create mode 100644 build/pkgs/wheel/distros/void.txt create mode 100644 build/pkgs/zipp/distros/void.txt diff --git a/build/pkgs/alabaster/distros/void.txt b/build/pkgs/alabaster/distros/void.txt new file mode 100644 index 00000000000..dcc39f9e849 --- /dev/null +++ b/build/pkgs/alabaster/distros/void.txt @@ -0,0 +1 @@ +python3-alabaster diff --git a/build/pkgs/argcomplete/distros/void.txt b/build/pkgs/argcomplete/distros/void.txt new file mode 100644 index 00000000000..11f098f9ee3 --- /dev/null +++ b/build/pkgs/argcomplete/distros/void.txt @@ -0,0 +1 @@ +python3-argcomplete diff --git a/build/pkgs/argon2_cffi/distros/void.txt b/build/pkgs/argon2_cffi/distros/void.txt new file mode 100644 index 00000000000..ba5a8c92b1b --- /dev/null +++ b/build/pkgs/argon2_cffi/distros/void.txt @@ -0,0 +1 @@ +python3-argon2 diff --git a/build/pkgs/attrs/distros/void.txt b/build/pkgs/attrs/distros/void.txt new file mode 100644 index 00000000000..7a0d05668f0 --- /dev/null +++ b/build/pkgs/attrs/distros/void.txt @@ -0,0 +1 @@ +python3-attrs diff --git a/build/pkgs/babel/distros/void.txt b/build/pkgs/babel/distros/void.txt new file mode 100644 index 00000000000..70bb05b1327 --- /dev/null +++ b/build/pkgs/babel/distros/void.txt @@ -0,0 +1 @@ +python3-Babel diff --git a/build/pkgs/backcall/distros/void.txt b/build/pkgs/backcall/distros/void.txt new file mode 100644 index 00000000000..8338506e588 --- /dev/null +++ b/build/pkgs/backcall/distros/void.txt @@ -0,0 +1 @@ +python3-backcall diff --git a/build/pkgs/beniget/distros/void.txt b/build/pkgs/beniget/distros/void.txt new file mode 100644 index 00000000000..90ac5122f63 --- /dev/null +++ b/build/pkgs/beniget/distros/void.txt @@ -0,0 +1 @@ +python3-beniget diff --git a/build/pkgs/bleach/distros/void.txt b/build/pkgs/bleach/distros/void.txt new file mode 100644 index 00000000000..6d37c4c79f0 --- /dev/null +++ b/build/pkgs/bleach/distros/void.txt @@ -0,0 +1 @@ +python3-bleach diff --git a/build/pkgs/certifi/distros/void.txt b/build/pkgs/certifi/distros/void.txt new file mode 100644 index 00000000000..f585a823bf3 --- /dev/null +++ b/build/pkgs/certifi/distros/void.txt @@ -0,0 +1 @@ +python3-certifi diff --git a/build/pkgs/cffi/distros/void.txt b/build/pkgs/cffi/distros/void.txt new file mode 100644 index 00000000000..68ec4dda5ba --- /dev/null +++ b/build/pkgs/cffi/distros/void.txt @@ -0,0 +1 @@ +python3-cffi diff --git a/build/pkgs/charset_normalizer/distros/void.txt b/build/pkgs/charset_normalizer/distros/void.txt new file mode 100644 index 00000000000..0d65ed70186 --- /dev/null +++ b/build/pkgs/charset_normalizer/distros/void.txt @@ -0,0 +1 @@ +python3-charset-normalizer diff --git a/build/pkgs/cycler/distros/void.txt b/build/pkgs/cycler/distros/void.txt new file mode 100644 index 00000000000..c77685dd417 --- /dev/null +++ b/build/pkgs/cycler/distros/void.txt @@ -0,0 +1 @@ +python3-cycler diff --git a/build/pkgs/dateutil/distros/void.txt b/build/pkgs/dateutil/distros/void.txt new file mode 100644 index 00000000000..2f46170765c --- /dev/null +++ b/build/pkgs/dateutil/distros/void.txt @@ -0,0 +1 @@ +python3-dateutil diff --git a/build/pkgs/decorator/distros/void.txt b/build/pkgs/decorator/distros/void.txt new file mode 100644 index 00000000000..46c478e1513 --- /dev/null +++ b/build/pkgs/decorator/distros/void.txt @@ -0,0 +1 @@ +python3-decorator diff --git a/build/pkgs/defusedxml/distros/void.txt b/build/pkgs/defusedxml/distros/void.txt new file mode 100644 index 00000000000..9788c955af5 --- /dev/null +++ b/build/pkgs/defusedxml/distros/void.txt @@ -0,0 +1 @@ +python3-defusedxml diff --git a/build/pkgs/docutils/distros/void.txt b/build/pkgs/docutils/distros/void.txt new file mode 100644 index 00000000000..a4bb792a5a4 --- /dev/null +++ b/build/pkgs/docutils/distros/void.txt @@ -0,0 +1 @@ +python3-docutils diff --git a/build/pkgs/entrypoints/distros/void.txt b/build/pkgs/entrypoints/distros/void.txt new file mode 100644 index 00000000000..6e1b57c91e7 --- /dev/null +++ b/build/pkgs/entrypoints/distros/void.txt @@ -0,0 +1 @@ +python3-entrypoints diff --git a/build/pkgs/flit_core/distros/void.txt b/build/pkgs/flit_core/distros/void.txt new file mode 100644 index 00000000000..213c6b4a5d2 --- /dev/null +++ b/build/pkgs/flit_core/distros/void.txt @@ -0,0 +1 @@ +python3-flit_core diff --git a/build/pkgs/gast/distros/void.txt b/build/pkgs/gast/distros/void.txt new file mode 100644 index 00000000000..40cddc76e37 --- /dev/null +++ b/build/pkgs/gast/distros/void.txt @@ -0,0 +1 @@ +python3-gast diff --git a/build/pkgs/html5lib/distros/void.txt b/build/pkgs/html5lib/distros/void.txt new file mode 100644 index 00000000000..6d7b8dfb001 --- /dev/null +++ b/build/pkgs/html5lib/distros/void.txt @@ -0,0 +1 @@ +python3-html5lib diff --git a/build/pkgs/idna/distros/void.txt b/build/pkgs/idna/distros/void.txt new file mode 100644 index 00000000000..de48e70887b --- /dev/null +++ b/build/pkgs/idna/distros/void.txt @@ -0,0 +1 @@ +python3-idna diff --git a/build/pkgs/imagesize/distros/void.txt b/build/pkgs/imagesize/distros/void.txt new file mode 100644 index 00000000000..f482427979f --- /dev/null +++ b/build/pkgs/imagesize/distros/void.txt @@ -0,0 +1 @@ +python3-imagesize diff --git a/build/pkgs/importlib_metadata/distros/void.txt b/build/pkgs/importlib_metadata/distros/void.txt new file mode 100644 index 00000000000..a410750cb05 --- /dev/null +++ b/build/pkgs/importlib_metadata/distros/void.txt @@ -0,0 +1 @@ +python3-importlib_metadata diff --git a/build/pkgs/ipykernel/distros/void.txt b/build/pkgs/ipykernel/distros/void.txt new file mode 100644 index 00000000000..55fb80fda1a --- /dev/null +++ b/build/pkgs/ipykernel/distros/void.txt @@ -0,0 +1 @@ +python3-ipython_ipykernel diff --git a/build/pkgs/ipython/distros/void.txt b/build/pkgs/ipython/distros/void.txt new file mode 100644 index 00000000000..c32c6b449cf --- /dev/null +++ b/build/pkgs/ipython/distros/void.txt @@ -0,0 +1 @@ +python3-ipython diff --git a/build/pkgs/ipython_genutils/distros/void.txt b/build/pkgs/ipython_genutils/distros/void.txt new file mode 100644 index 00000000000..b553f94d87c --- /dev/null +++ b/build/pkgs/ipython_genutils/distros/void.txt @@ -0,0 +1 @@ +python3-ipython_genutils diff --git a/build/pkgs/ipywidgets/distros/void.txt b/build/pkgs/ipywidgets/distros/void.txt new file mode 100644 index 00000000000..1586c455342 --- /dev/null +++ b/build/pkgs/ipywidgets/distros/void.txt @@ -0,0 +1 @@ +python3-jupyter_ipywidgets diff --git a/build/pkgs/jedi/distros/void.txt b/build/pkgs/jedi/distros/void.txt new file mode 100644 index 00000000000..9aefdab6b23 --- /dev/null +++ b/build/pkgs/jedi/distros/void.txt @@ -0,0 +1 @@ +python3-jedi diff --git a/build/pkgs/jinja2/distros/void.txt b/build/pkgs/jinja2/distros/void.txt new file mode 100644 index 00000000000..5d90a223f55 --- /dev/null +++ b/build/pkgs/jinja2/distros/void.txt @@ -0,0 +1 @@ +python3-Jinja2 diff --git a/build/pkgs/jsonschema/distros/void.txt b/build/pkgs/jsonschema/distros/void.txt new file mode 100644 index 00000000000..047e6cc5d1d --- /dev/null +++ b/build/pkgs/jsonschema/distros/void.txt @@ -0,0 +1 @@ +python3-jsonschema diff --git a/build/pkgs/jupyter_client/distros/void.txt b/build/pkgs/jupyter_client/distros/void.txt new file mode 100644 index 00000000000..0e3654f20d1 --- /dev/null +++ b/build/pkgs/jupyter_client/distros/void.txt @@ -0,0 +1 @@ +python3-jupyter_client diff --git a/build/pkgs/jupyter_core/distros/void.txt b/build/pkgs/jupyter_core/distros/void.txt new file mode 100644 index 00000000000..9b5a641dbc8 --- /dev/null +++ b/build/pkgs/jupyter_core/distros/void.txt @@ -0,0 +1 @@ +python3-jupyter_core diff --git a/build/pkgs/jupyterlab_pygments/distros/void.txt b/build/pkgs/jupyterlab_pygments/distros/void.txt new file mode 100644 index 00000000000..979cc3e9c13 --- /dev/null +++ b/build/pkgs/jupyterlab_pygments/distros/void.txt @@ -0,0 +1 @@ +python3-jupyterlab_pygments diff --git a/build/pkgs/kiwisolver/distros/void.txt b/build/pkgs/kiwisolver/distros/void.txt new file mode 100644 index 00000000000..aab17cc1272 --- /dev/null +++ b/build/pkgs/kiwisolver/distros/void.txt @@ -0,0 +1 @@ +python3-kiwisolver diff --git a/build/pkgs/markupsafe/distros/void.txt b/build/pkgs/markupsafe/distros/void.txt new file mode 100644 index 00000000000..483c7ee1e18 --- /dev/null +++ b/build/pkgs/markupsafe/distros/void.txt @@ -0,0 +1 @@ +python3-MarkupSafe diff --git a/build/pkgs/matplotlib/distros/void.txt b/build/pkgs/matplotlib/distros/void.txt new file mode 100644 index 00000000000..13743297213 --- /dev/null +++ b/build/pkgs/matplotlib/distros/void.txt @@ -0,0 +1 @@ +python3-matplotlib diff --git a/build/pkgs/matplotlib_inline/distros/void.txt b/build/pkgs/matplotlib_inline/distros/void.txt new file mode 100644 index 00000000000..2e46aafab96 --- /dev/null +++ b/build/pkgs/matplotlib_inline/distros/void.txt @@ -0,0 +1 @@ +python3-matplotlib-inline diff --git a/build/pkgs/mistune/distros/void.txt b/build/pkgs/mistune/distros/void.txt new file mode 100644 index 00000000000..587df34ac38 --- /dev/null +++ b/build/pkgs/mistune/distros/void.txt @@ -0,0 +1 @@ +python3-mistune diff --git a/build/pkgs/mpmath/distros/void.txt b/build/pkgs/mpmath/distros/void.txt new file mode 100644 index 00000000000..fbc82a97e07 --- /dev/null +++ b/build/pkgs/mpmath/distros/void.txt @@ -0,0 +1 @@ +python3-mpmath diff --git a/build/pkgs/nbclient/distros/void.txt b/build/pkgs/nbclient/distros/void.txt new file mode 100644 index 00000000000..17730f59437 --- /dev/null +++ b/build/pkgs/nbclient/distros/void.txt @@ -0,0 +1 @@ +python3-nbclient diff --git a/build/pkgs/nbconvert/distros/void.txt b/build/pkgs/nbconvert/distros/void.txt new file mode 100644 index 00000000000..7e21caaeb49 --- /dev/null +++ b/build/pkgs/nbconvert/distros/void.txt @@ -0,0 +1 @@ +python3-jupyter_nbconvert diff --git a/build/pkgs/nbformat/distros/void.txt b/build/pkgs/nbformat/distros/void.txt new file mode 100644 index 00000000000..54c83bd7ef3 --- /dev/null +++ b/build/pkgs/nbformat/distros/void.txt @@ -0,0 +1 @@ +python3-jupyter_nbformat diff --git a/build/pkgs/nest_asyncio/distros/void.txt b/build/pkgs/nest_asyncio/distros/void.txt new file mode 100644 index 00000000000..e51cb6bf7f8 --- /dev/null +++ b/build/pkgs/nest_asyncio/distros/void.txt @@ -0,0 +1 @@ +python3-nest_asyncio diff --git a/build/pkgs/networkx/distros/void.txt b/build/pkgs/networkx/distros/void.txt new file mode 100644 index 00000000000..67790667af2 --- /dev/null +++ b/build/pkgs/networkx/distros/void.txt @@ -0,0 +1 @@ +python3-networkx diff --git a/build/pkgs/notebook/distros/void.txt b/build/pkgs/notebook/distros/void.txt new file mode 100644 index 00000000000..bc5e8da49a8 --- /dev/null +++ b/build/pkgs/notebook/distros/void.txt @@ -0,0 +1 @@ +python3-jupyter_notebook diff --git a/build/pkgs/numpy/distros/void.txt b/build/pkgs/numpy/distros/void.txt new file mode 100644 index 00000000000..79d5c5a1429 --- /dev/null +++ b/build/pkgs/numpy/distros/void.txt @@ -0,0 +1 @@ +python3-numpy diff --git a/build/pkgs/packaging/distros/void.txt b/build/pkgs/packaging/distros/void.txt new file mode 100644 index 00000000000..8f1c0ffc29f --- /dev/null +++ b/build/pkgs/packaging/distros/void.txt @@ -0,0 +1 @@ +python3-packaging diff --git a/build/pkgs/pandocfilters/distros/void.txt b/build/pkgs/pandocfilters/distros/void.txt new file mode 100644 index 00000000000..d0d4c24e15e --- /dev/null +++ b/build/pkgs/pandocfilters/distros/void.txt @@ -0,0 +1 @@ +python3-pandocfilters diff --git a/build/pkgs/parso/distros/void.txt b/build/pkgs/parso/distros/void.txt new file mode 100644 index 00000000000..72fc6162fb9 --- /dev/null +++ b/build/pkgs/parso/distros/void.txt @@ -0,0 +1 @@ +python3-parso diff --git a/build/pkgs/pexpect/distros/void.txt b/build/pkgs/pexpect/distros/void.txt new file mode 100644 index 00000000000..8d745ee4a07 --- /dev/null +++ b/build/pkgs/pexpect/distros/void.txt @@ -0,0 +1 @@ +python3-pexpect diff --git a/build/pkgs/pickleshare/distros/void.txt b/build/pkgs/pickleshare/distros/void.txt new file mode 100644 index 00000000000..a00907d167b --- /dev/null +++ b/build/pkgs/pickleshare/distros/void.txt @@ -0,0 +1 @@ +python3-pickleshare diff --git a/build/pkgs/pillow/distros/void.txt b/build/pkgs/pillow/distros/void.txt new file mode 100644 index 00000000000..88283bea6d9 --- /dev/null +++ b/build/pkgs/pillow/distros/void.txt @@ -0,0 +1 @@ +python3-Pillow diff --git a/build/pkgs/pip/distros/void.txt b/build/pkgs/pip/distros/void.txt new file mode 100644 index 00000000000..39bd9fc5097 --- /dev/null +++ b/build/pkgs/pip/distros/void.txt @@ -0,0 +1 @@ +python3-pip diff --git a/build/pkgs/pluggy/distros/void.txt b/build/pkgs/pluggy/distros/void.txt new file mode 100644 index 00000000000..43a3acf0462 --- /dev/null +++ b/build/pkgs/pluggy/distros/void.txt @@ -0,0 +1 @@ +python3-pluggy diff --git a/build/pkgs/ply/distros/void.txt b/build/pkgs/ply/distros/void.txt new file mode 100644 index 00000000000..8dd3058e8c4 --- /dev/null +++ b/build/pkgs/ply/distros/void.txt @@ -0,0 +1 @@ +python3-ply diff --git a/build/pkgs/prometheus_client/distros/void.txt b/build/pkgs/prometheus_client/distros/void.txt new file mode 100644 index 00000000000..4d7723ec37e --- /dev/null +++ b/build/pkgs/prometheus_client/distros/void.txt @@ -0,0 +1 @@ +python3-prometheus_client diff --git a/build/pkgs/prompt_toolkit/distros/void.txt b/build/pkgs/prompt_toolkit/distros/void.txt new file mode 100644 index 00000000000..424253f1340 --- /dev/null +++ b/build/pkgs/prompt_toolkit/distros/void.txt @@ -0,0 +1 @@ +python3-prompt_toolkit diff --git a/build/pkgs/ptyprocess/distros/void.txt b/build/pkgs/ptyprocess/distros/void.txt new file mode 100644 index 00000000000..ad4f6db1ca7 --- /dev/null +++ b/build/pkgs/ptyprocess/distros/void.txt @@ -0,0 +1 @@ +python3-ptyprocess diff --git a/build/pkgs/py/distros/void.txt b/build/pkgs/py/distros/void.txt new file mode 100644 index 00000000000..81fefe60903 --- /dev/null +++ b/build/pkgs/py/distros/void.txt @@ -0,0 +1 @@ +python3-py diff --git a/build/pkgs/pybind11/distros/void.txt b/build/pkgs/pybind11/distros/void.txt new file mode 100644 index 00000000000..ac2d3cb471d --- /dev/null +++ b/build/pkgs/pybind11/distros/void.txt @@ -0,0 +1 @@ +python3-pybind11 diff --git a/build/pkgs/pycparser/distros/void.txt b/build/pkgs/pycparser/distros/void.txt new file mode 100644 index 00000000000..0ba4f8b19f5 --- /dev/null +++ b/build/pkgs/pycparser/distros/void.txt @@ -0,0 +1 @@ +python3-pycparser diff --git a/build/pkgs/pygments/distros/void.txt b/build/pkgs/pygments/distros/void.txt new file mode 100644 index 00000000000..9ff5740e79c --- /dev/null +++ b/build/pkgs/pygments/distros/void.txt @@ -0,0 +1 @@ +python3-Pygments diff --git a/build/pkgs/pyparsing/distros/void.txt b/build/pkgs/pyparsing/distros/void.txt new file mode 100644 index 00000000000..0a627b732d8 --- /dev/null +++ b/build/pkgs/pyparsing/distros/void.txt @@ -0,0 +1 @@ +python3-parsing diff --git a/build/pkgs/pyrsistent/distros/void.txt b/build/pkgs/pyrsistent/distros/void.txt new file mode 100644 index 00000000000..77485df49f0 --- /dev/null +++ b/build/pkgs/pyrsistent/distros/void.txt @@ -0,0 +1 @@ +python3-pyrsistent diff --git a/build/pkgs/pythran/distros/void.txt b/build/pkgs/pythran/distros/void.txt new file mode 100644 index 00000000000..86d056b339f --- /dev/null +++ b/build/pkgs/pythran/distros/void.txt @@ -0,0 +1 @@ +pythran diff --git a/build/pkgs/pytz/distros/void.txt b/build/pkgs/pytz/distros/void.txt new file mode 100644 index 00000000000..1b20e1dbb77 --- /dev/null +++ b/build/pkgs/pytz/distros/void.txt @@ -0,0 +1 @@ +python3-pytz diff --git a/build/pkgs/pyzmq/distros/void.txt b/build/pkgs/pyzmq/distros/void.txt new file mode 100644 index 00000000000..265a272130e --- /dev/null +++ b/build/pkgs/pyzmq/distros/void.txt @@ -0,0 +1 @@ +python3-pyzmq diff --git a/build/pkgs/requests/distros/void.txt b/build/pkgs/requests/distros/void.txt new file mode 100644 index 00000000000..43147b2be74 --- /dev/null +++ b/build/pkgs/requests/distros/void.txt @@ -0,0 +1 @@ +python3-requests diff --git a/build/pkgs/scipy/distros/void.txt b/build/pkgs/scipy/distros/void.txt new file mode 100644 index 00000000000..12b366666d6 --- /dev/null +++ b/build/pkgs/scipy/distros/void.txt @@ -0,0 +1 @@ +python3-scipy diff --git a/build/pkgs/send2trash/distros/void.txt b/build/pkgs/send2trash/distros/void.txt new file mode 100644 index 00000000000..2f9abb6f584 --- /dev/null +++ b/build/pkgs/send2trash/distros/void.txt @@ -0,0 +1 @@ +python3-send2trash diff --git a/build/pkgs/setuptools/distros/void.txt b/build/pkgs/setuptools/distros/void.txt new file mode 100644 index 00000000000..1c0901c0374 --- /dev/null +++ b/build/pkgs/setuptools/distros/void.txt @@ -0,0 +1 @@ +python3-setuptools diff --git a/build/pkgs/setuptools_scm/distros/void.txt b/build/pkgs/setuptools_scm/distros/void.txt new file mode 100644 index 00000000000..2aa5ca12cba --- /dev/null +++ b/build/pkgs/setuptools_scm/distros/void.txt @@ -0,0 +1 @@ +python3-setuptools_scm diff --git a/build/pkgs/simplegeneric/distros/void.txt b/build/pkgs/simplegeneric/distros/void.txt new file mode 100644 index 00000000000..d788a7233a7 --- /dev/null +++ b/build/pkgs/simplegeneric/distros/void.txt @@ -0,0 +1 @@ +python3-simplegeneric diff --git a/build/pkgs/six/distros/void.txt b/build/pkgs/six/distros/void.txt new file mode 100644 index 00000000000..68ff8595d0b --- /dev/null +++ b/build/pkgs/six/distros/void.txt @@ -0,0 +1 @@ +python3-six diff --git a/build/pkgs/snowballstemmer/distros/void.txt b/build/pkgs/snowballstemmer/distros/void.txt new file mode 100644 index 00000000000..09b2636df60 --- /dev/null +++ b/build/pkgs/snowballstemmer/distros/void.txt @@ -0,0 +1 @@ +python3-snowballstemmer diff --git a/build/pkgs/sphinx/distros/void.txt b/build/pkgs/sphinx/distros/void.txt new file mode 100644 index 00000000000..bc54d0bd553 --- /dev/null +++ b/build/pkgs/sphinx/distros/void.txt @@ -0,0 +1 @@ +python3-Sphinx diff --git a/build/pkgs/sphinxcontrib_applehelp/distros/void.txt b/build/pkgs/sphinxcontrib_applehelp/distros/void.txt new file mode 100644 index 00000000000..adedbd455f8 --- /dev/null +++ b/build/pkgs/sphinxcontrib_applehelp/distros/void.txt @@ -0,0 +1 @@ +python3-sphinxcontrib-applehelp diff --git a/build/pkgs/sphinxcontrib_devhelp/distros/void.txt b/build/pkgs/sphinxcontrib_devhelp/distros/void.txt new file mode 100644 index 00000000000..14357dcb071 --- /dev/null +++ b/build/pkgs/sphinxcontrib_devhelp/distros/void.txt @@ -0,0 +1 @@ +python3-sphinxcontrib-devhelp diff --git a/build/pkgs/sphinxcontrib_htmlhelp/distros/void.txt b/build/pkgs/sphinxcontrib_htmlhelp/distros/void.txt new file mode 100644 index 00000000000..3362a84ccc8 --- /dev/null +++ b/build/pkgs/sphinxcontrib_htmlhelp/distros/void.txt @@ -0,0 +1 @@ +python3-sphinxcontrib-htmlhelp diff --git a/build/pkgs/sphinxcontrib_jsmath/distros/void.txt b/build/pkgs/sphinxcontrib_jsmath/distros/void.txt new file mode 100644 index 00000000000..2ee3087e541 --- /dev/null +++ b/build/pkgs/sphinxcontrib_jsmath/distros/void.txt @@ -0,0 +1 @@ +python3-sphinxcontrib-jsmath diff --git a/build/pkgs/sphinxcontrib_qthelp/distros/void.txt b/build/pkgs/sphinxcontrib_qthelp/distros/void.txt new file mode 100644 index 00000000000..9e8fef277fc --- /dev/null +++ b/build/pkgs/sphinxcontrib_qthelp/distros/void.txt @@ -0,0 +1 @@ +python3-sphinxcontrib-qthelp diff --git a/build/pkgs/sphinxcontrib_serializinghtml/distros/void.txt b/build/pkgs/sphinxcontrib_serializinghtml/distros/void.txt new file mode 100644 index 00000000000..1a8ea8424a7 --- /dev/null +++ b/build/pkgs/sphinxcontrib_serializinghtml/distros/void.txt @@ -0,0 +1 @@ +python3-sphinxcontrib-serializinghtml diff --git a/build/pkgs/sympy/distros/void.txt b/build/pkgs/sympy/distros/void.txt new file mode 100644 index 00000000000..db423c87ba7 --- /dev/null +++ b/build/pkgs/sympy/distros/void.txt @@ -0,0 +1 @@ +python3-sympy diff --git a/build/pkgs/terminado/distros/void.txt b/build/pkgs/terminado/distros/void.txt new file mode 100644 index 00000000000..8db56abc3d0 --- /dev/null +++ b/build/pkgs/terminado/distros/void.txt @@ -0,0 +1 @@ +python3-terminado diff --git a/build/pkgs/testpath/distros/void.txt b/build/pkgs/testpath/distros/void.txt new file mode 100644 index 00000000000..6c622800768 --- /dev/null +++ b/build/pkgs/testpath/distros/void.txt @@ -0,0 +1 @@ +python3-testpath diff --git a/build/pkgs/texttable/distros/void.txt b/build/pkgs/texttable/distros/void.txt new file mode 100644 index 00000000000..8f8e7e29d7a --- /dev/null +++ b/build/pkgs/texttable/distros/void.txt @@ -0,0 +1 @@ +python3-texttable diff --git a/build/pkgs/toml/distros/void.txt b/build/pkgs/toml/distros/void.txt new file mode 100644 index 00000000000..543e89d2a6f --- /dev/null +++ b/build/pkgs/toml/distros/void.txt @@ -0,0 +1 @@ +python3-toml diff --git a/build/pkgs/tomli/distros/void.txt b/build/pkgs/tomli/distros/void.txt new file mode 100644 index 00000000000..cfd9f618b76 --- /dev/null +++ b/build/pkgs/tomli/distros/void.txt @@ -0,0 +1 @@ +python3-tomli diff --git a/build/pkgs/tornado/distros/void.txt b/build/pkgs/tornado/distros/void.txt new file mode 100644 index 00000000000..426685be95b --- /dev/null +++ b/build/pkgs/tornado/distros/void.txt @@ -0,0 +1 @@ +python3-tornado diff --git a/build/pkgs/traitlets/distros/void.txt b/build/pkgs/traitlets/distros/void.txt new file mode 100644 index 00000000000..93cb8375e46 --- /dev/null +++ b/build/pkgs/traitlets/distros/void.txt @@ -0,0 +1 @@ +python3-traitlets diff --git a/build/pkgs/typing_extensions/distros/void.txt b/build/pkgs/typing_extensions/distros/void.txt new file mode 100644 index 00000000000..01704716c9e --- /dev/null +++ b/build/pkgs/typing_extensions/distros/void.txt @@ -0,0 +1 @@ +python3-typing_extensions diff --git a/build/pkgs/tzlocal/distros/void.txt b/build/pkgs/tzlocal/distros/void.txt new file mode 100644 index 00000000000..95d2d705c05 --- /dev/null +++ b/build/pkgs/tzlocal/distros/void.txt @@ -0,0 +1 @@ +python3-tzlocal diff --git a/build/pkgs/urllib3/distros/void.txt b/build/pkgs/urllib3/distros/void.txt new file mode 100644 index 00000000000..918569f9677 --- /dev/null +++ b/build/pkgs/urllib3/distros/void.txt @@ -0,0 +1 @@ +python3-urllib3 diff --git a/build/pkgs/wcwidth/distros/void.txt b/build/pkgs/wcwidth/distros/void.txt new file mode 100644 index 00000000000..2974220c878 --- /dev/null +++ b/build/pkgs/wcwidth/distros/void.txt @@ -0,0 +1 @@ +python3-wcwidth diff --git a/build/pkgs/webencodings/distros/void.txt b/build/pkgs/webencodings/distros/void.txt new file mode 100644 index 00000000000..ac30c2f3307 --- /dev/null +++ b/build/pkgs/webencodings/distros/void.txt @@ -0,0 +1 @@ +python3-webencodings diff --git a/build/pkgs/wheel/distros/void.txt b/build/pkgs/wheel/distros/void.txt new file mode 100644 index 00000000000..3c066725a1d --- /dev/null +++ b/build/pkgs/wheel/distros/void.txt @@ -0,0 +1 @@ +python3-wheel diff --git a/build/pkgs/zipp/distros/void.txt b/build/pkgs/zipp/distros/void.txt new file mode 100644 index 00000000000..029ff9c75da --- /dev/null +++ b/build/pkgs/zipp/distros/void.txt @@ -0,0 +1 @@ +python3-zipp From 90e1be77f6fc8f793e0ba9c1b1480d63c4a721bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Fri, 31 Dec 2021 14:09:12 -0300 Subject: [PATCH 088/253] void linux: more standard python3 packages --- build/pkgs/appdirs/distros/void.txt | 1 + build/pkgs/cython/distros/void.txt | 1 + build/pkgs/distlib/distros/void.txt | 1 + build/pkgs/filelock/distros/void.txt | 1 + build/pkgs/gmpy2/distros/void.txt | 1 + build/pkgs/virtualenv/distros/void.txt | 1 + 6 files changed, 6 insertions(+) create mode 100644 build/pkgs/appdirs/distros/void.txt create mode 100644 build/pkgs/cython/distros/void.txt create mode 100644 build/pkgs/distlib/distros/void.txt create mode 100644 build/pkgs/filelock/distros/void.txt create mode 100644 build/pkgs/gmpy2/distros/void.txt create mode 100644 build/pkgs/virtualenv/distros/void.txt diff --git a/build/pkgs/appdirs/distros/void.txt b/build/pkgs/appdirs/distros/void.txt new file mode 100644 index 00000000000..649b89f0bf9 --- /dev/null +++ b/build/pkgs/appdirs/distros/void.txt @@ -0,0 +1 @@ +python3-appdirs diff --git a/build/pkgs/cython/distros/void.txt b/build/pkgs/cython/distros/void.txt new file mode 100644 index 00000000000..6ea41f29a4c --- /dev/null +++ b/build/pkgs/cython/distros/void.txt @@ -0,0 +1 @@ +python3-Cython diff --git a/build/pkgs/distlib/distros/void.txt b/build/pkgs/distlib/distros/void.txt new file mode 100644 index 00000000000..a39e063e6b0 --- /dev/null +++ b/build/pkgs/distlib/distros/void.txt @@ -0,0 +1 @@ +python3-distlib diff --git a/build/pkgs/filelock/distros/void.txt b/build/pkgs/filelock/distros/void.txt new file mode 100644 index 00000000000..3c587f8b286 --- /dev/null +++ b/build/pkgs/filelock/distros/void.txt @@ -0,0 +1 @@ +python3-filelock diff --git a/build/pkgs/gmpy2/distros/void.txt b/build/pkgs/gmpy2/distros/void.txt new file mode 100644 index 00000000000..afdd6281722 --- /dev/null +++ b/build/pkgs/gmpy2/distros/void.txt @@ -0,0 +1 @@ +python3-gmpy2 diff --git a/build/pkgs/virtualenv/distros/void.txt b/build/pkgs/virtualenv/distros/void.txt new file mode 100644 index 00000000000..030879e0d89 --- /dev/null +++ b/build/pkgs/virtualenv/distros/void.txt @@ -0,0 +1 @@ +python3-virtualenv From 5d8c6a0b995acaf87f5548fbd0f7606c61d07ca3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Wed, 29 Dec 2021 11:55:36 -0300 Subject: [PATCH 089/253] void linux: more optional python3 packages --- build/pkgs/beautifulsoup4/distros/void.txt | 1 + build/pkgs/jupyterlab/distros/void.txt | 1 + build/pkgs/pyflakes/distros/void.txt | 1 + build/pkgs/pytest/distros/void.txt | 1 + build/pkgs/pyx/distros/void.txt | 1 + build/pkgs/sip/distros/void.txt | 1 + build/pkgs/sqlalchemy/distros/void.txt | 1 + 7 files changed, 7 insertions(+) create mode 100644 build/pkgs/beautifulsoup4/distros/void.txt create mode 100644 build/pkgs/jupyterlab/distros/void.txt create mode 100644 build/pkgs/pyflakes/distros/void.txt create mode 100644 build/pkgs/pytest/distros/void.txt create mode 100644 build/pkgs/pyx/distros/void.txt create mode 100644 build/pkgs/sip/distros/void.txt create mode 100644 build/pkgs/sqlalchemy/distros/void.txt diff --git a/build/pkgs/beautifulsoup4/distros/void.txt b/build/pkgs/beautifulsoup4/distros/void.txt new file mode 100644 index 00000000000..9966852f94a --- /dev/null +++ b/build/pkgs/beautifulsoup4/distros/void.txt @@ -0,0 +1 @@ +python3-BeautifulSoup4 diff --git a/build/pkgs/jupyterlab/distros/void.txt b/build/pkgs/jupyterlab/distros/void.txt new file mode 100644 index 00000000000..c9356a72837 --- /dev/null +++ b/build/pkgs/jupyterlab/distros/void.txt @@ -0,0 +1 @@ +jupyterlab diff --git a/build/pkgs/pyflakes/distros/void.txt b/build/pkgs/pyflakes/distros/void.txt new file mode 100644 index 00000000000..a16ae878a72 --- /dev/null +++ b/build/pkgs/pyflakes/distros/void.txt @@ -0,0 +1 @@ +python3-pyflakes diff --git a/build/pkgs/pytest/distros/void.txt b/build/pkgs/pytest/distros/void.txt new file mode 100644 index 00000000000..6665fd281bb --- /dev/null +++ b/build/pkgs/pytest/distros/void.txt @@ -0,0 +1 @@ +python3-pytest diff --git a/build/pkgs/pyx/distros/void.txt b/build/pkgs/pyx/distros/void.txt new file mode 100644 index 00000000000..036148d5904 --- /dev/null +++ b/build/pkgs/pyx/distros/void.txt @@ -0,0 +1 @@ +python3-pyx diff --git a/build/pkgs/sip/distros/void.txt b/build/pkgs/sip/distros/void.txt new file mode 100644 index 00000000000..87c3df8807a --- /dev/null +++ b/build/pkgs/sip/distros/void.txt @@ -0,0 +1 @@ +python3-sip diff --git a/build/pkgs/sqlalchemy/distros/void.txt b/build/pkgs/sqlalchemy/distros/void.txt new file mode 100644 index 00000000000..023e06b7468 --- /dev/null +++ b/build/pkgs/sqlalchemy/distros/void.txt @@ -0,0 +1 @@ +python3-SQLAlchemy From c44fe9b306d72afce6c63cad769ead0ba535d13e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Wed, 29 Dec 2021 12:04:28 -0300 Subject: [PATCH 090/253] void linux: add more optional and experimental packages --- build/pkgs/gdb/distros/void.txt | 1 + build/pkgs/libogg/distros/void.txt | 1 + build/pkgs/libtheora/distros/void.txt | 1 + build/pkgs/nodejs/distros/void.txt | 1 + build/pkgs/valgrind/distros/void.txt | 1 + 5 files changed, 5 insertions(+) create mode 100644 build/pkgs/gdb/distros/void.txt create mode 100644 build/pkgs/libogg/distros/void.txt create mode 100644 build/pkgs/libtheora/distros/void.txt create mode 100644 build/pkgs/nodejs/distros/void.txt create mode 100644 build/pkgs/valgrind/distros/void.txt diff --git a/build/pkgs/gdb/distros/void.txt b/build/pkgs/gdb/distros/void.txt new file mode 100644 index 00000000000..59ccb367d89 --- /dev/null +++ b/build/pkgs/gdb/distros/void.txt @@ -0,0 +1 @@ +gdb diff --git a/build/pkgs/libogg/distros/void.txt b/build/pkgs/libogg/distros/void.txt new file mode 100644 index 00000000000..b49d83743c0 --- /dev/null +++ b/build/pkgs/libogg/distros/void.txt @@ -0,0 +1 @@ +libogg-devel diff --git a/build/pkgs/libtheora/distros/void.txt b/build/pkgs/libtheora/distros/void.txt new file mode 100644 index 00000000000..cc4b4b3d8be --- /dev/null +++ b/build/pkgs/libtheora/distros/void.txt @@ -0,0 +1 @@ +libtheora-devel diff --git a/build/pkgs/nodejs/distros/void.txt b/build/pkgs/nodejs/distros/void.txt new file mode 100644 index 00000000000..e36de65c4cc --- /dev/null +++ b/build/pkgs/nodejs/distros/void.txt @@ -0,0 +1 @@ +nodejs diff --git a/build/pkgs/valgrind/distros/void.txt b/build/pkgs/valgrind/distros/void.txt new file mode 100644 index 00000000000..e7af4129194 --- /dev/null +++ b/build/pkgs/valgrind/distros/void.txt @@ -0,0 +1 @@ +valgrind From 670634e7c46ea655311849f94661073ddb473a71 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 31 Dec 2021 20:33:36 -0800 Subject: [PATCH 091/253] build/pkgs/gmpy2/install-requires.txt: Use >=2.1.0 --- build/pkgs/gmpy2/install-requires.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/build/pkgs/gmpy2/install-requires.txt b/build/pkgs/gmpy2/install-requires.txt index 51d24518ef6..5f50ec2dd25 100644 --- a/build/pkgs/gmpy2/install-requires.txt +++ b/build/pkgs/gmpy2/install-requires.txt @@ -1,3 +1 @@ -# We would like to write gmpy2 >=2.1.0b5, but pipenv does not accept prereleases in version ranges -# https://github.com/pypa/pipenv/issues/1760 -gmpy2 ==2.1.0rc1 +gmpy2 >=2.1.0 From 7229a1935fff089be50f0efcd52d0e76869361be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 1 Jan 2022 13:14:53 +0100 Subject: [PATCH 092/253] some details about shuffle of words and multizetas --- src/sage/combinat/words/shuffle_product.py | 80 +++++++--------------- src/sage/modular/multiple_zeta.py | 14 ++-- 2 files changed, 31 insertions(+), 63 deletions(-) diff --git a/src/sage/combinat/words/shuffle_product.py b/src/sage/combinat/words/shuffle_product.py index 23d199ec75f..101e7ca695c 100644 --- a/src/sage/combinat/words/shuffle_product.py +++ b/src/sage/combinat/words/shuffle_product.py @@ -125,7 +125,6 @@ def __contains__(self, x): sage: x*w in w.shuffle(x) True """ - from sage.combinat.words.word import Word if not isinstance(x, Word_class): return False if x.length() != self._w1.length() + self._w2.length(): @@ -177,86 +176,57 @@ def cardinality(self): len_w2 = self._w2.length() return binomial(len_w1 + len_w2, len_w1) - def _proc(self, vect): + def __iter__(self): """ - Return the shuffle of ``w1`` with ``w2`` with 01-vector - ``vect``. - - The 01-vector of a shuffle is a list of 0s and 1s whose - length is the sum of the lengths of ``w1`` and ``w2``, - and whose `k`-th entry is `1` if the `k`-th letter of - the shuffle is taken from ``w1`` and `0` if it is taken - from ``w2``. + Return an iterator for the words in the + shuffle product of ``w1`` and ``w2``. EXAMPLES:: sage: from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2 sage: w, u = map(Words("abcd"), ["ab", "cd"]) sage: S = ShuffleProduct_w1w2(w,u) - sage: S._proc([0,1,0,1]) - word: cadb - sage: S._proc([1,1,0,0]) - word: abcd + sage: S.list() #indirect test + [word: abcd, word: acbd, word: acdb, word: cabd, + word: cadb, word: cdab] sage: I = Composition([1, 1]) sage: J = Composition([2]) sage: S = ShuffleProduct_w1w2(I, J) - sage: S._proc([1,0,1]) - [1, 2, 1] + sage: next(iter(S)) + [1, 1, 2] TESTS: - Sage is no longer confused by a too-restrictive parent - of `I` when shuffling two compositions `I` and `J` - (cf. :trac:`15131`):: + Sage is no longer confused by a too-restrictive parent of `I` + when shuffling compositions `I` and `J` (cf. :trac:`15131`):: sage: I = Compositions(2)([1, 1]) sage: J = Composition([2]) sage: S = ShuffleProduct_w1w2(I, J) - sage: S._proc([1,0,1]) - [1, 2, 1] sage: S.list() [[1, 1, 2], [1, 2, 1], [2, 1, 1]] """ - i1 = -1 - i2 = -1 - res = [] - for v in vect: - if v == 1: - i1 += 1 - res.append(self._w1[i1]) - else: - i2 += 1 - res.append(self._w2[i2]) + n1 = len(self._w1) + n2 = len(self._w2) + w1_parent = self._w1.parent() + use_w1_parent = True try: - return self._w1.parent()(res, check=self._check) + w1_parent(list(self._w1) + list(self._w2), check=self._check) except (ValueError, TypeError): - # Special situation: the parent of w1 is too - # restrictive to be cast on res. + use_w1_parent = False if isinstance(self._w1, Composition): - return Composition(res) + large_parent = Composition elif isinstance(self._w1, Word_class): - return Word(res) - return res - - def __iter__(self): - """ - Return an iterator for the words in the - shuffle product of ``w1`` and ``w2``. - - EXAMPLES:: - - sage: from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2 - sage: w, u = map(Words("abcd"), ["ab", "cd"]) - sage: S = ShuffleProduct_w1w2(w,u) - sage: S.list() #indirect test - [word: abcd, word: acbd, word: acdb, word: cabd, - word: cadb, word: cdab] - """ - n1 = len(self._w1) - n2 = len(self._w2) + large_parent = Word for iv in IntegerVectors(n1, n1 + n2, max_part=1): - yield self._proc(iv) + it1 = iter(self._w1) + it2 = iter(self._w2) + w = [next(it1) if v else next(it2) for v in iv] + if use_w1_parent: + yield w1_parent(w, check=self._check) + else: + yield large_parent(w) class ShuffleProduct_shifted(ShuffleProduct_w1w2): diff --git a/src/sage/modular/multiple_zeta.py b/src/sage/modular/multiple_zeta.py index 561ddccd5cd..ebe48c205f0 100644 --- a/src/sage/modular/multiple_zeta.py +++ b/src/sage/modular/multiple_zeta.py @@ -1005,11 +1005,10 @@ def _element_constructor_(self, x): W = self.basis().keys() if isinstance(x, list): x = tuple(x) - return self.monomial(W(x, check=False)) + return self._monomial(W(x, check=False)) elif isinstance(parent(x), Multizetas_iterated): return x.composition() - else: - raise TypeError('invalid input for building a multizeta value') + raise TypeError('invalid input for building a multizeta value') def algebra_generators(self, n): """ @@ -1544,8 +1543,7 @@ def product_on_basis(self, w1, w2): sage: M.product_on_basis(y,x) I(10110) + 3*I(11010) + 6*I(11100) """ - B = self.basis() - return sum(B[u] for u in shuffle(w1, w2, False)) + return self.sum(self._monomial(u) for u in shuffle(w1, w2, False)) def half_product_on_basis(self, w1, w2): r""" @@ -1914,7 +1912,7 @@ def _element_constructor_(self, x): W = self.basis().keys() if isinstance(x, list): x = tuple(x) - return self.monomial(W(x, check=False)) + return self._monomial(W(x, check=False)) P = x.parent() if isinstance(P, Multizetas_iterated): @@ -2188,7 +2186,7 @@ def _element_constructor_(self, x): if w[0] == w[-1] or (len(w) >= 4 and all(x == w[1] for x in w[2:-1])): return self.zero() - return self.monomial(w) + return self._monomial(w) def dual_on_basis(self, w): """ @@ -2257,7 +2255,7 @@ def reversal_on_basis(self, w): if w[0] == 0 and w[-1] == 1: return self(w) W = self.basis().keys() - image = self.monomial(W(list(reversed(w)), check=False)) + image = self._monomial(W(list(reversed(w)), check=False)) return -image if len(w) % 2 else image @lazy_attribute From 89c46c64dce40c074c45a29f6def75c43e819c5e Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 2 Jan 2022 11:16:41 -0500 Subject: [PATCH 093/253] Trac #33107: cholesky() for trivial matrices. Somehow the trivial matrix was overlooked (probably by myself) in the generic cholesky() method for matrices. Here we add a special-case and a doctest for it; the trivial matrix itself satisfies the definition of its Cholesky factor. --- src/sage/matrix/matrix2.pyx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index 7d319bd54b9..bb935a2ae8c 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -12620,6 +12620,13 @@ cdef class Matrix(Matrix1): sage: A.cholesky() [ 1.0 0.0] [-1.0*I 1.0] + + Try the trivial case (:trac:`33107`):: + + sage: all( matrix(R,[]).cholesky() == matrix(R,[]) + ....: for R in (RR,CC,RDF,CDF,ZZ,QQ,AA,QQbar) ) + True + """ cdef Matrix C # output matrix C = self.fetch('cholesky') @@ -12631,6 +12638,12 @@ cdef class Matrix(Matrix1): if not self.is_hermitian(): raise ValueError("matrix is not Hermitian") + if n == 0: + # The trivial matrix has a trivial cholesky decomposition. + # We special-case this after is_hermitian() to ensure that + # the matrix is square. + return self + # Use classical=True to ensure that we don't get a permuted L. cdef Matrix L # block_ldlt() results cdef list d # block_ldlt() results From 64d90284660e19f486fd7b6d44f2dcf528b778fc Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Mon, 3 Jan 2022 11:57:15 -0500 Subject: [PATCH 094/253] Trac #33107: return immutable trivial Cholesky factors. We usually return an immutable factor from cholesky(), but in the special trivial case the factor was mutable (a copy of the input matrix). Here we make it immutable in both the superclass method and in the RDF/CDF subclass. --- src/sage/matrix/matrix2.pyx | 7 ++++++- src/sage/matrix/matrix_double_dense.pyx | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index bb935a2ae8c..ba196895e52 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -12626,6 +12626,9 @@ cdef class Matrix(Matrix1): sage: all( matrix(R,[]).cholesky() == matrix(R,[]) ....: for R in (RR,CC,RDF,CDF,ZZ,QQ,AA,QQbar) ) True + sage: all( matrix(R,[]).cholesky().is_immutable() + ....: for R in (RR,CC,RDF,CDF,ZZ,QQ,AA,QQbar) ) + True """ cdef Matrix C # output matrix @@ -12642,7 +12645,9 @@ cdef class Matrix(Matrix1): # The trivial matrix has a trivial cholesky decomposition. # We special-case this after is_hermitian() to ensure that # the matrix is square. - return self + C = self.__copy__() + C.set_immutable() + return C # Use classical=True to ensure that we don't get a permuted L. cdef Matrix L # block_ldlt() results diff --git a/src/sage/matrix/matrix_double_dense.pyx b/src/sage/matrix/matrix_double_dense.pyx index 8168239ff1c..59e84ab276d 100644 --- a/src/sage/matrix/matrix_double_dense.pyx +++ b/src/sage/matrix/matrix_double_dense.pyx @@ -3746,7 +3746,9 @@ cdef class Matrix_double_dense(Matrix_dense): raise ValueError(msg.format(self.nrows(), self.ncols())) if self._nrows == 0: # special case self.cache(cache_posdef, True) - return self.__copy__() + L = self.__copy__() + L.set_immutable() + return L L = self.fetch(cache_cholesky) if L is None: From cfee1d4ece2866e3903f012f62a8d6fdc2241f37 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Wed, 5 Jan 2022 10:52:48 +0100 Subject: [PATCH 095/253] remove deprecated methods and keywords in combinatorial polyhedron deprecated in sage <= 9.1 --- .../combinatorial_polyhedron/base.pyx | 57 +----------- .../combinatorial_face.pyx | 91 ------------------- 2 files changed, 1 insertion(+), 147 deletions(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index 6e795febc0e..f2ab3b19bec 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -357,7 +357,7 @@ cdef class CombinatorialPolyhedron(SageObject): # ``self._length_edges_list*2*sizeof(size_t *)``. self._length_edges_list = 16348 - def __init__(self, data, Vrep=None, facets=None, unbounded=False, far_face=None, Vrepr=None): + def __init__(self, data, Vrep=None, facets=None, unbounded=False, far_face=None): r""" Initialize :class:`CombinatorialPolyhedron`. @@ -369,16 +369,7 @@ cdef class CombinatorialPolyhedron(SageObject): ....: [0,2,3],[1,2,3]]) # indirect doctest sage: TestSuite(sage.geometry.polyhedron.combinatorial_polyhedron.base.CombinatorialPolyhedron).run() - - sage: C = CombinatorialPolyhedron(Matrix([[1,0],[0,1]]), Vrepr=['zero', 'one']) - doctest:...: DeprecationWarning: the keyword ``Vrepr`` is deprecated; use ``Vrep`` - See https://trac.sagemath.org/28608 for details. - """ - if Vrepr: - from sage.misc.superseded import deprecation - deprecation(28608, "the keyword ``Vrepr`` is deprecated; use ``Vrep``", 3) - Vrep = Vrepr data_modified = None if isinstance(data, Polyhedron_base): @@ -1317,29 +1308,6 @@ cdef class CombinatorialPolyhedron(SageObject): adjacency_matrix.set_immutable() return adjacency_matrix - def edge_graph(self, names=True): - r""" - Return the edge graph. - - If ``names`` is set to ``False``, the Vrepresentatives will - carry names according to the indexing of the Vrepresentation. - - EXAMPLES:: - - sage: P = polytopes.cyclic_polytope(3,5) - sage: C = CombinatorialPolyhedron(P) - sage: C.edge_graph() - doctest:...: DeprecationWarning: the method edge_graph of CombinatorialPolyhedron is deprecated; use vertex_graph - See https://trac.sagemath.org/28603 for details. - Graph on 5 vertices - sage: G = C.edge_graph() - sage: sorted(G.degree()) - [3, 3, 4, 4, 4] - """ - from sage.misc.superseded import deprecation - deprecation(28603, "the method edge_graph of CombinatorialPolyhedron is deprecated; use vertex_graph", 3) - return Graph(self.edges(names=names), format="list_of_edges") - def ridges(self, add_equations=False, names=True, add_equalities=False): r""" Return the ridges. @@ -1514,29 +1482,6 @@ cdef class CombinatorialPolyhedron(SageObject): V = list(v[0] for v in V) return Graph([V, E], format="vertices_and_edges") - def ridge_graph(self, names=True): - r""" - Return the ridge graph. - - The ridge graph of a polyhedron consists of - ridges as edges and facets as vertices. - - If ``names`` is ``False``, the ``vertices`` of the graph will - be the incidences of the facets in the Hrepresentation. - - EXAMPLES:: - - sage: P = polytopes.cyclic_polytope(4,6) - sage: C = CombinatorialPolyhedron(P) - sage: C.ridge_graph() - doctest:...: DeprecationWarning: the method ridge_graph of CombinatorialPolyhedron is deprecated; use facet_graph - See https://trac.sagemath.org/28604 for details. - Graph on 9 vertices - """ - from sage.misc.superseded import deprecation - deprecation(28604, "the method ridge_graph of CombinatorialPolyhedron is deprecated; use facet_graph", 3) - return Graph(self.ridges(names=names), format="list_of_edges") - @cached_method def vertex_facet_graph(self, names=True): r""" diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx index 89f1987c5e7..9189f587922 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx @@ -66,8 +66,6 @@ AUTHOR: from cysignals.memory cimport check_allocarray, sig_free -from sage.misc.superseded import deprecated_function_alias - import numbers from sage.rings.integer cimport smallInteger from .conversions cimport bit_rep_to_Vrep_list @@ -654,45 +652,6 @@ cdef class CombinatorialFace(SageObject): return tuple(smallInteger(self.atom_rep[i]) for i in range(length)) - def Vrepr(self, names=True): - r""" - The method is deprecated. Use one of the following: - - :meth:`CombinatorialFace.ambient_Vrepresentation` - - :meth:`CombinatorialFace.ambient_V_indices` - - Return the vertex-representation of the current face. - - The vertex-representation consists of - the ``[vertices, rays, lines]`` that face contains. - - INPUT: - - - ``names`` -- if ``True`` returns the names of the ``[vertices, rays, lines]`` - as given on initialization of the :class:`~sage.geometry.polyhedron.combinatorial_polyhedron.base.CombinatorialPolyhedron` - - TESTS:: - - sage: P = polytopes.permutahedron(5) - sage: C = CombinatorialPolyhedron(P) - sage: it = C.face_iter(dimension=2) - sage: face = next(it) - sage: face.Vrepr() - doctest:...: DeprecationWarning: the method Vrepr of CombinatorialPolyhedron is deprecated; use ambient_V_indices or ambient_Vrepresentation - See https://trac.sagemath.org/28616 for details. - (A vertex at (1, 3, 2, 5, 4), - A vertex at (2, 3, 1, 5, 4), - A vertex at (3, 1, 2, 5, 4), - A vertex at (3, 2, 1, 5, 4), - A vertex at (2, 1, 3, 5, 4), - A vertex at (1, 2, 3, 5, 4)) - """ - from sage.misc.superseded import deprecation - deprecation(28616, "the method Vrepr of CombinatorialPolyhedron is deprecated; use ambient_V_indices or ambient_Vrepresentation", 3) - if names: - return self.ambient_Vrepresentation() - else: - return self.ambient_V_indices() - def n_ambient_Vrepresentation(self): r""" Return the length of the :meth:`CombinatorialFace.ambient_V_indices`. @@ -713,17 +672,12 @@ cdef class CombinatorialFace(SageObject): sage: C = CombinatorialPolyhedron(P) sage: it = C.face_iter() sage: face = next(it) - sage: _ = face.n_Vrepr() - doctest:...: DeprecationWarning: n_Vrepr is deprecated. Please use n_ambient_Vrepresentation instead. - See https://trac.sagemath.org/28614 for details. """ if self._dual: return smallInteger(self.set_coatom_rep()) else: return smallInteger(self.n_atom_rep()) - n_Vrepr = deprecated_function_alias(28614, n_ambient_Vrepresentation) - def ambient_Hrepresentation(self): r""" Return the Hrepresentation objects of the ambient polyhedron @@ -854,46 +808,6 @@ cdef class CombinatorialFace(SageObject): return tuple(smallInteger(self.atom_rep[i]) for i in range(length)) + equations - def Hrepr(self, names=True): - r""" - The method is deprecated. Use one of the following: - - :meth:`CombinatorialFace.ambient_Hrepresentation` - - :meth:`CombinatorialFace.ambient_H_indices` - - Return the Hrepresentation of the face. - - If ``names`` is ``False`` this is just the indices - of the facets the face is contained in. - If ``names`` is ``True`` this the defining facets - and equations of the face. - - The facet-representation consists of the facets - that contain the face and of the equations of the polyhedron. - - INPUT: - - - ``names`` -- if ``True`` returns the names of the ``[facets, equations]`` - as given on initialization of :class:`~sage.geometry.polyhedron.combinatorial_polyhedron.base.CombinatorialPolyhedron` - - TESTS:: - - sage: P = polytopes.permutahedron(5) - sage: C = CombinatorialPolyhedron(P) - sage: it = C.face_iter(2) - sage: next(it).Hrepr() - doctest:...: DeprecationWarning: the method Hrepr of CombinatorialPolyhedron is deprecated; use ambient_H_indices or ambient_Hrepresentation - See https://trac.sagemath.org/28616 for details. - (An inequality (1, 1, 1, 0, 0) x - 6 >= 0, - An inequality (0, 0, 0, -1, 0) x + 5 >= 0, - An equation (1, 1, 1, 1, 1) x - 15 == 0) - """ - from sage.misc.superseded import deprecation - deprecation(28616, "the method Hrepr of CombinatorialPolyhedron is deprecated; use ambient_H_indices or ambient_Hrepresentation", 3) - if names: - return self.ambient_Hrepresentation() - else: - return self.ambient_H_indices() - def n_ambient_Hrepresentation(self, add_equations=True): r""" Return the length of the :meth:`CombinatorialFace.ambient_H_indices`. @@ -929,9 +843,6 @@ cdef class CombinatorialFace(SageObject): 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. """ cdef size_t n_equations = self._n_equations if add_equations else 0 if not self._dual: @@ -939,8 +850,6 @@ cdef class CombinatorialFace(SageObject): else: return smallInteger(self.n_atom_rep() + n_equations) - n_Hrepr = deprecated_function_alias(28614, n_ambient_Hrepresentation) - def as_combinatorial_polyhedron(self, quotient=False): r""" Return ``self`` as combinatorial polyhedron. From e89193f4f32246ad9ded6d37f1f2f12a589a81f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Tue, 21 Dec 2021 13:08:44 -0300 Subject: [PATCH 096/253] sage_docbuild: do not fail when cache cannot be saved --- src/sage_docbuild/__init__.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sage_docbuild/__init__.py b/src/sage_docbuild/__init__.py index 466ca829a75..f8c8ebd4ca3 100644 --- a/src/sage_docbuild/__init__.py +++ b/src/sage_docbuild/__init__.py @@ -856,9 +856,12 @@ def save_cache(self): Pickle the current reference cache for later retrieval. """ cache = self.get_cache() - with open(self.cache_filename(), 'wb') as file: - pickle.dump(cache, file) - logger.debug("Saved the reference cache: %s", self.cache_filename()) + try: + with open(self.cache_filename(), 'wb') as file: + pickle.dump(cache, file) + logger.debug("Saved the reference cache: %s", self.cache_filename()) + except PermissionError: + logger.debug("Permission denied for the reference cache: %s", self.cache_filename()) def get_sphinx_environment(self): """ From 18d0477153af6f453a0e84f78030535f6a36ce87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Sun, 26 Dec 2021 18:21:18 -0300 Subject: [PATCH 097/253] doctests: remove dochtml label from some tests that don't need docs installed --- src/sage/docs/conf.py | 4 ++-- src/sage/misc/sagedoc.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/docs/conf.py b/src/sage/docs/conf.py index c78862355e5..527ed905805 100644 --- a/src/sage/docs/conf.py +++ b/src/sage/docs/conf.py @@ -719,8 +719,8 @@ def call_intersphinx(app, env, node, contnode): Check that the link from the thematic tutorials to the reference manual is relative, see :trac:`20118`:: - sage: from sage.env import SAGE_DOC # optional - sagemath_doc_html - sage: thematic_index = os.path.join(SAGE_DOC, "html", "en", "thematic_tutorials", "index.html") # optional - sagemath_doc_html + sage: from sage.env import SAGE_DOC + sage: thematic_index = os.path.join(SAGE_DOC, "html", "en", "thematic_tutorials", "index.html") sage: for line in open(thematic_index).readlines(): # optional - sagemath_doc_html ....: if "padics" in line: ....: _ = sys.stdout.write(line) diff --git a/src/sage/misc/sagedoc.py b/src/sage/misc/sagedoc.py index 4c56aea0782..583ca069456 100644 --- a/src/sage/misc/sagedoc.py +++ b/src/sage/misc/sagedoc.py @@ -18,8 +18,8 @@ Check that argspecs of extension function/methods appear correctly, see :trac:`12849`:: - sage: from sage.env import SAGE_DOC # optional - sagemath_doc_html - sage: docfilename = os.path.join(SAGE_DOC, 'html', 'en', 'reference', 'calculus', 'sage', 'symbolic', 'expression.html') # optional - sagemath_doc_html + sage: from sage.env import SAGE_DOC + sage: docfilename = os.path.join(SAGE_DOC, 'html', 'en', 'reference', 'calculus', 'sage', 'symbolic', 'expression.html') sage: with open(docfilename) as fobj: # optional - sagemath_doc_html ....: for line in fobj: ....: if "#sage.symbolic.expression.Expression.numerical_approx" in line: @@ -845,12 +845,12 @@ def _search_src_or_doc(what, string, extra1='', extra2='', extra3='', :: - sage: from sage.misc.sagedoc import _search_src_or_doc # optional - sagemath_doc_html - sage: len(_search_src_or_doc('src', r'matrix\(', 'incidence_structures', 'self', 'combinat', interact=False).splitlines()) > 1 # optional - sagemath_doc_html + sage: from sage.misc.sagedoc import _search_src_or_doc + sage: len(_search_src_or_doc('src', r'matrix\(', 'incidence_structures', 'self', 'combinat', interact=False).splitlines()) > 1 True sage: 'abvar/homology' in _search_src_or_doc('doc', 'homology', 'variety', interact=False) # optional - sagemath_doc_html, long time (4s on sage.math, 2012) True - sage: 'divisors' in _search_src_or_doc('src', '^ *def prime', interact=False) # optional - sagemath_doc_html + sage: 'divisors' in _search_src_or_doc('src', '^ *def prime', interact=False) True When passing ``interactive=True``, in a terminal session this will pass the @@ -1369,7 +1369,7 @@ class _sage_doc: sage: browse_sage_doc._open("reference", testing=True)[0] # optional - sagemath_doc_html, indirect doctest 'http://localhost:8000/doc/live/reference/index.html' - sage: browse_sage_doc(identity_matrix, 'rst')[-107:-47] # optional - sagemath_doc_html + sage: browse_sage_doc(identity_matrix, 'rst')[-107:-47] 'Full MatrixSpace of 3 by 3 sparse matrices over Integer Ring' """ def __init__(self): From 88dd9f3a1611fed0cc66fb838eb85739646dd34d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Sun, 26 Dec 2021 18:22:13 -0300 Subject: [PATCH 098/253] doctests: add dochtml label to some tests that need docs installed --- src/sage_docbuild/__init__.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage_docbuild/__init__.py b/src/sage_docbuild/__init__.py index f8c8ebd4ca3..d32900973d1 100644 --- a/src/sage_docbuild/__init__.py +++ b/src/sage_docbuild/__init__.py @@ -105,7 +105,7 @@ def builder_helper(type): sage: from sage_docbuild import builder_helper, build_ref_doc sage: from sage_docbuild import _build_many as build_many sage: helper = builder_helper("html") - sage: try: + sage: try: # optional - sagemath_doc_html ....: build_many(build_ref_doc, [("docname", "en", "html", {})]) ....: except Exception as E: ....: "Non-exception during docbuild: abort pool operation" in str(E) @@ -186,7 +186,7 @@ def _output_dir(self, type): sage: from sage_docbuild import DocBuilder sage: b = DocBuilder('tutorial') - sage: b._output_dir('html') + sage: b._output_dir('html') # optional - sagemath_doc_html '.../html/en/tutorial' """ d = os.path.join(SAGE_DOC, type, self.lang, self.name) @@ -203,7 +203,7 @@ def _doctrees_dir(self): sage: from sage_docbuild import DocBuilder sage: b = DocBuilder('tutorial') - sage: b._doctrees_dir() + sage: b._doctrees_dir() # optional - sagemath_doc_html '.../doctrees/en/tutorial' """ d = os.path.join(SAGE_DOC, 'doctrees', self.lang, self.name) @@ -529,7 +529,7 @@ def _output_dir(self, type, lang=None): sage: from sage_docbuild import ReferenceBuilder sage: b = ReferenceBuilder('reference') - sage: b._output_dir('html') + sage: b._output_dir('html') # optional - sagemath_doc_html '.../html/en/reference' """ if lang is None: @@ -640,7 +640,7 @@ def _output_dir(self, type, lang=None): sage: from sage_docbuild import ReferenceTopBuilder sage: b = ReferenceTopBuilder('reference') - sage: b._output_dir('html') + sage: b._output_dir('html') # optional - sagemath_doc_html '.../html/en/reference' """ if lang is None: From 8435c780eea6a5d6749d80d914e20dc433301a1b Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 10 Jan 2022 12:17:25 +0900 Subject: [PATCH 099/253] Reformatting output, simplifying basis construction, other misc changes. --- src/sage/combinat/free_module.py | 13 +- src/sage/modules/fp_graded/free_homspace.py | 7 +- src/sage/modules/fp_graded/free_module.py | 260 +++++++++----------- src/sage/modules/fp_graded/free_morphism.py | 54 ++-- src/sage/modules/fp_graded/homspace.py | 41 ++- src/sage/modules/fp_graded/module.py | 216 ++++++++-------- src/sage/modules/fp_graded/morphism.py | 111 +++++---- src/sage/structure/indexed_generators.py | 119 ++++++++- 8 files changed, 463 insertions(+), 358 deletions(-) diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index 9f3e07bf013..6484a8221a7 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -313,6 +313,13 @@ def __classcall_private__(cls, base_ring, basis_keys=None, category=None, if prefix is None: prefix = "B" + if keywords.get('latex_names', None) is not None: + latex_names = keywords['latex_names'] + if isinstance(latex_names, str): + latex_names = latex_names.split(',') + latex_names = tuple(latex_names) + keywords['latex_names'] = latex_names + return super(CombinatorialFreeModule, cls).__classcall__(cls, base_ring, basis_keys, category=category, prefix=prefix, names=names, **keywords) @@ -413,9 +420,9 @@ def __init__(self, R, basis_keys=None, element_class=None, category=None, ValueError: keyy is not a valid print option. """ # Make sure R is a ring with unit element - from sage.categories.all import Rings + from sage.categories.rings import Rings if R not in Rings(): - raise TypeError("Argument R must be a ring.") + raise TypeError("argument R must be a ring") if element_class is not None: self.Element = element_class @@ -438,7 +445,7 @@ def __init__(self, R, basis_keys=None, element_class=None, category=None, kwds['sorting_key'] = kwds.pop('monomial_key') if 'monomial_reverse' in kwds: kwds['sorting_reverse'] = kwds.pop('monomial_reverse') - IndexedGenerators.__init__(self, basis_keys, prefix, **kwds) + IndexedGenerators.__init__(self, basis_keys, prefix, names=names, **kwds) if category is None: category = ModulesWithBasis(R) diff --git a/src/sage/modules/fp_graded/free_homspace.py b/src/sage/modules/fp_graded/free_homspace.py index 5524a3b2197..f167fa5fe1d 100755 --- a/src/sage/modules/fp_graded/free_homspace.py +++ b/src/sage/modules/fp_graded/free_homspace.py @@ -41,17 +41,12 @@ from sage.categories.homset import Homset from sage.misc.cachefunc import cached_method - +from sage.modules.fp_graded.free_morphism import FreeGradedModuleMorphism class FreeGradedModuleHomspace(Homset): """ Homspace between two free graded modules. """ - # In the category framework, Elements of the class FPModule are of the - # class FPElement, see - # http://doc.sagemath.org/html/en/thematic_tutorials/coercion_and_categories.html#implementing-the-category-framework-for-the-elements - from .free_morphism import FreeGradedModuleMorphism - Element = FreeGradedModuleMorphism def _element_constructor_(self, values): diff --git a/src/sage/modules/fp_graded/free_module.py b/src/sage/modules/fp_graded/free_module.py index a389d271da6..a104d53ea13 100755 --- a/src/sage/modules/fp_graded/free_module.py +++ b/src/sage/modules/fp_graded/free_module.py @@ -17,7 +17,7 @@ sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: M = FreeGradedModule(algebra=A, generator_degrees=(0,1)) sage: M - Finitely presented free left module on 2 generators over + Free graded left module on 2 generators over mod 2 Steenrod algebra, milnor basis The resulting free module will have generators in the degrees as specified:: @@ -48,26 +48,26 @@ Module elements are displayed by their algebra coefficients:: sage: M.an_element(n=5) - Sq(2,1)*g_{0} + Sq(4)*g_{1} + Sq(2,1)*G[0] + Sq(4)*G[1] sage: M.an_element(n=15) - Sq(0,0,0,1)*g_{0} + Sq(1,2,1)*g_{1} + Sq(0,0,0,1)*G[0] + Sq(1,2,1)*G[1] The generators are themselves elements of the module:: sage: M.generators() - [g_{0}, g_{1}] + (G[0], G[1]) Producing elements from a given set of coefficients is possible as usual:: sage: coeffs = [Sq(5), Sq(1,1)] sage: x = M(coeffs); x - Sq(5)*g_{0} + Sq(1,1)*g_{1} + Sq(5)*G[0] + Sq(1,1)*G[1] The module action produces new elements:: sage: Sq(2) * x - (Sq(4,1)+Sq(7))*g_{0} + Sq(3,1)*g_{1} + (Sq(4,1)+Sq(7))*G[0] + Sq(3,1)*G[1] Each non-zero element has a well-defined degree:: @@ -86,9 +86,9 @@ Any two elements can be added as long as they are in the same degree:: sage: y = M.an_element(5); y - Sq(2,1)*g_{0} + Sq(4)*g_{1} + Sq(2,1)*G[0] + Sq(4)*G[1] sage: x + y - (Sq(2,1)+Sq(5))*g_{0} + (Sq(1,1)+Sq(4))*g_{1} + (Sq(2,1)+Sq(5))*G[0] + (Sq(1,1)+Sq(4))*G[1] or when at least one of them is zero:: @@ -105,7 +105,7 @@ computed:: sage: M.basis_elements(5) - [Sq(2,1)*g_{0}, Sq(5)*g_{0}, Sq(1,1)*g_{1}, Sq(4)*g_{1}] + (Sq(2,1)*G[0], Sq(5)*G[0], Sq(1,1)*G[1], Sq(4)*G[1]) together with a corresponding vector space presentation:: @@ -122,7 +122,7 @@ sage: x_ = M.element_from_coordinates((0,1,1,0), 5) sage: x_ - Sq(5)*g_{0} + Sq(1,1)*g_{1} + Sq(5)*G[0] + Sq(1,1)*G[1] sage: x_ == x True @@ -139,9 +139,9 @@ sage: M = FreeGradedModule(A, (0,1)) sage: N. = FreeGradedModule(A, (2,)) sage: homspace = Hom(M, N); homspace - Set of Morphisms from Finitely presented free left module on 2 generators + Set of Morphisms from Free graded left module on 2 generators over mod 2 Steenrod algebra, milnor basis - to Finitely presented free left module on 1 generator + to Free graded left module on 1 generator over mod 2 Steenrod algebra, milnor basis in Category of finite dimensional graded modules with basis over mod 2 Steenrod algebra, milnor basis @@ -158,9 +158,9 @@ sage: f Module homomorphism of degree 4 defined by sending the generators - [g_{0}, g_{1}] + (G[0], G[1]) to - [Sq(2)*c2, (Sq(0,1)+Sq(3))*c2] + (Sq(2)*c2, (Sq(0,1)+Sq(3))*c2) Convenience methods exist for creating the trivial morphism:: @@ -206,9 +206,9 @@ sage: f2 = homspace([Sq(2)*c2, Sq(3)*c2]) sage: f + f2 Module homomorphism of degree 4 defined by sending the generators - [g_{0}, g_{1}] + (G[0], G[1]) to - [0, Sq(0,1)*c2] + (0, Sq(0,1)*c2) or when at least one of them is zero:: @@ -267,12 +267,12 @@ from sage.misc.cachefunc import cached_method from sage.modules.free_module import VectorSpace +from sage.modules.fp_graded.free_element import FreeGradedModuleElement from sage.rings.infinity import PlusInfinity from sage.categories.graded_modules import GradedModules +from sage.categories.fields import Fields from sage.combinat.free_module import CombinatorialFreeModule -from .free_element import FreeGradedModuleElement - class FreeGradedModule(CombinatorialFreeModule): r""" Create a finitely generated free graded module over a connected @@ -289,7 +289,7 @@ class FreeGradedModule(CombinatorialFreeModule): - ``names`` -- optional, the names of the generators. If ``names`` is a comma-separated string like ``'a, b, c'``, then those will be the names. Otherwise, for example if ``names`` is ``abc``, - then the names will be ``abc_{d,i}``. + then the names will be ``abc(d,i)``. By default, if all generators are in distinct degrees, then the ``names`` of the generators will have the form ``g_{d}`` where @@ -304,7 +304,7 @@ class FreeGradedModule(CombinatorialFreeModule): sage: E. = ExteriorAlgebra(QQ) sage: M = FreeGradedModule(E, (-1,3)) sage: M - Finitely presented free left module on 2 generators over + Free graded left module on 2 generators over The exterior algebra of rank 3 over Rational Field sage: M.generator_degrees() (-1, 3) @@ -315,25 +315,52 @@ class FreeGradedModule(CombinatorialFreeModule): ``names`` of generators:: sage: M.generators() - [g_{-1}, g_{3}] + (G[-1], G[3]) sage: FreeGradedModule(E, (0, 0, 2)).generators() - [g_{0,0}, g_{0,1}, g_{2,0}] + (G(0, 0), G(0, 1), G(2, 0)) sage: FreeGradedModule(E, (0, 0, 2), names='x, y, z').generators() - [x, y, z] + (x, y, z) sage: FreeGradedModule(E, (0, 0, 2), names='xyz').generators() - [xyz_{0,0}, xyz_{0,1}, xyz_{2,0}] + (xyz(0, 0), xyz(0, 1), xyz(2, 0)) ``names`` can also be defined implicitly using Sage's ``M.<...>`` syntax:: sage: A = SteenrodAlgebra(2) sage: M. = FreeGradedModule(A, (-2,2,4)) sage: M - Finitely presented free left module on 3 generators over + Free graded left module on 3 generators over mod 2 Steenrod algebra, milnor basis sage: M.gens() (x, y, z) """ - def __init__(self, algebra, generator_degrees, names=None): + def __classcall_private__(cls, algebra, generator_degrees, category=None, + names=None, prefix=None, **kwds): + """ + Normalize input to ensure a unique representation. + """ + if algebra.base_ring() not in Fields(): + raise ValueError('the ground ring of the algebra must be a field') + + generator_degrees = tuple(generator_degrees) + category = GradedModules(algebra).WithBasis().FiniteDimensional().or_subcategory(category) + if names is not None: + from sage.structure.category_object import normalize_names + names = normalize_names(-1, names) + if len(generator_degrees) > 1: + if len(names) == 1: + if prefix is None: + prefix = names[0] + names = None # if prefix is specified and takes priority + if names is not None and len(names) != len(generator_degrees): + raise ValueError("the names do not correspond to the generators") + if prefix is None: + prefix = 'G' + return super(cls, FreeGradedModule).__classcall__(cls, algebra=algebra, + generator_degrees=generator_degrees, + category=category, names=names, + prefix=prefix, **kwds) + + def __init__(self, algebra, generator_degrees, category, names=None, **kwds): r""" Create a finitely generated free graded module over a connected graded algebra. @@ -347,56 +374,63 @@ def __init__(self, algebra, generator_degrees, names=None): # If generator_degrees is [d_0, d_1, ...], then # the generators are indexed by (0,d_0), (1,d_1), ... keys = list(enumerate(generator_degrees)) - self._generator_keys = keys + self._generator_degrees = generator_degrees - degs_and_indices = [] + keys = [] degs_so_far = {} + unique = True for i in generator_degrees: - try: + if i in degs_so_far: idx = degs_so_far[i] + 1 degs_so_far[i] += 1 - except KeyError: + unique = False + else: idx = 0 degs_so_far[i] = 0 - degs_and_indices.append((i, idx)) - if not degs_so_far or max(degs_so_far.values()) == 0: - degs_and_indices = [str(i[0]) for i in degs_and_indices] - else: - degs_and_indices = ['{},{}'.format(i[0],i[1]) for i in degs_and_indices] - - # _latex_term is defined to be the same as _repr_term, so the - # names should be valid LaTeX. - if names is None: - names = tuple('g_{{{}}}'.format(s) for s in degs_and_indices) - elif isinstance(names, str): - if names.find(',') == -1: - names = tuple('{}_{{{}}}'.format(names, s) for s in degs_and_indices) - else: - names = tuple(s.strip() for s in names.split(',')) + keys.append((i, idx)) + if unique: + keys = [i[0] for i in keys] else: - names = tuple(names) - self._names = names - - self._names_dict = dict(zip(keys, degs_and_indices)) - - if not algebra.base_ring().is_field(): - raise ValueError('the ground ring of the algebra must be a field') + kwds['bracket'] = False # Call the base class constructor. - cat = GradedModules(algebra).WithBasis().FiniteDimensional() CombinatorialFreeModule.__init__(self, algebra, basis_keys=keys, - category=cat) + category=category, + names=names, + **kwds) Element = FreeGradedModuleElement + + def _repr_(self): + r""" + Construct a string representation of ``self``. + + TESTS:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A = SteenrodAlgebra(2) + sage: M = FreeGradedModule(A, (0,2,4)) + sage: M + Free graded left module on 3 generators over + mod 2 Steenrod algebra, milnor basis + """ + return ("Free graded left module on %s generator%s over %s" + %(len(self._generator_degrees), + "" if len(self._generator_degrees) == 1 else "s", + self.base_ring())) + + def generator_degrees(self): r""" The degrees of the module generators. - OUTPUT: A tuple containing the degrees of the generators for this - module, in the order that the generators were given when this module - was constructed. + OUTPUT: + + A tuple containing the degrees of the generators for this + module, in the order that the generators were given when + ``self`` was constructed. EXAMPLES:: @@ -406,15 +440,12 @@ def generator_degrees(self): sage: M.generator_degrees() (-2, 2, 4) """ - return tuple(a[1] for a in self._generator_keys) + return self._generator_degrees def is_trivial(self): r""" - Decide if this module is trivial or not. - - OUTPUT: The boolean value ``True`` if the module is trivial, and - ``False`` otherwise. + Return ``True`` if this module is trivial and ``False`` otherwise. EXAMPLES:: @@ -425,7 +456,7 @@ def is_trivial(self): sage: FreeGradedModule(A, ()).is_trivial() True """ - return not len(self.generator_degrees()) + return not len(self._generator_degrees) def connectivity(self): @@ -489,11 +520,13 @@ def _element_constructor_(self, coefficients): """ if isinstance(coefficients, self.element_class): return coefficients + if not coefficients: return self.zero() - B = self.basis() - return sum(c * B[b] for (c,b) in zip(coefficients, self._generator_keys)) + A = self.base_ring() + return self._from_dict({b: A(c) for (c,b) in zip(coefficients, self._indices) if c}, + remove_zeros=False) def an_element(self, n=None): @@ -517,14 +550,14 @@ def an_element(self, n=None): sage: A = SteenrodAlgebra(2) sage: M = FreeGradedModule(A, (0,2,4)) sage: M.an_element(172) - Sq(0,0,2,0,1,0,1)*g_{0} + Sq(0,4,0,0,1,0,1)*g_{2} + Sq(7,1,0,0,1,0,1)*g_{4} + Sq(0,0,2,0,1,0,1)*G[0] + Sq(0,4,0,0,1,0,1)*G[2] + Sq(7,1,0,0,1,0,1)*G[4] Zero is the only element in the trivial module:: sage: FreeGradedModule(A, ()).an_element() 0 """ - if not len(self.generator_degrees()): + if not self._generator_degrees: return self.zero() if n is None: @@ -545,51 +578,6 @@ def an_element(self, n=None): return self(coefficients) - - def _repr_(self): - r""" - Construct a string representation of ``self``. - - TESTS:: - - sage: from sage.modules.fp_graded.free_module import FreeGradedModule - sage: A = SteenrodAlgebra(2) - sage: M = FreeGradedModule(A, (0,2,4)) - sage: M._repr_() - 'Finitely presented free left module on 3 generators over mod 2 Steenrod algebra, milnor basis' - """ - return "Finitely presented free left module on %s generator%s over %s"\ - %(len(self.generator_degrees()), "" if len(self.generator_degrees()) == 1 else "s", - self.base_ring()) - - - def _repr_term(self, m): - """ - Return a string representing the generator indexed by ``m``. - - INPUT: - - - ``m`` -- a key corresponding to a generator. This will be a - pair ``(idx, deg)`` where ``deg`` is the generator's degree - and ``idx`` is its index in the list of all generators. - - TESTS:: - - sage: from sage.modules.fp_graded.free_module import FreeGradedModule - sage: A = SteenrodAlgebra(2) - sage: M = FreeGradedModule(A, (0,2,4)) - sage: M._repr_term((1,2)) - 'g_{2}' - sage: M. = FreeGradedModule(A, (0,2,4)) - sage: M._repr_term((1,2)) - 'b' - """ - return self._names[m[0]] - - - _latex_term = _repr_term - - @cached_method def basis_elements(self, n): r""" @@ -619,7 +607,7 @@ def basis_elements(self, n): sage: A = SteenrodAlgebra(2) sage: M. = FreeGradedModule(A, (0,2,4)) sage: M.basis_elements(8) - [Sq(1,0,1)*m0, + (Sq(1,0,1)*m0, Sq(2,2)*m0, Sq(5,1)*m0, Sq(8)*m0, @@ -627,14 +615,13 @@ def basis_elements(self, n): Sq(3,1)*m2, Sq(6)*m2, Sq(1,1)*m4, - Sq(4)*m4] + Sq(4)*m4) """ - basis_n = [] - for i, generator_degree in enumerate(self.generator_degrees()): - l = n - generator_degree - basis_n += [a*self.generator(i) for a in self.base_ring().basis(l)] - - return basis_n + A = self.base_ring() + B = self.basis() + return tuple([self.term(self._indices[i], coeff) + for i, generator_degree in enumerate(self._generator_degrees) + for coeff in A.basis(n - generator_degree)]) @cached_method @@ -663,7 +650,7 @@ def element_from_coordinates(self, coordinates, n): sage: A = SteenrodAlgebra(2) sage: M = FreeGradedModule(A, (0,1)) sage: x = M.element_from_coordinates((0,1,0,1), 5); x - Sq(5)*g_{0} + Sq(4)*g_{1} + Sq(5)*G[0] + Sq(4)*G[1] sage: basis = M.basis_elements(5) sage: y = 0*basis[0] + 1*basis[1] + 0*basis[2] + 1*basis[3] sage: x == y @@ -693,7 +680,7 @@ def element_from_coordinates(self, coordinates, n): # and the total running time of the entire computation dropped from # 57 to 21 seconds by adding the optimization. # - element = sum(c*element for c, element in zip(coordinates, basis_elements) if c) + element = sum(c * element for c, element in zip(coordinates, basis_elements) if c) if not element: # The previous sum was over the empty list, yielding the integer @@ -766,14 +753,13 @@ def vector_presentation(self, n): sage: M.vector_presentation(3) Vector space of dimension 2 over Finite Field of size 2 sage: M.basis_elements(3) - [Sq(0,1)*x, Sq(3)*x] + (Sq(0,1)*x, Sq(3)*x) sage: [M.vector_presentation(i).dimension() for i in range(-2, 9)] [0, 0, 1, 1, 1, 2, 1, 1, 1, 0, 0] """ return VectorSpace(self.base_ring().base_ring(), len(self.basis_elements(n))) - @cached_method def generator(self, index): r""" Return the module generator with the given index. @@ -784,18 +770,18 @@ def generator(self, index): sage: A = SteenrodAlgebra(2) sage: M = FreeGradedModule(A, (0,2,4)) sage: M.generator(0) - g_{0} + G[0] sage: M.generator(1) - g_{2} + G[2] sage: M.generator(2) - g_{4} + G[4] """ try: - return self.monomial(self._generator_keys[index]) + return self.gens()[index] except IndexError: raise ValueError('the parent module has generators in the index ' - 'range [0, %s]; generator %s does not exist' % - (len(self.generator_degrees()) - 1, index)) + 'range [0, %s]; generator %s does not exist' % + (len(self.generator_degrees()) - 1, index)) gen = generator @@ -810,9 +796,9 @@ def generators(self): sage: A = SteenrodAlgebra(2) sage: M = FreeGradedModule(A, (-2,1)) sage: M.generators() - [g_{-2}, g_{1}] + (G[-2], G[1]) """ - return [self.generator(i) for i in range(len(self.generator_degrees()))] + return self.gens() def _Hom_(self, Y, category): @@ -827,9 +813,9 @@ def _Hom_(self, Y, category): sage: A = SteenrodAlgebra(2) sage: M = FreeGradedModule(A, (0,1)) sage: M._Hom_(M, category=None) - Set of Morphisms from Finitely presented free left module on 2 generators + Set of Morphisms from Free graded left module on 2 generators over mod 2 Steenrod algebra, milnor basis - to Finitely presented free left module on 2 generators + to Free graded left module on 2 generators over mod 2 Steenrod algebra, milnor basis in Category of finite dimensional graded modules with basis over mod 2 Steenrod algebra, milnor basis @@ -865,8 +851,8 @@ def suspension(self, t): generator_degrees=tuple([g + t for g in self.generator_degrees()])) - def to_fp_module(self): - """ + def as_fp_module(self): + r""" Create a finitely presented module from ``self``. OUTPUT: @@ -879,7 +865,7 @@ def to_fp_module(self): sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: A = SteenrodAlgebra(2) sage: F = FreeGradedModule(A, (-2,2,4)) - sage: F.to_fp_module() + sage: F.as_fp_module() Finitely presented left module on 3 generators and 0 relations over mod 2 Steenrod algebra, milnor basis """ diff --git a/src/sage/modules/fp_graded/free_morphism.py b/src/sage/modules/fp_graded/free_morphism.py index 71121deea02..a32e9fd6e91 100755 --- a/src/sage/modules/fp_graded/free_morphism.py +++ b/src/sage/modules/fp_graded/free_morphism.py @@ -109,21 +109,21 @@ def __init__(self, parent, values): # Compute the degree. if all(v.is_zero() for v in _values): # The zero homomorphism does not get a degree. - _degree = None + degree = None else: degrees = [] for i, value in enumerate(_values): if not value.is_zero(): x = value.degree() xx = D.generator_degrees()[i] - degrees.append(x-xx) + degrees.append(x - xx) - _degree = min(degrees) - if _degree != max(degrees): + degree = min(degrees) + if degree != max(degrees): raise ValueError('ill-defined homomorphism: degrees do not match') - self._degree = _degree - self._values = _values + self._degree = degree + self._values = tuple(_values) Morphism.__init__(self, parent) @@ -179,9 +179,9 @@ def values(self): sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] sage: f = homspace(values) sage: f.values() - [Sq(5)*g_{2}, Sq(3,1)*g_{2}] + (Sq(5)*G[2], Sq(3,1)*G[2]) sage: homspace.zero().values() - [0, 0] + (0, 0) """ return self._values @@ -278,13 +278,13 @@ def _neg_(self): sage: f = homspace(values) sage: f_inverse = -f; f_inverse Module homomorphism of degree 7 defined by sending the generators - [g_{0}, g_{1}] + [G[0], g_{1}] to - [Sq(5)*g_{2}, Sq(3,1)*g_{2}] + [Sq(5)*G[2], Sq(3,1)*G[2]] sage: (f + f_inverse).is_zero() True """ - return self.parent()([-x for x in self.values()]) + return self.parent()([-x for x in self._values]) def _sub_(self, g): @@ -325,9 +325,9 @@ def __mul__(self, g): sage: g = Hom(N, M)(values2) sage: fg = f * g; fg Module homomorphism of degree 7 defined by sending the generators - [g_{2}] + [G[2]] to - [(Sq(4,1)+Sq(7))*g_{2}] + [(Sq(4,1)+Sq(7))*G[2]] sage: fg.is_endomorphism() True @@ -373,7 +373,7 @@ def is_zero(self): sage: (f-f).is_zero() True """ - return all(v.is_zero() for v in self.values()) + return all(not v for v in self._values) __bool__ = is_zero @@ -427,14 +427,14 @@ def __call__(self, x): sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] sage: f = Hom(M, N)(values) sage: f.__call__(M.generator(0)) - Sq(5)*g_{2} + Sq(5)*G[2] sage: f.__call__(M.generator(1)) - Sq(3,1)*g_{2} + Sq(3,1)*G[2] """ if x.parent() != self.domain(): raise ValueError('cannot evaluate morphism on element not in the domain') - value = sum((c * v for c, v in zip(x.dense_coefficient_list(), self.values())), + value = sum((c * v for c, v in zip(x.dense_coefficient_list(), self._values)), self.codomain().zero()) return value @@ -454,7 +454,7 @@ def _repr_(self): sage: Hom(M, N)(values)._repr_() 'Module homomorphism of degree 7 defined by sending the generators\n - [g_{0}, g_{1}]\nto\n [Sq(5)*g_{2}, Sq(3,1)*g_{2}]' + [G[0], g_{1}]\nto\n [Sq(5)*G[2], Sq(3,1)*G[2]]' sage: Hom(M, N).zero()._repr_() 'The trivial homomorphism' @@ -468,7 +468,7 @@ def _repr_(self): return "The identity homomorphism" else: r = "Module homomorphism of degree {} defined by sending the generators\n {}\nto\n {}" - return r.format(self.degree(), self.domain().generators(), self.values()) + return r.format(self.degree(), self.domain().generators(), self._values) def vector_presentation(self, n): @@ -548,10 +548,10 @@ def vector_presentation(self, n): C_n = self.codomain().vector_presentation(n + self.degree()) values = [self(e) for e in self.domain().basis_elements(n)] - return Hom(D_n, C_n)([ - C_n.zero() if e.is_zero() else e.vector_presentation() for e in values]) + return Hom(D_n, C_n)([C_n.zero() if e.is_zero() else e.vector_presentation() + for e in values]) - def to_fp_module(self): + def fp_module(self): r""" Create a finitely presented module from ``self``. @@ -561,22 +561,22 @@ def to_fp_module(self): EXAMPLES:: - sage: from sage.modules.fp_graded.free_module import * + sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: A = SteenrodAlgebra(2) sage: F1 = FreeGradedModule(A, (2,)) sage: F2 = FreeGradedModule(A, (0,)) sage: v = F2([Sq(2)]) sage: pres = Hom(F1, F2)([v]) - sage: M = pres.to_fp_module(); M + sage: M = pres.fp_module(); M Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis sage: M.generator_degrees() (0,) sage: M.relations() - [Sq(2)*g_{0}] + [Sq(2)*G[0]] """ from .module import FPModule return FPModule(algebra=self.base_ring(), - generator_degrees=self.codomain().generator_degrees(), - relations=tuple([r.dense_coefficient_list() for r in self.values()])) + generator_degrees=self.codomain().generator_degrees(), + relations=tuple([r.dense_coefficient_list() for r in self._values])) diff --git a/src/sage/modules/fp_graded/homspace.py b/src/sage/modules/fp_graded/homspace.py index b59f65a5ff9..f295c8fde0b 100755 --- a/src/sage/modules/fp_graded/homspace.py +++ b/src/sage/modules/fp_graded/homspace.py @@ -50,11 +50,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from __future__ import absolute_import - -from sage.categories.homset import Homset - -from sage.categories.homset import Hom +from sage.categories.homset import Homset, Hom class FPModuleHomspace(Homset): @@ -62,9 +58,6 @@ class FPModuleHomspace(Homset): # not happen at the top level. from .morphism import FPModuleMorphism - # In the category framework, Elements of the class FPModuleHomspace are of the - # class FPModuleMorphism, see - # http://doc.sagemath.org/html/en/thematic_tutorials/coercion_and_categories.html#implementing-the-category-framework-for-the-elements Element = FPModuleMorphism def _element_constructor_(self, values): @@ -328,34 +321,34 @@ def _basis_elements(self, n, basis): Hom(Free, Free): basis==False: Module homomorphism of degree 7 defined by sending the generators - [g_{0}] + (G[0],) to - [Sq(0,0,1)*g_{0}] + (Sq(0,0,1)*G[0],), basis==True: [Module homomorphism of degree 7 defined by sending the generators - [g_{0}] + (G[0],) to - [Sq(0,0,1)*g_{0}], Module homomorphism of degree 7 defined by sending the generators - [g_{0}] + (Sq(0,0,1)*G[0],), Module homomorphism of degree 7 defined by sending the generators + (G[0],) to - [Sq(1,2)*g_{0}], Module homomorphism of degree 7 defined by sending the generators - [g_{0}] + (Sq(1,2)*G[0],), Module homomorphism of degree 7 defined by sending the generators + (G[0],) to - [Sq(4,1)*g_{0}], Module homomorphism of degree 7 defined by sending the generators - [g_{0}] + (Sq(4,1)*G[0],), Module homomorphism of degree 7 defined by sending the generators + (G[0],) to - [Sq(7)*g_{0}]] + (Sq(7)*G[0],)] Hom(Free, Hko): basis==False: Module homomorphism of degree 7 defined by sending the generators [g_{0}] to - [Sq(0,0,1)*g_{0}] + (Sq(0,0,1)*G[0],)] basis==True: [Module homomorphism of degree 7 defined by sending the generators [g_{0}] to - [Sq(0,0,1)*g_{0}]] + (Sq(0,0,1)*G[0],)] Hom(Free, Trivial): basis==False: The trivial homomorphism @@ -374,14 +367,14 @@ def _basis_elements(self, n, basis): Hom(Hko, Hko): basis==False: Module homomorphism of degree 7 defined by sending the generators - [g_{0}] + (G[0],) to - [Sq(0,0,1)*g_{0}] + (Sq(0,0,1)*G[0],)] basis==True: [Module homomorphism of degree 7 defined by sending the generators - [g_{0}] + (G[0],) to - [Sq(0,0,1)*g_{0}]] + (Sq(0,0,1)*G[0],)] Hom(Hko, Trivial): basis==False: The trivial homomorphism diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index 5214ed33fa8..6582fdd3a74 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -49,15 +49,15 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.structure.element import parent -from .free_module import FreeGradedModule -from .free_element import FreeGradedModuleElement -from .element import FPElement +from sage.modules.fp_graded.free_module import FreeGradedModule +from sage.modules.fp_graded.free_element import FreeGradedModuleElement +from sage.modules.fp_graded.element import FPElement # These are not free modules over the algebra, but they are free as # vector spaces. They have a distinguished set of generators over the # algebra, and as long as the algebra has a vector space basis # implemented in Sage, the modules will have a vector space basis as well. -class FPModule(Module, IndexedGenerators, UniqueRepresentation): +class FPModule(UniqueRepresentation, IndexedGenerators, Module): r""" Create a finitely presented module over a connected graded algebra. @@ -94,17 +94,17 @@ class FPModule(Module, IndexedGenerators, UniqueRepresentation): sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) sage: M = FPModule(A3, [0, 1], [[Sq(2), Sq(1)]]) sage: M.generators() - [g_{0}, g_{1}] + (G[0], G[1]) sage: M.relations() - [Sq(2)*g_{0} + Sq(1)*g_{1}] + (Sq(2)*G[0] + Sq(1)*G[1],) sage: M.is_trivial() False sage: Z = FPModule(A3, []) sage: Z.generators() - [] + () sage: Z.relations() - [] + () sage: Z.is_trivial() True """ @@ -117,10 +117,14 @@ def __classcall_private__(cls, algebra, generator_degrees, relations=(), names=N sage: from sage.modules.fp_graded.module import FPModule sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) - sage: FPModule(A3, [0, 1], [[Sq(2), Sq(1)]]) - Finitely presented left module on 2 generators and 1 relation over - sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] + sage: M1. = FPModule(A3, [0, 1], [[Sq(2), Sq(1)]]) + sage: M2 = FPModule(A3, (0, 1), [[Sq(2), Sq(1)]], names='m0,m1') + sage: M1 is M2 + True """ + if names is not None: + from sage.structure.category_object import normalize_names + names = normalize_names(-1, names) return super(FPModule, cls).__classcall__(cls, algebra=algebra, generator_degrees=tuple(generator_degrees), @@ -138,15 +142,11 @@ def __init__(self, algebra, generator_degrees, relations=(), names=None): sage: M = FPModule(A3, [0, 1], [[Sq(2), Sq(1)]]) sage: TestSuite(M).run() """ - self._generator_degrees = generator_degrees self._relations = relations - # if generator_degrees is [d_0, d_1, ...], then - # the generators are indexed by (0,d_0), (1,d_1), ... - keys = list(enumerate(generator_degrees)) - self._generator_keys = keys + self._generator_degrees = generator_degrees # The free module on the generators of the module. - generator_module = FreeGradedModule(algebra, generator_degrees, names) + generator_module = FreeGradedModule(algebra, generator_degrees, names=names) # Use the coefficients given for the relations and make module elements # from them. Filter out the zero elements, as they are redundant. rels = [v for v in [generator_module(r) for r in relations] if not v.is_zero()] @@ -160,15 +160,19 @@ def __init__(self, algebra, generator_degrees, relations=(), names=None): self.j = Hom(relations_module, generator_module)(rels) # Call the base class constructors. + keys = generator_module.basis().keys() cat = GradedModules(algebra).WithBasis().FinitelyPresented() IndexedGenerators.__init__(self, keys) Module.__init__(self, algebra, category=cat) + from sage.combinat.family import Family + self._spanning_set = Family(self._indices, self.monomial) + Element = FPElement def _free_module(self): """ - The free module of which this is a quotient + Return the free module of which ``self`` is a quotient. EXAMPLES:: @@ -176,10 +180,10 @@ def _free_module(self): sage: A = SteenrodAlgebra() sage: M. = FPModule(A, [0, 1], [[Sq(2), Sq(1)]]) sage: M.generators() - [x, y] + (x, y) sage: F = M._free_module() sage: F.generators() - [x, y] + (x, y) """ return self.j.codomain() @@ -241,7 +245,7 @@ def from_free_module_morphism(cls, morphism): sage: M.generator_degrees() (0,) sage: M.relations() - [Sq(2)*g_{0}] + (Sq(2)*G[0],) """ return cls(algebra=morphism.base_ring(), generator_degrees=morphism.codomain().generator_degrees(), @@ -250,7 +254,7 @@ def from_free_module_morphism(cls, morphism): def change_ring(self, algebra): r""" - Change the base ring of this module. + Change the base ring of ``self``. INPUT: @@ -283,7 +287,7 @@ def change_ring(self, algebra): return FPModule(algebra, self.generator_degrees(), relations) - def __contains__(self, x): + def __contains__(self, x): # Probably can be removed """ EXAMPLES:: @@ -297,7 +301,7 @@ def __contains__(self, x): sage: y in M False """ - return parent(x) == self + return parent(x) is self def _from_dict(self, d, coerce=False, remove_zeros=True): @@ -335,10 +339,8 @@ def _monomial(self, index): sage: from sage.modules.fp_graded.module import FPModule sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) - sage: M._monomial((0,0)) - g_{0} - sage: M._monomial((1,1)) - g_{1} + sage: M._monomial(0) + G[0] """ return self._from_dict({index: self.base_ring().one()}, remove_zeros=False) @@ -355,23 +357,35 @@ def monomial(self): sage: from sage.modules.fp_graded.module import FPModule sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) - sage: M.monomial((0,0)) - g_{0} - sage: M.monomial((1,1)) - g_{1} + sage: M.monomial(0) + G[0] + sage: M.monomial(1) + G[1] """ # Should use a real Map, as soon as combinatorial_classes are enumerated sets, and therefore parents from sage.categories.poor_man_map import PoorManMap return PoorManMap(self._monomial, domain=self._indices, codomain=self, name="Term map") + @cached_method + def zero(self): + r""" + Return the zero element. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FPModule + sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) + sage: M.zero() + 0 + """ + return self.element_class(self, {}) + + def _element_constructor_(self, x): r""" Construct any element of ``self``. - This function is used internally by the ()-method when creating - module elements, and should not be called by the user explicitly. - INPUT: - ``x`` -- a tuple of coefficients, an element of FPModule, or the @@ -408,20 +422,20 @@ def _element_constructor_(self, x): """ if isinstance(x, self.element_class): return x - ngens = len(self._generator_keys) - if ngens == 0: # the trivial module - return self._free_module().zero() + if not self._generator_degrees: # the trivial module + return self.zero() if not x: - x = [self.base_ring().zero()] * ngens - from sage.combinat.family import Family - B = Family(self._indices, self.monomial) + return self.zero() + ngens = len(self._generator_degrees) + B = self._spanning_set if isinstance(x, FreeGradedModuleElement): - if x.parent() == self._free_module(): + if x.parent() is self._free_module(): # x.parent() should have the same generator list as self. coeffs = x.monomial_coefficients() - return sum(coeffs[idx]*B[idx] for idx in coeffs) + return sum(coeffs[idx] * B[idx] for idx in coeffs) raise ValueError("element is not in this module") - return sum(c*B[b] for (c,b) in zip(x, self._generator_keys)) + return self._from_dict({b: c for (c,b) in zip(x, self._indices) if c}, + remove_zeros=False) def _repr_(self): @@ -443,7 +457,8 @@ def _repr_(self): mod 2 Steenrod algebra, milnor basis """ return "Finitely presented left module on %s generator%s and %s relation%s over %s"\ - %(len(self._free_module().generator_degrees()), "" if len(self._free_module().generator_degrees()) == 1 else "s", + %(len(self._free_module().generator_degrees()), + "" if len(self._free_module().generator_degrees()) == 1 else "s", len(self.j.values()), "" if len(self.j.values()) == 1 else "s", self.base_ring()) @@ -457,8 +472,8 @@ def _repr_term(self, m): sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) sage: M = FPModule(A, [0,2,4], [[Sq(4),Sq(2),0]]) - sage: M._repr_term((2,4)) - 'g_{4}' + sage: M._repr_term(4) + 'G[4]' """ return self._free_module()._repr_term(m) @@ -472,8 +487,8 @@ def _latex_term(self, m): sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) sage: M = FPModule(A, [0,2,4], [[Sq(4),Sq(2),0]]) - sage: M._latex_term((2,4)) - 'g_{4}' + sage: M._latex_term(4) + 'G_{4}' """ return self._free_module()._latex_term(m) @@ -540,10 +555,8 @@ def connectivity(self): def is_trivial(self): r""" - Decide if this module is isomorphic to the trivial module. - - OUTPUT: Returns ``True`` if the relations generate every non-zero - element of the module, and ``False`` otherwise. + Return ``True`` if ``self`` is isomorphic to the trivial module + and ``False`` otherwise. EXAMPLES:: @@ -635,16 +648,16 @@ def an_element(self, n=None): sage: M = FPModule(A2, [0,2,4], [[0, Sq(5), Sq(3)], [Sq(7), 0, Sq(2)*Sq(1)]]) sage: [M.an_element(i) for i in range(10)] - [g_{0}, - Sq(1)*g_{0}, - Sq(2)*g_{0} + g_{2}, - Sq(0,1)*g_{0} + Sq(1)*g_{2}, - Sq(1,1)*g_{0} + Sq(2)*g_{2} + g_{4}, - Sq(2,1)*g_{0} + Sq(0,1)*g_{2} + Sq(1)*g_{4}, - Sq(0,2)*g_{0} + Sq(1,1)*g_{2} + Sq(2)*g_{4}, - Sq(0,0,1)*g_{0} + Sq(2,1)*g_{2} + Sq(0,1)*g_{4}, - Sq(1,0,1)*g_{0} + Sq(6)*g_{2} + Sq(1,1)*g_{4}, - Sq(2,0,1)*g_{0} + Sq(4,1)*g_{2} + Sq(2,1)*g_{4}] + [G[0], + Sq(1)*G[0], + Sq(2)*G[0] + G[2], + Sq(0,1)*G[0] + Sq(1)*G[2], + Sq(1,1)*G[0] + Sq(2)*G[2] + G[4], + Sq(2,1)*G[0] + Sq(0,1)*G[2] + Sq(1)*G[4], + Sq(0,2)*G[0] + Sq(1,1)*G[2] + Sq(2)*G[4], + Sq(0,0,1)*G[0] + Sq(2,1)*G[2] + Sq(0,1)*G[4], + Sq(1,0,1)*G[0] + Sq(6)*G[2] + Sq(1,1)*G[4], + Sq(2,0,1)*G[0] + Sq(4,1)*G[2] + Sq(2,1)*G[4]] """ a_free_element = self._free_module().an_element(n) return self(a_free_element) @@ -679,32 +692,32 @@ def basis_elements(self, n, verbose=False): sage: M. = FPModule(A2, [0,2], [[Sq(4), Sq(2)], [0, Sq(6)]]) sage: M.basis_elements(4) - [Sq(1,1)*m0, Sq(4)*m0] + (Sq(1,1)*m0, Sq(4)*m0) sage: M.basis_elements(5) - [Sq(2,1)*m0, Sq(5)*m0, Sq(0,1)*m2] + (Sq(2,1)*m0, Sq(5)*m0, Sq(0,1)*m2) sage: M.basis_elements(25) - [] + () sage: M.basis_elements(0) - [m0] + (m0,) sage: M.basis_elements(2) - [Sq(2)*m0, m2] + (Sq(2)*m0, m2) TESTS:: sage: Z0 = FPModule(A2, []) sage: Z0.basis_elements(n=10) - [] + () sage: Z1 = FPModule(A2, [1], [[1]]) sage: Z1.basis_elements(n=10) - [] + () """ - return [self.element_from_coordinates(x, n) for - x in self.vector_presentation(n, verbose).basis()] + return tuple([self.element_from_coordinates(x, n) for + x in self.vector_presentation(n, verbose).basis()]) @cached_method @@ -719,7 +732,6 @@ def element_from_coordinates(self, coordinates, n): INPUT: - ``coordinates`` -- a vector of coordinates - - ``n`` -- the degree of the element to construct OUTPUT: @@ -736,7 +748,7 @@ def element_from_coordinates(self, coordinates, n): sage: M.vector_presentation(12).dimension() 3 sage: x = M.element_from_coordinates((0,1,0), 12); x - Sq(0,4)*g_{0} + Sq(0,4)*G[0] Applying the inverse function brings us back to the coordinate form:: @@ -748,7 +760,8 @@ def element_from_coordinates(self, coordinates, n): sage: M.element_from_coordinates((0,1,0,0), 12) Traceback (most recent call last): ... - ValueError: the given coordinate vector has incorrect length (4); it should have length 3 + ValueError: the given coordinate vector has incorrect length (4); + it should have length 3 .. SEEALSO:: @@ -786,7 +799,7 @@ def __getitem__(self, n): sage: M = FPModule(A, [0,2,4], [[Sq(4),Sq(2),0]]) sage: M[4] - [Sq(1,1)*g_{0}, Sq(4)*g_{0}, g_{4}] + (Sq(1,1)*G[0], Sq(4)*G[0], G[4]) .. SEEALSO:: @@ -864,7 +877,7 @@ def vector_presentation(self, n, verbose=False): R_n = F_n.subspace(spanning_set) # Return the quotient of the free part by the relations. - return F_n/R_n + return F_n / R_n def _Hom_(self, Y, category): @@ -919,17 +932,17 @@ def generators(self): sage: M = FPModule(A4, [0,0,2,3]) sage: M.generators() - [g_{0,0}, g_{0,1}, g_{2,0}, g_{3,0}] + (g_{0,0}, g_{0,1}, g_{2,0}, g_{3,0}) sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]], names='h') sage: N.generators() - [h_{0}, h_{1}] + (h[0], h[1]) sage: Z = FPModule(A4, []) sage: Z.generators() - [] + () """ - return [self.generator(i) for i in range(len(self.generator_degrees()))] + return tuple([self.generator(i) for i in range(len(self.generator_degrees()))]) gens = generators @@ -945,11 +958,11 @@ def generator(self, index): sage: M = FPModule(A4, [0,2,3]) sage: M.generator(0) - g_{0} + G[0] sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]], names='h') sage: N.generator(1) - h_{1} + h[1] """ return self(self._free_module().generator(index)) @@ -967,15 +980,15 @@ def relations(self): sage: M = FPModule(A4, [0,2,3]) sage: M.relations() - [] + () sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]]) sage: N.relations() - [Sq(2)*g_{0} + Sq(1)*g_{1}] + (Sq(2)*G[0] + Sq(1)*G[1],) sage: Z = FPModule(A4, []) sage: Z.relations() - [] + () """ return self.j.values() @@ -990,7 +1003,7 @@ def relation(self, index): sage: A4 = SteenrodAlgebra(2, profile=(4,3,2,1)) sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]]) sage: N.relation(0) - Sq(2)*g_{0} + Sq(1)*g_{1} + Sq(2)*G[0] + Sq(1)*G[1] """ return self.j.values()[index] @@ -1013,7 +1026,8 @@ def min_presentation(self, top_dim=None, verbose=False): sage: i = M.min_presentation() sage: M_min = i.domain() - sage: # i is an isomorphism between M_min and M: + ``i`` is an isomorphism between ``M_min`` and ``M``:: + sage: i.codomain() is M True sage: i.is_injective() @@ -1021,11 +1035,12 @@ def min_presentation(self, top_dim=None, verbose=False): sage: i.is_surjective() True - sage: # There are more relations in M than in M_min: + There are more relations in ``M`` than in ``M_min``:: + sage: M.relations() - [Sq(2)*g_{0} + Sq(1)*g_{1}, Sq(2)*g_{1}, Sq(3)*g_{0}] + (Sq(2)*G[0] + Sq(1)*G[1], Sq(2)*G[1], Sq(3)*G[0]) sage: M_min.relations() - [Sq(2)*g_{0} + Sq(1)*g_{1}, Sq(2)*g_{1}] + (Sq(2)*G[0] + Sq(1)*G[1], Sq(2)*G[1]) TESTS:: @@ -1063,14 +1078,14 @@ def suspension(self, t): sage: X.generator_degrees() (4,) sage: X.relations() - [Sq(1)*g_{4}] + (Sq(1)*G[4],) sage: M = FPModule(A, [2,3], [[Sq(2), Sq(1)], [0, Sq(2)]]) sage: Q = M.suspension(1) sage: Q.generator_degrees() (3, 4) sage: Q.relations() - [Sq(2)*g_{3} + Sq(1)*g_{4}, Sq(2)*g_{4}] + (Sq(2)*G[3] + Sq(1)*G[4], Sq(2)*G[4]) sage: Q = M.suspension(-3) sage: Q.generator_degrees() (-1, 0) @@ -1079,7 +1094,7 @@ def suspension(self, t): (2, 3) """ return FPModule(algebra=self.base_ring(), - generator_degrees=tuple([g + t for g in self.generator_degrees()]), + generator_degrees=tuple([g + t for g in self._generator_degrees]), relations=self._relations) @@ -1117,7 +1132,7 @@ def submodule_inclusion(self, spanning_elements): sage: i.domain().generator_degrees() (0,) sage: i.domain().relations() - [Sq(3)*g_{0}] + (Sq(3)*G[0],) """ # Create the free graded module on the set of spanning elements. degs = [x.degree() for x in spanning_elements] @@ -1134,7 +1149,6 @@ def resolution(self, k, top_dim=None, verbose=False): INPUT: - ``k`` -- an non-negative integer - - ``verbose`` -- (default: ``False``) a boolean to control if log messages should be emitted @@ -1184,17 +1198,17 @@ def resolution(self, k, top_dim=None, verbose=False): 5 sage: res [Module homomorphism of degree 0 defined by sending the generators - [g_{0}, g_{1}] + [G[0], G[1]] to - (g_{0}, g_{1}), + (G[0], G[1]), Module homomorphism of degree 0 defined by sending the generators [g_{2}] to - (Sq(2)*g_{0} + Sq(1)*g_{1},), + (Sq(2)*G[0] + Sq(1)*G[1],), Module homomorphism of degree 0 defined by sending the generators [g_{8}] to - (Sq(3,1)*g_{2},), + (Sq(3,1)*G[2],), Module homomorphism of degree 0 defined by sending the generators [g_{9}, g_{10}] to @@ -1217,7 +1231,7 @@ def _print_progress(i, k): # Epsilon: F_0 -> M F_0 = FPModule.from_free_module(self._free_module()) - epsilon = Hom(F_0, self)(tuple(self.generators())) + epsilon = Hom(F_0, self)(self.generators()) ret_complex.append(epsilon) if k == 0: diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py index 66f90dc926a..3fd29252d12 100755 --- a/src/sage/modules/fp_graded/morphism.py +++ b/src/sage/modules/fp_graded/morphism.py @@ -170,7 +170,7 @@ class FPModuleMorphism(Morphism): sage: w = Hom(Q, F)( (F((1, 0)), F((0, 1))) ) Traceback (most recent call last): ... - ValueError: relation Sq(6)*g_{2} + Sq(5)*g_{3} is not sent to zero + ValueError: relation Sq(6)*G[2] + Sq(5)*g_{3} is not sent to zero """ def __init__(self, parent, values): r""" @@ -198,7 +198,7 @@ def __init__(self, parent, values): Homspace = Hom(parent.domain().j.codomain(), parent.codomain().j.codomain()) self.free_morphism = Homspace([v.lift_to_free() for v in values]) - self._values = values + self._values = tuple(values) # Call the base class constructor. Morphism.__init__(self, parent) @@ -229,9 +229,9 @@ def change_ring(self, algebra): sage: f = Hom(M,N)([A2.Sq(3)*N.generator(0)]); f Module homomorphism of degree 3 defined by sending the generators - [g_{0}] + [G[0]] to - [Sq(3)*g_{0}] + [Sq(3)*G[0]] sage: f.base_ring() sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] @@ -314,10 +314,10 @@ def values(self): sage: f = homspace(values) sage: f.values() - [Sq(5)*g_{2}, Sq(3,1)*g_{2}] + (Sq(5)*G[2], Sq(3,1)*G[2]) sage: homspace.zero().values() - [0, 0] + (0, 0) """ return self._values @@ -415,9 +415,9 @@ def __neg__(self): sage: f = homspace(values) sage: f_inverse = f.__neg__(); f_inverse Module homomorphism of degree 7 defined by sending the generators - [g_{0}, g_{1}] + [G[0], g_{1}] to - [Sq(5)*g_{2}, Sq(3,1)*g_{2}] + [Sq(5)*G[2], Sq(3,1)*G[2]] sage: (f + f_inverse).is_zero() True """ @@ -439,17 +439,17 @@ def __sub__(self, g): sage: g = Hom(M, N)( [Sq(0,1)*N.generator(0)] ) sage: f.__sub__(g) Module homomorphism of degree 3 defined by sending the generators - [g_{0}] + [G[0]] to - [(Sq(0,1)+Sq(3))*g_{0}] + [(Sq(0,1)+Sq(3))*G[0]] sage: f = Hom(M, N)( [Sq(4)*N.generator(0)] ) # the zero map sage: g = Hom(M, N)( [Sq(1,1)*N.generator(0)] ) sage: f.__sub__(g) Module homomorphism of degree 4 defined by sending the generators - [g_{0}] + [G[0]] to - [Sq(1,1)*g_{0}] + [Sq(1,1)*G[0]] """ return self.__add__(g.__neg__()) @@ -468,9 +468,9 @@ def __mul__(self, g): sage: g = Hom(N, M)( [Sq(2,2)*M.generator(0)] ) sage: fg = f.__mul__(g); fg Module homomorphism of degree 10 defined by sending the generators - [g_{0}] + [G[0]] to - [(Sq(0,1,1)+Sq(1,3)+Sq(3,0,1))*g_{0}] + [(Sq(0,1,1)+Sq(1,3)+Sq(3,0,1))*G[0]] sage: fg.is_endomorphism() True @@ -572,10 +572,10 @@ def __call__(self, x): sage: f = Hom(M, N)(values) sage: f.__call__(M.generator(0)) - Sq(5)*g_{2} + Sq(5)*G[2] sage: f.__call__(M.generator(1)) - Sq(3,1)*g_{2} + Sq(3,1)*G[2] """ if x.parent() != self.domain(): raise ValueError('cannot evaluate morphism on element not in domain') @@ -594,21 +594,24 @@ def _repr_(self): sage: M = FPModule(A, [0,1], [[Sq(2), Sq(1)]]) sage: N = FPModule(A, [2], [[Sq(4)]]) sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] - sage: Hom(M, N)(values)._repr_() - 'Module homomorphism of degree 7 defined by sending the generators\n - [g_{0}, g_{1}]\nto\n [Sq(5)*g_{2}, Sq(3,1)*g_{2}]' - sage: Hom(M, N).zero()._repr_() - 'The trivial homomorphism' - sage: Hom(M, M).identity()._repr_() - 'The identity homomorphism' + sage: Hom(M, N)(values) + Module homomorphism of degree 7 defined by sending the generators + [G[0], g_{1}] + to + [Sq(5)*G[2], Sq(3,1)*G[2]] + sage: Hom(M, N).zero() + The trivial homomorphism + sage: Hom(M, M).identity() + The identity homomorphism """ if self.is_zero(): return "The trivial homomorphism" elif self.is_identity(): return "The identity homomorphism" else: - return "Module homomorphism of degree %d defined by sending "\ - "the generators\n %s\nto\n %s" % (self.degree(), self.domain().generators(), self._values) + return ("Module homomorphism of degree %d defined by sending " + "the generators\n %s\nto\n %s" + % (self.degree(), self.domain().generators(), self._values)) @cached_method @@ -739,9 +742,9 @@ def solve(self, x): sage: N = FPModule(A, [0], [[Sq(2,2)]]) sage: f = Hom(M, N)( [Sq(2)*N.generator(0)] ) sage: y = Sq(1,1)*N.generator(0); y - Sq(1,1)*g_{0} + Sq(1,1)*G[0] sage: x = f.solve(y); x - Sq(2)*g_{0} + Sq(2)*G[0] sage: y == f(x) True @@ -841,9 +844,9 @@ def lift(self, f, verbose=False): True sage: f_ Module homomorphism of degree 1 defined by sending the generators - [g_{0}] + [G[0]] to - [Sq(1)*g_{0}] + [Sq(1)*G[0]] A split projection:: @@ -858,7 +861,7 @@ def lift(self, f, verbose=False): sage: id = Hom(HZ,HZ).identity() sage: j = id.lift(q); j Module homomorphism of degree 0 defined by sending the generators - [g_{0}] + [G[0]] to [g_{0,1}] sage: q*j @@ -872,9 +875,9 @@ def lift(self, f, verbose=False): sage: im = f.image(top_dim=10) sage: f.lift(im) Module homomorphism of degree 2 defined by sending the generators - [g_{0}] + [G[0]] to - [g_{2}] + [G[2]] When a lift cannot be found, the ``None`` value is returned. By setting the verbose argument to ``True``, an explanation of why @@ -924,7 +927,7 @@ def lift(self, f, verbose=False): sage: k = f.kernel_inclusion() # long time sage: f.lift(k) # long time Module homomorphism of degree 21 defined by sending the generators - [g_{0}] + [G[0]] to [Sq(1)*g_{20}] @@ -1081,7 +1084,7 @@ def split(self, verbose=False): sage: p = Hom(M, N)([N.generator(0), N.generator(0)]) sage: s = p.split(); s Module homomorphism of degree 0 defined by sending the generators - [g_{0}] + [G[0]] to [g_{0,1}] sage: # Verify that `s` is a splitting: @@ -1230,9 +1233,9 @@ def cokernel_projection(self): sage: r = Hom(F, M)([A1.Sq(1)*M.generator(0)]) sage: co = r.cokernel_projection(); co Module homomorphism of degree 0 defined by sending the generators - [g_{0}] + [G[0]] to - [g_{0}] + [G[0]] sage: co.domain().is_trivial() False @@ -1319,11 +1322,11 @@ def kernel_inclusion(self, top_dim=None, verbose=False): j1 = j0._resolve_kernel(top_dim, verbose) # Create a module isomorphic to the ker(self). - K = j1.to_fp_module() + K = j1.fp_module() # Return an injection of K into the domain of self such that # its image equals ker(self). - return Hom(K, j0.codomain())(j0.values()) + return Hom(K, j0.codomain())(j0._values) def image(self, top_dim=None, verbose=False): @@ -1359,7 +1362,7 @@ def image(self, top_dim=None, verbose=False): Module homomorphism of degree 0 defined by sending the generators [g_{3}] to - (Sq(1)*g_{2} + g_{3},) + (Sq(1)*G[2] + g_{3},) sage: M = FPModule(A3, [0,7], [[Sq(1), 0], [Sq(2), 0], [Sq(4), 0], [Sq(8), Sq(1)], [0, Sq(7)], [0, Sq(0,1,1)+Sq(4,2)]]) sage: F2 = FPModule(A3, [0], [[Sq(1)], [Sq(2)], [Sq(4)], [Sq(8)], [Sq(15)]]) @@ -1378,7 +1381,7 @@ def image(self, top_dim=None, verbose=False): sage: K.domain().generator_degrees() (0,) sage: K.domain().relations() - [Sq(1)*g_{0}, Sq(2)*g_{0}, Sq(4)*g_{0}, Sq(8)*g_{0}] + [Sq(1)*G[0], Sq(2)*G[0], Sq(4)*G[0], Sq(8)*G[0]] sage: K.domain().is_trivial() False @@ -1391,11 +1394,11 @@ def image(self, top_dim=None, verbose=False): j1 = j0._resolve_kernel(top_dim, verbose) # Create a module isomorphic to the im(self). - I = j1.to_fp_module() + I = j1.fp_module() # Return an injection of I into the codomain of self such that # its image equals im(self) - return Hom(I, j0.codomain())(j0.values()) + return Hom(I, j0.codomain())(j0._values) def is_injective(self, top_dim=None, verbose=False): @@ -1484,7 +1487,7 @@ def _resolve_kernel(self, top_dim=None, verbose=False): sage: A = SteenrodAlgebra(2) sage: F = FPModule(A, [0,0]) sage: L = FPModule(A, [0,0], [[Sq(3),Sq(0,1)], [0,Sq(2)]]) - sage: f = Hom(F, L)([L([Sq(2),0]), L([0, Sq(2)])]) + sage: f = Hom(F, L)([L([Sq(2), 0]), L([0, Sq(2)])]) sage: f._resolve_kernel() Traceback (most recent call last): ... @@ -1516,7 +1519,7 @@ def _resolve_kernel(self, top_dim=None, verbose=False): if self.is_zero(): # Epsilon: F_0 -> M M = self.domain() - F_0 = self.domain().j.codomain().to_fp_module() + F_0 = self.domain().j.codomain().as_fp_module() epsilon = Hom(F_0, M)(tuple(M.generators())) return epsilon @@ -1592,7 +1595,7 @@ def _resolve_kernel(self, top_dim=None, verbose=False): # Create a new homomorphism which is surjective onto the kernel # in all degrees less than, and including `n`. - j = Hom(F_, self.domain()) (j.values() + new_values) + j = Hom(F_, self.domain()) (j._values + new_values) if verbose: print('.') @@ -1634,13 +1637,13 @@ def _resolve_image(self, top_dim=None, verbose=False): ValueError: a top dimension must be specified for this calculation to terminate sage: f._resolve_image(top_dim=20) Module homomorphism of degree 0 defined by sending the generators - [g_{2}] + [G[2]] to (Sq(2)*g_{0,0},) sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) sage: f.change_ring(A3)._resolve_image() # long time Module homomorphism of degree 0 defined by sending the generators - [g_{2}] + [G[2]] to (Sq(2)*g_{0,0},) """ @@ -1672,7 +1675,7 @@ def _resolve_image(self, top_dim=None, verbose=False): print ('The homomorphism is trivial, so there is nothing to resolve.') return j - degree_values = [0] + [v.degree() for v in self.values() if v] + degree_values = [0] + [v.degree() for v in self._values if v] limit = PlusInfinity() if not self.base_ring().is_finite() else\ (self.base_ring().top_class().degree() + max(degree_values)) @@ -1728,13 +1731,13 @@ def _resolve_image(self, top_dim=None, verbose=False): # Create a new homomorphism which is surjective onto the image # in all degrees less than, and including `n`. - j = Hom(F_, self.codomain()) (j.values() + new_values) + j = Hom(F_, self.codomain()) (j._values + new_values) if verbose: print('.') return j - def to_fp_module(self): + def fp_module(self): r""" Create a finitely presented module from ``self``. @@ -1751,17 +1754,17 @@ def to_fp_module(self): sage: F2 = FPModule(A, (0,)) sage: v = F2([Sq(2)]) sage: pres = Hom(F1, F2)([v]) - sage: M = pres.to_fp_module(); M + sage: M = pres.fp_module(); M Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis sage: M.generator_degrees() (0,) sage: M.relations() - [Sq(2)*g_{0}] + [Sq(2)*G[0]] sage: F3 = FPModule(A, (0,), [[Sq(4)]]) sage: pres = Hom(F1, F3)([v]) - sage: pres.to_fp_module() + sage: pres.fp_module() Traceback (most recent call last): ... ValueError: this is not a morphism between free modules @@ -1771,5 +1774,5 @@ def to_fp_module(self): from .module import FPModule return FPModule(algebra=self.base_ring(), generator_degrees=self.codomain().generator_degrees(), - relations=tuple([r.coefficients() for r in self.values()])) + relations=tuple([r.coefficients() for r in self._values])) diff --git a/src/sage/structure/indexed_generators.py b/src/sage/structure/indexed_generators.py index 9d274e722a8..ab4d68ed84c 100644 --- a/src/sage/structure/indexed_generators.py +++ b/src/sage/structure/indexed_generators.py @@ -28,12 +28,20 @@ class IndexedGenerators(object): - ``latex_prefix`` -- string or ``None``, prefix used in the `\LaTeX` representation of elements (optional, default ``None``). If this is anything except the empty string, it prints the index as a - subscript. If this is None, it uses the setting for ``prefix``, + subscript. If this is ``None``, it uses the setting for ``prefix``, so if ``prefix`` is set to "B", then a monomial indexed by 'a' would be printed as ``B_{a}``. If this is the empty string, then don't print monomials as subscripts: the monomial indexed by 'a' would be printed as ``a``, or as ``[a]`` if ``latex_bracket`` is - True. + ``True``. + + - ``names`` -- dict with strings as values or list of strings (optional): + a mapping from the indices of the generators to strings giving the + generators explicit names. This is used instead of the print options + ``prefix`` and ``bracket`` when ``names`` is specified. + + - ``latex_names`` -- dict with strings as values or list of strings + (optional): same as ``names`` except using the `\LaTeX` representation - ``bracket`` -- ``None``, bool, string, or list or tuple of strings (optional, default ``None``): if ``None``, use the value of the @@ -135,9 +143,11 @@ def __init__(self, indices, prefix="x", **kwds): # compatibility, declared to be True by default, needs to be # overridden explicitly). self._print_options = {'prefix': prefix, + 'names': None, 'bracket': None, 'latex_bracket': False, 'latex_prefix': None, + 'latex_names': None, 'scalar_mult': "*", 'latex_scalar_mult': None, 'tensor_symbol': None, @@ -193,6 +203,8 @@ def print_options(self, **kwds): - ``prefix`` - ``latex_prefix`` + - ``names`` + - ``latex_names`` - ``bracket`` - ``latex_bracket`` - ``scalar_mult`` @@ -222,8 +234,9 @@ def print_options(self, **kwds): sage: sorted(F.print_options().items()) [('bracket', '('), - ('latex_bracket', False), ('latex_prefix', None), - ('latex_scalar_mult', None), ('prefix', 'x'), + ('latex_bracket', False), ('latex_names', None), + ('latex_prefix', None), ('latex_scalar_mult', None), + ('names', None), ('prefix', 'x'), ('scalar_mult', '*'), ('sorting_key', at ...>), ('sorting_reverse', False), ('string_quotes', True), @@ -244,6 +257,67 @@ def print_options(self, **kwds): _repr_option_bracket = True + def _parse_names(self, m, use_latex): + """ + Return the name corresponding to ``m`` if it exists, + otherwise return ``None``. + + EXAMPLES:: + + sage: F = CombinatorialFreeModule(ZZ, [1,2,3], names='a,b,c', + ....: latex_names='x,y,z') + sage: F._parse_names(1, False) + 'a' + sage: F._parse_names(1, True) + 'x' + + sage: F.print_options(latex_names=None) + sage: F._parse_names(1, True) + 'a' + + sage: F.print_options(latex_names={1:'x', 2:'y'}, names=None) + sage: F._parse_names(1, False) is None + True + sage: F._parse_names(1, True) + 'x' + sage: F._parse_names(3, True) is None + True + + sage: F.print_options(names={1:'a', 3:'c'}, latex_names=None) + sage: F._parse_names(1, False) + 'a' + sage: F._parse_names(1, True) + 'a' + sage: F._parse_names(2, False) is None + True + sage: F._parse_names(2, True) is None + True + """ + names = self._print_options.get('names', None) + if use_latex: + latex_names = self._print_options.get('latex_names', None) + if latex_names is not None: + names = latex_names + + if names is not None: + if isinstance(names, dict): + try: + return names[m] + except KeyError: + return None + else: # treat it like a list + try: + i = self._indices.rank(m) + except (AttributeError, TypeError, KeyError, ValueError): + return None + if i >= len(names): + return None + try: + return names[i] + except (AttributeError, TypeError, KeyError, ValueError): + return None + return None + def _repr_generator(self, m): """ Return a string representing the generator indexed by ``m``. @@ -254,6 +328,7 @@ def _repr_generator(self, m): - ``prefix`` - ``bracket`` - ``scalar_mult`` + - ``names`` Alternatively, one can use the :meth:`print_options` method to achieve the same effect. To modify the bracket setting, @@ -306,7 +381,14 @@ def _repr_generator(self, m): sage: e = F.basis() sage: e[('a','b')] + 2*e[('c','d')] # indirect doctest B[('a', 'b')] + 2*B[('c', 'd')] + + sage: F. = CombinatorialFreeModule(QQ) + sage: a + 2*b + a + 2*b """ + ret = self._parse_names(m, False) + if ret is not None: + return ret bracket = self._print_options.get('bracket', None) bracket_d = {"{": "}", "[": "]", "(": ")"} if bracket is None: @@ -352,8 +434,16 @@ def _ascii_art_generator(self, m): ## #### sage: Partitions.options._reset() + + sage: F. = CombinatorialFreeModule(QQ) + sage: ascii_art(a + 2*b) + a + 2*b """ from sage.typeset.ascii_art import AsciiArt, ascii_art + ret = self._parse_names(m, False) + if ret is not None: + return ascii_art(ret) + pref = AsciiArt([self.prefix()]) r = pref * (AsciiArt([" " * len(pref)]) + ascii_art(m)) r._baseline = r._h - 1 @@ -382,8 +472,16 @@ def _unicode_art_generator(self, m): └┼┼┬┬┐ └┴┴┴┘ sage: Partitions.options._reset() + + sage: F. = CombinatorialFreeModule(QQ) + sage: unicode_art(a + 2*b) + a + 2*b """ from sage.typeset.unicode_art import UnicodeArt, unicode_art + ret = self._parse_names(m, False) + if ret is not None: + return unicode_art(ret) + pref = UnicodeArt([self.prefix()]) r = pref * (UnicodeArt([" " * len(pref)]) + unicode_art(m)) r._baseline = r._h - 1 @@ -399,6 +497,8 @@ def _latex_generator(self, m): - ``prefix`` - ``latex_prefix`` - ``latex_bracket`` + - ``names`` + - ``latex_names`` (Alternatively, one can use the :meth:`print_options` method to achieve the same effect.) @@ -446,9 +546,17 @@ def _latex_generator(self, m): sage: e = F.basis() sage: latex(2*e[(0,1,2)]) # indirect doctest 2\left(0, 1, 2\right) + + sage: F. = CombinatorialFreeModule(QQ, latex_names='x,y,z') + sage: latex(a + 2*b) + x + 2y """ from sage.misc.latex import latex + ret = self._parse_names(m, True) + if ret is not None: + return ret + s = latex(m) if s.find('\\text{\\textt') != -1: # m contains "non-LaTeXed" strings, use string representation @@ -557,7 +665,7 @@ def parse_indices_names(names, index_set, prefix, kwds=None): sage: parse_indices_names('x,y,z', None, None, d) (('x', 'y', 'z'), {'x', 'y', 'z'}, '') sage: d - {'bracket': False, 'string_quotes': False} + {'string_quotes': False} sage: d = {} sage: parse_indices_names(None, ZZ, None, d) (None, Integer Ring, None) @@ -585,7 +693,6 @@ def parse_indices_names(names, index_set, prefix, kwds=None): if kwds is None: kwds = {} kwds.setdefault('string_quotes', False) - kwds.setdefault('bracket', False) names, index_set = standardize_names_index_set(names, index_set, -1) From 51191fe56dfaf5d721e6d5025e58c92804cafec1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 9 Jan 2022 23:00:51 -0800 Subject: [PATCH 100/253] .github/workflows/tox.yml (local-macos): Fix filtering of experimental packages --- .github/workflows/tox.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tox.yml b/.github/workflows/tox.yml index 67de9c01593..1d7623b7f7c 100644 --- a/.github/workflows/tox.yml +++ b/.github/workflows/tox.yml @@ -159,7 +159,7 @@ jobs: 2-experimental*) export TARGETS_PRE="build/make/Makefile" TARGETS="build/make/Makefile" targets_pattern="${{ matrix.stage }}" targets_pattern="${targets_pattern#2-experimental-}" - export TARGETS_OPTIONAL=$( echo $(export PATH=build/bin:$PATH && sage-package list :experimental: --has-file spkg-install.in && sage-package list :experimental: --has-file spkg-install && sage-package list :experimental: --has-file requirements.txt | grep -v ^_ | grep -v database_stein_watkins\\$ | grep -v polytopes_db_4d | grep -v cplex | grep -v gurobi | grep "^[$targets_pattern]" ) ) + export TARGETS_OPTIONAL=$( echo $(export PATH=build/bin:$PATH && (sage-package list :experimental: --has-file spkg-install.in && sage-package list :experimental: --has-file spkg-install && sage-package list :experimental: --has-file requirements.txt) | grep -v ^_ | grep -v database_stein_watkins\\$ | grep -v polytopes_db_4d | grep -v cplex | grep -v gurobi | grep "^[$targets_pattern]" ) ) ;; esac MAKE="make -j12" tox -e $TOX_ENV -- SAGE_NUM_THREADS=4 $TARGETS From 12f88cfaafdd85b85f4ac117793cc4a2616476cc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 9 Jan 2022 23:04:42 -0800 Subject: [PATCH 101/253] .github/workflows/tox.yml (local-macos): Group optional/experimental package builds into fewer jobs --- .github/workflows/tox.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tox.yml b/.github/workflows/tox.yml index 1d7623b7f7c..872f00bb715 100644 --- a/.github/workflows/tox.yml +++ b/.github/workflows/tox.yml @@ -109,7 +109,7 @@ jobs: strategy: fail-fast: false matrix: - stage: ["1", "2", "2-optional-0-g", "2-optional-h-o", "2-optional-p", "2-optional-q-z", "2-experimental-0-g", "2-experimental-h-o", "2-experimental-p", "2-experimental-q-z"] + stage: ["1", "2", "2-optional-0-o", "2-optional-p-z", "2-experimental-0-o", "2-experimental-p-z"] # python3_xcode is only accepted if enough packages are available from the system # --> to test "minimal", we would need https://trac.sagemath.org/ticket/30949 tox_env: [homebrew-macos-usrlocal-minimal, homebrew-macos-usrlocal-standard, homebrew-macos-usrlocal-maximal, homebrew-macos-usrlocal-python3_xcode-standard, conda-forge-macos-minimal, conda-forge-macos-standard, conda-forge-macos-maximal] From 208b2c073beb5669478e94f2581e61560f145c18 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Sun, 9 Jan 2022 17:34:01 +0800 Subject: [PATCH 102/253] elliptic-curve points: use PARI for .discrete_log() and .weil_pairing() This yields huge speedups. --- src/sage/schemes/elliptic_curves/ell_point.py | 147 ++++++++++++++---- 1 file changed, 114 insertions(+), 33 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_point.py b/src/sage/schemes/elliptic_curves/ell_point.py index dc3e63bedf1..9ef37f9906b 100644 --- a/src/sage/schemes/elliptic_curves/ell_point.py +++ b/src/sage/schemes/elliptic_curves/ell_point.py @@ -1515,20 +1515,24 @@ def _miller_(self, Q, n): t = 1/(t*vee) return t - def weil_pairing(self, Q, n): + def weil_pairing(self, Q, n, algorithm='pari'): r""" - Compute the Weil pairing of self and `Q` using Miller's algorithm. + Compute the Weil pairing of this point with another point `Q` + on the same curve. INPUT: - - ``Q`` -- a point on self.curve(). + - ``Q`` -- another point on the same curve as ``self``. - - ``n`` -- an integer `n` such that `nP = nQ = (0:1:0)` where - `P` = self. + - ``n`` -- an integer `n` such that `nP = nQ = (0:1:0)`, where + `P` is ``self``. + + - ``algorithm`` (default: ``pari``) -- choices are ``pari`` + and ``sage``. PARI is usually significantly faster. OUTPUT: - An `n`'th root of unity in the base field self.curve().base_field() + An `n`'th root of unity in the base field of the curve. EXAMPLES:: @@ -1548,7 +1552,7 @@ def weil_pairing(self, Q, n): sage: Px.weil_pairing(O,41) == Fx(1) True - An error is raised if either point is not n-torsion:: + An error is raised if either point is not `n`-torsion:: sage: Px.weil_pairing(O,40) Traceback (most recent call last): @@ -1575,26 +1579,57 @@ def weil_pairing(self, Q, n): sage: Q.weil_pairing(P,5) # long time zeta5^3 + TESTS: + + Check that the original Sage implementation still works:: + + sage: GF(65537^2).inject_variables() + Defining z2 + sage: E = EllipticCurve(GF(65537^2), [0,1]) + sage: P = E(22, 28891) + sage: Q = E(-93, 40438*z2 + 31573) + sage: P.weil_pairing(Q, 7282, algorithm='sage') + 19937*z2 + 65384 + + Passing an unknown ``algorithm=`` argument should fail:: + + sage: P.weil_pairing(Q, 7282, algorithm='_invalid_') + Traceback (most recent call last): + ... + ValueError: unknown algorithm + ALGORITHM: - Implemented using Proposition 8 in [Mil2004]_. The value 1 is - returned for linearly dependent input points. This condition - is caught via a DivisionByZeroError, since the use of a - discrete logarithm test for linear dependence, is much too slow - for large `n`. + - For ``algorithm='pari'``: :pari:`ellweilpairing`. + + - For ``algorithm='sage'``: + Implemented using Proposition 8 in [Mil2004]_. The value 1 is + returned for linearly dependent input points. This condition + is caught via a DivisionByZeroError, since the use of a + discrete logarithm test for linear dependence is much too slow + for large `n`. AUTHOR: - David Hansen (2009-01-25) + - Lorenz Panny (2022): ``algorithm='pari'`` """ P = self E = P.curve() - if not Q.curve() is E: + if Q.curve() is not E: raise ValueError("points must both be on the same curve") + if algorithm == 'pari': + if pari.ellmul(E,P,n) != [0] or pari.ellmul(E,Q,n) != [0]: + raise ValueError("points must both be n-torsion") + return E.base_field()(pari.ellweilpairing(E, P, Q, n)) + + if algorithm != 'sage': + raise ValueError('unknown algorithm') + # Test if P, Q are both in E[n] - if not ((n*P).is_zero() and (n*Q).is_zero()): + if n*P or n*Q: raise ValueError("points must both be n-torsion") one = E.base_field().one() @@ -3440,27 +3475,44 @@ def _magma_init_(self, magma): def discrete_log(self, Q, ord=None): r""" - Returns discrete log of `Q` with respect to `P` =self. + Returns the discrete logarithm of `Q` to base `P` = ``self``, + that is, an integer `x` such that `xP = Q`. - INPUT: + A :class:`ValueError` is raised if there is no solution. - - ``Q`` (point) -- another point on the same curve as self. + ALGORITHM: - - ``ord`` (integer or ``None`` (default)) -- the order of self. + To compute the actual logarithm, :pari:`elllog` is called. - OUTPUT: + However, ``elllog()`` does not guarantee termination if `Q` + is not a multiple of `P`, so we first need to check subgroup + membership. This is done as follows: - (integer) -- The discrete log of `Q` with respect to `P`, which is an - integer `m` with `0\le m okay + elif self.weil_pairing(Q, n) != 1: + raise ValueError('ECDLog problem has no solution (non-trivial Weil pairing)') + return ZZ(pari.elllog(self.curve(), Q, self, n)) def has_finite_order(self): r""" From a9cd12fad15b5f084af0b85a68f38a29e5911a5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 10 Jan 2022 14:29:42 +0100 Subject: [PATCH 103/253] remove doctest handling of long L suffix --- src/sage/doctest/parsing.py | 70 ++++++++++++------------------------- 1 file changed, 23 insertions(+), 47 deletions(-) diff --git a/src/sage/doctest/parsing.py b/src/sage/doctest/parsing.py index e90235bdacc..c4e45396088 100644 --- a/src/sage/doctest/parsing.py +++ b/src/sage/doctest/parsing.py @@ -97,33 +97,11 @@ def fake_RIFtol(*args): _RIFtol = RealIntervalField(1044) return _RIFtol(*args) + # This is the correct pattern to match ISO/IEC 6429 ANSI escape sequences: -# ansi_escape_sequence = re.compile(r'(\x1b[@-Z\\-~]|\x1b\[.*?[@-~]|\x9b.*?[@-~])') -_long_repr_re = re.compile(r'([+-]?[0-9]+)[lL]') -def normalize_long_repr(s): - """ - Simple conversion from Python 2 representation of ``long`` ints (that - is, integers with the ``L``) suffix, to the Python 3 representation - (same number, without the suffix, since Python 3 doesn't have a - distinct ``long`` type). - - Note: This just uses a simple regular expression that can't distinguish - representations of long objects from strings containing a long repr. - - EXAMPLES:: - - sage: from sage.doctest.parsing import normalize_long_repr - sage: normalize_long_repr('10L') - '10' - sage: normalize_long_repr('[10L, -10L, +10L, "ALL"]') - '[10, -10, +10, "ALL"]' - """ - return _long_repr_re.sub(lambda m: m.group(1), s) - - # Collection of fixups applied in the SageOutputChecker. Each element in this # this list a pair of functions applied to the actual test output ('g' for # "got") and the expected test output ('w' for "wanted"). The first function @@ -132,12 +110,7 @@ def normalize_long_repr(s): # fixup, which is applied if the test function passes. In most fixups only one # of the expected or received outputs are normalized, depending on the # application. -# For example, on Python 3 we strip all u prefixes from unicode strings in the -# expected output, because we never expect to see those on Python 3. -_repr_fixups = [ - (lambda g, w: 'L' in w or 'l' in w, - lambda g, w: (g, normalize_long_repr(w))) -] +_repr_fixups = [] def parse_optional_tags(string): @@ -193,8 +166,8 @@ def parse_optional_tags(string): first_line = safe.split('\n', 1)[0] if '#' not in first_line: return set() - comment = first_line[first_line.find('#')+1:] - comment = comment[comment.index('(')+1 : comment.rindex(')')] + comment = first_line[first_line.find('#') + 1:] + comment = comment[comment.index('(') + 1: comment.rindex(')')] # strip_string_literals replaces comments comment = "#" + (literals[comment]).lower() @@ -202,7 +175,7 @@ def parse_optional_tags(string): for m in optional_regex.finditer(comment): cmd = m.group(1) if cmd == 'known bug': - tags.append('bug') # so that such tests will be run by sage -t ... -only-optional=bug + tags.append('bug') # so that such tests will be run by sage -t ... -only-optional=bug elif cmd: tags.append(cmd) else: @@ -243,8 +216,8 @@ def parse_tolerance(source, want): first_line = safe.split('\n', 1)[0] if '#' not in first_line: return want - comment = first_line[first_line.find('#')+1:] - comment = comment[comment.index('(')+1 : comment.rindex(')')] + comment = first_line[first_line.find('#') + 1:] + comment = comment[comment.index('(') + 1: comment.rindex(')')] # strip_string_literals replaces comments comment = literals[comment] if random_marker.search(comment): @@ -301,6 +274,7 @@ def get_source(example): """ return getattr(example, 'sage_source', example.source) + def reduce_hex(fingerprints): """ Return a symmetric function of the arguments as hex strings. @@ -346,6 +320,7 @@ class MarkedOutput(str): rel_tol = 0 abs_tol = 0 tol = 0 + def update(self, **kwds): """ EXAMPLES:: @@ -654,14 +629,14 @@ def parse(self, string, *args): # doctest system. m = backslash_replacer.search(string) while m is not None: - next_prompt = find_sage_prompt.search(string,m.end()) + next_prompt = find_sage_prompt.search(string, m.end()) g = m.groups() if next_prompt: future = string[m.end():next_prompt.start()] + '\n' + string[next_prompt.start():] else: future = string[m.end():] string = string[:m.start()] + g[0] + "sage:" + g[1] + future - m = backslash_replacer.search(string,m.start()) + m = backslash_replacer.search(string, m.start()) replace_ellipsis = not python_prompt.search(string) if replace_ellipsis: @@ -689,7 +664,7 @@ def parse(self, string, *args): continue if self.optional_tags is not True: - extra = optional_tags - self.optional_tags # set difference + extra = optional_tags - self.optional_tags # set difference if extra: if not available_software.issuperset(extra): continue @@ -709,6 +684,7 @@ def parse(self, string, *args): filtered.append(item) return filtered + class SageOutputChecker(doctest.OutputChecker): r""" A modification of the doctest OutputChecker that can check @@ -764,9 +740,8 @@ def human_readable(match): ansi_escape = match.group(1) assert len(ansi_escape) >= 2 if len(ansi_escape) == 2: - return '' - else: - return '' + return '' + return '' return ansi_escape_sequence.subn(human_readable, string)[0] def add_tolerance(self, wantval, want): @@ -811,13 +786,13 @@ def add_tolerance(self, wantval, want): """ if want.tol: if wantval == 0: - return RIFtol(want.tol) * RIFtol(-1,1) + return RIFtol(want.tol) * RIFtol(-1, 1) else: - return wantval * (1 + RIFtol(want.tol) * RIFtol(-1,1)) + return wantval * (1 + RIFtol(want.tol) * RIFtol(-1, 1)) elif want.abs_tol: - return wantval + RIFtol(want.abs_tol) * RIFtol(-1,1) + return wantval + RIFtol(want.abs_tol) * RIFtol(-1, 1) elif want.rel_tol: - return wantval * (1 + RIFtol(want.rel_tol) * RIFtol(-1,1)) + return wantval * (1 + RIFtol(want.rel_tol) * RIFtol(-1, 1)) else: return wantval @@ -1114,6 +1089,7 @@ def output_difference(self, example, got, optionflags): got_str = [g[0] for g in float_regex.findall(got)] if len(want_str) == len(got_str): failures = [] + def fail(x, y, actual, desired): failstr = " {} vs {}, tolerance {} > {}".format(x, y, RIFtol(actual).upper().str(digits=1, no_sci=False), @@ -1129,17 +1105,17 @@ def fail(x, y, actual, desired): if not w: fail(wstr, gstr, abs(g), want.tol) else: - fail(wstr, gstr, abs(1 - g/w), want.tol) + fail(wstr, gstr, abs(1 - g / w), want.tol) elif want.abs_tol: fail(wstr, gstr, abs(g - w), want.abs_tol) else: - fail(wstr, gstr, abs(1 - g/w), want.rel_tol) + fail(wstr, gstr, abs(1 - g / w), want.rel_tol) if failures: if len(want_str) == 1: diff += "Tolerance exceeded:\n" else: - diff += "Tolerance exceeded in %s of %s:\n"%(len(failures), len(want_str)) + diff += "Tolerance exceeded in %s of %s:\n" % (len(failures), len(want_str)) diff += "\n".join(failures) + "\n" elif "..." in want: diff += "Note: combining tolerance (# tol) with ellipsis (...) is not supported\n" From 6bd688ef6a92a267136c8f59b0ca0cc1d4b673d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 10 Jan 2022 17:12:46 +0100 Subject: [PATCH 104/253] fixing the few failing doctests --- src/sage/arith/multi_modular.pyx | 6 +++--- src/sage/combinat/permutation_cython.pyx | 22 +++++++++++----------- src/sage/quivers/paths.pyx | 5 ++--- src/sage/repl/preparse.py | 5 +++-- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/sage/arith/multi_modular.pyx b/src/sage/arith/multi_modular.pyx index 68a71d816b5..342a07b2614 100644 --- a/src/sage/arith/multi_modular.pyx +++ b/src/sage/arith/multi_modular.pyx @@ -2,7 +2,7 @@ Utility classes for multi-modular algorithms """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 William Stein # # This program is free software: you can redistribute it and/or modify @@ -10,7 +10,7 @@ Utility classes for multi-modular algorithms # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # https://www.gnu.org/licenses/ -#***************************************************************************** +# **************************************************************************** from cysignals.memory cimport check_allocarray, check_reallocarray, sig_free @@ -297,7 +297,7 @@ cdef class MultiModularBasis_base(object): sage: from sage.arith.multi_modular import MultiModularBasis_base sage: mm = MultiModularBasis_base([10007, 10009]) sage: mm.__getstate__() - ([10007, 10009], 1024L, 32768L) + ([10007, 10009], 1024, 32768) """ return (self.list(), self._l_bound, self._u_bound) diff --git a/src/sage/combinat/permutation_cython.pyx b/src/sage/combinat/permutation_cython.pyx index eb5e805bf3e..62f7be60102 100644 --- a/src/sage/combinat/permutation_cython.pyx +++ b/src/sage/combinat/permutation_cython.pyx @@ -203,17 +203,17 @@ cpdef bint next_perm(array l): sage: L = array('I', [1, 1, 2, 3]) sage: while next_perm(L): ....: print(L) - array('I', [1L, 1L, 3L, 2L]) - array('I', [1L, 2L, 1L, 3L]) - array('I', [1L, 2L, 3L, 1L]) - array('I', [1L, 3L, 1L, 2L]) - array('I', [1L, 3L, 2L, 1L]) - array('I', [2L, 1L, 1L, 3L]) - array('I', [2L, 1L, 3L, 1L]) - array('I', [2L, 3L, 1L, 1L]) - array('I', [3L, 1L, 1L, 2L]) - array('I', [3L, 1L, 2L, 1L]) - array('I', [3L, 2L, 1L, 1L]) + array('I', [1, 1, 3, 2]) + array('I', [1, 2, 1, 3]) + array('I', [1, 2, 3, 1]) + array('I', [1, 3, 1, 2]) + array('I', [1, 3, 2, 1]) + array('I', [2, 1, 1, 3]) + array('I', [2, 1, 3, 1]) + array('I', [2, 3, 1, 1]) + array('I', [3, 1, 1, 2]) + array('I', [3, 1, 2, 1]) + array('I', [3, 2, 1, 1]) """ cdef Py_ssize_t n = len(l) diff --git a/src/sage/quivers/paths.pyx b/src/sage/quivers/paths.pyx index 48395e1cb4d..7a6134d18b2 100644 --- a/src/sage/quivers/paths.pyx +++ b/src/sage/quivers/paths.pyx @@ -818,12 +818,11 @@ def NewQuiverPath(Q, start, end, biseq_data): (Partial semigroup formed by the directed paths of Multi-digraph on 3 vertices, 1, 3, - ((0, 4L, 1, ..., (4L,)), 2L, 2))) - + ((0, 4, 1, ..., (4,)), 2, 2))) """ cdef QuiverPath out = QuiverPath.__new__(Q.element_class) out._parent = Q out._start = start - out._end = end + out._end = end biseq_unpickle(out._path, biseq_data[0], biseq_data[1], biseq_data[2]) return out diff --git a/src/sage/repl/preparse.py b/src/sage/repl/preparse.py index 53c59e7d0a2..b4748b04f24 100644 --- a/src/sage/repl/preparse.py +++ b/src/sage/repl/preparse.py @@ -478,6 +478,7 @@ def safe_delimiter(self): else: return None + class QuoteStackFrame(SimpleNamespace): """ The state of a single level of a string literal being parsed. @@ -1154,9 +1155,9 @@ def preparse_numeric_literals(code, extract=False, quotes="'"): sage: preparse_numeric_literals("5jr") '5J' sage: preparse_numeric_literals("5l") - '5l' + '5' sage: preparse_numeric_literals("5L") - '5L' + '5' sage: preparse_numeric_literals("1.5") "RealNumber('1.5')" sage: preparse_numeric_literals("1.5j") From 9b329d59bc1e06922f33a39758221f1d9ea3ec48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 10 Jan 2022 21:53:49 +0100 Subject: [PATCH 105/253] some more specific imports in combinat --- .../cluster_algebra_quiver/mutation_class.py | 2 +- .../cluster_algebra_quiver/mutation_type.py | 4 ++-- src/sage/combinat/cluster_algebra_quiver/quiver.py | 3 ++- .../cluster_algebra_quiver/quiver_mutation_type.py | 3 ++- src/sage/combinat/combinat.py | 2 +- src/sage/combinat/combination.py | 3 ++- src/sage/combinat/crystals/alcove_path.py | 11 +++++------ src/sage/combinat/crystals/crystals.py | 14 ++++---------- src/sage/combinat/interval_posets.py | 2 +- .../combinat/non_decreasing_parking_function.py | 2 +- src/sage/combinat/partition.py | 5 ++++- src/sage/combinat/partition_kleshchev.py | 4 +++- src/sage/combinat/partition_shifting_algebras.py | 3 ++- src/sage/combinat/partition_tuple.py | 4 +++- src/sage/combinat/path_tableaux/semistandard.py | 3 ++- src/sage/combinat/permutation.py | 6 ++++-- src/sage/combinat/root_system/coxeter_matrix.py | 4 +++- src/sage/combinat/schubert_polynomial.py | 4 +++- src/sage/combinat/sf/jack.py | 10 +++++----- src/sage/combinat/sf/k_dual.py | 9 +++++---- src/sage/combinat/sf/new_kschur.py | 3 ++- src/sage/combinat/sf/ns_macdonald.py | 3 ++- src/sage/combinat/similarity_class_type.py | 4 +++- src/sage/combinat/sine_gordon.py | 8 ++++---- src/sage/combinat/skew_tableau.py | 4 +++- src/sage/combinat/species/generating_series.py | 11 ++++++----- src/sage/combinat/symmetric_group_algebra.py | 3 ++- src/sage/combinat/tableau_tuple.py | 2 +- src/sage/combinat/words/abstract_word.py | 9 +++++---- src/sage/combinat/words/finite_word.py | 12 ++++++++---- src/sage/combinat/words/infinite_word.py | 2 +- src/sage/combinat/words/morphic.py | 3 ++- src/sage/combinat/words/paths.py | 10 ++++++---- src/sage/combinat/words/word_generators.py | 4 +++- src/sage/combinat/words/word_infinite_datatypes.py | 9 +++++---- src/sage/combinat/words/words.py | 2 +- 36 files changed, 109 insertions(+), 78 deletions(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/mutation_class.py b/src/sage/combinat/cluster_algebra_quiver/mutation_class.py index f8954fcc00d..54b58e568db 100644 --- a/src/sage/combinat/cluster_algebra_quiver/mutation_class.py +++ b/src/sage/combinat/cluster_algebra_quiver/mutation_class.py @@ -22,7 +22,7 @@ from sage.groups.perm_gps.partn_ref.refinement_graphs import search_tree, get_orbits from sage.rings.integer_ring import ZZ from sage.rings.infinity import infinity -from sage.graphs.all import DiGraph +from sage.graphs.digraph import DiGraph from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import _edge_list_to_matrix diff --git a/src/sage/combinat/cluster_algebra_quiver/mutation_type.py b/src/sage/combinat/cluster_algebra_quiver/mutation_type.py index 181e911c43d..66279cdb9a9 100644 --- a/src/sage/combinat/cluster_algebra_quiver/mutation_type.py +++ b/src/sage/combinat/cluster_algebra_quiver/mutation_type.py @@ -27,8 +27,8 @@ from sage.misc.cachefunc import cached_function from sage.misc.flatten import flatten -from sage.graphs.all import DiGraph -from sage.combinat.all import Combinations +from sage.graphs.digraph import DiGraph +from sage.combinat.combination import Combinations from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import QuiverMutationType diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver.py b/src/sage/combinat/cluster_algebra_quiver/quiver.py index 4766fa71d2c..b12e94f45a5 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver.py @@ -42,7 +42,8 @@ from sage.rings.integer_ring import ZZ from sage.rings.cc import CC from sage.rings.infinity import infinity -from sage.graphs.all import Graph, DiGraph +from sage.graphs.digraph import DiGraph +from sage.graphs.graph import Graph from sage.graphs.views import EdgesView from sage.arith.misc import gcd from sage.modules.free_module_element import vector diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py b/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py index 8925dc6d17b..53492d688d7 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py @@ -25,7 +25,8 @@ from sage.misc.cachefunc import cached_method from sage.rings.integer_ring import ZZ from sage.rings.infinity import infinity -from sage.graphs.all import Graph, DiGraph +from sage.graphs.digraph import DiGraph +from sage.graphs.graph import Graph from sage.arith.all import binomial, euler_phi from sage.misc.misc_c import prod from sage.matrix.constructor import matrix diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index 8b24bf73aea..b43a1af3112 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -417,7 +417,7 @@ def bell_number(n, algorithm='flint', **options) -> Integer: break b += v k += si - from sage.rings.all import RealField + from sage.rings.real_mpfr import RealField R = RealField(b.exact_log(2) + 1, rnd='RNDD') return ((R(-1).exp() / q) * b).ceil() diff --git a/src/sage/combinat/combination.py b/src/sage/combinat/combination.py index 7936bbc3516..f6d5a2a1860 100644 --- a/src/sage/combinat/combination.py +++ b/src/sage/combinat/combination.py @@ -26,7 +26,8 @@ # **************************************************************************** import itertools -from sage.rings.all import ZZ, Integer +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ from sage.arith.all import binomial from .integer_vector import IntegerVectors from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets diff --git a/src/sage/combinat/crystals/alcove_path.py b/src/sage/combinat/crystals/alcove_path.py index 6ef9d20720d..4c0303c7a1d 100644 --- a/src/sage/combinat/crystals/alcove_path.py +++ b/src/sage/combinat/crystals/alcove_path.py @@ -8,10 +8,9 @@ - Travis Scrimshaw (2016-06-23): implemented `\mathcal{B}(\infty)` Special thanks to: Nicolas Borie, Anne Schilling, Travis Scrimshaw, and -Nicolas Thiery. +Nicolas Thiéry. """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 Brant Jones # Copyright (C) 2013 Arthur Lubovsky # @@ -19,8 +18,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 sage.structure.parent import Parent from sage.structure.element import Element @@ -29,7 +28,7 @@ from sage.structure.richcmp import richcmp from sage.categories.classical_crystals import ClassicalCrystals from sage.categories.loop_crystals import LoopCrystals -from sage.graphs.all import DiGraph +from sage.graphs.digraph import DiGraph from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.root_system.root_system import RootSystem from sage.all import vector diff --git a/src/sage/combinat/crystals/crystals.py b/src/sage/combinat/crystals/crystals.py index b7288753fba..0b3fa3998df 100644 --- a/src/sage/combinat/crystals/crystals.py +++ b/src/sage/combinat/crystals/crystals.py @@ -155,20 +155,14 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#**************************************************************************** +# *************************************************************************** # Acknowledgment: most of the design and implementation of this # library is heavily inspired from MuPAD-Combinat. -#**************************************************************************** - -#from sage.structure.unique_representation import UniqueRepresentation -#from sage.structure.parent import Parent -#from sage.structure.element import Element -#from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -#from sage.graphs.all import DiGraph -#from sage.combinat import ranker -#from sage.combinat.root_system.weyl_characters import WeylCharacter +# *************************************************************************** + from sage.combinat.backtrack import GenericBacktracker + class CrystalBacktracker(GenericBacktracker): def __init__(self, crystal, index_set=None): r""" diff --git a/src/sage/combinat/interval_posets.py b/src/sage/combinat/interval_posets.py index d698ef689ad..b1cd1b7c939 100644 --- a/src/sage/combinat/interval_posets.py +++ b/src/sage/combinat/interval_posets.py @@ -48,7 +48,7 @@ from sage.misc.latex import latex from sage.misc.lazy_attribute import lazy_attribute from sage.rings.integer import Integer -from sage.rings.all import NN +from sage.rings.semirings.non_negative_integer_semiring import NN from sage.sets.non_negative_integers import NonNegativeIntegers from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.family import Family diff --git a/src/sage/combinat/non_decreasing_parking_function.py b/src/sage/combinat/non_decreasing_parking_function.py index cea50974f0c..9763793bb1b 100644 --- a/src/sage/combinat/non_decreasing_parking_function.py +++ b/src/sage/combinat/non_decreasing_parking_function.py @@ -38,7 +38,7 @@ from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.sets_with_grading import SetsWithGrading from sage.categories.monoids import Monoids -from sage.rings.all import NN +from sage.rings.semirings.non_negative_integer_semiring import NN from sage.rings.integer import Integer from sage.structure.element import Element from sage.structure.parent import Parent diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index c85dcf8b4d9..70806da2211 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -304,7 +304,10 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.sets.non_negative_integers import NonNegativeIntegers -from sage.rings.all import QQ, ZZ, NN, IntegerModRing +from sage.rings.finite_rings.integer_mod_ring import IntegerModRing +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.semirings.non_negative_integer_semiring import NN from sage.arith.all import factorial, gcd from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.integer import Integer diff --git a/src/sage/combinat/partition_kleshchev.py b/src/sage/combinat/partition_kleshchev.py index 093eabf8a3a..1663674bfa9 100644 --- a/src/sage/combinat/partition_kleshchev.py +++ b/src/sage/combinat/partition_kleshchev.py @@ -83,7 +83,9 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.misc.lazy_attribute import lazy_attribute -from sage.rings.all import NN, ZZ, IntegerModRing +from sage.rings.finite_rings.integer_mod_ring import IntegerModRing +from sage.rings.integer_ring import ZZ +from sage.rings.semirings.non_negative_integer_semiring import NN from sage.cpython.getattr import getattr_from_other_class from collections import defaultdict diff --git a/src/sage/combinat/partition_shifting_algebras.py b/src/sage/combinat/partition_shifting_algebras.py index 7395fdd4776..f632e769ef8 100644 --- a/src/sage/combinat/partition_shifting_algebras.py +++ b/src/sage/combinat/partition_shifting_algebras.py @@ -28,7 +28,8 @@ from sage.combinat.sf.sf import SymmetricFunctions from sage.misc.fast_methods import Singleton from sage.misc.cachefunc import cached_method -from sage.rings.all import QQ, NonNegativeIntegerSemiring +from sage.rings.rational_field import QQ +from sage.rings.semirings.non_negative_integer_semiring import NonNegativeIntegerSemiring from sage.rings.integer_ring import ZZ diff --git a/src/sage/combinat/partition_tuple.py b/src/sage/combinat/partition_tuple.py index 56f9290b17e..71220fa65dc 100644 --- a/src/sage/combinat/partition_tuple.py +++ b/src/sage/combinat/partition_tuple.py @@ -265,7 +265,9 @@ class of modules for the algebras, which are generalisations of the Specht from sage.groups.perm_gps.permgroup import PermutationGroup from sage.libs.pari.all import pari from sage.misc.cachefunc import cached_method -from sage.rings.all import NN, ZZ, IntegerModRing +from sage.rings.finite_rings.integer_mod_ring import IntegerModRing +from sage.rings.integer_ring import ZZ +from sage.rings.semirings.non_negative_integer_semiring import NN from sage.rings.integer import Integer from sage.sets.positive_integers import PositiveIntegers from sage.structure.parent import Parent diff --git a/src/sage/combinat/path_tableaux/semistandard.py b/src/sage/combinat/path_tableaux/semistandard.py index 98b9d3905fa..b22a3e0acdc 100644 --- a/src/sage/combinat/path_tableaux/semistandard.py +++ b/src/sage/combinat/path_tableaux/semistandard.py @@ -85,10 +85,11 @@ from sage.combinat.tableau import Tableau from sage.combinat.gelfand_tsetlin_patterns import GelfandTsetlinPattern from sage.combinat.partition import _Partitions -from sage.rings.all import NN +from sage.rings.semirings.non_negative_integer_semiring import NN ############################################################################### + class SemistandardPathTableau(PathTableau): r""" An instance is a sequence of lists. Usually the entries will be non-negative integers diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py index cf053311550..bdc4c30cd2e 100644 --- a/src/sage/combinat/permutation.py +++ b/src/sage/combinat/permutation.py @@ -246,7 +246,9 @@ from sage.structure.list_clone import ClonableArray from sage.structure.global_options import GlobalOptions from sage.libs.gap.libgap import libgap -from sage.rings.all import ZZ, Integer, PolynomialRing +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.arith.all import factorial, multinomial from sage.matrix.matrix_space import MatrixSpace from sage.combinat.tools import transitive_ideal @@ -7503,7 +7505,7 @@ def bistochastic_as_sum_of_permutations(M, check = True): """ from sage.graphs.bipartite_graph import BipartiteGraph from sage.combinat.free_module import CombinatorialFreeModule - from sage.rings.all import RR + from sage.rings.real_mpfr import RR n = M.nrows() diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index 2595166bf57..63d153d7281 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -24,7 +24,9 @@ from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall from sage.matrix.matrix_generic_dense import Matrix_generic_dense from sage.graphs.graph import Graph -from sage.rings.all import ZZ, QQ, RR +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.real_mpfr import RR from sage.rings.infinity import infinity from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.root_system.coxeter_type import CoxeterType diff --git a/src/sage/combinat/schubert_polynomial.py b/src/sage/combinat/schubert_polynomial.py index c01bd684c61..af28a8e45d7 100644 --- a/src/sage/combinat/schubert_polynomial.py +++ b/src/sage/combinat/schubert_polynomial.py @@ -17,7 +17,9 @@ # **************************************************************************** from sage.combinat.free_module import CombinatorialFreeModule from sage.categories.all import GradedAlgebrasWithBasis -from sage.rings.all import Integer, PolynomialRing, ZZ +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.multi_polynomial import is_MPolynomial from sage.combinat.permutation import Permutations, Permutation import sage.libs.symmetrica.all as symmetrica diff --git a/src/sage/combinat/sf/jack.py b/src/sage/combinat/sf/jack.py index 5ca78639572..d0c46d29ccc 100644 --- a/src/sage/combinat/sf/jack.py +++ b/src/sage/combinat/sf/jack.py @@ -18,8 +18,7 @@ The Clarendon Press, Oxford University Press, New York, 1995, With contributions by A. Zelevinsky, Oxford Science Publications. """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 Mike Hansen # 2012 Mike Zabrocki # @@ -27,12 +26,13 @@ # 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.unique_representation import UniqueRepresentation import sage.categories.all -from sage.rings.all import Integer, QQ +from sage.rings.integer import Integer +from sage.rings.rational_field import QQ from sage.arith.all import gcd, lcm from sage.rings.fraction_field import is_FractionField from sage.misc.misc_c import prod diff --git a/src/sage/combinat/sf/k_dual.py b/src/sage/combinat/sf/k_dual.py index 65f27bf7be0..6e41c90affc 100644 --- a/src/sage/combinat/sf/k_dual.py +++ b/src/sage/combinat/sf/k_dual.py @@ -12,7 +12,7 @@ - Mike Zabrocki - `k`-bounded Hall Littlewood P and dual `k`-Schur functions (2012-12-02) """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Chris Berg # Based off of similar code of Jason Bandlow, Anne Schilling # and Mike Zabrocki @@ -26,8 +26,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation @@ -38,7 +38,8 @@ from sage.misc.cachefunc import cached_method from sage.misc.constant_function import ConstantFunction from sage.categories.graded_hopf_algebras_with_basis import GradedHopfAlgebrasWithBasis -from sage.rings.all import Integer, ZZ +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ from sage.cpython.getattr import raw_getattr diff --git a/src/sage/combinat/sf/new_kschur.py b/src/sage/combinat/sf/new_kschur.py index bc7da8cd621..d40aee2d92e 100644 --- a/src/sage/combinat/sf/new_kschur.py +++ b/src/sage/combinat/sf/new_kschur.py @@ -16,7 +16,8 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.all import Integer, ZZ +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.categories.realizations import Realizations, Category_realization_of_parent diff --git a/src/sage/combinat/sf/ns_macdonald.py b/src/sage/combinat/sf/ns_macdonald.py index a6d9420a5da..c36a0fd99a9 100644 --- a/src/sage/combinat/sf/ns_macdonald.py +++ b/src/sage/combinat/sf/ns_macdonald.py @@ -7,7 +7,8 @@ from sage.combinat.words.word import Word from sage.combinat.combination import Combinations from sage.combinat.permutation import Permutation -from sage.rings.all import QQ, PolynomialRing +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.rational_field import QQ from sage.misc.misc_c import prod from sage.combinat.backtrack import GenericBacktracker from sage.structure.parent import Parent diff --git a/src/sage/combinat/similarity_class_type.py b/src/sage/combinat/similarity_class_type.py index a77f5b65bca..7cd8fd3ab56 100644 --- a/src/sage/combinat/similarity_class_type.py +++ b/src/sage/combinat/similarity_class_type.py @@ -186,7 +186,9 @@ class type, it is also possible to compute the number of classes of that type from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.combinat.combinat import CombinatorialElement from sage.combinat.partition import Partitions, Partition -from sage.rings.all import ZZ, QQ, FractionField +from sage.rings.fraction_field import FractionField +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.misc.cachefunc import cached_in_parent_method, cached_function from sage.combinat.misc import IterableFunctionCall diff --git a/src/sage/combinat/sine_gordon.py b/src/sage/combinat/sine_gordon.py index a3c63e7b2d8..8a887a76dbd 100644 --- a/src/sage/combinat/sine_gordon.py +++ b/src/sage/combinat/sine_gordon.py @@ -31,21 +31,21 @@ .. [NS] \T. Nakanishi, S. Stella, Wonder of sine-Gordon Y-systems, to appear in Trans. Amer. Math. Soc., :arxiv:`1212.6853` """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2014 Salvatore Stella # # 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.structure.sage_object import SageObject from sage.rings.integer_ring import ZZ from sage.rings.real_mpfr import RR -from sage.rings.all import NN +from sage.rings.semirings.non_negative_integer_semiring import NN from sage.functions.trig import cos, sin from sage.plot.plot import parametric_plot from sage.plot.graphics import Graphics diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index 676aff61440..906b86f2930 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -32,7 +32,9 @@ from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -from sage.rings.all import Integer, QQ, ZZ +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.arith.all import factorial from sage.rings.infinity import PlusInfinity from sage.matrix.all import zero_matrix diff --git a/src/sage/combinat/species/generating_series.py b/src/sage/combinat/species/generating_series.py index bd57b4cd572..77749fc79b7 100644 --- a/src/sage/combinat/species/generating_series.py +++ b/src/sage/combinat/species/generating_series.py @@ -63,23 +63,24 @@ .. [BLL] \F. Bergeron, G. Labelle, and P. Leroux. "Combinatorial species and tree-like structures". Encyclopedia of Mathematics and its Applications, vol. 67, Cambridge Univ. Press. 1998. -.. [BLL-Intro] Francois Bergeron, Gilbert Labelle, and Pierre Leroux. +.. [BLL-Intro] François Bergeron, Gilbert Labelle, and Pierre Leroux. "Introduction to the Theory of Species of Structures", March 14, 2008. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 Mike Hansen # # 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 .series import LazyPowerSeriesRing, LazyPowerSeries from .stream import Stream, _integers_from -from sage.rings.all import Integer, RationalField +from sage.rings.integer import Integer +from sage.rings.rational_field import RationalField from sage.arith.all import moebius, gcd, lcm, divisors from sage.combinat.partition import Partition, Partitions from functools import partial diff --git a/src/sage/combinat/symmetric_group_algebra.py b/src/sage/combinat/symmetric_group_algebra.py index 6263dfea7cb..adcb397646a 100644 --- a/src/sage/combinat/symmetric_group_algebra.py +++ b/src/sage/combinat/symmetric_group_algebra.py @@ -19,7 +19,8 @@ from sage.combinat.tableau import Tableau, StandardTableaux_size, StandardTableaux_shape, StandardTableaux from sage.algebras.group_algebra import GroupAlgebra_class from sage.categories.weyl_groups import WeylGroups -from sage.rings.all import QQ, PolynomialRing +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.rational_field import QQ from sage.arith.all import factorial from sage.matrix.constructor import matrix from sage.modules.free_module_element import vector diff --git a/src/sage/combinat/tableau_tuple.py b/src/sage/combinat/tableau_tuple.py index a7b98a63743..83adaed546e 100644 --- a/src/sage/combinat/tableau_tuple.py +++ b/src/sage/combinat/tableau_tuple.py @@ -231,7 +231,7 @@ from sage.arith.all import factorial from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.rings.integer import Integer -from sage.rings.all import NN +from sage.rings.semirings.non_negative_integer_semiring import NN from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.family import Family from sage.sets.positive_integers import PositiveIntegers diff --git a/src/sage/combinat/words/abstract_word.py b/src/sage/combinat/words/abstract_word.py index 33261cad6f2..c24d90164d7 100644 --- a/src/sage/combinat/words/abstract_word.py +++ b/src/sage/combinat/words/abstract_word.py @@ -30,13 +30,14 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** +from itertools import islice, groupby from sage.structure.sage_object import SageObject from sage.combinat.words.word_options import word_options -from itertools import islice, groupby -from sage.rings.all import Integers, ZZ, Infinity -from sage.structure.richcmp import (richcmp_method, rich_to_bool, - richcmp_item) +from sage.rings.finite_rings.integer_mod_ring import Integers +from sage.rings.infinity import Infinity +from sage.rings.integer_ring import ZZ +from sage.structure.richcmp import richcmp_method, rich_to_bool, richcmp_item @richcmp_method diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index 7cdc289a290..fd589624796 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -202,7 +202,7 @@ sage: f.bispecial_factors() [word: , word: 0, word: 010, word: 010010, word: 01001010010] """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 Arnaud Bergeron , # 2008 Amy Glen , # 2008-2012 Sébastien Labbé , @@ -212,8 +212,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 collections import defaultdict from itertools import islice, cycle @@ -221,9 +221,13 @@ from sage.combinat.words.words import Words from sage.misc.cachefunc import cached_method from sage.combinat.words.word_options import word_options -from sage.rings.all import Integer, Infinity, ZZ, QQ +from sage.rings.infinity import Infinity +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.sets.set import Set + class FiniteWord_class(Word_class): def __str__(self): r""" diff --git a/src/sage/combinat/words/infinite_word.py b/src/sage/combinat/words/infinite_word.py index dc547c5ddaf..db8f15d577e 100644 --- a/src/sage/combinat/words/infinite_word.py +++ b/src/sage/combinat/words/infinite_word.py @@ -75,7 +75,7 @@ # **************************************************************************** from sage.combinat.words.abstract_word import Word_class from sage.combinat.words.word_options import word_options -from sage.rings.all import Infinity +from sage.rings.infinity import Infinity class InfiniteWord_class(Word_class): diff --git a/src/sage/combinat/words/morphic.py b/src/sage/combinat/words/morphic.py index 3fbbe48f26b..5ff1befeebd 100644 --- a/src/sage/combinat/words/morphic.py +++ b/src/sage/combinat/words/morphic.py @@ -30,9 +30,10 @@ """ from sage.combinat.words.word_infinite_datatypes import WordDatatype_callable -from sage.rings.all import Infinity +from sage.rings.infinity import Infinity from sage.modules.free_module_element import vector + class WordDatatype_morphic(WordDatatype_callable): r""" Datatype for a morphic word defined by a morphism, a starting letter diff --git a/src/sage/combinat/words/paths.py b/src/sage/combinat/words/paths.py index 902ba16ab54..9cf3483bedd 100644 --- a/src/sage/combinat/words/paths.py +++ b/src/sage/combinat/words/paths.py @@ -167,7 +167,7 @@ - [5] :wikipedia:`Dyck_word` """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 Arnaud bergeron , # Copyright (C) 2009 Sebastien Labbe , # @@ -175,8 +175,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 builtins import zip @@ -188,7 +188,9 @@ from sage.combinat.words.alphabet import build_alphabet from sage.plot.all import arrow, line, polygon, point, Graphics from sage.modules.free_module_element import vector -from sage.rings.all import ZZ, RR, QuadraticField +from sage.rings.integer_ring import ZZ +from sage.rings.number_field.number_field import QuadraticField +from sage.rings.real_mpfr import RR from .word_datatypes import (WordDatatype_str, WordDatatype_list, WordDatatype_tuple) diff --git a/src/sage/combinat/words/word_generators.py b/src/sage/combinat/words/word_generators.py index 910dc30098e..18540ba241c 100644 --- a/src/sage/combinat/words/word_generators.py +++ b/src/sage/combinat/words/word_generators.py @@ -57,7 +57,8 @@ from itertools import cycle, count from random import randint from sage.misc.cachefunc import cached_method -from sage.rings.all import ZZ, RR +from sage.rings.integer_ring import ZZ +from sage.rings.real_mpfr import RR from sage.rings.infinity import Infinity from sage.combinat.words.abstract_word import Word_class from sage.combinat.words.word import FiniteWord_list @@ -67,6 +68,7 @@ from sage.arith.all import gcd from sage.misc.decorators import rename_keyword + def _build_tab(sym, tab, W): r""" Internal function building a coding table for the ``phi_inv_tab`` function. diff --git a/src/sage/combinat/words/word_infinite_datatypes.py b/src/sage/combinat/words/word_infinite_datatypes.py index a42901cbc5a..95664b687af 100644 --- a/src/sage/combinat/words/word_infinite_datatypes.py +++ b/src/sage/combinat/words/word_infinite_datatypes.py @@ -1,7 +1,7 @@ r""" Datatypes for words defined by iterators and callables """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009 Franco Saliola # Vincent Delecroix <20100.delecroix@gmail.com> # @@ -9,14 +9,15 @@ # 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.combinat.words.word_datatypes import WordDatatype -from sage.rings.all import Infinity +from sage.rings.infinity import Infinity from math import ceil import itertools + class WordDatatype_callable(WordDatatype): r""" Datatype for a word defined by a callable. diff --git a/src/sage/combinat/words/words.py b/src/sage/combinat/words/words.py index 5a75921c47f..15bcf880ab4 100644 --- a/src/sage/combinat/words/words.py +++ b/src/sage/combinat/words/words.py @@ -54,7 +54,7 @@ from sage.structure.list_clone import ClonableElement from sage.combinat.words.alphabet import build_alphabet -from sage.rings.all import Infinity +from sage.rings.infinity import Infinity from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ From 130eb194027921343da922a9d267aa4ae0999f8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 11 Jan 2022 10:11:51 +0100 Subject: [PATCH 106/253] pep cleanup and doctest fix in quantum_group_gap --- .../quantum_groups/quantum_group_gap.py | 153 ++++++++++-------- 1 file changed, 83 insertions(+), 70 deletions(-) diff --git a/src/sage/algebras/quantum_groups/quantum_group_gap.py b/src/sage/algebras/quantum_groups/quantum_group_gap.py index 0fa487bf697..3e58d5576e8 100644 --- a/src/sage/algebras/quantum_groups/quantum_group_gap.py +++ b/src/sage/algebras/quantum_groups/quantum_group_gap.py @@ -85,11 +85,12 @@ def _repr_(self): # Replace Ei and Fi with the corresponding root in short form. # Do the largest index first so, e.g., F12 gets replaced as 12 # instead of as 1. - for i,al in reversed(list(enumerate(self.parent()._pos_roots))): - short = '+'.join('%s*a%s'%(coeff,index) if coeff != 1 else 'a%s'%index - for index,coeff in al) - ret = ret.replace('F%s'%(i+1), 'F[%s]'%short) - ret = ret.replace('E%s'%(i+1), 'E[%s]'%short) + for i, al in reversed(list(enumerate(self.parent()._pos_roots))): + short = '+'.join('%s*a%s' % (coeff, index) + if coeff != 1 else 'a%s' % index + for index, coeff in al) + ret = ret.replace('F%s' % (i + 1), 'F[%s]' % short) + ret = ret.replace('E%s' % (i + 1), 'E[%s]' % short) return ret def _latex_(self): @@ -112,11 +113,11 @@ def _latex_(self): ret = repr(self._libgap) # Do the largest index first so, e.g., F12 gets replaced as 12 # instead of as 1. - for i,al in reversed(list(enumerate(self.parent()._pos_roots))): - ret = ret.replace('F%s'%(i+1), 'F_{%s}'%latex(al)) - ret = ret.replace('E%s'%(i+1), 'E_{%s}'%latex(al)) - for i,ii in reversed(list(enumerate(self.parent()._cartan_type.index_set()))): - ret = ret.replace('K%s'%(i+1), 'K_{%s}'%ii) + for i, al in reversed(list(enumerate(self.parent()._pos_roots))): + ret = ret.replace('F%s' % (i + 1), 'F_{%s}' % latex(al)) + ret = ret.replace('E%s' % (i + 1), 'E_{%s}' % latex(al)) + for i, ii in reversed(list(enumerate(self.parent()._cartan_type.index_set()))): + ret = ret.replace('K%s' % (i + 1), 'K_{%s}' % ii) # Fugly string parsing to get good looking latex # TODO: Find a better way ret = ret.replace('(', '{(') @@ -125,7 +126,7 @@ def _latex_(self): ret = ret.replace('*', ' ') c = re.compile(r"q\^-?[0-9]*") for m in reversed(list(c.finditer(ret))): - ret = ret[:m.start()+2] + '{' + ret[m.start()+2:m.end()] + '}' + ret[m.end():] + ret = ret[:m.start() + 2] + '{' + ret[m.start() + 2:m.end()] + '}' + ret[m.end():] return ret def __reduce__(self): @@ -142,9 +143,9 @@ def __reduce__(self): data = self._libgap.ExtRepOfObj() R = self.base_ring() ret = [] - for i in range(len(data)//2): - ret.append(data[2*i].sage()) - ret.append( R(str(data[2*i+1])) ) + for i in range(len(data) // 2): + ret.append(data[2 * i].sage()) + ret.append(R(str(data[2 * i + 1]))) return (_unpickle_generic_element, (self.parent(), ret)) def __hash__(self): @@ -269,7 +270,7 @@ def e_tilde(self, i): if isinstance(i, (list, tuple)): ret = self for j in i: - if not ret: # ret == 0 + if not ret: # ret == 0 return ret ret = ret._et(j) return ret @@ -299,12 +300,13 @@ def f_tilde(self, i): if isinstance(i, (list, tuple)): ret = self for j in i: - if not ret: # ret == 0 + if not ret: # ret == 0 return ret ret = ret._ft(j) return ret return self._ft(i) + class QuantumGroup(UniqueRepresentation, Parent): r""" A Drinfel'd-Jimbo quantum group (implemented using the optional GAP @@ -368,10 +370,11 @@ def __init__(self, cartan_type, q): self._cartan_type = cartan_type GapPackage("QuaGroup", spkg="gap_packages").require() libgap.LoadPackage('QuaGroup') - R = libgap.eval('RootSystem("%s",%s)'%(cartan_type.type(), cartan_type.rank())) + R = libgap.eval('RootSystem("%s",%s)' % (cartan_type.type(), cartan_type.rank())) Q = self._cartan_type.root_system().root_lattice() I = cartan_type.index_set() - self._pos_roots = [Q.sum_of_terms([(ii, root[i]) for i,ii in enumerate(I) + self._pos_roots = [Q.sum_of_terms([(ii, root[i]) + for i, ii in enumerate(I) if root[i] != 0]) for root in R.PositiveRootsInConvexOrder().sage()] if q is None: @@ -412,7 +415,7 @@ def _latex_(self): U_{\zeta_{3}}(G_2) """ from sage.misc.latex import latex - return "U_{%s}(%s)"%(latex(self._q), latex(self._cartan_type)) + return "U_{%s}(%s)" % (latex(self._q), latex(self._cartan_type)) def gap(self): """ @@ -521,8 +524,8 @@ def E(self): sage: list(Q.E()) # optional - gap_packages [E[a1], E[a1+a2], E[a1+2*a2], E[a2]] """ - N = len(self._pos_roots) + len(self._cartan_type.index_set())*2 - d = {al: self.gens()[N+i] for i,al in enumerate(self._pos_roots)} + N = len(self._pos_roots) + len(self._cartan_type.index_set()) * 2 + d = {al: self.gens()[N + i] for i, al in enumerate(self._pos_roots)} return Family(self._pos_roots, d.__getitem__) def E_simple(self): @@ -537,7 +540,7 @@ def E_simple(self): """ I = self._cartan_type.index_set() gens = self.algebra_generators() - d = {i: gens['E%s'%i] for i in I} + d = {i: gens['E%s' % i] for i in I} return Family(I, d.__getitem__) def F(self): @@ -551,7 +554,7 @@ def F(self): sage: list(Q.F()) # optional - gap_packages [F[a1], F[3*a1+a2], F[2*a1+a2], F[3*a1+2*a2], F[a1+a2], F[a2]] """ - d = {al: self.gens()[i] for i,al in enumerate(self._pos_roots)} + d = {al: self.gens()[i] for i, al in enumerate(self._pos_roots)} return Family(self._pos_roots, d.__getitem__) def F_simple(self): @@ -566,7 +569,7 @@ def F_simple(self): """ I = self._cartan_type.index_set() gens = self.algebra_generators() - d = {i: gens['F%s'%i] for i in I} + d = {i: gens['F%s' % i] for i in I} return Family(I, d.__getitem__) def K(self): @@ -585,7 +588,7 @@ def K(self): """ N = len(self._pos_roots) I = self._cartan_type.index_set() - d = {ii: self.gens()[N+2*i] for i,ii in enumerate(I)} + d = {ii: self.gens()[N + 2 * i] for i, ii in enumerate(I)} return Family(I, d.__getitem__) def K_inverse(self): @@ -602,7 +605,7 @@ def K_inverse(self): """ N = len(self._pos_roots) I = self._cartan_type.index_set() - d = {ii: self.gens()[N+2*i+1] for i,ii in enumerate(I)} + d = {ii: self.gens()[N + 2 * i + 1] for i, ii in enumerate(I)} return Family(I, d.__getitem__) @cached_method @@ -622,14 +625,14 @@ def algebra_generators(self): I = self._cartan_type.index_set() simples = self._cartan_type.root_system().root_lattice().simple_roots() ret = {} - for i,al in enumerate(simples): + for i, al in enumerate(simples): ii = I[i] - ret['F%s'%ii] = self.F()[al] - ret['K%s'%ii] = self.K()[ii] - ret['Ki%s'%ii] = self.K_inverse()[ii] - ret['E%s'%ii] = self.E()[al] - keys = (['F%s'%i for i in I] + ['K%s'%i for i in I] - + ['Ki%s'%i for i in I] + ['E%s'%i for i in I]) + ret['F%s' % ii] = self.F()[al] + ret['K%s' % ii] = self.K()[ii] + ret['Ki%s' % ii] = self.K_inverse()[ii] + ret['E%s' % ii] = self.E()[al] + keys = (['F%s' % i for i in I] + ['K%s' % i for i in I] + + ['Ki%s' % i for i in I] + ['E%s' % i for i in I]) return Family(keys, ret.__getitem__) def _an_element_(self): @@ -696,9 +699,9 @@ def _Hom_(self, Y, category): """ if category is not None and not category.is_subcategory(Rings()): - raise TypeError("%s is not a subcategory of Rings()"%category) + raise TypeError("%s is not a subcategory of Rings()" % category) if Y not in Rings(): - raise TypeError("%s is not a ring"%Y) + raise TypeError("%s is not a ring" % Y) return QuantumGroupHomset(self, Y, category=category) def highest_weight_module(self, weight): @@ -826,16 +829,16 @@ def counit(self, elt): R = self.base_ring() ext_rep = list(elt._libgap.ExtRepOfObj()) constant = R.zero() - for i in range(len(ext_rep)//2): - if ext_rep[2*i].Length() == 0: - ext_rep.pop(2*i) # Pop the key - constant = R(str(ext_rep.pop(2*i))) # Pop the coefficient + for i in range(len(ext_rep) // 2): + if ext_rep[2 * i].Length() == 0: + ext_rep.pop(2 * i) # Pop the key + constant = R(str(ext_rep.pop(2 * i))) # Pop the coefficient break # To reconstruct, we need the following F = libgap.eval('ElementsFamily')(libgap.eval('FamilyObj')(self._libgap)) elt = F.ObjByExtRep(ext_rep) co = self._libgap.CounitMap() - return R( str(co(elt)) ) + constant + return R(str(co(elt))) + constant class Element(QuaGroupModuleElement): def _mul_(self, other): @@ -1023,7 +1026,7 @@ def _et(self, i): sage: Q.zero().e_tilde(1) # optional - gap_packages 0 """ - if not self: # self == 0 + if not self: # self == 0 return self ret = self._libgap.Ealpha(i) if not ret: @@ -1054,15 +1057,16 @@ def _ft(self, i): sage: Q.zero().f_tilde(1) # optional - gap_packages 0 """ - if not self: # self == 0 + if not self: # self == 0 return self ret = self._libgap.Falpha(i) if not ret: return self.parent().zero() return self.__class__(self.parent(), ret) + ##################################################################### -## Morphisms +# Morphisms class QuantumGroupMorphism(Morphism): r""" @@ -1192,9 +1196,10 @@ def _repr_defn(self): (-q + q^-1)*[ K1 ; 1 ] + K1 |--> K1 E[a1] |--> F[a1] """ - return '\n'.join('%s |--> %s'%(gen, self._im_gens[i]) + return '\n'.join('%s |--> %s' % (gen, self._im_gens[i]) for i, gen in enumerate(self.domain().algebra_generators())) + class QuantumGroupHomset(HomsetWithBase): r""" The homset whose domain is a quantum group. @@ -1234,6 +1239,7 @@ def __call__(self, im_gens, check=True): raise TypeError("unable to coerce {}".format(im_gens)) return QuantumGroupMorphism(self, im_gens) + def projection_lower_half(Q): r""" Return the projection onto the lower half of the quantum group. @@ -1260,10 +1266,11 @@ def projection_lower_half(Q): True """ I = Q._cartan_type.index_set() - return Hom(Q,Q)(list(Q.F_simple()) + [Q.zero()]*(len(I)*3)) + return Hom(Q, Q)(list(Q.F_simple()) + [Q.zero()] * (len(I) * 3)) + ##################################################################### -## Representations +# Representations class QuaGroupRepresentationElement(QuaGroupModuleElement): """ @@ -1314,7 +1321,7 @@ def _acted_upon_(self, scalar, self_on_left=False): """ try: if scalar.parent() is self.parent()._Q: - if self_on_left: # Only act: scalar * v + if self_on_left: # Only act: scalar * v return None return self.__class__(self.parent(), scalar._libgap ** self._libgap) except AttributeError: @@ -1337,7 +1344,7 @@ def _et(self, i): sage: V.zero().e_tilde(1) # optional - gap_packages 0*v0 """ - if not self: # self == 0 + if not self: # self == 0 return self V = self.parent() ret = V._libgap.Ealpha(self._libgap, i) @@ -1367,7 +1374,7 @@ def _ft(self, i): sage: V.zero().f_tilde(1) # optional - gap_packages 0*v0 """ - if not self: # self == 0 + if not self: # self == 0 return self V = self.parent() ret = V._libgap.Falpha(self._libgap, i) @@ -1393,7 +1400,7 @@ def monomial_coefficients(self, copy=True): R = self.parent()._Q.base_ring() B = self.parent()._libgap.Basis() data = [R(str(c)) for c in libgap.Coefficients(B, self._libgap)] - return {i: c for i,c in enumerate(data) if c != 0} + return {i: c for i, c in enumerate(data) if c != 0} def _vector_(self, R=None): """ @@ -1415,10 +1422,11 @@ def _vector_(self, R=None): """ V = self.parent()._dense_free_module(R) v = copy(V.zero()) - for i,c in self.monomial_coefficients().items(): + for i, c in self.monomial_coefficients().items(): v[i] = c return v + class CrystalGraphVertex(SageObject): r""" Helper class used as the vertices of a crystal graph. @@ -1501,12 +1509,12 @@ def _latex_(self): """ # Essentially same as QuaGroupModuleElement._latex_ from sage.misc.latex import latex - ret = self.s[1:-1] # Strip leading '<' and trailing '>' - for i,al in enumerate(self.V._pos_roots): - ret = ret.replace('F%s'%(i+1), 'F_{%s}'%latex(al)) - ret = ret.replace('E%s'%(i+1), 'E_{%s}'%latex(al)) - for i,ii in enumerate(self.V._cartan_type.index_set()): - ret = ret.replace('K%s'%(i+1), 'K_{%s}'%ii) + ret = self.s[1:-1] # Strip leading '<' and trailing '>' + for i, al in enumerate(self.V._pos_roots): + ret = ret.replace('F%s' % (i + 1), 'F_{%s}' % latex(al)) + ret = ret.replace('E%s' % (i + 1), 'E_{%s}' % latex(al)) + for i, ii in enumerate(self.V._cartan_type.index_set()): + ret = ret.replace('K%s' % (i + 1), 'K_{%s}' % ii) # Fugly string parsing to get good looking latex # TODO: Find a better way ret = ret.replace('(', '{(') @@ -1519,6 +1527,7 @@ def _latex_(self): ret = ret[:m.start()+2]+'{'+ret[m.start()+2:m.end()]+'}'+ret[m.end():] return '\\langle {} \\rangle'.format(ret) + class QuantumGroupModule(Parent, UniqueRepresentation): r""" Abstract base class for quantum group representations. @@ -1688,6 +1697,7 @@ def zero(self): """ return self.element_class(self, self._libgap.ZeroImmutable()) + class HighestWeightModule(QuantumGroupModule): """ A highest weight module of a quantum group. @@ -1708,7 +1718,7 @@ def __classcall_private__(cls, Q, weight): P = Q._cartan_type.root_system().weight_lattice() if isinstance(weight, (list, tuple)): La = P.fundamental_weights() - weight = P.sum(la*weight[i] for i,la in enumerate(La)) + weight = P.sum(la * weight[i] for i, la in enumerate(La)) else: weight = P(weight) return super(HighestWeightModule, cls).__classcall__(cls, Q, weight) @@ -1750,7 +1760,7 @@ def _latex_(self): sage: Q = QuantumGroup(['A',2]) # optional - gap_packages sage: V = Q.highest_weight_module([1,2]) # optional - gap_packages sage: latex(V) # optional - gap_packages - V(\Lambda_{1} + 2\Lambda_{2}) + V(\Lambda_{1} + 2 \Lambda_{2}) """ from sage.misc.latex import latex return "V({})".format(latex(self._weight)) @@ -1788,6 +1798,7 @@ def tensor(self, *V, **options): Element = QuaGroupRepresentationElement + class TensorProductOfHighestWeightModules(QuantumGroupModule): def __init__(self, *modules, **options): """ @@ -1903,11 +1914,12 @@ def highest_weight_decomposition(self): Highest weight submodule with weight Lambda[2] generated by -q^-1*(1*v0F[a1]*v0) + 1*(F[a1]*v01*v0)] """ return [HighestWeightSubmodule(self, self.element_class(self, v), tuple(wt.sage())) - for wt,vecs in zip(*self._highest_weights_and_vectors) + for wt, vecs in zip(*self._highest_weights_and_vectors) for v in vecs] Element = QuaGroupRepresentationElement + class HighestWeightSubmodule(QuantumGroupModule): def __init__(self, ambient, gen, weight): """ @@ -1932,7 +1944,7 @@ def __init__(self, ambient, gen, weight): # Convert the weight to an element of the weight lattice P = self._Q._cartan_type.root_system().weight_lattice() La = P.fundamental_weights() - self._weight = P.sum(la*weight[i] for i,la in enumerate(La)) + self._weight = P.sum(la * weight[i] for i, la in enumerate(La)) def _repr_(self): """ @@ -2108,6 +2120,7 @@ def crystal_graph(self, use_ambient=True): Element = QuaGroupRepresentationElement + # TODO: Generalized this to Verma modules class LowerHalfQuantumGroup(Parent, UniqueRepresentation): """ @@ -2173,7 +2186,7 @@ def _latex_(self): U^-_{q}(A_{2}) """ from sage.misc.latex import latex - return "U^-_{%s}(%s)"%(latex(self._Q._q), latex(self._cartan_type)) + return "U^-_{%s}(%s)" % (latex(self._Q._q), latex(self._cartan_type)) def _element_constructor_(self, elt): r""" @@ -2280,10 +2293,10 @@ def _construct_monomial(self, k): F = libgap.eval('ElementsFamily')(libgap.eval('FamilyObj')(self._libgap)) one = self._libgap_base.One() data = [] - for i,val in enumerate(k): + for i, val in enumerate(k): if val == 0: continue - data.append(i+1) + data.append(i + 1) data.append(val) return self.element_class(self, F.ObjByExtRep([data, one])) @@ -2589,7 +2602,7 @@ def _et(self, i): sage: L.zero().e_tilde(1) # optional - gap_packages 0 """ - if not self: # self == 0 + if not self: # self == 0 return self Q = self.parent() ret = self._libgap.Ealpha(i) @@ -2611,7 +2624,7 @@ def _ft(self, i): sage: L.zero().f_tilde(1) # optional - gap_packages 0 """ - if not self: # self == 0 + if not self: # self == 0 return self Q = self.parent() ret = self._libgap.Falpha(i) @@ -2619,6 +2632,7 @@ def _ft(self, i): return self.parent().zero() return self.__class__(Q, Q._proj(ret)._libgap) + def _unpickle_generic_element(parent, data): """ Used to unpickle an element of ``parent`` using ``data``. @@ -2634,8 +2648,7 @@ def _unpickle_generic_element(parent, data): ret = [] # We need to multiply by this to get the right type in GAP one = parent._libgap_base.One() - for i in range(len(data)//2): - ret.append( libgap(data[2*i]) ) - ret.append( one * libgap(data[2*i+1].subs(q=parent._libgap_q)) ) + for i in range(len(data) // 2): + ret.append(libgap(data[2 * i])) + ret.append(one * libgap(data[2 * i + 1].subs(q=parent._libgap_q))) return parent.element_class(parent, F.ObjByExtRep(ret)) - From d52da94bd4a6a47d5260478c48a24b4d3088f366 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Tue, 11 Jan 2022 15:33:06 -0500 Subject: [PATCH 107/253] Trac #33069: remove optional speaklater package. Nothing in the tree needs this, and it's a python package, so it can be installed with pip anyway. --- build/pkgs/speaklater/SPKG.rst | 14 -------------- build/pkgs/speaklater/checksums.ini | 4 ---- build/pkgs/speaklater/dependencies | 5 ----- build/pkgs/speaklater/distros/conda.txt | 1 - build/pkgs/speaklater/distros/macports.txt | 1 - build/pkgs/speaklater/distros/opensuse.txt | 1 - build/pkgs/speaklater/distros/repology.txt | 2 -- build/pkgs/speaklater/install-requires.txt | 1 - build/pkgs/speaklater/package-version.txt | 1 - build/pkgs/speaklater/spkg-install.in | 1 - build/pkgs/speaklater/type | 1 - 11 files changed, 32 deletions(-) delete mode 100644 build/pkgs/speaklater/SPKG.rst delete mode 100644 build/pkgs/speaklater/checksums.ini delete mode 100644 build/pkgs/speaklater/dependencies delete mode 100644 build/pkgs/speaklater/distros/conda.txt delete mode 100644 build/pkgs/speaklater/distros/macports.txt delete mode 100644 build/pkgs/speaklater/distros/opensuse.txt delete mode 100644 build/pkgs/speaklater/distros/repology.txt delete mode 100644 build/pkgs/speaklater/install-requires.txt delete mode 100644 build/pkgs/speaklater/package-version.txt delete mode 100644 build/pkgs/speaklater/spkg-install.in delete mode 100644 build/pkgs/speaklater/type diff --git a/build/pkgs/speaklater/SPKG.rst b/build/pkgs/speaklater/SPKG.rst deleted file mode 100644 index 0d8099c0027..00000000000 --- a/build/pkgs/speaklater/SPKG.rst +++ /dev/null @@ -1,14 +0,0 @@ -speaklater: Lazy strings for Python -=================================== - -Description ------------ - -Implements a lazy string for python useful for use with gettext - -A module that provides lazy strings for translations. Basically you get -an object that appears to be a string but changes the value every time -the value is evaluated based on a callable you provide. - -For example you can have a global lazy_gettext function that returns a -lazy string with the value of the current set language. diff --git a/build/pkgs/speaklater/checksums.ini b/build/pkgs/speaklater/checksums.ini deleted file mode 100644 index 7b88b7ec37e..00000000000 --- a/build/pkgs/speaklater/checksums.ini +++ /dev/null @@ -1,4 +0,0 @@ -tarball=speaklater-VERSION.tar.gz -sha1=65551c6896de20e58dbae795392b7e551ccfe318 -md5=e8d5dbe36e53d5a35cff227e795e8bbf -cksum=75663587 diff --git a/build/pkgs/speaklater/dependencies b/build/pkgs/speaklater/dependencies deleted file mode 100644 index 15df0c4d6d8..00000000000 --- a/build/pkgs/speaklater/dependencies +++ /dev/null @@ -1,5 +0,0 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) - ----------- -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/speaklater/distros/conda.txt b/build/pkgs/speaklater/distros/conda.txt deleted file mode 100644 index 3c5b92dbb17..00000000000 --- a/build/pkgs/speaklater/distros/conda.txt +++ /dev/null @@ -1 +0,0 @@ -speaklater diff --git a/build/pkgs/speaklater/distros/macports.txt b/build/pkgs/speaklater/distros/macports.txt deleted file mode 100644 index 98fe1bd0672..00000000000 --- a/build/pkgs/speaklater/distros/macports.txt +++ /dev/null @@ -1 +0,0 @@ -py-speaklater diff --git a/build/pkgs/speaklater/distros/opensuse.txt b/build/pkgs/speaklater/distros/opensuse.txt deleted file mode 100644 index f06cf684b6f..00000000000 --- a/build/pkgs/speaklater/distros/opensuse.txt +++ /dev/null @@ -1 +0,0 @@ -python3-speaklater diff --git a/build/pkgs/speaklater/distros/repology.txt b/build/pkgs/speaklater/distros/repology.txt deleted file mode 100644 index 5ecb1edfeb0..00000000000 --- a/build/pkgs/speaklater/distros/repology.txt +++ /dev/null @@ -1,2 +0,0 @@ -speaklater -python:speaklater diff --git a/build/pkgs/speaklater/install-requires.txt b/build/pkgs/speaklater/install-requires.txt deleted file mode 100644 index e5c328f97ae..00000000000 --- a/build/pkgs/speaklater/install-requires.txt +++ /dev/null @@ -1 +0,0 @@ -speaklater >=1.3 diff --git a/build/pkgs/speaklater/package-version.txt b/build/pkgs/speaklater/package-version.txt deleted file mode 100644 index 1b2c57f2d4a..00000000000 --- a/build/pkgs/speaklater/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -1.3.p0 diff --git a/build/pkgs/speaklater/spkg-install.in b/build/pkgs/speaklater/spkg-install.in deleted file mode 100644 index deba1bb42bb..00000000000 --- a/build/pkgs/speaklater/spkg-install.in +++ /dev/null @@ -1 +0,0 @@ -cd src && sdh_pip_install . diff --git a/build/pkgs/speaklater/type b/build/pkgs/speaklater/type deleted file mode 100644 index 134d9bc32d5..00000000000 --- a/build/pkgs/speaklater/type +++ /dev/null @@ -1 +0,0 @@ -optional From 49236ddcb076fccc4325dc2b3142fe8baab536be Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 11 Jan 2022 20:44:53 -0800 Subject: [PATCH 108/253] tox.ini: Add local-macos-python3_pythonorg-python3.9 etc., refactor CONFIG_CONFIGURE_ARGS_1=...--with-python --- tox.ini | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/tox.ini b/tox.ini index 1675106d45f..a1fb0996a48 100644 --- a/tox.ini +++ b/tox.ini @@ -481,22 +481,24 @@ setenv = # # Setting "--with-system-python3=yes" explicitly in case we change the configure default # to "--with-system-python3=force" as originally proposed in #32060 + PYTHON_MAJOR=3 + PYTHON_MINOR=9 + python3.7: PYTHON_MINOR=7 + python3.8: PYTHON_MINOR=8 + python3.9: PYTHON_MINOR=9 + python3.10: PYTHON_MINOR=10 + python3.11: PYTHON_MINOR=11 CONFIG_CONFIGURE_ARGS_1=--with-system-python3=yes python3_spkg: CONFIG_CONFIGURE_ARGS_1=--without-system-python3 macos-python3_xcode: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/usr/bin/python3 - macos-{python3_xcode,nohomebrew}-python3.7: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.7/bin/python3 - macos-{python3_xcode,nohomebrew}-python3.8: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/bin/python3 - # Must manually download and install from https://www.python.org/ftp/python/3.7.7/python-3.7.7-macosx10.9.pkg - macos-python3_pythonorg: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/Library/Frameworks/Python.framework/Versions/3.7/bin/python3 + macos-{python3_xcode,nohomebrew}-{python3.7,python3.8}: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/{env:PYTHON_MAJOR}.{env:PYTHON_MINOR}/bin/python3 # Homebrew keg installs - homebrew-python3.7: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python={env:HOMEBREW}/opt/python@3.7/bin/python3 - homebrew-python3.8: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python={env:HOMEBREW}/opt/python@3.8/bin/python3 - homebrew-python3.9: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python={env:HOMEBREW}/opt/python@3.9/bin/python3 + homebrew-{python3.7,python3.8,python3.9,python3.10,python3.11}: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python={env:HOMEBREW}/opt/python@{env:PYTHON_MAJOR}.{env:PYTHON_MINOR}/bin/python3 + # Installers from https://www.python.org/downloads/macos/ (must manually download and install) + macos-python3_pythonorg: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/Library/Frameworks/Python.framework/Versions/{env:PYTHON_MAJOR}.{env:PYTHON_MINOR}/bin/python3 # https://github.com/pypa/manylinux - manylinux-standard: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/opt/python/cp38-cp38/bin/python3 + manylinux-standard: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/opt/python/cp{env:PYTHON_MAJOR}{env:PYTHON_MINOR}-cp{env:PYTHON_MAJOR}{env:PYTHON_MINOR}/bin/python3 manylinux-python3.7: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/opt/python/cp37-cp37m/bin/python3 - manylinux-python3.8: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/opt/python/cp38-cp38/bin/python3 - manylinux-python3.9: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/opt/python/cp39-cp39/bin/python3 conda: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=python3 # # - toolchain From 1fcdc91d7f719b165c3cf912e500e831f5bb493e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 11 Jan 2022 20:47:41 -0800 Subject: [PATCH 109/253] tox.ini: Updates for macos and manylinux from #31396 --- tox.ini | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tox.ini b/tox.ini index a1fb0996a48..c9ebe586029 100644 --- a/tox.ini +++ b/tox.ini @@ -453,7 +453,7 @@ setenv = # We use liblzma from the macOS system - which is available but its headers are not (neither is the xz executable). # So we use /usr/local/opt/xz/{bin,include} (but not lib!). # This ensures that /usr/bin/python3 is accepted by configure - this is needed until #30948 is done. - local-macos-nohomebrew: PATH={env:HOMEBREW}/opt/xz/bin:{env:HOMEBREW}/opt/gpatch/bin:/usr/bin:/bin:/usr/sbin:/sbin + local-macos-nohomebrew: PATH={env:HOMEBREW}/opt/xz/bin:{env:HOMEBREW}/opt/gpatch/bin:{env:HOMEBREW}/opt/cmake/bin:/usr/bin:/bin:/usr/sbin:/sbin local-macos-nohomebrew: CPATH={env:HOMEBREW}/opt/xz/include local-homebrew: PATH={env:HOMEBREW}/bin:/usr/bin:/bin:/usr/sbin:/sbin local-{homebrew-nokegonly,nohomebrew}: BOOTSTRAP=ACLOCAL_PATH="$HOMEBREW/opt/gettext/share/aclocal:$ACLOCAL_PATH" PATH="$HOMEBREW/opt/gettext/bin/:$HOMEBREW/bin:$PATH" ./bootstrap @@ -499,6 +499,7 @@ setenv = # https://github.com/pypa/manylinux manylinux-standard: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/opt/python/cp{env:PYTHON_MAJOR}{env:PYTHON_MINOR}-cp{env:PYTHON_MAJOR}{env:PYTHON_MINOR}/bin/python3 manylinux-python3.7: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/opt/python/cp37-cp37m/bin/python3 + manylinux-{python3.7,python3.8,python3.9,python3.10,python3.11}: EXTRA_SAGE_PACKAGES=_bootstrap xz bzip2 libffi libpng conda: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=python3 # # - toolchain @@ -511,7 +512,7 @@ setenv = llvm: EXTRA_SAGE_PACKAGES_2=llvm # LLVM is keg-only homebrew-llvm: CONFIG_CONFIGURE_ARGS_2=--with-system-gcc=force CC={env:HOMEBREW}/opt/llvm/bin/clang CXX={env:HOMEBREW}/opt/llvm/bin/clang++ - macos-nohomebrew: CONFIG_CONFIGURE_ARGS_2=--with-system-gcc=force CC="$CONFIGURED_CC" CXX="$CONFIGURED_CXX" --with-mp=gmp --without-system-mpfr --without-system-readline --without-system-boost --without-system-boost_cropped + macos-nohomebrew: CONFIG_CONFIGURE_ARGS_2=--with-system-gcc=force CC="$CONFIGURED_CC" CXX="$CONFIGURED_CXX" --without-system-gmp --without-system-mpfr --without-system-readline --without-system-boost_cropped macos-nohomebrew: CONFIGURED_CXX=g++ -isysroot {env:MACOS_SDK} macos-nohomebrew: CONFIGURED_CC=gcc -isysroot {env:MACOS_SDK} # Prevent /usr/local to leak in: @@ -528,6 +529,10 @@ setenv = macos-10.15: MACOSX_DEPLOYMENT_TARGET=10.15 macos-11.1: MACOS_SDK=/Library/Developer/CommandLineTools/SDKs/MacOSX11.1.sdk macos-11.1: MACOSX_DEPLOYMENT_TARGET=11.1 + macos-11.3: MACOS_SDK=/Library/Developer/CommandLineTools/SDKs/MacOSX11.3.sdk + macos-11.3: MACOSX_DEPLOYMENT_TARGET=11.3 + macos-12.1: MACOS_SDK=/Library/Developer/CommandLineTools/SDKs/MacOSX12.1.sdk + macos-12.1: MACOSX_DEPLOYMENT_TARGET=12.1 # # Resulting full configuration args, including EXTRA_CONFIGURE_ARGS from the user environment # @@ -621,7 +626,7 @@ commands = local: {env:SETENV_CONFIGURE} && \ local: case "{env:SKIP_CONFIGURE:}" in 1|y*|Y*);; *) ./configure --prefix={env:PREFIX:{envdir}/local} {env:CONFIGURE_ARGS} ;; esac && \ local: case "{posargs:}" in \ - local: bash) bash -i; exit ;; \ + local: bash) PS1="(tox -e {envname}) \w\$ " bash -i; exit ;; \ local: config*) ;; \ local: *) make -k V=0 base-toolchain ;; \ local: esac && \ From 41ec3aa15693c69d68e9fdf2fae08e1999706a55 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 11 Jan 2022 21:20:11 -0800 Subject: [PATCH 110/253] tox.ini: Reindent --- tox.ini | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tox.ini b/tox.ini index c9ebe586029..971c1d46f2a 100644 --- a/tox.ini +++ b/tox.ini @@ -481,26 +481,26 @@ setenv = # # Setting "--with-system-python3=yes" explicitly in case we change the configure default # to "--with-system-python3=force" as originally proposed in #32060 - PYTHON_MAJOR=3 - PYTHON_MINOR=9 - python3.7: PYTHON_MINOR=7 - python3.8: PYTHON_MINOR=8 - python3.9: PYTHON_MINOR=9 - python3.10: PYTHON_MINOR=10 - python3.11: PYTHON_MINOR=11 - CONFIG_CONFIGURE_ARGS_1=--with-system-python3=yes - python3_spkg: CONFIG_CONFIGURE_ARGS_1=--without-system-python3 - macos-python3_xcode: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/usr/bin/python3 + PYTHON_MAJOR=3 + PYTHON_MINOR=9 + python3.7: PYTHON_MINOR=7 + python3.8: PYTHON_MINOR=8 + python3.9: PYTHON_MINOR=9 + python3.10: PYTHON_MINOR=10 + python3.11: PYTHON_MINOR=11 + CONFIG_CONFIGURE_ARGS_1=--with-system-python3=yes + python3_spkg: CONFIG_CONFIGURE_ARGS_1=--without-system-python3 + macos-python3_xcode: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/usr/bin/python3 macos-{python3_xcode,nohomebrew}-{python3.7,python3.8}: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/{env:PYTHON_MAJOR}.{env:PYTHON_MINOR}/bin/python3 # Homebrew keg installs homebrew-{python3.7,python3.8,python3.9,python3.10,python3.11}: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python={env:HOMEBREW}/opt/python@{env:PYTHON_MAJOR}.{env:PYTHON_MINOR}/bin/python3 # Installers from https://www.python.org/downloads/macos/ (must manually download and install) macos-python3_pythonorg: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/Library/Frameworks/Python.framework/Versions/{env:PYTHON_MAJOR}.{env:PYTHON_MINOR}/bin/python3 # https://github.com/pypa/manylinux - manylinux-standard: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/opt/python/cp{env:PYTHON_MAJOR}{env:PYTHON_MINOR}-cp{env:PYTHON_MAJOR}{env:PYTHON_MINOR}/bin/python3 - manylinux-python3.7: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/opt/python/cp37-cp37m/bin/python3 - manylinux-{python3.7,python3.8,python3.9,python3.10,python3.11}: EXTRA_SAGE_PACKAGES=_bootstrap xz bzip2 libffi libpng - conda: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=python3 + manylinux-standard: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/opt/python/cp{env:PYTHON_MAJOR}{env:PYTHON_MINOR}-cp{env:PYTHON_MAJOR}{env:PYTHON_MINOR}/bin/python3 + manylinux-python3.7: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/opt/python/cp37-cp37m/bin/python3 + manylinux-{python3.7,python3.8,python3.9,python3.10,python3.11}: EXTRA_SAGE_PACKAGES=_bootstrap xz bzip2 libffi libpng + conda: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=python3 # # - toolchain # From a995d143fd651bb41961cc5dcbb60631b0adc1ea Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Thu, 13 Jan 2022 09:15:40 +0100 Subject: [PATCH 111/253] =?UTF-8?q?#33157=20fix=20issue=20in=20SR=20?= =?UTF-8?q?=E2=86=92=20CBF=20conversion=20from=20#32871?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sage/symbolic/expression.pyx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index e7c756acf3c..297a88b6324 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -384,6 +384,7 @@ from cpython.object cimport Py_EQ, Py_NE, Py_LE, Py_GE, Py_LT, Py_GT from sage.cpython.string cimport str_to_bytes, char_to_str +from sage.structure.element cimport parent from sage.structure.element cimport RingElement, Element, Matrix from sage.structure.element cimport Expression as Expression_abc from sage.symbolic.complexity_measures import string_length @@ -1804,6 +1805,9 @@ cdef class Expression(Expression_abc): Traceback (most recent call last): ... TypeError: unable to convert bogus_builtin_function(1) to a ComplexBall + + sage: CBF(acos(float(1/4) * sqrt(int(5)))) + [0.97759655064526...] """ cdef bint progress = False cdef int i @@ -1841,7 +1845,7 @@ cdef class Expression(Expression_abc): # not bother trying to stay in the real field. try: for i in range(len(args)): - if args[i].parent() is not C: + if parent(args[i]) is not C: progress = True args[i] = C(args[i]) except (TypeError, ValueError): From c257926061b29babf3afce6eb1747831066c02c2 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 13 Jan 2022 13:16:30 +0100 Subject: [PATCH 112/253] Trac #33158: move check "right_side in" --- src/sage/combinat/k_regular_sequence.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 8cc1e860b4c..d4df4ec4387 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -1039,16 +1039,15 @@ def parse_one_summand(summand, eq): "%s is not a polynomial in %s of degree smaller than 2." % (left_side, eq, polynomial_left, var)) from None if polynomial_left in ZZ: - if right_side in coefficient_ring: - if (polynomial_left in initial_values.keys() and - initial_values[polynomial_left] != right_side): - raise ValueError("Initial value %s is given twice." - % (function(polynomial_left))) from None - initial_values.update({polynomial_left: right_side}) - else: + if right_side not in coefficient_ring: raise ValueError("Initial value %s given by the equation %s " "is not in %s." % (right_side, eq, coefficient_ring)) from None + if (polynomial_left in initial_values.keys() and + initial_values[polynomial_left] != right_side): + raise ValueError("Initial value %s is given twice." + % (function(polynomial_left))) from None + initial_values.update({polynomial_left: right_side}) else: [r, base_power_M] = list(polynomial_left) M_new = log(base_power_M, base=k) From a9a4be124ff3d5fea6a991d36a6c5a58300e721c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 13 Jan 2022 13:21:42 +0100 Subject: [PATCH 113/253] Trac #33158: move check "coeff not in" --- src/sage/combinat/k_regular_sequence.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index d4df4ec4387..5a7603f0b01 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -987,6 +987,11 @@ def parse_one_summand(summand, eq): else: raise ValueError('Term %s in the equation %s is not a valid summand.' % (summand, eq)) from None + if coeff not in coefficient_ring: + raise ValueError("Term %s in the equation %s: " + "%s is not a valid coefficient " + "since it is not in %s." + % (summand, eq, coeff, coefficient_ring)) from None if len(op.operands()) > 1: raise ValueError('Term %s in the equation %s has more than one argument.' % (op, eq)) from None @@ -1095,11 +1100,6 @@ def parse_one_summand(summand, eq): % (right_side,)) from None for summand in summands: coeff, new_m, d = parse_one_summand(summand, eq) - if coeff not in coefficient_ring: - raise ValueError("Term %s in the equation %s: " - "%s is not a valid coefficient " - "since it is not in %s." - % (summand, eq, coeff, coefficient_ring)) from None if m is not None and m != new_m: raise ValueError(("Term {0} in the equation {1}: " "{2} does not equal {3}. Expected " From 102e766dcefef673694beb802607f0e00d6fbef5 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 13 Jan 2022 13:26:54 +0100 Subject: [PATCH 114/253] Trac #33158: move check "M not in" --- src/sage/combinat/k_regular_sequence.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 5a7603f0b01..d1b1517cbfc 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -1056,6 +1056,11 @@ def parse_one_summand(summand, eq): else: [r, base_power_M] = list(polynomial_left) M_new = log(base_power_M, base=k) + if M_new not in ZZ: + raise ValueError("Term %s in the equation %s: " + "%s is not a power of %s." + % (left_side, eq, + base_power_M, k)) from None if M and M != M_new: raise ValueError(("Term {0} in the equation {1}: " "{2} does not equal {3}. Expected " @@ -1065,11 +1070,6 @@ def parse_one_summand(summand, eq): base_power_M, k**M)) from None elif not M: M = M_new - if M not in ZZ: - raise ValueError("Term %s in the equation %s: " - "%s is not a power of %s." - % (left_side, eq, - base_power_M, k)) from None if M < 1: raise ValueError(("Term {0} in the equation {1}: " "{2} is less than {3}. Modulus must " From e061849f3f7c298cff36a9648dc783c13f62b6c2 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 13 Jan 2022 13:30:45 +0100 Subject: [PATCH 115/253] Trac #33158: move check "m not in" --- src/sage/combinat/k_regular_sequence.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index d1b1517cbfc..eeff3a92842 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -1010,6 +1010,11 @@ def parse_one_summand(summand, eq): % (op, eq, poly)) from None d, base_power_m = list(poly) m = log(base_power_m, base=k) + if m not in ZZ: + raise ValueError("Term %s in the equation %s: " + "%s is not a power of %s." + % (summand, eq, + k**m, k)) from None return [coeff, m, d] if not equations: @@ -1110,11 +1115,6 @@ def parse_one_summand(summand, eq): k**new_m, k**m)) from None elif m is None: m = new_m - if m not in ZZ: - raise ValueError("Term %s in the equation %s: " - "%s is not a power of %s." - % (summand, eq, - k**m, k)) from None if M <= m: raise ValueError("Term %s in the equation %s: " "%s is not smaller than %s." From 78c790c175ddda8a766662d643eb32184ea9509d Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 13 Jan 2022 13:40:01 +0100 Subject: [PATCH 116/253] Trac #33158: cleanup raise ... from None --- src/sage/combinat/k_regular_sequence.py | 56 ++++++++++++------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index eeff3a92842..14c7b5c6b7e 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -977,7 +977,7 @@ def parse_multiplication(op, eq): else: raise ValueError('Term %s in the equation %s ' 'does not contain %s.' - % (op, eq, function)) from None + % (op, eq, function)) def parse_one_summand(summand, eq): if summand.operator() == mul_vararg: @@ -986,18 +986,18 @@ def parse_one_summand(summand, eq): coeff, op = 1, summand else: raise ValueError('Term %s in the equation %s is not a valid summand.' - % (summand, eq)) from None + % (summand, eq)) if coeff not in coefficient_ring: raise ValueError("Term %s in the equation %s: " "%s is not a valid coefficient " "since it is not in %s." - % (summand, eq, coeff, coefficient_ring)) from None + % (summand, eq, coeff, coefficient_ring)) if len(op.operands()) > 1: raise ValueError('Term %s in the equation %s has more than one argument.' - % (op, eq)) from None + % (op, eq)) elif len(op.operands()) == 0: raise ValueError('Term %s in the equation %s has no argument.' - % (op, eq)) from None + % (op, eq)) try: poly = ZZ[var](op.operands()[0]) except TypeError: @@ -1007,35 +1007,35 @@ def parse_one_summand(summand, eq): if poly.degree() != 1: raise ValueError("Term %s in the equation %s: " "polynomial %s does not have degree 1." - % (op, eq, poly)) from None + % (op, eq, poly)) d, base_power_m = list(poly) m = log(base_power_m, base=k) if m not in ZZ: raise ValueError("Term %s in the equation %s: " "%s is not a power of %s." % (summand, eq, - k**m, k)) from None + k**m, k)) return [coeff, m, d] if not equations: - raise ValueError("List of recurrence equations is empty.") from None + raise ValueError("List of recurrence equations is empty.") for eq in equations: try: if eq.operator() != operator.eq: raise ValueError("%s is not an equation with ==." - % eq) from None + % eq) except AttributeError: raise ValueError("%s is not a symbolic expression." % eq) from None left_side, right_side = eq.operands() if left_side.operator() != function: raise ValueError("Term %s in the equation %s is not an evaluation of %s." - % (left_side, eq, function)) from None + % (left_side, eq, function)) if len(left_side.operands()) != 1: raise ValueError("Term %s in the equation %s does not have " "one argument." - % (left_side, eq)) from None + % (left_side, eq)) try: polynomial_left = ZZ[var](left_side.operands()[0]) except TypeError: @@ -1047,16 +1047,16 @@ def parse_one_summand(summand, eq): if polynomial_left.degree() > 1: raise ValueError("Term %s in the equation %s: " "%s is not a polynomial in %s of degree smaller than 2." - % (left_side, eq, polynomial_left, var)) from None + % (left_side, eq, polynomial_left, var)) if polynomial_left in ZZ: if right_side not in coefficient_ring: raise ValueError("Initial value %s given by the equation %s " "is not in %s." - % (right_side, eq, coefficient_ring)) from None + % (right_side, eq, coefficient_ring)) if (polynomial_left in initial_values.keys() and initial_values[polynomial_left] != right_side): raise ValueError("Initial value %s is given twice." - % (function(polynomial_left))) from None + % (function(polynomial_left))) initial_values.update({polynomial_left: right_side}) else: [r, base_power_M] = list(polynomial_left) @@ -1065,14 +1065,14 @@ def parse_one_summand(summand, eq): raise ValueError("Term %s in the equation %s: " "%s is not a power of %s." % (left_side, eq, - base_power_M, k)) from None + base_power_M, k)) if M and M != M_new: raise ValueError(("Term {0} in the equation {1}: " "{2} does not equal {3}. Expected " "subsequence modulo {3} as in another " "equation, got subsequence modulo {2}.").format( left_side, eq, - base_power_M, k**M)) from None + base_power_M, k**M)) elif not M: M = M_new if M < 1: @@ -1080,18 +1080,18 @@ def parse_one_summand(summand, eq): "{2} is less than {3}. Modulus must " "be at least {3}.").format( left_side, eq, - base_power_M, k)) from None + base_power_M, k)) if r in remainders: raise ValueError("There are more than one recurrence relation for %s." - % (left_side,)) from None + % (left_side,)) if r >= k**M: raise ValueError("Term %s in the equation %s: " "remainder %s is not smaller than modulus %s." - % (left_side, eq, r, k**M)) from None + % (left_side, eq, r, k**M)) elif r < 0: raise ValueError("Term %s in the equation %s: " "remainder %s is smaller than 0." - % (left_side, eq, r)) from None + % (left_side, eq, r)) else: remainders.add(r) if right_side != 0: @@ -1102,7 +1102,7 @@ def parse_one_summand(summand, eq): summands = right_side.operands() else: raise ValueError("%s is not a valid right hand side." - % (right_side,)) from None + % (right_side,)) for summand in summands: coeff, new_m, d = parse_one_summand(summand, eq) if m is not None and m != new_m: @@ -1112,18 +1112,18 @@ def parse_one_summand(summand, eq): "summand or equation, got subsequence " "modulo {2}.").format( summand, eq, - k**new_m, k**m)) from None + k**new_m, k**m)) elif m is None: m = new_m if M <= m: raise ValueError("Term %s in the equation %s: " "%s is not smaller than %s." % (summand, eq, - k**m, k**M)) from None + k**m, k**M)) coeffs.update({(r, d): coeff}) if not M: - raise ValueError("No recurrence relations are given.") from None + raise ValueError("No recurrence relations are given.") elif M and m is None: # for the zero sequence m = M - 1 @@ -1253,13 +1253,13 @@ def parameters(self, M, m, coeffs, initial_values, offset): dim = (k**M - 1)/(k - 1) + (M - m)*(uu - ll - k**m + 1) + n1 if not initial_values: - raise ValueError("No initial values are given.") from None + raise ValueError("No initial values are given.") keys_initial = initial_values.keys() values_not_in_ring = [n for n in keys_initial if initial_values[n] not in coefficient_ring] if values_not_in_ring: raise ValueError("Initial values for arguments in %s are not in %s." - % (values_not_in_ring, coefficient_ring)) from None + % (values_not_in_ring, coefficient_ring)) last_value_needed = max( k**(M-1) - k**m + uu + (n1 > 0)*k**(M-1)*(k*(n1 - 1) + k - 1), # for matrix W @@ -1439,7 +1439,7 @@ def f(n): if missing_values: raise ValueError("Initial values for arguments in %s are missing." - % (list(set(missing_values)),)) from None + % (list(set(missing_values)),)) for n in keys_initial: q, r = ZZ(n).quo_rem(k**M) @@ -1448,7 +1448,7 @@ def f(n): for j in srange(l, u + 1)])): raise ValueError("Initial value for argument %s does not match with " "the given recurrence relations." - % (n,)) from None + % (n,)) values.update({n: 0 for n in srange(ll, 0)}) From a96f013f4e826e1148176fd40449335b2c8e4635 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 13 Jan 2022 14:00:25 +0100 Subject: [PATCH 117/253] Trac #33158: rewrite conversions --- src/sage/combinat/k_regular_sequence.py | 30 ++++++++++++++++++------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 14c7b5c6b7e..b808f8f9235 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -987,11 +987,13 @@ def parse_one_summand(summand, eq): else: raise ValueError('Term %s in the equation %s is not a valid summand.' % (summand, eq)) - if coeff not in coefficient_ring: + try: + coeff = coefficient_ring(coeff) + except (TypeError, ValueError): raise ValueError("Term %s in the equation %s: " "%s is not a valid coefficient " "since it is not in %s." - % (summand, eq, coeff, coefficient_ring)) + % (summand, eq, coeff, coefficient_ring)) from None if len(op.operands()) > 1: raise ValueError('Term %s in the equation %s has more than one argument.' % (op, eq)) @@ -1010,7 +1012,9 @@ def parse_one_summand(summand, eq): % (op, eq, poly)) d, base_power_m = list(poly) m = log(base_power_m, base=k) - if m not in ZZ: + try: + m = ZZ(m) + except (TypeError, ValueError): raise ValueError("Term %s in the equation %s: " "%s is not a power of %s." % (summand, eq, @@ -1049,7 +1053,9 @@ def parse_one_summand(summand, eq): "%s is not a polynomial in %s of degree smaller than 2." % (left_side, eq, polynomial_left, var)) if polynomial_left in ZZ: - if right_side not in coefficient_ring: + try: + right_side = coefficient_ring(right_side) + except (TypeError, ValueError): raise ValueError("Initial value %s given by the equation %s " "is not in %s." % (right_side, eq, coefficient_ring)) @@ -1061,11 +1067,13 @@ def parse_one_summand(summand, eq): else: [r, base_power_M] = list(polynomial_left) M_new = log(base_power_M, base=k) - if M_new not in ZZ: + try: + M_new = ZZ(M_new) + except (TypeError, ValueError): raise ValueError("Term %s in the equation %s: " "%s is not a power of %s." % (left_side, eq, - base_power_M, k)) + base_power_M, k)) from None if M and M != M_new: raise ValueError(("Term {0} in the equation {1}: " "{2} does not equal {3}. Expected " @@ -1255,8 +1263,14 @@ def parameters(self, M, m, coeffs, initial_values, offset): if not initial_values: raise ValueError("No initial values are given.") keys_initial = initial_values.keys() - values_not_in_ring = [n for n in keys_initial - if initial_values[n] not in coefficient_ring] + values_not_in_ring = [] + def converted_value(n, v): + try: + return coefficient_ring(v) + except (TypeError, ValueError): + values_not_in_ring.append(n) + initial_values = {n: converted_value(n, v) + for n, v in initial_values.items()} if values_not_in_ring: raise ValueError("Initial values for arguments in %s are not in %s." % (values_not_in_ring, coefficient_ring)) From 79e17c515a5576f27c3294b2e4bbaaea370f9c45 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 13 Jan 2022 14:00:54 +0100 Subject: [PATCH 118/253] Trac #33158: use correct check for None-parameters --- src/sage/combinat/k_regular_sequence.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index b808f8f9235..8858e2edc65 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -1074,14 +1074,14 @@ def parse_one_summand(summand, eq): "%s is not a power of %s." % (left_side, eq, base_power_M, k)) from None - if M and M != M_new: + if M is not None and M != M_new: raise ValueError(("Term {0} in the equation {1}: " "{2} does not equal {3}. Expected " "subsequence modulo {3} as in another " "equation, got subsequence modulo {2}.").format( left_side, eq, base_power_M, k**M)) - elif not M: + elif M is None: M = M_new if M < 1: raise ValueError(("Term {0} in the equation {1}: " From daaf4d6a5851df697e7f3dfebffbbd5bce7b050c Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 13 Jan 2022 14:10:42 +0100 Subject: [PATCH 119/253] Trac #33158: doctest fix and original issued posted on ticket --- src/sage/combinat/k_regular_sequence.py | 28 +++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 8858e2edc65..3242616b715 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -953,6 +953,34 @@ def parse_recurrence(self, equations, function, var): sage: RP.parse_recurrence([f(2*n) == 0, f(2*n + 1) == 0], f, n) (1, 0, {}, {}) + + We check that the output is of the correct type (:trac:`33158`):: + + sage: RP = RecurrenceParser(2, QQ) + sage: equations = [ + ....: f(4*n) == 5/3*f(2*n) - 1/3*f(2*n + 1), + ....: f(4*n + 1) == 4/3*f(2*n) + 1/3*f(2*n + 1), + ....: f(4*n + 2) == 1/3*f(2*n) + 4/3*f(2*n + 1), + ....: f(4*n + 3) == -1/3*f(2*n) + 5/3*f(2*n + 1), + ....: f(0) == 1, f(1) == 2] + sage: M, m, coeffs, initial_values = RP.parse_recurrence(equations, f, n) + sage: M.parent() + Integer Ring + sage: m.parent() + Integer Ring + sage: all(v.parent() == QQ for v in coeffs.values()) + True + sage: all(v.parent() == QQ for v in initial_values.values()) + True + + This results in giving the correct (see :trac:`33158`) minimization in:: + + sage: Seq2 = kRegularSequenceSpace(2, QQ) + sage: P = Seq2.from_recurrence(equations, f, n) + sage: P + 2-regular sequence 1, 2, 3, 3, 4, 5, 5, 4, 5, 7, ... + sage: P.minimized() + 2-regular sequence 1, 2, 3, 3, 4, 5, 5, 4, 5, 7, ... """ from sage.arith.srange import srange from sage.functions.log import log From 553e11557888a69e2a21845957ac7b1f140e9daa Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Thu, 13 Jan 2022 13:30:25 -0500 Subject: [PATCH 120/253] Trac #33154: fix random failure in sage.plot.matrix_plot. There's a random 3x3 polynomial matrix in this file that's supposed to be "nonconstant," which in this context means that it contains at least one polynomial entry of degree one or higher. But if you are extremely unlucky, random_matrix() may generate you nine entries of degree < 1. Here we avoid the issue by generating an additional polynomial of degree >= 1, and inserting it into the matrix at a random location. with '#' will be ignored, and an empty message aborts the commit. # # On branch u/mjo/ticket/33154 # Changes to be committed: # modified: src/sage/plot/matrix_plot.py # # Untracked files: # test.py # --- src/sage/plot/matrix_plot.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/plot/matrix_plot.py b/src/sage/plot/matrix_plot.py index 041405f2171..e15b007184e 100644 --- a/src/sage/plot/matrix_plot.py +++ b/src/sage/plot/matrix_plot.py @@ -515,7 +515,10 @@ def matrix_plot(mat, xrange=None, yrange=None, **options): TESTS:: sage: P. = RR[] - sage: matrix_plot(random_matrix(P, 3, 3)) + sage: M = random_matrix(P, 3, 3) + sage: (i,j) = (ZZ.random_element(3), ZZ.random_element(3)) + sage: M[i,j] = P.random_element(degree=(1,5)) # always nonconstant + sage: matrix_plot(M) Traceback (most recent call last): ... TypeError: cannot convert nonconstant polynomial From 4d094d627acbd93a2c234dcf66e7ea5742bc6d9f Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Tue, 26 May 2020 23:29:24 -0400 Subject: [PATCH 121/253] Trac #33159: add special case to solve_right() for symbolic systems. Elements of SR remember whether or not they are exact, and if we are given a system consisting entirely of exact elements, then the checks for correctness in solve_left() and solve_right() need not be skipped as they are for other inexact rings. This commit adds a special case to the solve_right() method for matrices to handle SR with care, and includes an additional test case from Trac 29729. Since solve_left() is implemented in terms of solve_right(), both are addressed. --- src/sage/matrix/matrix2.pyx | 63 +++++++++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 10 deletions(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index 7d319bd54b9..a637f25c051 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -224,8 +224,8 @@ cdef class Matrix(Matrix1): - ``check`` -- boolean (default: ``True``); verify the answer if the system is non-square or rank-deficient, and if its - entries lie in an exact ring. Meaningless over inexact rings, - or when the system is square and of full rank. + entries lie in an exact ring. Meaningless over most inexact + rings, or when the system is square and of full rank. OUTPUT: @@ -239,12 +239,13 @@ cdef class Matrix(Matrix1): If the system is not square or does not have full rank, then a solution is attempted via other means. For example, over ``RDF`` or ``CDF`` a least-squares solution is returned, as - with MATLAB's "backslash" operator. For inexact rings, the + with MATLAB's "backslash" operator. For most inexact rings, the ``check`` parameter is ignored because an approximate solution will be returned in any case. Over exact rings, on the other hand, setting the ``check`` parameter results in an additional test to determine whether or not the answer actually solves the - system exactly. + system exactly. If a symbolic system involves only exact elements, + its solution can still be checked. If `B` is a vector, the result is returned as a vector, as well, and as a matrix, otherwise. @@ -395,6 +396,21 @@ cdef class Matrix(Matrix1): (0.5 - 1.5*I, 0.5 + 0.5*I) sage: b = vector(QQ[I], [1+I, 2]) sage: x = A.solve_left(b) + + Over the inexact ring ``SR``, we can still verify the solution + if all of the elements involved were exact to begin with; if + any are inexact, however, the ``check`` is still skipped + (:trac:`29729` and :trac:`33159`):: + + sage: A = matrix(SR, [[1, 1]]) + sage: b = vector(SR, [2, 3]) + sage: A.solve_left(b) + Traceback (most recent call last): + ... + ValueError: matrix equation has no solutions + sage: A.solve_left(b, check=False) + (2) + """ if is_Vector(B): try: @@ -433,8 +449,8 @@ cdef class Matrix(Matrix1): - ``check`` -- boolean (default: ``True``); verify the answer if the system is non-square or rank-deficient, and if its - entries lie in an exact ring. Meaningless over inexact rings, - or when the system is square and of full rank. + entries lie in an exact ring. Meaningless over most inexact + rings, or when the system is square and of full rank. OUTPUT: @@ -448,12 +464,13 @@ cdef class Matrix(Matrix1): If the system is not square or does not have full rank, then a solution is attempted via other means. For example, over ``RDF`` or ``CDF`` a least-squares solution is returned, as - with MATLAB's "backslash" operator. For inexact rings, the + with MATLAB's "backslash" operator. For most inexact rings, the ``check`` parameter is ignored because an approximate solution will be returned in any case. Over exact rings, on the other hand, setting the ``check`` parameter results in an additional test to determine whether or not the answer actually solves the - system exactly. + system exactly. If a symbolic system involves only exact elements, + its solution can still be checked. If `B` is a vector, the result is returned as a vector, as well, and as a matrix, otherwise. @@ -780,6 +797,23 @@ cdef class Matrix(Matrix1): sage: A = matrix(RF, [[0.24, 1, 0], [1, 0, 0]]) sage: 0 < (A * A.solve_right(B) - B).norm() < 1e-14 True + + Over the inexact ring ``SR``, we can still verify the solution + if all of the elements involved were exact to begin with; if + any are inexact, however, the ``check`` is still skipped + (:trac:`29729` and :trac:`33159`):: + + sage: m = matrix(SR, [0]) + sage: b = vector(SR, [1]) + sage: m.solve_right(b, check=True) + Traceback (most recent call last): + ... + ValueError: matrix equation has no solutions + sage: m.solve_right(b, check=False) + (0) + sage: m = matrix(SR, [0.0]) + sage: m.solve_right(b, check=True) + (0) """ try: L = B.base_ring() @@ -812,8 +846,17 @@ cdef class Matrix(Matrix1): K = P self = self.change_ring(P) - # If our field is inexact, checking the answer is doomed anyway. - check = (check and K.is_exact()) + # If our field is inexact, checking the answer is doomed in + # most cases. But here we handle the special ones. + from sage.symbolic.ring import SR + if K is SR: + # Elements of SR "remember" whether or not they are exact. + # If every element in the system is exact, we can probably + # still check the solution over the inexact ring SR. + check = (check and all( e.is_exact() + for e in self.list() + B.list() )) + else: + check = (check and K.is_exact()) if not K.is_integral_domain(): # The non-integral-domain case is handled almost entirely From 750af3d381348c8a98d7d9f6b6b311e9b82faf07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 13 Jan 2022 20:26:06 +0100 Subject: [PATCH 122/253] modified imports of NN in combinat --- src/sage/combinat/cluster_complex.py | 2 +- src/sage/combinat/crystals/tensor_product.py | 2 +- src/sage/combinat/integer_lists/nn.py | 2 +- src/sage/combinat/interval_posets.py | 2 +- src/sage/combinat/non_decreasing_parking_function.py | 2 +- src/sage/combinat/partition.py | 2 +- src/sage/combinat/partition_kleshchev.py | 2 +- src/sage/combinat/partition_tuple.py | 2 +- src/sage/combinat/path_tableaux/semistandard.py | 2 +- src/sage/combinat/posets/poset_examples.py | 4 ++-- src/sage/combinat/root_system/cartan_type.py | 2 +- src/sage/combinat/root_system/root_lattice_realizations.py | 2 +- src/sage/combinat/root_system/type_super_A.py | 2 +- src/sage/combinat/sine_gordon.py | 2 +- src/sage/combinat/symmetric_group_algebra.py | 2 +- src/sage/combinat/tableau_tuple.py | 2 +- src/sage/combinat/words/abstract_word.py | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/sage/combinat/cluster_complex.py b/src/sage/combinat/cluster_complex.py index ba5645b14ca..31562e6bc80 100644 --- a/src/sage/combinat/cluster_complex.py +++ b/src/sage/combinat/cluster_complex.py @@ -50,7 +50,7 @@ from sage.categories.coxeter_groups import CoxeterGroups from sage.combinat.root_system.coxeter_group import CoxeterGroup from sage.combinat.subword_complex import SubwordComplex, SubwordComplexFacet -from sage.rings.semirings.non_negative_integer_semiring import NN +from sage.rings.semirings.all import NN class ClusterComplexFacet(SubwordComplexFacet): diff --git a/src/sage/combinat/crystals/tensor_product.py b/src/sage/combinat/crystals/tensor_product.py index 4b8ee8480d8..7cacfeb335b 100644 --- a/src/sage/combinat/crystals/tensor_product.py +++ b/src/sage/combinat/crystals/tensor_product.py @@ -51,7 +51,7 @@ TensorProductOfSuperCrystalsElement, TensorProductOfQueerSuperCrystalsElement) from sage.misc.flatten import flatten from sage.structure.element import get_coercion_model -from sage.rings.semirings.non_negative_integer_semiring import NN +from sage.rings.semirings.all import NN from sage.arith.misc import integer_trunc as trunc diff --git a/src/sage/combinat/integer_lists/nn.py b/src/sage/combinat/integer_lists/nn.py index 4329c6164d9..6fe0cb0adb5 100644 --- a/src/sage/combinat/integer_lists/nn.py +++ b/src/sage/combinat/integer_lists/nn.py @@ -1,6 +1,6 @@ from sage.sets.family import Family from sage.combinat.integer_lists import IntegerListsLex -from sage.rings.semirings.non_negative_integer_semiring import NN +from sage.rings.semirings.all import NN from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets diff --git a/src/sage/combinat/interval_posets.py b/src/sage/combinat/interval_posets.py index b1cd1b7c939..129709c82cb 100644 --- a/src/sage/combinat/interval_posets.py +++ b/src/sage/combinat/interval_posets.py @@ -48,7 +48,7 @@ from sage.misc.latex import latex from sage.misc.lazy_attribute import lazy_attribute from sage.rings.integer import Integer -from sage.rings.semirings.non_negative_integer_semiring import NN +from sage.rings.semirings.all import NN from sage.sets.non_negative_integers import NonNegativeIntegers from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.family import Family diff --git a/src/sage/combinat/non_decreasing_parking_function.py b/src/sage/combinat/non_decreasing_parking_function.py index 9763793bb1b..b5ecf2bb8c0 100644 --- a/src/sage/combinat/non_decreasing_parking_function.py +++ b/src/sage/combinat/non_decreasing_parking_function.py @@ -38,7 +38,7 @@ from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.sets_with_grading import SetsWithGrading from sage.categories.monoids import Monoids -from sage.rings.semirings.non_negative_integer_semiring import NN +from sage.rings.semirings.all import NN from sage.rings.integer import Integer from sage.structure.element import Element from sage.structure.parent import Parent diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index 70806da2211..66ec83e7413 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -307,7 +307,7 @@ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.rings.semirings.non_negative_integer_semiring import NN +from sage.rings.semirings.all import NN from sage.arith.all import factorial, gcd from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.integer import Integer diff --git a/src/sage/combinat/partition_kleshchev.py b/src/sage/combinat/partition_kleshchev.py index 1663674bfa9..cad6332374a 100644 --- a/src/sage/combinat/partition_kleshchev.py +++ b/src/sage/combinat/partition_kleshchev.py @@ -85,7 +85,7 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.rings.integer_ring import ZZ -from sage.rings.semirings.non_negative_integer_semiring import NN +from sage.rings.semirings.all import NN from sage.cpython.getattr import getattr_from_other_class from collections import defaultdict diff --git a/src/sage/combinat/partition_tuple.py b/src/sage/combinat/partition_tuple.py index 71220fa65dc..c5febd95569 100644 --- a/src/sage/combinat/partition_tuple.py +++ b/src/sage/combinat/partition_tuple.py @@ -267,7 +267,7 @@ class of modules for the algebras, which are generalisations of the Specht from sage.misc.cachefunc import cached_method from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.rings.integer_ring import ZZ -from sage.rings.semirings.non_negative_integer_semiring import NN +from sage.rings.semirings.all import NN from sage.rings.integer import Integer from sage.sets.positive_integers import PositiveIntegers from sage.structure.parent import Parent diff --git a/src/sage/combinat/path_tableaux/semistandard.py b/src/sage/combinat/path_tableaux/semistandard.py index b22a3e0acdc..3aa0dc1937d 100644 --- a/src/sage/combinat/path_tableaux/semistandard.py +++ b/src/sage/combinat/path_tableaux/semistandard.py @@ -85,7 +85,7 @@ from sage.combinat.tableau import Tableau from sage.combinat.gelfand_tsetlin_patterns import GelfandTsetlinPattern from sage.combinat.partition import _Partitions -from sage.rings.semirings.non_negative_integer_semiring import NN +from sage.rings.semirings.all import NN ############################################################################### diff --git a/src/sage/combinat/posets/poset_examples.py b/src/sage/combinat/posets/poset_examples.py index f47310ccb35..18251fde9fd 100644 --- a/src/sage/combinat/posets/poset_examples.py +++ b/src/sage/combinat/posets/poset_examples.py @@ -612,7 +612,7 @@ def IntegerPartitionsDominanceOrder(n): [[4, 2], [5, 1]], [[5, 1], [6]]] """ - from sage.rings.semirings.non_negative_integer_semiring import NN + from sage.rings.semirings.all import NN if n not in NN: raise ValueError('n must be an integer') from sage.combinat.partition import Partitions, Partition @@ -963,7 +963,7 @@ def SetPartitions(n): sage: posets.SetPartitions(4) Finite lattice containing 15 elements """ - from sage.rings.semirings.non_negative_integer_semiring import NN + from sage.rings.semirings.all import NN if n not in NN: raise ValueError('n must be an integer') from sage.combinat.set_partition import SetPartitions diff --git a/src/sage/combinat/root_system/cartan_type.py b/src/sage/combinat/root_system/cartan_type.py index 6bdee48235f..26781f566c6 100644 --- a/src/sage/combinat/root_system/cartan_type.py +++ b/src/sage/combinat/root_system/cartan_type.py @@ -594,7 +594,7 @@ def __call__(self, *args): if isinstance(t, (CartanType_abstract, SuperCartanType_standard)): return t - from sage.rings.semirings.non_negative_integer_semiring import NN + from sage.rings.semirings.all import NN if isinstance(t, str): if "x" in t: from . import type_reducible diff --git a/src/sage/combinat/root_system/root_lattice_realizations.py b/src/sage/combinat/root_system/root_lattice_realizations.py index 377ce53376c..fafaa9fa82f 100644 --- a/src/sage/combinat/root_system/root_lattice_realizations.py +++ b/src/sage/combinat/root_system/root_lattice_realizations.py @@ -3833,7 +3833,7 @@ def is_dominant_weight(self): # Or is_dominant_integral_weight? True """ alphacheck = self.parent().simple_coroots() - from sage.rings.semirings.non_negative_integer_semiring import NN + from sage.rings.semirings.all import NN return all(self.inner_product(alphacheck[i]) in NN for i in self.parent().index_set()) diff --git a/src/sage/combinat/root_system/type_super_A.py b/src/sage/combinat/root_system/type_super_A.py index 1bbbbfdcbff..d77b82d6782 100644 --- a/src/sage/combinat/root_system/type_super_A.py +++ b/src/sage/combinat/root_system/type_super_A.py @@ -442,7 +442,7 @@ def is_dominant_weight(self): """ alpha = self.parent().simple_roots() l = self.parent().cartan_type().symmetrizer() - from sage.rings.semirings.non_negative_integer_semiring import NN + from sage.rings.semirings.all import NN return all(l[i] * self.inner_product(alpha[i]) in NN for i in self.parent().index_set()) diff --git a/src/sage/combinat/sine_gordon.py b/src/sage/combinat/sine_gordon.py index 8a887a76dbd..dcdd91e5f0a 100644 --- a/src/sage/combinat/sine_gordon.py +++ b/src/sage/combinat/sine_gordon.py @@ -45,7 +45,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.real_mpfr import RR -from sage.rings.semirings.non_negative_integer_semiring import NN +from sage.rings.semirings.all import NN from sage.functions.trig import cos, sin from sage.plot.plot import parametric_plot from sage.plot.graphics import Graphics diff --git a/src/sage/combinat/symmetric_group_algebra.py b/src/sage/combinat/symmetric_group_algebra.py index adcb397646a..7ac314bd934 100644 --- a/src/sage/combinat/symmetric_group_algebra.py +++ b/src/sage/combinat/symmetric_group_algebra.py @@ -215,7 +215,7 @@ def SymmetricGroupAlgebra(R, W, category=None): sage: SGg.group().conjugacy_classes_representatives() [(), (1,2), (1,2,3)] """ - from sage.rings.semirings.non_negative_integer_semiring import NN + from sage.rings.semirings.all import NN if W in NN: W = Permutations(W) if category is None: diff --git a/src/sage/combinat/tableau_tuple.py b/src/sage/combinat/tableau_tuple.py index 83adaed546e..35804c7adcb 100644 --- a/src/sage/combinat/tableau_tuple.py +++ b/src/sage/combinat/tableau_tuple.py @@ -231,7 +231,7 @@ from sage.arith.all import factorial from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.rings.integer import Integer -from sage.rings.semirings.non_negative_integer_semiring import NN +from sage.rings.semirings.all import NN from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.family import Family from sage.sets.positive_integers import PositiveIntegers diff --git a/src/sage/combinat/words/abstract_word.py b/src/sage/combinat/words/abstract_word.py index c24d90164d7..beb05eb21a8 100644 --- a/src/sage/combinat/words/abstract_word.py +++ b/src/sage/combinat/words/abstract_word.py @@ -833,7 +833,7 @@ def delta(self): word: 1211222112112112221122211222112112112221... """ from sage.combinat.words.word import Word - from sage.rings.semirings.non_negative_integer_semiring import NN + from sage.rings.semirings.all import NN return Word(self._delta_iterator(), alphabet=NN) def _iterated_right_palindromic_closure_iterator(self, f=None): From 585dbcdb2e3480738ed5ccbf00024472d435cfab Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 13 Jan 2022 20:30:02 +0100 Subject: [PATCH 123/253] Trac #33159: handle subrings of SR as well --- src/sage/matrix/matrix2.pyx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index a637f25c051..d1b4d141577 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -814,6 +814,16 @@ cdef class Matrix(Matrix1): sage: m = matrix(SR, [0.0]) sage: m.solve_right(b, check=True) (0) + + :: + + sage: SC = SR.subring(no_variables=True) + sage: m = matrix(SC, [0]) + sage: b = vector(SC, [1]) + sage: m.solve_right(b) + Traceback (most recent call last): + ... + ValueError: matrix equation has no solutions """ try: L = B.base_ring() @@ -848,8 +858,8 @@ cdef class Matrix(Matrix1): # If our field is inexact, checking the answer is doomed in # most cases. But here we handle the special ones. - from sage.symbolic.ring import SR - if K is SR: + from sage.symbolic.ring import SymbolicRing + if isinstance(K, SymbolicRing): # Elements of SR "remember" whether or not they are exact. # If every element in the system is exact, we can probably # still check the solution over the inexact ring SR. From 0abe6bd78f82ec10ad041571be37c16fdf72fbf5 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Thu, 13 Jan 2022 20:35:33 +0100 Subject: [PATCH 124/253] Trac #33159: comment examples producing wrong output --- src/sage/matrix/matrix2.pyx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index d1b4d141577..8e8c744545d 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -408,6 +408,10 @@ cdef class Matrix(Matrix1): Traceback (most recent call last): ... ValueError: matrix equation has no solutions + + + In this case, turning off the ``check`` leads to a wrong result:: + sage: A.solve_left(b, check=False) (2) @@ -809,8 +813,15 @@ cdef class Matrix(Matrix1): Traceback (most recent call last): ... ValueError: matrix equation has no solutions + + In this case, turning off the ``check`` leads to a wrong result:: + sage: m.solve_right(b, check=False) (0) + + In the following, we have an inexact entry in the matrix, so + the ``check`` is still skipped leading to a wrong result:: + sage: m = matrix(SR, [0.0]) sage: m.solve_right(b, check=True) (0) From 8bb3a23c3edf9211b558f0d4d923273d5f2c5ac0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Fri, 14 Jan 2022 15:46:48 +0100 Subject: [PATCH 125/253] 33045: adding -nostdin argument to ffmpeg command --- src/sage/plot/animate.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/plot/animate.py b/src/sage/plot/animate.py index e3557569e78..57eeb45ce1d 100644 --- a/src/sage/plot/animate.py +++ b/src/sage/plot/animate.py @@ -956,7 +956,9 @@ def ffmpeg(self, savefile=None, show_path=False, output_format=None, # ...', need to come before the input file names, while # some options, like '-pix_fmt rgb24', need to come # afterwards. Hence 'early_options' and 'ffmpeg_options' - cmd = 'cd "%s"; sage-native-execute ffmpeg -y -f image2 %s -i %s %s %s' % (pngdir, early_options, pngs, ffmpeg_options, savefile) + # The `-nostdin` is needed to avoid the command to hang, see + # https://stackoverflow.com/questions/16523746/ffmpeg-hangs-when-run-in-background + cmd = 'cd "%s"; sage-native-execute ffmpeg -nostdin -y -f image2 %s -i %s %s %s' % (pngdir, early_options, pngs, ffmpeg_options, savefile) from subprocess import check_call, CalledProcessError, PIPE try: if sage.misc.verbose.get_verbose() > 0: From 3cf8105bb913ed0f098342f3fe6353ccbe3cb4e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 14 Jan 2022 21:21:09 +0100 Subject: [PATCH 126/253] fix pycodestyle E111 (indentation) in combinat --- .../cluster_algebra_quiver/cluster_seed.py | 6 +-- .../cluster_algebra_quiver/mutation_type.py | 6 +-- src/sage/combinat/crystals/littelmann_path.py | 12 ++--- .../orthogonal_arrays_build_recursive.py | 6 +-- src/sage/combinat/designs/twographs.py | 4 +- src/sage/combinat/k_tableau.py | 5 +- .../multiset_partition_into_sets_ordered.py | 6 +-- src/sage/combinat/path_tableaux/dyck_path.py | 17 +++--- .../rigged_configuration_element.py | 6 +-- .../weight_lattice_realizations.py | 31 ++++++----- src/sage/combinat/sf/llt.py | 54 ++++++++++--------- .../symmetric_group_representations.py | 9 ++-- src/sage/combinat/words/finite_word.py | 11 ++-- src/sage/combinat/words/word_generators.py | 16 +++--- 14 files changed, 96 insertions(+), 93 deletions(-) diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index dc7b23b4d78..a1c02205c39 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -3224,11 +3224,11 @@ def set_cluster( self, cluster, force=False ): for x in cluster][0:self._n] self._is_principal = None else: - print("Warning: clusters not being tracked so this command is ignored.") + print("Warning: clusters not being tracked so this command is ignored.") - def reset_cluster( self ): + def reset_cluster(self): r""" - Resets the cluster of ``self`` to the initial cluster. + Reset the cluster of ``self`` to the initial cluster. EXAMPLES:: diff --git a/src/sage/combinat/cluster_algebra_quiver/mutation_type.py b/src/sage/combinat/cluster_algebra_quiver/mutation_type.py index 181e911c43d..da16dc00019 100644 --- a/src/sage/combinat/cluster_algebra_quiver/mutation_type.py +++ b/src/sage/combinat/cluster_algebra_quiver/mutation_type.py @@ -601,14 +601,14 @@ def _connected_mutation_type(dg): elif len( exc_labels ) == 2: label1, label2 = exc_labels if label1[1] == label2[0]: - pass + pass elif label2[1] == label1[0]: label1, label2 = label2, label1 else: # the exceptional case in affine type BC_2 is checked - if label2[2] == (1,-2) and label1[2] == (2,-1): + if label2[2] == (1, -2) and label1[2] == (2, -1): label1, label2 = label2, label1 - if label1[2] == (1,-2) and label2[2] == (2,-1): + if label1[2] == (1, -2) and label2[2] == (2, -1): if label1[1] == label2[1] and dict_in_out[label1[1]][2] == 2 and dict_in_out[label1[0]][2] == 1 and dict_in_out[label2[0]][2] == 1: return QuiverMutationType(['BC',2,1]) elif label1[0] == label2[0] and dict_in_out[label1[0]][2] == 2 and dict_in_out[label1[1]][2] == 1 and dict_in_out[label2[1]][2] == 1: diff --git a/src/sage/combinat/crystals/littelmann_path.py b/src/sage/combinat/crystals/littelmann_path.py index 04cddcf7278..6f45611e85c 100644 --- a/src/sage/combinat/crystals/littelmann_path.py +++ b/src/sage/combinat/crystals/littelmann_path.py @@ -205,14 +205,14 @@ def __init__(self, starting_weight, starting_weight_parent): self.R = RootSystem(cartan_type) self.weight = starting_weight if not self.weight.parent().base_ring().has_coerce_map_from(QQ): - raise ValueError("Please use the weight space, rather than weight lattice for your weights") + raise ValueError("Please use the weight space, rather than weight lattice for your weights") self._cartan_type = cartan_type - self._name = "The crystal of LS paths of type %s and weight %s"%(cartan_type,starting_weight) + self._name = "The crystal of LS paths of type %s and weight %s" % (cartan_type,starting_weight) if cartan_type.is_affine(): - if all(i>=0 for i in starting_weight.coefficients()): - Parent.__init__( self, category=(RegularCrystals(), - HighestWeightCrystals(), - InfiniteEnumeratedSets()) ) + if all(i >= 0 for i in starting_weight.coefficients()): + Parent.__init__(self, category=(RegularCrystals(), + HighestWeightCrystals(), + InfiniteEnumeratedSets())) elif starting_weight.parent().is_extended(): Parent.__init__(self, category=(RegularCrystals(), InfiniteEnumeratedSets())) else: diff --git a/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py b/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py index 17cf84606b5..a71e7e1ab0f 100644 --- a/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py +++ b/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py @@ -1490,9 +1490,9 @@ def brouwer_separable_design(k,t,q,x,check=False,verbose=False,explain_construct # OA(k-1,N) for PBD_parallel_class in partition_of_blocks_of_size_t: for OA_class in OA_t_classes: - rOA_N_classes.append([[B[x] for x in BB] - for BB in OA_class - for B in PBD_parallel_class]) + rOA_N_classes.append([[B[x] for x in BB] + for BB in OA_class + for B in PBD_parallel_class]) # 2) We build a Nx(q+t) matrix such that: # diff --git a/src/sage/combinat/designs/twographs.py b/src/sage/combinat/designs/twographs.py index 66ddb8f75ca..c0e15ed24fe 100644 --- a/src/sage/combinat/designs/twographs.py +++ b/src/sage/combinat/designs/twographs.py @@ -92,7 +92,7 @@ def __init__(self, points=None, blocks=None, incidence_matrix=None, incidence_matrix=incidence_matrix, name=name, check=False, copy=copy) if check: # it is a very slow, O(|points|^4), test... - assert is_twograph(self), "the structure is not a 2-graph!" + assert is_twograph(self), "the structure is not a 2-graph!" def is_regular_twograph(self, alpha=False): r""" @@ -119,7 +119,7 @@ def is_regular_twograph(self, alpha=False): sage: p.is_regular_twograph() False """ - r, (_,_,_,a) = self.is_t_design(t=2, k=3, return_parameters=True) + r, (_, _, _, a) = self.is_t_design(t=2, k=3, return_parameters=True) if r and alpha: return a return r diff --git a/src/sage/combinat/k_tableau.py b/src/sage/combinat/k_tableau.py index 9d5a40e532d..793461c8717 100644 --- a/src/sage/combinat/k_tableau.py +++ b/src/sage/combinat/k_tableau.py @@ -4205,8 +4205,9 @@ def marked_given_unmarked_and_weight_iterator(cls, unmarkedT, k, weight): import itertools dsc = Composition(weight).descents() for m in itertools.product(*[td[key] for key in sorted(td)]): - if all(((m[i][1]-m[i][0] Date: Sat, 15 Jan 2022 10:00:51 +0100 Subject: [PATCH 127/253] fix some u-prefix optional doctests --- src/sage/databases/findstat.py | 76 +++++++++++++++--------------- src/sage/databases/oeis.py | 2 +- src/sage/interfaces/mathematica.py | 6 +-- 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/sage/databases/findstat.py b/src/sage/databases/findstat.py index ffc1e5a4bfd..7fed038bc41 100644 --- a/src/sage/databases/findstat.py +++ b/src/sage/databases/findstat.py @@ -1605,7 +1605,7 @@ def id_str(self): EXAMPLES:: sage: findstat(51).id_str() # optional -- internet - u'St000051' + 'St000051' """ return self._id @@ -1679,7 +1679,7 @@ def name(self): EXAMPLES:: sage: findstat(51).name() # optional -- internet - u'The size of the left subtree of a binary tree.' + 'The size of the left subtree of a binary tree.' """ return self._data()["Name"] @@ -1882,10 +1882,10 @@ def _first_terms_raw(self, max_values): TESTS:: sage: findstat(41)._first_terms_raw(4) # optional -- internet - [(u'[(1,2)]', 0), - (u'[(1,2),(3,4)]', 0), - (u'[(1,3),(2,4)]', 0), - (u'[(1,4),(2,3)]', 1)] + [('[(1,2)]', 0), + ('[(1,2),(3,4)]', 0), + ('[(1,3),(2,4)]', 0), + ('[(1,4),(2,3)]', 1)] """ # initialize self._first_terms_raw_cache on first call if self._first_terms_raw_cache is None: @@ -2176,16 +2176,16 @@ def _fetch_data(self): TESTS:: sage: findstat(41)._data() # optional -- internet, indirect doctest - {u'Bibliography': {u'MathSciNet:1288802': {u'Author': u'de M\xe9dicis, A., Viennot, X. G.', - u'Title': u'Moments des $q$-polyn\xf4mes de Laguerre et la bijection de Foata-Zeilberger'}, - u'MathSciNet:1418763': {u'Author': u'Simion, R., Stanton, D.', - u'Title': u'Octabasic Laguerre polynomials and permutation statistics'}}, - u'Code': u'def statistic(x):\r\n return len(x.nestings())', - u'Description': u'The number of nestings of a perfect matching. \r\n\r\n\r\nThis is the number of pairs of edges $((a,b), (c,d))$ such that $a\\le c\\le d\\le b$. i.e., the edge $(c,d)$ is nested inside $(a,b)$.', - u'Domain': u'Cc0012', - u'Name': u'The number of nestings of a perfect matching.', - u'References': u'[1] [[MathSciNet:1288802]]\n[2] [[MathSciNet:1418763]]', - u'SageCode': u'def statistic(x):\r\n return len(x.nestings())'} + {'Bibliography': {'MathSciNet:1288802': {'Author': 'de M\xe9dicis, A., Viennot, X. G.', + 'Title': 'Moments des $q$-polyn\xf4mes de Laguerre et la bijection de Foata-Zeilberger'}, + 'MathSciNet:1418763': {'Author': 'Simion, R., Stanton, D.', + 'Title': 'Octabasic Laguerre polynomials and permutation statistics'}}, + 'Code': 'def statistic(x):\r\n return len(x.nestings())', + 'Description': 'The number of nestings of a perfect matching. \r\n\r\n\r\nThis is the number of pairs of edges $((a,b), (c,d))$ such that $a\\le c\\le d\\le b$. i.e., the edge $(c,d)$ is nested inside $(a,b)$.', + 'Domain': 'Cc0012', + 'Name': 'The number of nestings of a perfect matching.', + 'References': '[1] [[MathSciNet:1288802]]\n[2] [[MathSciNet:1418763]]', + 'SageCode': 'def statistic(x):\r\n return len(x.nestings())'} """ fields = "Bibliography,Code,Description,Domain,Name,References,SageCode" fields_Bibliography = "Author,Title" @@ -2209,10 +2209,10 @@ def _fetch_first_terms_raw(self): TESTS:: sage: findstat(41)._first_terms_raw(4) # optional -- internet, indirect doctest - [(u'[(1,2)]', 0), - (u'[(1,2),(3,4)]', 0), - (u'[(1,3),(2,4)]', 0), - (u'[(1,4),(2,3)]', 1)] + [('[(1,2)]', 0), + ('[(1,2),(3,4)]', 0), + ('[(1,3),(2,4)]', 0), + ('[(1,4),(2,3)]', 1)] """ fields = "Values" url = FINDSTAT_API_STATISTICS + self.id_str() + "?fields=" + fields @@ -2762,10 +2762,10 @@ def _fetch_first_terms_raw(self): TESTS:: sage: findstat("St000042oMp00116")._first_terms_raw(4) # optional -- internet, indirect doctest - [(u'[(1,2)]', 0), - (u'[(1,2),(3,4)]', 0), - (u'[(1,3),(2,4)]', 0), - (u'[(1,4),(2,3)]', 1)] + [('[(1,2)]', 0), + ('[(1,2),(3,4)]', 0), + ('[(1,3),(2,4)]', 0), + ('[(1,4),(2,3)]', 1)] """ fields = "Values" url = FINDSTAT_API_STATISTICS + self.id_str() + "?fields=" + fields @@ -3102,14 +3102,14 @@ def _fetch_data(self): TESTS:: sage: findmap(64)._data() # optional -- internet, indirect doctest - {u'Bibliography': {}, - u'Codomain': u'Cc0001', - u'Description': u'Sends a permutation to its reverse.\r\n\r\nThe reverse of a permutation $\\sigma$ of length $n$ is given by $\\tau$ with $\\tau(i) = \\sigma(n+1-i)$.', - u'Domain': u'Cc0001', - u'Name': u'reverse', - u'Properties': u'bijective, graded, involutive', - u'References': u'', - u'SageCode': u'def mapping(sigma):\r\n return sigma.reverse()'} + {'Bibliography': {}, + 'Codomain': 'Cc0001', + 'Description': 'Sends a permutation to its reverse.\r\n\r\nThe reverse of a permutation $\\sigma$ of length $n$ is given by $\\tau$ with $\\tau(i) = \\sigma(n+1-i)$.', + 'Domain': 'Cc0001', + 'Name': 'reverse', + 'Properties': 'bijective, graded, involutive', + 'References': '', + 'SageCode': 'def mapping(sigma):\r\n return sigma.reverse()'} """ fields = "Bibliography,Codomain,Description,Domain,Name,Properties,References,SageCode" fields_Bibliography = "Author,Title" @@ -3210,7 +3210,7 @@ def properties_raw(self): sage: from sage.databases.findstat import FindStatMap # optional -- internet sage: FindStatMap(61).properties_raw() # optional -- internet - u'surjective, graded' + 'surjective, graded' """ return self._data()["Properties"] @@ -3221,9 +3221,9 @@ def set_properties_raw(self, value): EXAMPLES:: sage: from sage.databases.findstat import FindStatMap # optional -- internet - sage: FindStatMap(61).set_properties_raw(u'surjective') # optional -- internet + sage: FindStatMap(61).set_properties_raw('surjective') # optional -- internet sage: FindStatMap(61).properties_raw() # optional -- internet - u'surjective' + 'surjective' sage: FindStatMap(61) # optional -- internet Mp00061(modified): to increasing tree sage: FindStatMap(61).reset() # optional -- internet @@ -4317,7 +4317,7 @@ def id_str(self): sage: from sage.databases.findstat import FindStatCollection sage: c = FindStatCollection("GelfandTsetlinPatterns") # optional -- internet sage: c.id_str() # optional -- internet - u'Cc0018' + 'Cc0018' """ return self._id @@ -4416,10 +4416,10 @@ def name(self, style="singular"): sage: from sage.databases.findstat import FindStatCollection sage: FindStatCollection("Binary trees").name() # optional -- internet - u'Binary tree' + 'Binary tree' sage: FindStatCollection("Binary trees").name(style="plural") # optional -- internet - u'Binary trees' + 'Binary trees' """ if style == "singular": return self._data["Name"] diff --git a/src/sage/databases/oeis.py b/src/sage/databases/oeis.py index 91d2a52e501..2018635bf2d 100644 --- a/src/sage/databases/oeis.py +++ b/src/sage/databases/oeis.py @@ -127,7 +127,7 @@ 'E.g.f.: exp(exp(x) - 1).' sage: [i for i in b.comments() if 'prime' in i][-1] # optional -- internet - 'Number n is prime if mod(a(n)-2,n) = 0. -_Dmitry Kruchinin_, Feb 14 2012' + 'Number n is prime if mod(a(n)-2,n) = 0...' sage: [n for n in range(2, 20) if (b(n)-2) % n == 0] # optional -- internet [2, 3, 5, 7, 11, 13, 17, 19] diff --git a/src/sage/interfaces/mathematica.py b/src/sage/interfaces/mathematica.py index ec3188bce32..4e1e8d24554 100644 --- a/src/sage/interfaces/mathematica.py +++ b/src/sage/interfaces/mathematica.py @@ -1211,7 +1211,7 @@ def parse_moutput_from_json(page_data, verbose=False): sage: from sage.interfaces.mathematica import parse_moutput_from_json sage: page_data = request_wolfram_alpha('integrate Sin[x]') # optional internet sage: parse_moutput_from_json(page_data) # optional internet - [u'-Cos[x]'] + ['-Cos[x]'] :: @@ -1244,7 +1244,7 @@ def parse_moutput_from_json(page_data, verbose=False): print(" Title: {}".format(result['title'])) if 'subpods' not in result: continue - subpods = result[u'subpods'] + subpods = result['subpods'] for j, subpod in enumerate(subpods): if verbose: print(" Subpod #{}".format(j)) @@ -1272,7 +1272,7 @@ def symbolic_expression_from_mathematica_string(mexpr): EXAMPLES:: sage: from sage.interfaces.mathematica import symbolic_expression_from_mathematica_string - sage: symbolic_expression_from_mathematica_string(u'-Cos[x]') + sage: symbolic_expression_from_mathematica_string('-Cos[x]') -cos(x) """ from sage.symbolic.expression import symbol_table From 62b5b9c2c9f7e573ffb76a3b4e23673e486369b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 15 Jan 2022 11:17:54 +0100 Subject: [PATCH 128/253] =?UTF-8?q?des=20accents=20fran=C3=A7ais?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sage/databases/findstat.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/databases/findstat.py b/src/sage/databases/findstat.py index 7fed038bc41..2db608e159d 100644 --- a/src/sage/databases/findstat.py +++ b/src/sage/databases/findstat.py @@ -2176,8 +2176,8 @@ def _fetch_data(self): TESTS:: sage: findstat(41)._data() # optional -- internet, indirect doctest - {'Bibliography': {'MathSciNet:1288802': {'Author': 'de M\xe9dicis, A., Viennot, X. G.', - 'Title': 'Moments des $q$-polyn\xf4mes de Laguerre et la bijection de Foata-Zeilberger'}, + {'Bibliography': {'MathSciNet:1288802': {'Author': 'de Médicis, A., Viennot, X. G.', + 'Title': 'Moments des $q$-polynômes de Laguerre et la bijection de Foata-Zeilberger'}, 'MathSciNet:1418763': {'Author': 'Simion, R., Stanton, D.', 'Title': 'Octabasic Laguerre polynomials and permutation statistics'}}, 'Code': 'def statistic(x):\r\n return len(x.nestings())', @@ -2605,7 +2605,7 @@ def __init__(self, data=None, values_of=None, distribution_of=None, FindStatFunction.__init__(self, FINDSTAT_STATISTIC_PADDED_IDENTIFIER % 0, data={"Bibliography": {}, "Code": _get_code_from_callable(function), - "Description" : "", + "Description": "", "Domain": domain, "Name": "a new statistic on %s" % domain.name("plural"), "References": "", @@ -3524,7 +3524,7 @@ def __init__(self, data=None, values_of=None, distribution_of=None, FindStatFunction.__init__(self, FINDSTAT_MAP_PADDED_IDENTIFIER % 0, data={"Bibliography": {}, "Code": _get_code_from_callable(function), - "Description" : "", + "Description": "", "Domain": domain, "Codomain": codomain, "Name": "a new map from %s to %s" % (domain.name("plural"), codomain.name("plural")), @@ -4645,7 +4645,7 @@ def __init__(self): data["Code"] = _SupportedFindStatCollections[data["NameWiki"]] else: print("%s provides a new collection:" % FindStat()) - print(" %s: %s" %(id, data["NamePlural"])) + print(" %s: %s" % (id, data["NamePlural"])) print("To use it with this interface, it has to be added to the dictionary") print(" _SupportedFindStatCollections in src/sage/databases/findstat.py") print("of the SageMath distribution. Please open a ticket on trac!") From b90a53468ea87e113babb9e3e9f490d3d5616a0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 15 Jan 2022 13:40:10 +0100 Subject: [PATCH 129/253] fix E111 (indentation) in misc, modular, schemes --- src/sage/misc/html.py | 8 +-- src/sage/misc/inline_fortran.py | 9 +-- src/sage/misc/sage_eval.py | 6 +- .../modular/arithgroup/arithgroup_perm.py | 8 +-- src/sage/modular/local_comp/type_space.py | 56 +++++++-------- src/sage/modular/modform/constructor.py | 8 +-- .../modform_hecketriangle/abstract_ring.py | 2 +- .../modform_hecketriangle/abstract_space.py | 13 ++-- .../modform_hecketriangle/analytic_type.py | 72 +++++++++---------- .../graded_ring_element.py | 10 ++- src/sage/schemes/affine/affine_morphism.py | 4 +- src/sage/schemes/affine/affine_point.py | 31 ++++---- src/sage/schemes/plane_conics/con_field.py | 4 +- 13 files changed, 109 insertions(+), 122 deletions(-) diff --git a/src/sage/misc/html.py b/src/sage/misc/html.py index cc310888512..9991b60f2ce 100644 --- a/src/sage/misc/html.py +++ b/src/sage/misc/html.py @@ -465,12 +465,12 @@ def eval(self, s, locals=None): while s: i = s.find('') if i == -1: - t += s - break + t += s + break j = s.find('') if j == -1: - t += s - break + t += s + break t += s[:i] + r'\({}\)'.format(latex(sage_eval(s[6+i:j], locals=locals))) s = s[j+7:] return HtmlFragment(t) diff --git a/src/sage/misc/inline_fortran.py b/src/sage/misc/inline_fortran.py index 749e997bfc9..d7ed02fe92b 100644 --- a/src/sage/misc/inline_fortran.py +++ b/src/sage/misc/inline_fortran.py @@ -204,11 +204,12 @@ def eval(self, x, globals=None, locals=None): if k[0] != '_': globals[k] = x - def add_library(self,s): - self.libraries.append(s) + def add_library(self, s): + self.libraries.append(s) + + def add_library_path(self, s): + self.library_paths.append(s) - def add_library_path(self,s): - self.library_paths.append(s) # An instance fortran = InlineFortran() diff --git a/src/sage/misc/sage_eval.py b/src/sage/misc/sage_eval.py index f65e90fce1a..d928a071619 100644 --- a/src/sage/misc/sage_eval.py +++ b/src/sage/misc/sage_eval.py @@ -1,7 +1,6 @@ r""" Evaluating a String in Sage """ - # **************************************************************************** # Copyright (C) 2006 William Stein # @@ -9,7 +8,6 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** - from copy import copy import sage.repl.preparse as preparser @@ -241,6 +239,6 @@ def sageobj(x, vars=None): """ try: - return x._sage_() + return x._sage_() except (TypeError, NotImplementedError, AttributeError): - return sage_eval(str(x), vars) + return sage_eval(str(x), vars) diff --git a/src/sage/modular/arithgroup/arithgroup_perm.py b/src/sage/modular/arithgroup/arithgroup_perm.py index 315af89f38b..5d06c3fa7a2 100644 --- a/src/sage/modular/arithgroup/arithgroup_perm.py +++ b/src/sage/modular/arithgroup/arithgroup_perm.py @@ -1240,15 +1240,15 @@ def coset_graph(self, if s2_edges: if s2_label is not None: - res.add_edges((i,S2[i],s2_label) for i in range(self.index())) + res.add_edges((i, S2[i], s2_label) for i in range(self.index())) else: - res.add_edges((i,S2[i]) for i in range(self.index())) + res.add_edges((i, S2[i]) for i in range(self.index())) if s3_edges: if s3_label is not None: - res.add_edges((i,S3[i],s3_label) for i in range(self.index())) + res.add_edges((i, S3[i], s3_label) for i in range(self.index())) else: - res.add_edges((i,S3) for i in range(self.index())) + res.add_edges((i, S3) for i in range(self.index())) if l_edges: if l_label is not None: diff --git a/src/sage/modular/local_comp/type_space.py b/src/sage/modular/local_comp/type_space.py index 12bb590b3bb..399a2828b7f 100644 --- a/src/sage/modular/local_comp/type_space.py +++ b/src/sage/modular/local_comp/type_space.py @@ -511,29 +511,29 @@ def _rho_unramified(self, g): return answer def _rho_ramified(self, g): - r""" - Calculate the action of a group element on the type space in the - ramified (odd conductor) case. - - For internal use (called by :meth:`~rho`). - - EXAMPLES:: - - sage: from sage.modular.local_comp.type_space import example_type_space - sage: T = example_type_space(3) - sage: T._rho_ramified([1,0,3,1]) - [ 0 1] - [-1 -1] - sage: T._rho_ramified([1,3,0,1]) == 1 - True - """ - A = self.t_space.ambient() - g = [ZZ(_) for _ in g] - p = self.prime() - assert g[2] % p == 0 - gg = lift_ramified(g, p, self.u(), self.tame_level()) - g3 = [p**self.u() * gg[0], gg[1], p**(2*self.u()) * gg[2], p**self.u() * gg[3]] - return A._action_on_modular_symbols(g3).restrict(self.t_space.free_module()).transpose() / ZZ(p**(self.u() * (self.form().weight()-2) ) ) + r""" + Calculate the action of a group element on the type space in the + ramified (odd conductor) case. + + For internal use (called by :meth:`~rho`). + + EXAMPLES:: + + sage: from sage.modular.local_comp.type_space import example_type_space + sage: T = example_type_space(3) + sage: T._rho_ramified([1,0,3,1]) + [ 0 1] + [-1 -1] + sage: T._rho_ramified([1,3,0,1]) == 1 + True + """ + A = self.t_space.ambient() + g = [ZZ(_) for _ in g] + p = self.prime() + assert g[2] % p == 0 + gg = lift_ramified(g, p, self.u(), self.tame_level()) + g3 = [p**self.u() * gg[0], gg[1], p**(2*self.u()) * gg[2], p**self.u() * gg[3]] + return A._action_on_modular_symbols(g3).restrict(self.t_space.free_module()).transpose() / ZZ(p**(self.u() * (self.form().weight()-2) ) ) def _group_gens(self): r""" @@ -667,17 +667,17 @@ def rho(self, g): True """ if not self.is_minimal(): - raise NotImplementedError( "Group action on non-minimal type space not implemented" ) + raise NotImplementedError("Group action on non-minimal type space not implemented") if self.u() == 0: - # silly special case: rep is principal series or special, so SL2 - # action on type space is trivial - raise ValueError( "Representation is not supercuspidal" ) + # silly special case: rep is principal series or special, so SL2 + # action on type space is trivial + raise ValueError("Representation is not supercuspidal") p = self.prime() f = p**self.u() g = [ZZ(_) for _ in g] - d = (g[0]*g[3] - g[2]*g[1]) + d = (g[0] * g[3] - g[2] * g[1]) # g is in S(K_0) (easy case) if d % f == 1: diff --git a/src/sage/modular/modform/constructor.py b/src/sage/modular/modform/constructor.py index 2b9b59085f3..e16b2e4f1df 100644 --- a/src/sage/modular/modform/constructor.py +++ b/src/sage/modular/modform/constructor.py @@ -313,10 +313,10 @@ def ModularForms(group = 1, raise ValueError("eis_only parameter only valid in weight 1") if use_cache and key in _cache: - M = _cache[key]() - if not (M is None): - M.set_precision(prec) - return M + M = _cache[key]() + if not (M is None): + M.set_precision(prec) + return M (level, group, weight, base_ring, eis_only) = key diff --git a/src/sage/modular/modform_hecketriangle/abstract_ring.py b/src/sage/modular/modform_hecketriangle/abstract_ring.py index 387d87f1b05..20385434b10 100644 --- a/src/sage/modular/modform_hecketriangle/abstract_ring.py +++ b/src/sage/modular/modform_hecketriangle/abstract_ring.py @@ -1524,7 +1524,7 @@ def g_inv(self): (x,y,z,d) = self._pol_ring.gens() return self.extend_type("weak", ring=True)(1/d*y*x**(self._group.n()/ZZ(2))/(x**self._group.n()-y**2)).reduce() else: - raise ArithmeticError("g_inv doesn't exist for odd n(={}).".format(self._group.n())) + raise ArithmeticError("g_inv doesn't exist for odd n(={}).".format(self._group.n())) @cached_method def E4(self): diff --git a/src/sage/modular/modform_hecketriangle/abstract_space.py b/src/sage/modular/modform_hecketriangle/abstract_space.py index ad4307e3936..c39d2893d86 100644 --- a/src/sage/modular/modform_hecketriangle/abstract_space.py +++ b/src/sage/modular/modform_hecketriangle/abstract_space.py @@ -1481,8 +1481,8 @@ def quasi_part_gens(self, r=None, min_exp=0, max_exp=infinity, order_1=ZZ(0)): """ if (not self.is_weakly_holomorphic()): - from warnings import warn - warn("This function only determines generators of (quasi) weakly modular forms!") + from warnings import warn + warn("This function only determines generators of (quasi) weakly modular forms!") (min_exp, order_1) = self._canonical_min_exp(min_exp, order_1) @@ -1586,8 +1586,8 @@ def quasi_part_dimension(self, r=None, min_exp=0, max_exp=infinity, order_1=ZZ(0 """ if (not self.is_weakly_holomorphic()): - from warnings import warn - warn("This function only determines the dimension of some (quasi) weakly subspace!") + from warnings import warn + warn("This function only determines the dimension of some (quasi) weakly subspace!") (min_exp, order_1) = self._canonical_min_exp(min_exp, order_1) @@ -2126,10 +2126,9 @@ def q_basis(self, m=None, min_exp=0, order_1=ZZ(0)): [1 - 168*q^2 + 2304*q^3 - 19320*q^4 + O(q^5), q - 18*q^2 + 180*q^3 - 1316*q^4 + O(q^5)] """ - if (not self.is_weakly_holomorphic()): - from warnings import warn - warn("This function only determines elements / a basis of (quasi) weakly modular forms!") + from warnings import warn + warn("This function only determines elements / a basis of (quasi) weakly modular forms!") (min_exp, order_1) = self._canonical_min_exp(min_exp, order_1) order_inf = self._l1 - order_1 diff --git a/src/sage/modular/modform_hecketriangle/analytic_type.py b/src/sage/modular/modform_hecketriangle/analytic_type.py index b56fc11ec00..b15e8b249a9 100644 --- a/src/sage/modular/modform_hecketriangle/analytic_type.py +++ b/src/sage/modular/modform_hecketriangle/analytic_type.py @@ -118,21 +118,19 @@ def analytic_space_name(self): sage: AT([]).analytic_space_name() 'Zero' """ - name = "" - if self.parent()("quasi") <= self: - name += "Quasi" - if self.parent()("mero") <= self: - name += "MeromorphicModular" - elif self.parent()("weak") <= self: - name += "WeakModular" - elif self.parent()("holo") <= self: - name += "Modular" - elif self.parent()("cusp") <= self: - name += "Cusp" + if self.parent()("quasi") <= self: + name += "Quasi" + if self.parent()("mero") <= self: + name += "MeromorphicModular" + elif self.parent()("weak") <= self: + name += "WeakModular" + elif self.parent()("holo") <= self: + name += "Modular" + elif self.parent()("cusp") <= self: + name += "Cusp" else: - name = "Zero" - + name = "Zero" return name def latex_space_name(self): @@ -155,21 +153,19 @@ def latex_space_name(self): sage: AT([]).latex_space_name() 'Z' """ - name = "" - if self.parent()("quasi") <= self: - name += "Q" - if self.parent()("mero") <= self: - name += "\\tilde{M}" - elif self.parent()("weak") <= self: - name += "M^!" - elif self.parent()("holo") <= self: - name += "M" - elif self.parent()("cusp") <= self: - name += "C" + if self.parent()("quasi") <= self: + name += "Q" + if self.parent()("mero") <= self: + name += "\\tilde{M}" + elif self.parent()("weak") <= self: + name += "M^!" + elif self.parent()("holo") <= self: + name += "M" + elif self.parent()("cusp") <= self: + name += "C" else: - name = "Z" - + name = "Z" return name def analytic_name(self): @@ -187,21 +183,19 @@ def analytic_name(self): sage: AT([]).analytic_name() 'zero' """ - name = "" - if self.parent()("quasi") <= self: - name += "quasi " - if self.parent()("mero") <= self: - name += "meromorphic modular" - elif self.parent()("weak") <= self: - name += "weakly holomorphic modular" - elif self.parent()("holo") <= self: - name += "modular" - elif self.parent()("cusp") <= self: - name += "cuspidal" + if self.parent()("quasi") <= self: + name += "quasi " + if self.parent()("mero") <= self: + name += "meromorphic modular" + elif self.parent()("weak") <= self: + name += "weakly holomorphic modular" + elif self.parent()("holo") <= self: + name += "modular" + elif self.parent()("cusp") <= self: + name += "cuspidal" else: - name = "zero" - + name = "zero" return name def reduce_to(self, reduce_type): diff --git a/src/sage/modular/modform_hecketriangle/graded_ring_element.py b/src/sage/modular/modform_hecketriangle/graded_ring_element.py index bbea13eb078..b0af21809f2 100644 --- a/src/sage/modular/modform_hecketriangle/graded_ring_element.py +++ b/src/sage/modular/modform_hecketriangle/graded_ring_element.py @@ -2151,7 +2151,7 @@ def evaluate(self, tau, prec = None, num_prec = None, check=False): # if tau is a point of HyperbolicPlane then we use it's coordinates in the UHP model if (tau in HyperbolicPlane()): - tau = tau.to_model('UHP').coordinates() + tau = tau.to_model('UHP').coordinates() if (prec is None): prec = self.parent().default_prec() @@ -2160,14 +2160,12 @@ def evaluate(self, tau, prec = None, num_prec = None, check=False): # In case the order is known try: - if (check or\ - tau == infinity or\ - tau == i or\ - tau == self.group().rho() or\ + if (check or tau == infinity or tau == i or + tau == self.group().rho() or tau == -self.group().rho().conjugate()): order_tau = self.order_at(tau) - if (order_tau > 0): + if order_tau > 0: return ZZ(0) elif (order_tau < 0): return infinity diff --git a/src/sage/schemes/affine/affine_morphism.py b/src/sage/schemes/affine/affine_morphism.py index 54c8a247309..97b84e2e855 100644 --- a/src/sage/schemes/affine/affine_morphism.py +++ b/src/sage/schemes/affine/affine_morphism.py @@ -205,9 +205,9 @@ def __init__(self, parent, polys, check=True): raise ValueError("there must be %s polynomials"%target.ngens()) try: polys = [source_ring(poly) for poly in polys] - except TypeError: # maybe given quotient ring elements + except TypeError: # maybe given quotient ring elements try: - polys = [source_ring(poly.lift()) for poly in polys] + polys = [source_ring(poly.lift()) for poly in polys] except (TypeError, AttributeError): # must be a rational function since we cannot have # rational functions for quotient rings diff --git a/src/sage/schemes/affine/affine_point.py b/src/sage/schemes/affine/affine_point.py index 5cfe8379fd8..bf86bc225c6 100644 --- a/src/sage/schemes/affine/affine_point.py +++ b/src/sage/schemes/affine/affine_point.py @@ -249,26 +249,23 @@ def homogenize(self, n): class SchemeMorphism_point_affine_field(SchemeMorphism_point_affine): def __hash__(self): - r""" - Computes the hash value of this affine point. - - EXAMPLES:: - - sage: A. = AffineSpace(QQ, 2) - sage: X = A.subscheme(x - y) - sage: hash(X([1, 1])) == hash((1,1)) - True + r""" + Compute the hash value of this affine point. - :: + EXAMPLES:: - sage: A. = AffineSpace(QQ, 2) - sage: X = A.subscheme(x^2 - y^3) - sage: pt = X([1, 1]) - sage: hash(pt) == hash(tuple(pt)) - True + sage: A. = AffineSpace(QQ, 2) + sage: X = A.subscheme(x - y) + sage: hash(X([1, 1])) == hash((1,1)) + True - """ - return hash(tuple(self)) + sage: A. = AffineSpace(QQ, 2) + sage: X = A.subscheme(x^2 - y^3) + sage: pt = X([1, 1]) + sage: hash(pt) == hash(tuple(pt)) + True + """ + return hash(tuple(self)) def weil_restriction(self): r""" diff --git a/src/sage/schemes/plane_conics/con_field.py b/src/sage/schemes/plane_conics/con_field.py index 57285966f19..db4e363236c 100644 --- a/src/sage/schemes/plane_conics/con_field.py +++ b/src/sage/schemes/plane_conics/con_field.py @@ -592,8 +592,8 @@ def has_singular_point(self, point = False): NotImplementedError: Sorry, find singular point on conics not implemented over all fields of characteristic 2. """ if not point: - ret = self.has_singular_point(point = True) - return ret[0] + ret = self.has_singular_point(point=True) + return ret[0] B = self.base_ring() if B.characteristic() == 2: [a,b,c,d,e,f] = self.coefficients() From a7d956cfd80bec1102868676bddd6f1d103a1fa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 15 Jan 2022 14:00:08 +0100 Subject: [PATCH 130/253] fix E111 in algebras calculus categories crypto databases tensor --- .../algebras/steenrod/steenrod_algebra_misc.py | 9 +++++---- src/sage/calculus/transforms/dft.py | 14 +++++++------- src/sage/categories/category_with_axiom.py | 2 +- src/sage/categories/crystals.py | 2 +- src/sage/categories/examples/crystals.py | 12 ++++++------ src/sage/categories/examples/sets_cat.py | 13 +++++++------ src/sage/categories/finite_coxeter_groups.py | 4 ++-- .../categories/triangular_kac_moody_algebras.py | 2 +- src/sage/crypto/stream.py | 8 ++++---- src/sage/crypto/stream_cipher.py | 14 +++++++------- src/sage/databases/knotinfo_db.py | 14 +++----------- src/sage/databases/sql_db.py | 14 +++++++------- src/sage/tensor/modules/comp.py | 6 +++--- .../tensor/modules/finite_rank_free_module.py | 16 ++++++++-------- src/sage/tensor/modules/free_module_homset.py | 2 +- src/sage/tensor/modules/free_module_morphism.py | 2 +- src/sage/tensor/modules/free_module_tensor.py | 3 +-- 17 files changed, 65 insertions(+), 72 deletions(-) diff --git a/src/sage/algebras/steenrod/steenrod_algebra_misc.py b/src/sage/algebras/steenrod/steenrod_algebra_misc.py index c221b17461d..ec265009b1b 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra_misc.py +++ b/src/sage/algebras/steenrod/steenrod_algebra_misc.py @@ -31,17 +31,18 @@ methods. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008-2010 John H. Palmieri # Distributed under the terms of the GNU General Public License (GPL) -#***************************************************************************** +# **************************************************************************** ###################################################### # basis names _steenrod_milnor_basis_names = ['milnor'] _steenrod_serre_cartan_basis_names = ['serre_cartan', 'serre-cartan', 'sc', - 'adem', 'admissible'] + 'adem', 'admissible'] + def get_basis_name(basis, p, generic=None): """ @@ -163,7 +164,7 @@ def get_basis_name(basis, p, generic=None): elif basis.find('z') >= 0: result = 'woodz' else: - raise ValueError("%s is not a recognized basis at the prime %s." % (basis, p)) + raise ValueError("%s is not a recognized basis at the prime %s." % (basis, p)) elif not generic and basis.find('arnon') >= 0: if basis.find('c') >= 0: result = 'arnonc' diff --git a/src/sage/calculus/transforms/dft.py b/src/sage/calculus/transforms/dft.py index d1b1dcf0928..a93b5436122 100644 --- a/src/sage/calculus/transforms/dft.py +++ b/src/sage/calculus/transforms/dft.py @@ -524,22 +524,22 @@ def convolution_periodic(self, other): J = other.index_object() F = self.base_ring() E = other.base_ring() - if F!=E: - raise TypeError("IndexedSequences must have same parent") - if I!=J: + if F != E: + raise TypeError("IndexedSequences must have same parent") + if I != J: raise TypeError("IndexedSequences must have same index set") M = len(S) N = len(T) - if MN: + if M > N: b = [T[i] for i in range(N)]+[E(0) for i in range(M-N)] a = self - if M==N: + if M == N: a = S b = T - N = max(M,N) + N = max(M, N) c = [sum([a[i]*b[(j-i)%N] for i in range(N)]) for j in range(2*N-1)] return c diff --git a/src/sage/categories/category_with_axiom.py b/src/sage/categories/category_with_axiom.py index cbd3823ab5e..adf25d36a29 100644 --- a/src/sage/categories/category_with_axiom.py +++ b/src/sage/categories/category_with_axiom.py @@ -2070,7 +2070,7 @@ def __classget__(cls, base_category, base_category_class): setattr(base_category_class, cls._axiom, cls) if base_category is None: - return cls + return cls # For Rings().Finite, this returns the method # Sets.SubcategoryMethods.Finite, with its first argument bound to Rings() return getattr(super(base_category.__class__.__base__, base_category), cls._axiom) diff --git a/src/sage/categories/crystals.py b/src/sage/categories/crystals.py index 69241ed8942..a3199e149c9 100644 --- a/src/sage/categories/crystals.py +++ b/src/sage/categories/crystals.py @@ -554,7 +554,7 @@ def subcrystal(self, index_set=None, generators=None, max_depth=float("inf"), if category is None: category = FiniteCrystals() else: - category = FiniteCrystals() & category + category = FiniteCrystals() & category if self in FiniteCrystals() and len(subset) == self.cardinality(): if index_set == self.index_set(): diff --git a/src/sage/categories/examples/crystals.py b/src/sage/categories/examples/crystals.py index 2ea5983b636..4ba3a82fb64 100644 --- a/src/sage/categories/examples/crystals.py +++ b/src/sage/categories/examples/crystals.py @@ -1,13 +1,12 @@ r""" Example of a crystal """ -#***************************************************************************** +# **************************************************************************** # 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.structure.parent import Parent from sage.structure.element_wrapper import ElementWrapper from sage.structure.unique_representation import UniqueRepresentation @@ -16,6 +15,7 @@ from sage.categories.enumerated_sets import EnumeratedSets from sage.combinat.root_system.cartan_type import CartanType + class HighestWeightCrystalOfTypeA(UniqueRepresentation, Parent): r""" An example of a crystal: the highest weight crystal of type `A_n` @@ -212,8 +212,8 @@ def e(self, i): """ assert i in self.index_set() for edge in self.parent().G.edges(): - if edge[1]==int(str(self)) and edge[2]==i: - return self.parent()(edge[0]) + if edge[1] == int(str(self)) and edge[2] == i: + return self.parent()(edge[0]) return None def f(self, i): diff --git a/src/sage/categories/examples/sets_cat.py b/src/sage/categories/examples/sets_cat.py index c2fba4de679..6cc88bc551b 100644 --- a/src/sage/categories/examples/sets_cat.py +++ b/src/sage/categories/examples/sets_cat.py @@ -219,22 +219,23 @@ def _element_constructor_(self, i): @abstract_method def _from_integer_(self, i): - """ - Fast construction of an element of self from an integer. No prime - checking is performed. To be defined. + """ + Fast construction of an element of self from an integer. + + No prime checking is performed. To be defined. - EXAMPLES:: + EXAMPLES:: sage: P = Sets().example("inherits") sage: P._from_integer_(13) 13 - sage: P._from_integer_(42) # Don't do that at home kids! + sage: P._from_integer_(42) # Do not do that at home kids! 42 sage: P(42) Traceback (most recent call last): ... ValueError: 42 is not a prime number - """ + """ def next(self, i): """ diff --git a/src/sage/categories/finite_coxeter_groups.py b/src/sage/categories/finite_coxeter_groups.py index 8e7df277404..f9da021a30c 100644 --- a/src/sage/categories/finite_coxeter_groups.py +++ b/src/sage/categories/finite_coxeter_groups.py @@ -566,11 +566,11 @@ def m_cambrian_lattice(self, c, m=1, on_roots=False): """ from sage.combinat.posets.lattices import LatticePoset if hasattr(c, "reduced_word"): - c = c.reduced_word() + c = c.reduced_word() c = list(c) sorting_word = self.long_element().coxeter_sorting_word(c) - + if on_roots: if not hasattr(self.long_element(), "reflection_to_root"): raise ValueError("The parameter 'on_root=True' needs " diff --git a/src/sage/categories/triangular_kac_moody_algebras.py b/src/sage/categories/triangular_kac_moody_algebras.py index a8182fce950..76840cc63a0 100644 --- a/src/sage/categories/triangular_kac_moody_algebras.py +++ b/src/sage/categories/triangular_kac_moody_algebras.py @@ -222,7 +222,7 @@ def verma_module(self, la, basis_key=None, **kwds): return VermaModule(self, la, basis_key=basis_key, **kwds) class ElementMethods: - def part(self): + def part(self): """ Return whether the element ``v`` is in the lower, zero, or upper part of ``self``. diff --git a/src/sage/crypto/stream.py b/src/sage/crypto/stream.py index d41a6a9d5a6..f0554d7a6cc 100644 --- a/src/sage/crypto/stream.py +++ b/src/sage/crypto/stream.py @@ -54,14 +54,14 @@ def __init__(self, field = None): because of the dependence on binary strings. """ if field is None: - field = FiniteField(2) + field = FiniteField(2) if field.cardinality() != 2: raise NotImplementedError("Not yet implemented.") S = BinaryStrings() SymmetricKeyCryptosystem.__init__(self, S, S, None) self._field = field - def __eq__(self,right): + def __eq__(self, right): return type(self) is type(right) and self._field == right._field def __call__(self, key): @@ -103,7 +103,7 @@ class ShrinkingGeneratorCryptosystem(SymmetricKeyCryptosystem): """ Shrinking generator cryptosystem class """ - def __init__(self, field = None): + def __init__(self, field=None): """ Create a shrinking generator cryptosystem. @@ -118,7 +118,7 @@ def __init__(self, field = None): Shrinking generator cryptosystem over Finite Field of size 2 """ if field is None: - field = FiniteField(2) + field = FiniteField(2) if field.cardinality() != 2: raise NotImplementedError("Not yet implemented.") S = BinaryStrings() diff --git a/src/sage/crypto/stream_cipher.py b/src/sage/crypto/stream_cipher.py index c077e00107b..07a9bf08251 100644 --- a/src/sage/crypto/stream_cipher.py +++ b/src/sage/crypto/stream_cipher.py @@ -265,18 +265,18 @@ def __call__(self, M, mode = "ECB"): IS_2 = e2.initial_state() k = 0 N = len(M) - n = max(n1,n2) + n = max(n1, n2) CStream = [] while k < N: r = max(N-k,2*n) KStream = lfsr_sequence(g1.list(), IS_1, r) DStream = lfsr_sequence(g2.list(), IS_2, r) - for i in range(r-n): - if DStream[i] != 0: - CStream.append(int(MStream[k]+KStream[i])) - k += 1 - if k == N: - break + for i in range(r - n): + if DStream[i] != 0: + CStream.append(int(MStream[k] + KStream[i])) + k += 1 + if k == N: + break IS_1 = KStream[r-n-1:r-n+n1] IS_2 = DStream[r-n-1:r-n+n2] return B(CStream) diff --git a/src/sage/databases/knotinfo_db.py b/src/sage/databases/knotinfo_db.py index 7ec59d4e501..7d789b42229 100644 --- a/src/sage/databases/knotinfo_db.py +++ b/src/sage/databases/knotinfo_db.py @@ -7,13 +7,10 @@ at the web-pages `KnotInfo `__ and `LinkInfo `__. - AUTHORS: - Sebastian Oehms August 2020: initial version """ - - ############################################################################## # Copyright (C) 2020 Sebastian Oehms # @@ -21,10 +18,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/ ############################################################################## - - import os from enum import Enum @@ -50,7 +45,6 @@ class KnotInfoColumnTypes(Enum): , ] """ - OnlyKnots = 'K' # column that is only used in the KnotInfo table OnlyLinks = 'L' # column that is only used in the LinkInfo table KnotsAndLinks = 'B' # column that is only used in both tables @@ -158,14 +152,12 @@ def description_webpage(self, new=0, autoraise=True): """ import webbrowser if self.column_type() == self.types.OnlyLinks: - url = KnotInfoFilename.links.description_url(self) + url = KnotInfoFilename.links.description_url(self) else: - url = KnotInfoFilename.knots.description_url(self) + url = KnotInfoFilename.knots.description_url(self) return webbrowser.open(url, new=new, autoraise=autoraise) - - class KnotInfoFilename(Enum): r""" Enum for the different data files. The following choices are possible: diff --git a/src/sage/databases/sql_db.py b/src/sage/databases/sql_db.py index 85773e7ca36..7cfdf0ce033 100644 --- a/src/sage/databases/sql_db.py +++ b/src/sage/databases/sql_db.py @@ -477,14 +477,14 @@ def __init__(self, database, *args, **kwds): + 'dictionary or a string and tuple') if 'query_dict' in kwds: - query_dict = kwds['query_dict'] + query_dict = kwds['query_dict'] else: - self.__query_string__ = kwds['query_string'] - if 'param_tuple' in kwds: - self.__param_tuple__ = tuple((str(x) for x in kwds['param_tuple'])) - else: - self.__param_tuple__ = tuple() - return + self.__query_string__ = kwds['query_string'] + if 'param_tuple' in kwds: + self.__param_tuple__ = tuple((str(x) for x in kwds['param_tuple'])) + else: + self.__param_tuple__ = tuple() + return if query_dict: skel = database.__skeleton__ if query_dict['table_name'] not in skel: diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 5b7eef7dc25..b122942c36e 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -1500,7 +1500,7 @@ def __neg__(self): """ result = self._new_instance() for ind, val in self._comp.items(): - result._comp[ind] = - val + result._comp[ind] = - val return result def __add__(self, other): @@ -2359,12 +2359,12 @@ def make_Contraction(this, other, local_list, rev_s, rev_o, ind_o[pos_o] = k ic += 1 sm += this[[ind_s]] * other[[ind_o]] - local_res.append([ind,sm]) + local_res.append([ind, sm]) return local_res for ii, val in make_Contraction(listParalInput): for jj in val: - res[[jj[0]]] = jj[1] + res[[jj[0]]] = jj[1] else: # sequential computation for ind in res.non_redundant_index_generator(): diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 74fc441cf0f..129725b5ff0 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1535,22 +1535,22 @@ def tensor_from_comp(self, tensor_type, comp, name=None, latex_name=None): """ from .comp import CompWithSym, CompFullyAntiSym - # + # 0/ Compatibility checks: if comp._ring is not self._ring: - raise TypeError("the components are not defined on the same" + + raise TypeError("the components are not defined on the same" " ring as the module") if comp._frame not in self._known_bases: - raise TypeError("the components are not defined on a basis of" + + raise TypeError("the components are not defined on a basis of" " the module") if comp._nid != tensor_type[0] + tensor_type[1]: - raise TypeError("number of component indices not compatible with "+ + raise TypeError("number of component indices not compatible with " " the tensor type") - # + # 1/ Construction of the tensor: - if tensor_type == (1,0): + if tensor_type == (1, 0): resu = self.element_class(self, name=name, latex_name=latex_name) - elif tensor_type == (0,1): + elif tensor_type == (0, 1): resu = self.linear_form(name=name, latex_name=latex_name) elif tensor_type[0] == 0 and tensor_type[1] > 1 and \ isinstance(comp, CompFullyAntiSym): @@ -1961,7 +1961,7 @@ def _latex_(self): if self._latex_name is None: return r'\mbox{' + str(self) + r'}' else: - return self._latex_name + return self._latex_name def rank(self): r""" diff --git a/src/sage/tensor/modules/free_module_homset.py b/src/sage/tensor/modules/free_module_homset.py index dcf5214c98f..ba6a738afdf 100644 --- a/src/sage/tensor/modules/free_module_homset.py +++ b/src/sage/tensor/modules/free_module_homset.py @@ -253,7 +253,7 @@ def _latex_(self): if self._latex_name is None: return r'\mbox{' + str(self) + r'}' else: - return self._latex_name + return self._latex_name def __call__(self, *args, **kwds): r""" diff --git a/src/sage/tensor/modules/free_module_morphism.py b/src/sage/tensor/modules/free_module_morphism.py index 404a91e38d1..986ac0a7d7d 100644 --- a/src/sage/tensor/modules/free_module_morphism.py +++ b/src/sage/tensor/modules/free_module_morphism.py @@ -334,7 +334,7 @@ def _latex_(self): if self._latex_name is None: return r'\mbox{' + str(self) + r'}' else: - return self._latex_name + return self._latex_name def __eq__(self, other): r""" diff --git a/src/sage/tensor/modules/free_module_tensor.py b/src/sage/tensor/modules/free_module_tensor.py index ad17b6018b5..f5c2da72c7c 100644 --- a/src/sage/tensor/modules/free_module_tensor.py +++ b/src/sage/tensor/modules/free_module_tensor.py @@ -1705,12 +1705,11 @@ def copy(self, name=None, latex_name=None): [ 0 0 2] sage: t1 == t False - """ 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._components[basis] = comp.copy() resu._is_zero = self._is_zero return resu From 354db4d2ec918dcb9a38f086885599b01a499526 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sat, 15 Jan 2022 18:50:06 -0500 Subject: [PATCH 131/253] Trac #33185: fix cython warnings for givaro elements. While compiling sage/rings/finite_rings/element_givaro.pyx, Cython emits several warnings of the form, warning: sage/rings/finite_rings/element_givaro.pyx:312:41: local variable 'res' referenced before assignment that are all harmless, since they refer to int variables being passed by reference to C functions to be overwritten. Nevertheless the warnings are unattractive and distracting. Here we silence them by initializing the variables to zero. --- .../rings/finite_rings/element_givaro.pyx | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/sage/rings/finite_rings/element_givaro.pyx b/src/sage/rings/finite_rings/element_givaro.pyx index e28808d84bf..0c4ee308d34 100644 --- a/src/sage/rings/finite_rings/element_givaro.pyx +++ b/src/sage/rings/finite_rings/element_givaro.pyx @@ -307,7 +307,7 @@ cdef class Cache_givaro(Cache_base): True """ cdef int seed = current_randstate().c_random() - cdef int res + cdef int res = 0 cdef GivRandom generator = GivRandomSeeded(seed) self.objectptr.random(generator, res) return make_FiniteField_givaroElement(self, res) @@ -360,7 +360,7 @@ cdef class Cache_givaro(Cache_base): For more examples, see ``finite_field_givaro.FiniteField_givaro._element_constructor_`` """ - cdef int res + cdef int res = 0 cdef int g cdef int x cdef int e_int @@ -490,7 +490,7 @@ cdef class Cache_givaro(Cache_base): sage: K._cache.gen() a """ - cdef int g + cdef int g = 0 if self.objectptr.exponent() == 1: self.objectptr.initi(g, -self.parent.modulus()[0]) else: @@ -524,7 +524,7 @@ cdef class Cache_givaro(Cache_base): elif n >= self.order_c(): raise IndexError("n=%d must be < self.order()" % n) - cdef int r + cdef int r = 0 sig_on() self.objectptr.convert(r, n) sig_off() @@ -554,7 +554,7 @@ cdef class Cache_givaro(Cache_base): sage: k.gen()^57 3 """ - cdef int r + cdef int r = 0 sig_on() self.objectptr.initi(r, n) sig_off() @@ -703,7 +703,7 @@ cdef class Cache_givaro(Cache_base): sage: k._cache.a_times_b_plus_c(a,a,k(1)) a^2 + 1 """ - cdef int r + cdef int r = 0 self.objectptr.axpy(r, a.element, b.element, c.element) return make_FiniteField_givaroElement(self, r) @@ -724,7 +724,7 @@ cdef class Cache_givaro(Cache_base): sage: k._cache.a_times_b_minus_c(a,a,k(1)) a^2 + 2 """ - cdef int r + cdef int r = 0 self.objectptr.axmy(r, a.element, b.element, c.element, ) return make_FiniteField_givaroElement(self, r) @@ -745,7 +745,7 @@ cdef class Cache_givaro(Cache_base): sage: k._cache.c_minus_a_times_b(a,a,k(1)) 2*a^2 + 1 """ - cdef int r + cdef int r = 0 self.objectptr.maxpy(r, a.element, b.element, c.element,) return make_FiniteField_givaroElement(self, r) @@ -1100,7 +1100,7 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement): sage: b^10 + 2*b # indirect doctest 2*b^3 + 2*b^2 + 2*b + 1 """ - cdef int r + cdef int r = 0 self._cache.objectptr.add(r, self.element, (right).element) return make_FiniteField_givaroElement(self._cache, r) @@ -1117,7 +1117,7 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement): sage: c*c c^2 """ - cdef int r + cdef int r = 0 self._cache.objectptr.mul(r, self.element, (right).element) return make_FiniteField_givaroElement(self._cache, r) @@ -1137,7 +1137,7 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement): ... ZeroDivisionError: division by zero in finite field """ - cdef int r + cdef int r = 0 if (right).element == 0: raise ZeroDivisionError('division by zero in finite field') self._cache.objectptr.div(r, self.element, @@ -1156,7 +1156,7 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement): sage: 2*a - a^2 2*a^2 + 2*a """ - cdef int r + cdef int r = 0 self._cache.objectptr.sub(r, self.element, (right).element) return make_FiniteField_givaroElement(self._cache, r) @@ -1172,7 +1172,7 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement): sage: -a 2*a """ - cdef int r + cdef int r = 0 self._cache.objectptr.neg(r, self.element) return make_FiniteField_givaroElement(self._cache, r) @@ -1203,7 +1203,7 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement): ZeroDivisionError: division by zero in finite field """ - cdef int r + cdef int r = 0 if self.element == 0: raise ZeroDivisionError('division by zero in finite field') self._cache.objectptr.inv(r, self.element) From c2bb732b61a47bd547fc772bbefb1870e1a243f6 Mon Sep 17 00:00:00 2001 From: Jieao Song <8d1h@tutanota.com> Date: Mon, 17 Jan 2022 01:40:11 +0100 Subject: [PATCH 132/253] Trac #33192: fix bug in LiE interface --- src/sage/interfaces/lie.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/interfaces/lie.py b/src/sage/interfaces/lie.py index 7e58d7a0ca0..777a5abe3e5 100644 --- a/src/sage/interfaces/lie.py +++ b/src/sage/interfaces/lie.py @@ -801,6 +801,8 @@ def _sage_(self): [12 4 -4 7] [-1 9 8 0] [ 3 -5 -2 9] + sage: lie('-1X[1,1]').sage() # optional - lie + -x0*x1 """ t = self.type() @@ -833,8 +835,7 @@ def _sage_(self): terms += termgrp.split('+') # Make sure we don't accidentally add a negative # sign to the first monomial - if s[0] != "-": - terms[0] = terms[0][1:] + terms[0] = terms[0][1:] # go through all the terms in s for term in terms: From 87b4a2dd53c66e76e84f880fe914794bf44da812 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Mon, 17 Jan 2022 07:49:25 -0500 Subject: [PATCH 133/253] Trac #33197: redeclare add_variable() in LP backend subclass. When overriding a C method to add optional parameters in Cython, you have to re-declare the method in the corresponding subclass pxd file; otherwise, you'll get warnings like those that Cython is throwing: warning: sage/numerical/backends/interactivelp_backend.pyx:171:10: Compatible but non-identical C method 'add_variable' not redeclared in definition part of extension type 'InteractiveLPBackend'. This may cause incorrect vtables to be generated. In this case the fix is simple, and we redeclare add_variable() with the additional optional parameter in interactivelp_backend.pxd. --- src/sage/numerical/backends/interactivelp_backend.pxd | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sage/numerical/backends/interactivelp_backend.pxd b/src/sage/numerical/backends/interactivelp_backend.pxd index 7347e2ef7e7..07e63a7bb44 100644 --- a/src/sage/numerical/backends/interactivelp_backend.pxd +++ b/src/sage/numerical/backends/interactivelp_backend.pxd @@ -19,6 +19,17 @@ cdef class InteractiveLPBackend(GenericBackend): cdef object final_dictionary cdef int verbosity + cpdef int add_variable(self, + lower_bound=*, + upper_bound=*, + binary=*, + continuous=*, + integer=*, + obj=*, + name=*, + coefficients=*) \ + except -1 + cpdef dictionary(self) cpdef interactive_lp_problem(self) From e1a2d3a7ea90934a62441b79c6318c0fb95146ee Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 17 Jan 2022 09:44:50 -0800 Subject: [PATCH 134/253] tox.ini: Add centos-stream-{8,9} --- tox.ini | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tox.ini b/tox.ini index 1675106d45f..a34255bc42d 100644 --- a/tox.ini +++ b/tox.ini @@ -265,6 +265,7 @@ setenv = scientificlinux-7: BASE_TAG=7 # # https://hub.docker.com/_/centos + # https://quay.io/repository/centos/centos?tab=tags # centos-6 only has autoconf 2.63 -- too old for bootstrap; download configure tarball instead. # centos: SYSTEM=fedora @@ -274,6 +275,10 @@ setenv = centos-6: BOOTSTRAP=./bootstrap -D centos-7: BASE_TAG=centos7 centos-8: BASE_TAG=centos8 + centos-stream: BASE_IMAGE=quay.io/centos/centos + centos-stream: BASE_TAG=stream + centos-stream-8: BASE_TAG=stream8 + centos-stream-9: BASE_TAG=stream9 # # https://hub.docker.com/r/sheerluck/sage-on-gentoo-stage4/tags # From 0694b049ca7539cc59688fced9166ba27eaca106 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 17 Jan 2022 11:49:01 -0800 Subject: [PATCH 135/253] git grep -l 'graphs.all.*import' | xargs sed -E -i.bak $'s/^( *)from sage.*all import Graph, DiGraph *$/\1from sage.graphs.graph import Graph\n\1from sage.graphs.digraph import Digraph/;s/from sage.*all import Graph/from sage.graphs.graph import Graph/;s/from sage.*all import DiGraph/from sage.graphs.digraph import DiGraph/;' --- src/sage/categories/crystals.py | 2 +- src/sage/categories/examples/crystals.py | 2 +- src/sage/categories/finite_coxeter_groups.py | 2 +- src/sage/categories/finite_groups.py | 2 +- .../categories/highest_weight_crystals.py | 2 +- src/sage/categories/regular_crystals.py | 2 +- src/sage/graphs/base/static_sparse_graph.pyx | 5 +- src/sage/graphs/digraph.py | 4 +- src/sage/graphs/generators/families.py | 2 +- src/sage/graphs/generic_graph.py | 52 ++++++++++--------- src/sage/graphs/graph.py | 6 +-- src/sage/graphs/graph_generators.py | 2 +- src/sage/graphs/line_graph.pyx | 2 +- .../perm_gps/partn_ref/refinement_graphs.pyx | 12 +++-- src/sage/matroids/constructor.py | 2 +- src/sage/matroids/linear_matroid.pyx | 3 +- src/sage/modular/btquotients/btquotient.py | 2 +- src/sage/sandpiles/sandpile.py | 2 +- src/sage/stats/hmm/hmm.pyx | 2 +- 19 files changed, 58 insertions(+), 50 deletions(-) diff --git a/src/sage/categories/crystals.py b/src/sage/categories/crystals.py index 69241ed8942..062c02b671e 100644 --- a/src/sage/categories/crystals.py +++ b/src/sage/categories/crystals.py @@ -889,7 +889,7 @@ def digraph(self, subset=None, index_set=None): .. TODO:: Add more tests. """ - from sage.graphs.all import DiGraph + from sage.graphs.digraph import DiGraph d = {} # Parse optional arguments diff --git a/src/sage/categories/examples/crystals.py b/src/sage/categories/examples/crystals.py index 2ea5983b636..d4f4a127d18 100644 --- a/src/sage/categories/examples/crystals.py +++ b/src/sage/categories/examples/crystals.py @@ -12,7 +12,7 @@ from sage.structure.element_wrapper import ElementWrapper from sage.structure.unique_representation import UniqueRepresentation from sage.categories.classical_crystals import ClassicalCrystals -from sage.graphs.all import DiGraph +from sage.graphs.digraph import DiGraph from sage.categories.enumerated_sets import EnumeratedSets from sage.combinat.root_system.cartan_type import CartanType diff --git a/src/sage/categories/finite_coxeter_groups.py b/src/sage/categories/finite_coxeter_groups.py index 8e7df277404..69d7a0813e7 100644 --- a/src/sage/categories/finite_coxeter_groups.py +++ b/src/sage/categories/finite_coxeter_groups.py @@ -890,7 +890,7 @@ def coxeter_knuth_graph(self): ... NotImplementedError: This has only been implemented in finite type A so far! """ - from sage.graphs.all import Graph + from sage.graphs.graph import Graph R = [tuple(v) for v in self.reduced_words()] G = Graph() G.add_vertices(R) diff --git a/src/sage/categories/finite_groups.py b/src/sage/categories/finite_groups.py index e0adb301ce2..901a23b4f44 100644 --- a/src/sage/categories/finite_groups.py +++ b/src/sage/categories/finite_groups.py @@ -136,7 +136,7 @@ def cayley_graph_disabled(self, connecting_set=None): if g not in self: raise RuntimeError("Each element of the connecting set must be in the group!") connecting_set = [self(g) for g in connecting_set] - from sage.graphs.all import DiGraph + from sage.graphs.digraph import DiGraph arrows = {} for x in self: arrows[x] = {} diff --git a/src/sage/categories/highest_weight_crystals.py b/src/sage/categories/highest_weight_crystals.py index 6ce57f2217e..266a1cab6fb 100644 --- a/src/sage/categories/highest_weight_crystals.py +++ b/src/sage/categories/highest_weight_crystals.py @@ -497,7 +497,7 @@ def digraph(self, subset=None, index_set=None, depth=None): raise NotImplementedError("crystals not known to be finite must" " specify either the subset or depth") - from sage.graphs.all import DiGraph + from sage.graphs.digraph import DiGraph if index_set is None: index_set = self.index_set() diff --git a/src/sage/categories/regular_crystals.py b/src/sage/categories/regular_crystals.py index 843e7ea628c..6fa2af200fa 100644 --- a/src/sage/categories/regular_crystals.py +++ b/src/sage/categories/regular_crystals.py @@ -446,7 +446,7 @@ def wt_zero(x): y = x.e(i).e(im).f(i).f(im) if checker(y): edges.append([x, y, i]) - from sage.graphs.all import DiGraph + from sage.graphs.digraph import DiGraph G = DiGraph([X, edges], format="vertices_and_edges", immutable=True) from sage.graphs.dot2tex_utils import have_dot2tex if have_dot2tex(): diff --git a/src/sage/graphs/base/static_sparse_graph.pyx b/src/sage/graphs/base/static_sparse_graph.pyx index 690cd85454c..b4f9e35e5b1 100644 --- a/src/sage/graphs/base/static_sparse_graph.pyx +++ b/src/sage/graphs/base/static_sparse_graph.pyx @@ -230,7 +230,8 @@ cdef int init_short_digraph(short_digraph g, G, edge_labelled=False, vertex_list cdef int isdigraph - from sage.graphs.all import Graph, DiGraph + from sage.graphs.graph import Graph + from sage.graphs.digraph import Digraph if isinstance(G, DiGraph): isdigraph = 1 @@ -1116,7 +1117,7 @@ def spectral_radius(G, prec=1e-10): # and the iteration is likely to reach a cycle of length 2 and hence the # algorithm never terminate. Here we compute the "square" reduced to # one component of the bipartition. - from sage.graphs.all import DiGraph + from sage.graphs.digraph import DiGraph H = DiGraph(loops=True, multiedges=True) if G.is_directed(): neighbors_iterator = G.neighbor_out_iterator diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index 77118925586..6edcb6000ee 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -670,7 +670,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, msg += "Non-symmetric or non-square matrix assumed to be an incidence matrix: " if format is None and isinstance(data, DiGraph): format = 'DiGraph' - from sage.graphs.all import Graph + from sage.graphs.graph import Graph if format is None and isinstance(data, Graph): data = data.to_directed() format = 'DiGraph' @@ -1062,7 +1062,7 @@ def to_undirected(self, data_structure=None, sparse=None): data_structure = "sparse" else: data_structure = "static_sparse" - from sage.graphs.all import Graph + from sage.graphs.graph import Graph G = Graph(name = self.name(), pos = self._pos, multiedges = self.allows_multiple_edges(), diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index 0c69a777250..6c24a345898 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -2950,7 +2950,7 @@ def line_graph_forbidden_subgraphs(): Graph on 5 vertices] """ - from sage.graphs.all import Graph + from sage.graphs.graph import Graph from sage.graphs.generators.basic import ClawGraph graphs = [ClawGraph()] diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 3dfced8db34..b7df6cc0955 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -614,7 +614,7 @@ def __eq__(self, other): # inputs must be (di)graphs: if not isinstance(other, GenericGraph): return False - from sage.graphs.all import Graph + from sage.graphs.graph import Graph g1_is_graph = isinstance(self, Graph) # otherwise, DiGraph g2_is_graph = isinstance(other, Graph) # otherwise, DiGraph # Fast checks @@ -6227,7 +6227,7 @@ def steiner_tree(self, vertices, weighted=False, solver=None, verbose=0, self._scream_if_not_simple(allow_loops=True) if self.is_directed(): - from sage.graphs.all import Graph + from sage.graphs.graph import Graph g = Graph(self) else: g = self @@ -8119,7 +8119,7 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, ################# if g.is_directed(): - from sage.graphs.all import DiGraph + from sage.graphs.digraph import DiGraph b = p.new_variable(binary=True) # Objective function @@ -8169,7 +8169,7 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, ################### else: - from sage.graphs.all import Graph + from sage.graphs.graph import Graph b = p.new_variable(binary=True) # Objective function @@ -8254,7 +8254,7 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, p.set_objective(p.sum(weight(l) * f[u,v] for u,v,l in g.edge_iterator())) # defining the answer when g is directed - from sage.graphs.all import DiGraph + from sage.graphs.digraph import DiGraph tsp = DiGraph() else: @@ -8270,7 +8270,7 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, if use_edge_labels: p.set_objective(p.sum(weight(l) * f[frozenset((u,v))] for u,v,l in g.edge_iterator())) - from sage.graphs.all import Graph + from sage.graphs.graph import Graph # defining the answer when g is not directed tsp = Graph() @@ -14913,7 +14913,7 @@ def distance_graph(self, dist): looped = True else: looped = False - from sage.graphs.all import Graph + from sage.graphs.graph import Graph D = Graph(vertices, pos=positions, multiedges=False, loops=looped) if len(distances) == 1: dstring = "distance " + str(distances[0]) @@ -18146,10 +18146,10 @@ def union(self, other, immutable=None): weighted = self.weighted() and other.weighted() if self._directed: - from sage.graphs.all import DiGraph + from sage.graphs.digraph import DiGraph G = DiGraph(multiedges=multiedges, loops=loops, weighted=weighted) else: - from sage.graphs.all import Graph + from sage.graphs.graph import Graph G = Graph(multiedges=multiedges, loops=loops, weighted=weighted) G.add_vertices(self) G.add_vertices(other) @@ -18216,10 +18216,10 @@ def cartesian_product(self, other): """ self._scream_if_not_simple(allow_loops=True) if self._directed and other._directed: - from sage.graphs.all import DiGraph + from sage.graphs.digraph import DiGraph G = DiGraph(loops=(self.has_loops() or other.has_loops())) elif (not self._directed) and (not other._directed): - from sage.graphs.all import Graph + from sage.graphs.graph import Graph G = Graph(loops=(self.has_loops() or other.has_loops())) else: raise TypeError('the graphs should be both directed or both undirected') @@ -18300,10 +18300,10 @@ def tensor_product(self, other): """ self._scream_if_not_simple(allow_loops=True) if self._directed and other._directed: - from sage.graphs.all import DiGraph + from sage.graphs.digraph import DiGraph G = DiGraph(loops=(self.has_loops() or other.has_loops())) elif (not self._directed) and (not other._directed): - from sage.graphs.all import Graph + from sage.graphs.graph import Graph G = Graph(loops=(self.has_loops() or other.has_loops())) else: raise TypeError('the graphs should be both directed or both undirected') @@ -18370,10 +18370,10 @@ def lexicographic_product(self, other): """ self._scream_if_not_simple(allow_loops=True) if self._directed and other._directed: - from sage.graphs.all import DiGraph + from sage.graphs.digraph import DiGraph G = DiGraph(loops=(self.has_loops() or other.has_loops())) elif (not self._directed) and (not other._directed): - from sage.graphs.all import Graph + from sage.graphs.graph import Graph G = Graph(loops=(self.has_loops() or other.has_loops())) else: raise TypeError('the graphs should be both directed or both undirected') @@ -18451,10 +18451,10 @@ def strong_product(self, other): """ self._scream_if_not_simple(allow_loops=True) if self._directed and other._directed: - from sage.graphs.all import DiGraph + from sage.graphs.digraph import DiGraph G = DiGraph(loops=(self.has_loops() or other.has_loops())) elif (not self._directed) and (not other._directed): - from sage.graphs.all import Graph + from sage.graphs.graph import Graph G = Graph(loops=(self.has_loops() or other.has_loops())) else: raise TypeError('the graphs should be both directed or both undirected') @@ -18522,10 +18522,10 @@ def disjunctive_product(self, other): """ self._scream_if_not_simple(allow_loops=True) if self._directed and other._directed: - from sage.graphs.all import DiGraph + from sage.graphs.digraph import DiGraph G = DiGraph(loops=(self.has_loops() or other.has_loops())) elif (not self._directed) and (not other._directed): - from sage.graphs.all import Graph + from sage.graphs.graph import Graph G = Graph(loops=(self.has_loops() or other.has_loops())) else: raise TypeError('the graphs should be both directed or both undirected') @@ -19355,7 +19355,7 @@ def layout_tree(self, tree_orientation="down", tree_root=None, if not self: return dict() - from sage.graphs.all import Graph + from sage.graphs.graph import Graph if not Graph(self).is_tree(): raise RuntimeError("cannot use tree layout on this graph: " "self.is_tree() returns False") @@ -22347,7 +22347,8 @@ def automorphism_group(self, partition=None, verbosity=0, from sage.groups.perm_gps.partn_ref.refinement_graphs import search_tree from sage.groups.perm_gps.permgroup import PermutationGroup - from sage.graphs.all import Graph, DiGraph + from sage.graphs.graph import Graph + from sage.graphs.digraph import Digraph from itertools import chain dig = (self._directed or self.has_loops()) @@ -22848,7 +22849,8 @@ def is_isomorphic(self, other, certificate=False, verbosity=0, edge_labels=False G2 = other partition2 = other_vertices G_to = {u: i for i,u in enumerate(self_vertices)} - from sage.graphs.all import Graph, DiGraph + from sage.graphs.graph import Graph + from sage.graphs.digraph import Digraph DoDG = DiGraph if self._directed else Graph H = DoDG(len(self_vertices), loops=G.allows_loops()) HB = H._backend @@ -23098,7 +23100,8 @@ class by some canonization function `c`. If `G` and `H` are graphs, # algorithm == 'sage': from sage.groups.perm_gps.partn_ref.refinement_graphs import search_tree - from sage.graphs.all import Graph, DiGraph + from sage.graphs.graph import Graph + from sage.graphs.digraph import Digraph from itertools import chain dig = (self.has_loops() or self._directed) @@ -24096,7 +24099,8 @@ def graph_isom_equivalent_non_edge_labeled_graph(g, partition=None, standard_lab sage: g[0].is_bipartite() False """ - from sage.graphs.all import Graph, DiGraph + from sage.graphs.graph import Graph + from sage.graphs.digraph import Digraph from itertools import chain g_has_multiple_edges = g.has_multiple_edges() diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 5833d463704..1a979bf3463 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1067,7 +1067,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, format = 'incidence_matrix' if format is None and isinstance(data, Graph): format = 'Graph' - from sage.graphs.all import DiGraph + from sage.graphs.digraph import DiGraph if format is None and isinstance(data, DiGraph): data = data.to_undirected() format = 'Graph' @@ -3312,7 +3312,7 @@ def bounded_outdegree_orientation(self, bound, solver=None, verbose=False, """ self._scream_if_not_simple() - from sage.graphs.all import DiGraph + from sage.graphs.digraph import DiGraph n = self.order() if not n: @@ -5541,7 +5541,7 @@ def to_directed(self, data_structure=None, sparse=None): data_structure = "sparse" else: data_structure = "static_sparse" - from sage.graphs.all import DiGraph + from sage.graphs.digraph import DiGraph D = DiGraph(name = self.name(), pos = self.get_pos(), multiedges = self.allows_multiple_edges(), diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index 99674f84e8d..8ae793b45f8 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -775,7 +775,7 @@ def __call__(self, vertices=None, property=None, augment='edges', def property(x): return True - from sage.graphs.all import Graph + from sage.graphs.graph import Graph from copy import copy as copyfun if degree_sequence is not None: diff --git a/src/sage/graphs/line_graph.pyx b/src/sage/graphs/line_graph.pyx index 95198350d51..592b6a50be3 100644 --- a/src/sage/graphs/line_graph.pyx +++ b/src/sage/graphs/line_graph.pyx @@ -366,7 +366,7 @@ def line_graph(g, labels=True): for f in g.outgoing_edge_iterator(v, labels=labels)) return G else: - from sage.graphs.all import Graph + from sage.graphs.graph import Graph G = Graph() # We must sort the edges' endpoints so that (1,2,None) is seen as the diff --git a/src/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx b/src/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx index 35369fc6702..6bb495a0738 100644 --- a/src/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +++ b/src/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx @@ -70,7 +70,8 @@ def isomorphic(G1, G2, partn, ordering2, dig, use_indicator_function, sparse=Fal cdef list partition, cell cdef bint loops = 0 - from sage.graphs.all import Graph, DiGraph + from sage.graphs.graph import Graph + from sage.graphs.digraph import Digraph from sage.graphs.generic_graph import GenericGraph from copy import copy which_G = 1 @@ -379,7 +380,8 @@ def search_tree(G_in, partition, lab=True, dig=False, dict_rep=False, certificat cdef bint loops cdef aut_gp_and_can_lab *output cdef PartitionStack *part - from sage.graphs.all import Graph, DiGraph + from sage.graphs.graph import Graph + from sage.graphs.digraph import Digraph from sage.graphs.generic_graph import GenericGraph from copy import copy if isinstance(G_in, GenericGraph): @@ -775,7 +777,7 @@ def all_labeled_graphs(n): 5 34 """ - from sage.graphs.all import Graph + from sage.graphs.graph import Graph TE = [] for i in range(n): for j in range(i): @@ -1291,7 +1293,7 @@ def generate_dense_graphs_edge_addition(int n, bint loops, G = None, depth = Non 12346 """ - from sage.graphs.all import Graph + from sage.graphs.graph import Graph cdef iterator *graph_iterator cdef DenseGraph DG, ODG cdef GraphStruct GS @@ -1561,7 +1563,7 @@ def generate_dense_graphs_vert_addition(int n, base_G = None, bint construct = F 11 """ - from sage.graphs.all import Graph + from sage.graphs.graph import Graph cdef iterator *graph_iterator cdef DenseGraph DG, ODG cdef GraphStruct GS diff --git a/src/sage/matroids/constructor.py b/src/sage/matroids/constructor.py index a2de93f9817..ec20bc3830a 100644 --- a/src/sage/matroids/constructor.py +++ b/src/sage/matroids/constructor.py @@ -103,7 +103,7 @@ from itertools import combinations from sage.matrix.constructor import Matrix -from sage.graphs.all import Graph +from sage.graphs.graph import Graph from sage.structure.element import is_Matrix from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ diff --git a/src/sage/matroids/linear_matroid.pyx b/src/sage/matroids/linear_matroid.pyx index 161b8dbc40d..8756e5b8e66 100644 --- a/src/sage/matroids/linear_matroid.pyx +++ b/src/sage/matroids/linear_matroid.pyx @@ -6032,7 +6032,8 @@ cdef class RegularMatroid(LinearMatroid): Digraph on 55 vertices """ # NEW VERSION, Uses Sage'S Graph Isomorphism - from sage.graphs.all import Graph, DiGraph + from sage.graphs.graph import Graph + from sage.graphs.digraph import Digraph if self._r_hypergraph is not None: return (self._hypergraph_vertex_partition, self._hypergraph_tuples, self._r_hypergraph) cdef Matrix P = self._projection() diff --git a/src/sage/modular/btquotients/btquotient.py b/src/sage/modular/btquotients/btquotient.py index a3adb0fc47e..5a77409ee2a 100644 --- a/src/sage/modular/btquotients/btquotient.py +++ b/src/sage/modular/btquotients/btquotient.py @@ -56,7 +56,7 @@ from sage.rings.finite_rings.finite_field_constructor import GF from sage.algebras.quatalg.all import QuaternionAlgebra from sage.quadratic_forms.all import QuadraticForm -from sage.graphs.all import Graph +from sage.graphs.graph import Graph from sage.libs.pari.all import pari from sage.interfaces.magma import magma from sage.plot.colors import rainbow diff --git a/src/sage/sandpiles/sandpile.py b/src/sage/sandpiles/sandpile.py index bfbf7466012..910ab3f56b8 100644 --- a/src/sage/sandpiles/sandpile.py +++ b/src/sage/sandpiles/sandpile.py @@ -330,7 +330,7 @@ from sage.functions.log import exp from sage.functions.other import binomial from sage.geometry.polyhedron.constructor import Polyhedron -from sage.graphs.all import DiGraph, Graph +from sage.graphs.digraph import DiGraph, Graph from sage.graphs.digraph_generators import digraphs from sage.probability.probability_distribution import GeneralDiscreteDistribution from sage.topology.simplicial_complex import SimplicialComplex diff --git a/src/sage/stats/hmm/hmm.pyx b/src/sage/stats/hmm/hmm.pyx index 8e184e9e251..6a1ebe2bdd2 100644 --- a/src/sage/stats/hmm/hmm.pyx +++ b/src/sage/stats/hmm/hmm.pyx @@ -144,7 +144,7 @@ cdef class HiddenMarkovModel: for j in range(self.N): if m[i,j] < eps: m[i,j] = 0 - from sage.graphs.all import DiGraph + from sage.graphs.digraph import DiGraph return DiGraph(m, weighted=True) def sample(self, Py_ssize_t length, number=None, starting_state=None): From 5ec356b0aebc3be1feea3a852e4cba71e965ab32 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 17 Jan 2022 11:51:06 -0800 Subject: [PATCH 136/253] git grep -l 'graphs.all.*import' | xargs sed -E -i.bak 's/from sage.graphs.all import graphs/from sage.graphs.graph_generators import graphs/' --- src/sage/geometry/hyperplane_arrangement/library.py | 2 +- src/sage/graphs/graph_generators.py | 2 +- src/sage/matroids/catalog.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/geometry/hyperplane_arrangement/library.py b/src/sage/geometry/hyperplane_arrangement/library.py index cd66827debb..14c5b747215 100644 --- a/src/sage/geometry/hyperplane_arrangement/library.py +++ b/src/sage/geometry/hyperplane_arrangement/library.py @@ -12,7 +12,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.graphs.all import graphs +from sage.graphs.graph_generators import graphs from sage.matrix.constructor import matrix, random_matrix from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index 8ae793b45f8..b4d7fffe477 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -1070,7 +1070,7 @@ def cospectral_graphs(self, vertices, matrix_function=lambda g: g.adjacency_matr sage: g[0][1].laplacian_matrix(normalized=True).charpoly()==g[0][1].laplacian_matrix(normalized=True).charpoly() # optional - sage.symbolic True """ - from sage.graphs.all import graphs as graph_gen + from sage.graphs.graph_generators import graphs as graph_gen if graphs is None: graph_list=graph_gen(vertices, property=lambda _: True) elif callable(graphs): diff --git a/src/sage/matroids/catalog.py b/src/sage/matroids/catalog.py index f80d1741248..61071b0c757 100644 --- a/src/sage/matroids/catalog.py +++ b/src/sage/matroids/catalog.py @@ -36,7 +36,7 @@ # **************************************************************************** from sage.matrix.constructor import Matrix -from sage.graphs.all import graphs +from sage.graphs.graph_generators import graphs from sage.rings.integer_ring import ZZ from sage.rings.finite_rings.finite_field_constructor import GF From cfb108695f4802309fa3c50fc54cbfb81342e3d7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 17 Jan 2022 11:53:04 -0800 Subject: [PATCH 137/253] src/sage/matroids/utilities.py: Replace imports from sage.graphs.all, sage.rings.all --- src/sage/matroids/utilities.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sage/matroids/utilities.py b/src/sage/matroids/utilities.py index f856e32c87d..477109f6e11 100644 --- a/src/sage/matroids/utilities.py +++ b/src/sage/matroids/utilities.py @@ -25,8 +25,11 @@ # **************************************************************************** from sage.matrix.constructor import Matrix -from sage.rings.all import ZZ, QQ, GF -from sage.graphs.all import BipartiteGraph, Graph +from sage.rings.finite_rings.finite_field_constructor import GF +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.graphs.graph import Graph +from sage.graphs.bipartite_graph import BipartiteGraph from sage.structure.all import SageObject from sage.graphs.spanning_tree import kruskal from operator import itemgetter From f12c46f132c7a6b713de9b2b443c0b84ac5e99c0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 17 Jan 2022 14:54:20 -0800 Subject: [PATCH 138/253] src/sage/sandpiles/sandpile.py: Fix up imports --- src/sage/sandpiles/sandpile.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/sandpiles/sandpile.py b/src/sage/sandpiles/sandpile.py index 910ab3f56b8..1dc48240162 100644 --- a/src/sage/sandpiles/sandpile.py +++ b/src/sage/sandpiles/sandpile.py @@ -330,7 +330,8 @@ from sage.functions.log import exp from sage.functions.other import binomial from sage.geometry.polyhedron.constructor import Polyhedron -from sage.graphs.digraph import DiGraph, Graph +from sage.graphs.graph import Graph +from sage.graphs.digraph import DiGraph from sage.graphs.digraph_generators import digraphs from sage.probability.probability_distribution import GeneralDiscreteDistribution from sage.topology.simplicial_complex import SimplicialComplex From 1dbef4d6659c10051fb52be37217277897fe1d6a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 18 Jan 2022 13:40:30 -0800 Subject: [PATCH 139/253] git grep -l 'import Digraph' | xargs sed -i.bak 's/import Digraph/import DiGraph/' --- src/sage/graphs/base/static_sparse_graph.pyx | 2 +- src/sage/graphs/generic_graph.py | 8 ++++---- src/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx | 4 ++-- src/sage/matroids/linear_matroid.pyx | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/graphs/base/static_sparse_graph.pyx b/src/sage/graphs/base/static_sparse_graph.pyx index b4f9e35e5b1..e55f5f4297b 100644 --- a/src/sage/graphs/base/static_sparse_graph.pyx +++ b/src/sage/graphs/base/static_sparse_graph.pyx @@ -231,7 +231,7 @@ cdef int init_short_digraph(short_digraph g, G, edge_labelled=False, vertex_list cdef int isdigraph from sage.graphs.graph import Graph - from sage.graphs.digraph import Digraph + from sage.graphs.digraph import DiGraph if isinstance(G, DiGraph): isdigraph = 1 diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index b7df6cc0955..f29ada2a04f 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -22348,7 +22348,7 @@ def automorphism_group(self, partition=None, verbosity=0, from sage.groups.perm_gps.partn_ref.refinement_graphs import search_tree from sage.groups.perm_gps.permgroup import PermutationGroup from sage.graphs.graph import Graph - from sage.graphs.digraph import Digraph + from sage.graphs.digraph import DiGraph from itertools import chain dig = (self._directed or self.has_loops()) @@ -22850,7 +22850,7 @@ def is_isomorphic(self, other, certificate=False, verbosity=0, edge_labels=False partition2 = other_vertices G_to = {u: i for i,u in enumerate(self_vertices)} from sage.graphs.graph import Graph - from sage.graphs.digraph import Digraph + from sage.graphs.digraph import DiGraph DoDG = DiGraph if self._directed else Graph H = DoDG(len(self_vertices), loops=G.allows_loops()) HB = H._backend @@ -23101,7 +23101,7 @@ class by some canonization function `c`. If `G` and `H` are graphs, # algorithm == 'sage': from sage.groups.perm_gps.partn_ref.refinement_graphs import search_tree from sage.graphs.graph import Graph - from sage.graphs.digraph import Digraph + from sage.graphs.digraph import DiGraph from itertools import chain dig = (self.has_loops() or self._directed) @@ -24100,7 +24100,7 @@ def graph_isom_equivalent_non_edge_labeled_graph(g, partition=None, standard_lab False """ from sage.graphs.graph import Graph - from sage.graphs.digraph import Digraph + from sage.graphs.digraph import DiGraph from itertools import chain g_has_multiple_edges = g.has_multiple_edges() diff --git a/src/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx b/src/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx index 6bb495a0738..1afc70ad67a 100644 --- a/src/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +++ b/src/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx @@ -71,7 +71,7 @@ def isomorphic(G1, G2, partn, ordering2, dig, use_indicator_function, sparse=Fal cdef bint loops = 0 from sage.graphs.graph import Graph - from sage.graphs.digraph import Digraph + from sage.graphs.digraph import DiGraph from sage.graphs.generic_graph import GenericGraph from copy import copy which_G = 1 @@ -381,7 +381,7 @@ def search_tree(G_in, partition, lab=True, dig=False, dict_rep=False, certificat cdef aut_gp_and_can_lab *output cdef PartitionStack *part from sage.graphs.graph import Graph - from sage.graphs.digraph import Digraph + from sage.graphs.digraph import DiGraph from sage.graphs.generic_graph import GenericGraph from copy import copy if isinstance(G_in, GenericGraph): diff --git a/src/sage/matroids/linear_matroid.pyx b/src/sage/matroids/linear_matroid.pyx index 8756e5b8e66..bdc88768dde 100644 --- a/src/sage/matroids/linear_matroid.pyx +++ b/src/sage/matroids/linear_matroid.pyx @@ -6033,7 +6033,7 @@ cdef class RegularMatroid(LinearMatroid): """ # NEW VERSION, Uses Sage'S Graph Isomorphism from sage.graphs.graph import Graph - from sage.graphs.digraph import Digraph + from sage.graphs.digraph import DiGraph if self._r_hypergraph is not None: return (self._hypergraph_vertex_partition, self._hypergraph_tuples, self._r_hypergraph) cdef Matrix P = self._projection() From a8a471f2194d98fd5f0954b50a89e7137a1652df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 20 Jan 2022 20:53:48 +0100 Subject: [PATCH 140/253] cleanup elliptic Tate curve file --- .../schemes/elliptic_curves/ell_tate_curve.py | 92 +++++++++---------- 1 file changed, 44 insertions(+), 48 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_tate_curve.py b/src/sage/schemes/elliptic_curves/ell_tate_curve.py index 533078f0808..ce945be6d16 100644 --- a/src/sage/schemes/elliptic_curves/ell_tate_curve.py +++ b/src/sage/schemes/elliptic_curves/ell_tate_curve.py @@ -25,9 +25,7 @@ - William Stein (2007-05-29): added some examples; editing. - Chris Wuthrich (04/09): reformatted docstrings. - """ - ###################################################################### # Copyright (C) 2007 chris wuthrich # @@ -42,7 +40,6 @@ # # https://www.gnu.org/licenses/ ###################################################################### - from sage.rings.integer_ring import ZZ from sage.rings.padics.factory import Qp from sage.structure.sage_object import SageObject @@ -63,8 +60,8 @@ class TateCurve(SageObject): .. NOTE:: - Some of the methods of this Tate curve only work when the - reduction is split multiplicative over `\QQ_p`. + Some of the methods of this Tate curve only work when the + reduction is split multiplicative over `\QQ_p`. EXAMPLES:: @@ -94,14 +91,14 @@ def __init__(self, E, p): if not p.is_prime(): raise ValueError("p (=%s) must be a prime" % p) if E.j_invariant().valuation(p) >= 0: - raise ValueError("The elliptic curve must have multiplicative reduction at %s" % p) + raise ValueError("the elliptic curve must have multiplicative reduction at %s" % p) self._p = ZZ(p) self._E = E self._q = self.parameter() def __richcmp__(self, other, op): r""" - Compare self and other. + Compare ``self`` and ``other``. TESTS:: @@ -196,7 +193,7 @@ def __sk(self, k, prec): def __delta(self, prec): q = self.parameter(prec=prec) - return q * prod([(1 - q ** n) ** 24 + return q * prod([(1 - q**n)**24 for n in range(1, prec + 1)]) def curve(self, prec=20): @@ -220,7 +217,6 @@ 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 """ - Eq = getattr(self, "__curve", None) if Eq and Eq.a6().precision_relative() >= prec: return Eq.change_ring(Qp(self._p, prec)) @@ -237,7 +233,7 @@ def curve(self, prec=20): def _Csquare(self, prec=20): r""" Return the square of the constant `C` such that the canonical - Neron differential `\omega` and the canonical differential + Néron differential `\omega` and the canonical differential `\frac{du}{u}` on `\QQ^{\times}/q^{\ZZ}` are linked by `\omega = C \frac{du}{u}`. @@ -254,7 +250,6 @@ def _Csquare(self, prec=20): sage: eq._Csquare(prec=5) 4 + 2*5^2 + 2*5^4 + O(5^5) """ - Csq = getattr(self, "__csquare", None) if Csq and Csq.precision_relative() >= prec: return Csq @@ -289,13 +284,13 @@ def E2(self, prec=20): qE = self.parameter(prec=prec) n = qE.valuation() R = Qp(p, prec) - e2 = Csq*(1 - 24 * sum([qE**i/(1-qE**i)**2 - for i in range(1, (prec / n).floor() + 5)])) + e2 = Csq * (1 - 24 * sum([qE**i / (1 - qE**i)**2 + for i in range(1, prec // n + 5)])) return R(e2) - def is_split(self): + def is_split(self) -> bool: r""" - Return True if the given elliptic curve has split multiplicative reduction. + Return ``True`` if the given elliptic curve has split multiplicative reduction. EXAMPLES:: @@ -321,7 +316,6 @@ def parametrisation_onto_tate_curve(self, u, prec=None): - ``prec`` -- the `p`-adic precision, default is the relative precision of ``u`` otherwise 20. - EXAMPLES:: sage: eq = EllipticCurve('130a1').tate_curve(5) @@ -332,33 +326,34 @@ def parametrisation_onto_tate_curve(self, u, prec=None): 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 - + ValueError: requested more precision than the precision of u """ - if prec is None: - prec = getattr(u, "precision_relative", lambda : 20)() + 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") + 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()) + un = u * q ** (-(u.valuation() // q.valuation())) - precn = (prec / q.valuation()).floor() + 4 + precn = (prec // q.valuation()) + 4 # formulas in Silverman II (Advanced Topics in the Arithmetic # of Elliptic curves, p. 425) - xx = un/(1-un)**2 + sum([q**n*un/(1-q**n*un)**2 + - q**n/un/(1-q**n/un)**2-2*q**n/(1-q**n)**2 - for n in range(1, precn)]) + powers_of_q = [(n, q**n) for n in range(1, precn)] + xx = un / (1 - un)**2 + sum([qn * un / (1 - qn * un)**2 + + qn / un / (1 - qn / un)**2 - + 2 * qn / (1 - qn)**2 + for n, qn in powers_of_q]) - yy = un**2/(1-un)**3 + sum([q**(2*n)*un**2/(1-q**n*un)**3 - - q**n/un/(1-q**n/un)**3+q**n/(1-q**n)**2 - for n in range(1, precn)]) + yy = un**2 / (1 - un)**3 + sum([qn**2 * un**2 / (1 - qn * un)**3 - + qn / un / (1 - qn / un)**3 + + qn / (1 - qn)**2 + for n, qn in powers_of_q]) return self.curve(prec=prec)([xx, yy]) @@ -385,7 +380,7 @@ def L_invariant(self, prec=20): 5^3 + 4*5^4 + 2*5^5 + 2*5^6 + 2*5^7 + 3*5^8 + 5^9 + O(5^10) """ if not self.is_split(): - raise RuntimeError("The curve must have split multiplicative " + raise RuntimeError("the curve must have split multiplicative " "reduction") qE = self.parameter(prec=prec) n = qE.valuation() @@ -419,7 +414,7 @@ def _isomorphism(self, prec=20): 2 + 5 + 3*5^2 + 5^3 + 5^4 + O(5^5)] """ if not self.is_split(): - raise RuntimeError("The curve must have split multiplicative " + raise RuntimeError("the curve must have split multiplicative " "reduction") C = self._Csquare(prec=prec + 4).sqrt() R = Qp(self._p, prec) @@ -454,7 +449,7 @@ def _inverse_isomorphism(self, prec=20): 1 + 5 + 4*5^3 + 2*5^4 + O(5^5), 5 + 2*5^2 + 3*5^4 + O(5^5)] """ if not self.is_split(): - raise RuntimeError("The curve must have split multiplicative " + raise RuntimeError("the curve must have split multiplicative " "reduction") u, r, s, t = self._isomorphism(prec=prec) return [1 / u, -r / u ** 2, -s / u, (r * s - t) / u ** 3] @@ -490,13 +485,13 @@ def lift(self, P, prec=20): p = self._p R = Qp(self._p, prec) if not self._E == P.curve(): - raise ValueError("The point must lie on the original curve.") + raise ValueError("the point must lie on the original curve.") if not self.is_split(): - raise ValueError("The curve must have split multiplicative reduction.") + raise ValueError("the curve must have split multiplicative reduction.") if P.is_zero(): return R.one() if P[0].valuation(p) >= 0: - raise ValueError("The point must lie in the formal group.") + raise ValueError("the point must lie in the formal group.") Eq = self.curve(prec=prec) C, r, s, t = self._isomorphism(prec=prec) @@ -505,8 +500,7 @@ def lift(self, P, prec=20): try: Eq([xx, yy]) except Exception: - raise RuntimeError("Bug : Point %s does not lie on the curve " % - (xx, yy)) + raise RuntimeError(f"Bug : Point ({xx, yy}) does not lie on the curve ") tt = -xx / yy eqhat = Eq.formal() @@ -541,7 +535,7 @@ def parametrisation_onto_original_curve(self, u, prec=None): 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 + ValueError: requested more precision than the precision of u Here is how one gets a 4-torsion point on `E` over `\QQ_5`:: @@ -553,10 +547,10 @@ def parametrisation_onto_original_curve(self, u, prec=None): (0 : 1 + O(5^30) : 0) """ if not self.is_split(): - raise ValueError("The curve must have split multiplicative " + raise ValueError("the curve must have split multiplicative " "reduction.") if prec is None: - prec = getattr(u, "precision_relative", lambda : 20)() + 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) @@ -568,9 +562,9 @@ def parametrisation_onto_original_curve(self, u, prec=None): def __padic_sigma_square(self, u, prec): q = self.parameter(prec=prec) - return (u - 1) ** 2 / u * prod([((1-q**n*u)*(1-q**n/u) / - (1 - q ** n) ** 2) ** 2 - for n in range(1, prec + 1)]) + return (u - 1)**2 / u * prod([((1 - q**n * u) * (1 - q**n / u) / + (1 - q**n)**2)**2 + for n in range(1, prec + 1)]) # the following functions are rather functions of the global curve # than the local curve @@ -603,12 +597,13 @@ def padic_height(self, prec=20): O(5^9) """ if not self.is_split(): - raise NotImplementedError("The p-adic height is not implemented for non-split multiplicative reduction.") + raise NotImplementedError("the p-adic height is not implemented " + "for non-split multiplicative reduction.") p = self._p # we will have to do it properly with David Harvey's _multiply_point(E, R, Q) - n = LCM(self._E.tamagawa_numbers()) * (p-1) + n = LCM(self._E.tamagawa_numbers()) * (p - 1) # this function is a closure, I don't see how to doctest it (PZ) def _height(P, check=True): @@ -624,7 +619,7 @@ def _height(P, check=True): q = self.parameter(prec=precp) nn = q.valuation() qEu = q / p ** nn - res = -(log(si*self._Csquare(prec=precp)/cQ) + log(uQ)**2/log(qEu)) / n**2 + res = -(log(si * self._Csquare(prec=precp) / cQ) + log(uQ)**2 / log(qEu)) / n**2 R = Qp(self._p, prec) return R(res) @@ -632,7 +627,7 @@ def _height(P, check=True): def padic_regulator(self, prec=20): r""" - Compute the canonical `p`-adic regulator on the extended + 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]_.) @@ -659,7 +654,8 @@ def padic_regulator(self, prec=20): return K.one() if not self.is_split(): - raise NotImplementedError("The p-adic regulator is not implemented for non-split multiplicative reduction.") + raise NotImplementedError("the p-adic regulator is not implemented " + "for non-split multiplicative reduction.") basis = self._E.gens() M = matrix.matrix(K, rank, rank, 0) From bd46445231fc46cf4e272f72edce839c171e9f45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 21 Jan 2022 11:28:45 +0100 Subject: [PATCH 141/253] fix one doctest --- .../elliptic_curves/ell_rational_field.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index ae86442455f..99feb39b57b 100644 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -431,9 +431,9 @@ def mwrank(self, options=''): .. NOTE:: - The output is a raw string and completely illegible using - automatic display, so it is recommended to use print for - legible output. + The output is a raw string and completely illegible using + automatic display, so it is recommended to use print for + legible output. EXAMPLES:: @@ -519,10 +519,10 @@ def conductor(self, algorithm="pari"): .. NOTE:: - The conductor computed using each algorithm is cached - separately. Thus calling ``E.conductor('pari')``, then - ``E.conductor('mwrank')`` and getting the same result - checks that both systems compute the same answer. + The conductor computed using each algorithm is cached + separately. Thus calling ``E.conductor('pari')``, then + ``E.conductor('mwrank')`` and getting the same result + checks that both systems compute the same answer. TESTS:: @@ -5554,7 +5554,7 @@ def tate_curve(self, p): sage: e.tate_curve(3) Traceback (most recent call last): ... - ValueError: The elliptic curve must have multiplicative reduction at 3 + ValueError: the elliptic curve must have multiplicative reduction at 3 We compute with `p=5`:: From c3ff1a8bb42f088747b09ce6689b46425af37787 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 21 Jan 2022 18:20:24 +0100 Subject: [PATCH 142/253] sums without lists inside --- .../schemes/elliptic_curves/ell_tate_curve.py | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_tate_curve.py b/src/sage/schemes/elliptic_curves/ell_tate_curve.py index ce945be6d16..5abb1dba4ad 100644 --- a/src/sage/schemes/elliptic_curves/ell_tate_curve.py +++ b/src/sage/schemes/elliptic_curves/ell_tate_curve.py @@ -188,8 +188,8 @@ def parameter(self, prec=20): def __sk(self, k, prec): q = self.parameter(prec=prec) - return sum([n ** k * q ** n / (1 - q ** n) - for n in range(1, prec + 1)]) + return sum(n ** k * q ** n / (1 - q ** n) + for n in range(1, prec + 1)) def __delta(self, prec): q = self.parameter(prec=prec) @@ -284,8 +284,8 @@ def E2(self, prec=20): qE = self.parameter(prec=prec) n = qE.valuation() R = Qp(p, prec) - e2 = Csq * (1 - 24 * sum([qE**i / (1 - qE**i)**2 - for i in range(1, prec // n + 5)])) + e2 = Csq * (1 - 24 * sum(qE**i / (1 - qE**i)**2 + for i in range(1, prec // n + 5))) return R(e2) def is_split(self) -> bool: @@ -345,15 +345,15 @@ def parametrisation_onto_tate_curve(self, u, prec=None): # of Elliptic curves, p. 425) powers_of_q = [(n, q**n) for n in range(1, precn)] - xx = un / (1 - un)**2 + sum([qn * un / (1 - qn * un)**2 + - qn / un / (1 - qn / un)**2 - - 2 * qn / (1 - qn)**2 - for n, qn in powers_of_q]) - - yy = un**2 / (1 - un)**3 + sum([qn**2 * un**2 / (1 - qn * un)**3 - - qn / un / (1 - qn / un)**3 + - qn / (1 - qn)**2 - for n, qn in powers_of_q]) + xx = un / (1 - un)**2 + sum(qn * un / (1 - qn * un)**2 + + qn / un / (1 - qn / un)**2 - + 2 * qn / (1 - qn)**2 + for n, qn in powers_of_q) + + yy = un**2 / (1 - un)**3 + sum(qn**2 * un**2 / (1 - qn * un)**3 - + qn / un / (1 - qn / un)**3 + + qn / (1 - qn)**2 + for n, qn in powers_of_q) return self.curve(prec=prec)([xx, yy]) From abafddc33ff85ad50eb67c6532984985a856e882 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Fri, 21 Jan 2022 21:34:30 +0000 Subject: [PATCH 143/253] disable-threads led to zombies see #33027 for details. --- build/pkgs/ecl/spkg-install.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/ecl/spkg-install.in b/build/pkgs/ecl/spkg-install.in index 5e007ef3135..e639070f7a8 100644 --- a/build/pkgs/ecl/spkg-install.in +++ b/build/pkgs/ecl/spkg-install.in @@ -45,7 +45,7 @@ else fi fi -sdh_configure $SAGE_CONFIGURE_GMP --disable-threads \ +sdh_configure $SAGE_CONFIGURE_GMP \ --enable-unicode=yes --with-defsystem $ECL_CONFIGURE # Before running make we touch build/TAGS so its building process is never triggered From c9b0b2ae4d95bc7144e267dd8cd8828d6f8eb0a3 Mon Sep 17 00:00:00 2001 From: Daniel Krenn Date: Sat, 22 Jan 2022 10:05:48 +0100 Subject: [PATCH 144/253] Trac #33158 review comment 1: fixup missing "raise ... from None" --- src/sage/combinat/k_regular_sequence.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index 3242616b715..a49a3c4c75b 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -1046,7 +1046,7 @@ def parse_one_summand(summand, eq): raise ValueError("Term %s in the equation %s: " "%s is not a power of %s." % (summand, eq, - k**m, k)) + k**m, k)) from None return [coeff, m, d] if not equations: @@ -1086,7 +1086,7 @@ def parse_one_summand(summand, eq): except (TypeError, ValueError): raise ValueError("Initial value %s given by the equation %s " "is not in %s." - % (right_side, eq, coefficient_ring)) + % (right_side, eq, coefficient_ring)) from None if (polynomial_left in initial_values.keys() and initial_values[polynomial_left] != right_side): raise ValueError("Initial value %s is given twice." From fe1407df2be76d74653f57568718f9633fd364c3 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Wed, 19 Jan 2022 12:06:37 +0100 Subject: [PATCH 145/253] #33218 speed up Polynomial.valuation() --- src/sage/rings/polynomial/polynomial_element.pyx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 4c2f63a28a5..df031877a11 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -8928,10 +8928,11 @@ cdef class Polynomial(CommutativeAlgebraElement): if p.degree() == 0: raise ArithmeticError("The polynomial, p, must have positive degree.") - k = 0 - while self % p == 0: - k = k + 1 - self //= p + k = -1 + rem = self.parent().zero() + while rem.is_zero(): + self, rem = self.quo_rem(p) + k += 1 return sage.rings.integer.Integer(k) def ord(self, p=None): From 69e74af12d50cacb673a5c5f952d9472481fa06a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 23 Jan 2022 09:18:36 +0100 Subject: [PATCH 146/253] use assert --- src/sage/schemes/elliptic_curves/ell_tate_curve.py | 6 +----- 1 file changed, 1 insertion(+), 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 5abb1dba4ad..165233fbe55 100644 --- a/src/sage/schemes/elliptic_curves/ell_tate_curve.py +++ b/src/sage/schemes/elliptic_curves/ell_tate_curve.py @@ -497,11 +497,7 @@ def lift(self, P, prec=20): C, r, s, t = self._isomorphism(prec=prec) xx = r + C ** 2 * P[0] yy = t + s * C ** 2 * P[0] + C ** 3 * P[1] - try: - Eq([xx, yy]) - except Exception: - raise RuntimeError(f"Bug : Point ({xx, yy}) does not lie on the curve ") - + assert Eq.defining_polynomial()(xx, yy, 1) == 0, f"bug: point ({xx}, {yy}) does not lie on the curve {Eq}" tt = -xx / yy eqhat = Eq.formal() eqlog = eqhat.log(prec + 3) From af760c9816025fa956b7d9499414d95d22bec6ab Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Sun, 23 Jan 2022 13:31:01 -0600 Subject: [PATCH 147/253] Add projective space --- src/sage/manifolds/catalog.py | 140 ++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/src/sage/manifolds/catalog.py b/src/sage/manifolds/catalog.py index a0a04f90bce..450bc982894 100644 --- a/src/sage/manifolds/catalog.py +++ b/src/sage/manifolds/catalog.py @@ -14,10 +14,12 @@ - :func:`Torus`: torus embedded in Euclidean space - :func:`Minkowski`: 4-dimensional Minkowski space - :func:`Kerr`: Kerr spacetime +- :func:`ProjectiveSpace`: projective space over a field AUTHORS: - Florentin Jaffredo (2018) : initial version +- Trevor K. Karn (2022) : projective space """ # ***************************************************************************** @@ -256,3 +258,141 @@ def Torus(R=2, r=1, names=None): M.induced_metric() return M +def ProjectiveSpace(dim=2, field=RR): + r""" + Generate projective space of dimension ``dim`` over + ``field``. + + This is the topological space of lines through the origin in `k^{d+1}` + for a field `k`. The standard atlas consists of `d+2` charts, which sends + the set `U_i = \{[x_1, x_2, \ldots, x_{d+1}] : x_i \neq 0 \}` to + `k^{d}` by dividing by `x_i` and omitting the `i`th coordinate `x_i/x_i = 1`. + + INPUT: + + - ``dim`` -- (default: ``2``) the dimension of projective space + - ``field`` -- (default: ``RR``) the field of coordinates + + OUTPUT: + + - ``P`` -- the projective space `P_{d}(k)` where `d =```dim`` + and `k =```field``. + + EXAMPLES:: + + sage: load('projective-space.sage') + sage: P = ProjectiveSpace(); P + 2-dimensional topological manifold P + + sage: C0, C1, C2 = P.atlas()[:3] + sage: p = P.point((2,0), chart = C0) + sage: q = P.point((0,3), chart = C0) + sage: p in C0.domain() + True + sage: p in C1.domain() + True + sage: C1(p) + (1/2, 0) + sage: p in C2.domain() + False + sage: q in C0.domain() + True + sage: q in C1.domain() + False + sage: q in C2.domain() + True + sage: C2(q) + (1/3, 0) + + sage: r = P.point((2,3)) + sage: r in C0.domain() and r in C1.domain() and r in C2.domain() + True + sage: C0(r) + (2, 3) + sage: C1(r) + (1/2, 3/2) + sage: C2(r) + (1/3, 2/3) + + sage: p = P.point((2,3), chart = C1) + sage: p in C0.domain() and p in C1.domain() and p in C2.domain() + True + sage: C0(p) + (1/2, 3/2) + sage: C2(p) + (2/3, 1/3) + + sage: P = ProjectiveSpace(1); P + 1-dimensional topological manifold P + sage: C0, C1 = P.atlas()[:2] + sage: p, q = P.point((2,)), P.point((0,)) + sage: p in C0.domain() + True + sage: p in C1.domain() + True + sage: q in C0.domain() + True + sage: q in C1.domain() + False + sage: C1(p) + (1/2,) + + sage: p, q = P.point((3,), chart = C1), P.point((0,), chart = C1) + sage: p in C0.domain() + True + sage: q in C0.domain() + False + sage: C0(p) + (1/3,) + + """ + + from sage.manifolds.manifold import Manifold + from itertools import combinations + + P = Manifold(dim, "P", + field = field, + structure = 'topological', + latex_name=f"P_{dim}{latex(field)}") + + # the trailing whitespace in the string is intentional for defining charts + names = [f'x_{i} ' for i in range(dim+1)] + + # create the charts + for i in range(dim+1): + U = P.open_subset(f'U{i}') + # The chart where we assert that x_i == 1 + C = U.chart(''.join(names[:i] + names[i+1:])) + + # this atlas is a global atlas + P.declare_union(P.subsets()) + #P.declare_union(map(lambda x: x.domain(), P.atlas())) + + # define the transition maps + for i,j in combinations(range(dim+1), 2): + + Ci, Cj = P.atlas()[i], P.atlas()[j] + + gi = Ci._first_ngens(-1) # all of the generators + gj = Cj._first_ngens(-1) + + # Ci to Cj: + xj = gi[j - 1] # use index j - 1 because i < j and xi is omitted from gi + + # the corresponding coordinates in k^{dim+1} + d_plus_one_coords = [g/xj for g in gi[:i]] + [1/xj] + [g/xj for g in gi[i:]] + cj_new_coords = d_plus_one_coords[:j] + d_plus_one_coords[j+1:] + + Ci_to_Cj = Ci.transition_map(Cj, cj_new_coords, restrictions1 = xj != 0) + + #Cj_to_Ci = Ci_to_Cj.inverse() + + # Ci to Cj: + xi = gj[i] + d_plus_one_coords = [g/xi for g in gj[:j]] + [1/xi] + [g/xi for g in gj[j:]] + ci_new_coords = d_plus_one_coords[:i] + d_plus_one_coords[i+1:] + + Cj_to_Ci = Cj.transition_map(Ci, ci_new_coords, restrictions1 = xi != 0) + + + return P \ No newline at end of file From 38f2be27a0e38d1d7d54095df5d2965d5b49efa7 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Sun, 23 Jan 2022 14:57:08 -0600 Subject: [PATCH 148/253] Fix inverse map and tests, and restrict to real projective space --- src/sage/manifolds/catalog.py | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/src/sage/manifolds/catalog.py b/src/sage/manifolds/catalog.py index 450bc982894..699aebcbeef 100644 --- a/src/sage/manifolds/catalog.py +++ b/src/sage/manifolds/catalog.py @@ -38,6 +38,7 @@ _lazy_import('sage.manifolds.differentiable.examples.real_line', 'RealLine') _lazy_import('sage.manifolds.differentiable.examples.euclidean', 'EuclideanSpace') _lazy_import('sage.manifolds.differentiable.examples.sphere', 'Sphere') +_lazy_import('sage.rings.real_mpfr','RealField_class') def Minkowski(positive_spacelike=True, names=None): """ @@ -258,7 +259,7 @@ def Torus(R=2, r=1, names=None): M.induced_metric() return M -def ProjectiveSpace(dim=2, field=RR): +def RealProjectiveSpace(dim=2): r""" Generate projective space of dimension ``dim`` over ``field``. @@ -280,8 +281,7 @@ def ProjectiveSpace(dim=2, field=RR): EXAMPLES:: - sage: load('projective-space.sage') - sage: P = ProjectiveSpace(); P + sage: P = manifolds.RealProjectiveSpace(); P 2-dimensional topological manifold P sage: C0, C1, C2 = P.atlas()[:3] @@ -322,7 +322,7 @@ def ProjectiveSpace(dim=2, field=RR): sage: C2(p) (2/3, 1/3) - sage: P = ProjectiveSpace(1); P + sage: P = manifolds.RealProjectiveSpace(1); P 1-dimensional topological manifold P sage: C0, C1 = P.atlas()[:2] sage: p, q = P.point((2,)), P.point((0,)) @@ -351,9 +351,8 @@ def ProjectiveSpace(dim=2, field=RR): from itertools import combinations P = Manifold(dim, "P", - field = field, structure = 'topological', - latex_name=f"P_{dim}{latex(field)}") + latex_name=f"RP^{dim}") # the trailing whitespace in the string is intentional for defining charts names = [f'x_{i} ' for i in range(dim+1)] @@ -366,7 +365,6 @@ def ProjectiveSpace(dim=2, field=RR): # this atlas is a global atlas P.declare_union(P.subsets()) - #P.declare_union(map(lambda x: x.domain(), P.atlas())) # define the transition maps for i,j in combinations(range(dim+1), 2): @@ -376,23 +374,17 @@ def ProjectiveSpace(dim=2, field=RR): gi = Ci._first_ngens(-1) # all of the generators gj = Cj._first_ngens(-1) - # Ci to Cj: + xi = gj[i] xj = gi[j - 1] # use index j - 1 because i < j and xi is omitted from gi # the corresponding coordinates in k^{dim+1} d_plus_one_coords = [g/xj for g in gi[:i]] + [1/xj] + [g/xj for g in gi[i:]] cj_new_coords = d_plus_one_coords[:j] + d_plus_one_coords[j+1:] - Ci_to_Cj = Ci.transition_map(Cj, cj_new_coords, restrictions1 = xj != 0) - - #Cj_to_Ci = Ci_to_Cj.inverse() - - # Ci to Cj: - xi = gj[i] - d_plus_one_coords = [g/xi for g in gj[:j]] + [1/xi] + [g/xi for g in gj[j:]] - ci_new_coords = d_plus_one_coords[:i] + d_plus_one_coords[i+1:] - - Cj_to_Ci = Cj.transition_map(Ci, ci_new_coords, restrictions1 = xi != 0) + Ci_to_Cj = Ci.transition_map(Cj, cj_new_coords, + restrictions1 = xj != 0, + restrictions2 = xi != 0) + Cj_to_Ci = Ci_to_Cj.inverse() return P \ No newline at end of file From bdc04413a6874f942feeded5e5da598f6e70c5d1 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Sun, 23 Jan 2022 15:05:49 -0600 Subject: [PATCH 149/253] Fix PEP8 compliance --- src/sage/manifolds/catalog.py | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/sage/manifolds/catalog.py b/src/sage/manifolds/catalog.py index 699aebcbeef..1036a8bc7c0 100644 --- a/src/sage/manifolds/catalog.py +++ b/src/sage/manifolds/catalog.py @@ -266,18 +266,17 @@ def RealProjectiveSpace(dim=2): This is the topological space of lines through the origin in `k^{d+1}` for a field `k`. The standard atlas consists of `d+2` charts, which sends - the set `U_i = \{[x_1, x_2, \ldots, x_{d+1}] : x_i \neq 0 \}` to - `k^{d}` by dividing by `x_i` and omitting the `i`th coordinate `x_i/x_i = 1`. - + the set `U_i = \{[x_1, x_2, \ldots, x_{d+1}] : x_i \neq 0 \}` to + `k^{d}` by dividing by `x_i` and omitting the `i`th coordinate + `x_i/x_i = 1`. + INPUT: - ``dim`` -- (default: ``2``) the dimension of projective space - - ``field`` -- (default: ``RR``) the field of coordinates OUTPUT: - - ``P`` -- the projective space `P_{d}(k)` where `d =```dim`` - and `k =```field``. + - ``P`` -- the projective space `RP^d` where `d =```dim``. EXAMPLES:: @@ -312,7 +311,7 @@ def RealProjectiveSpace(dim=2): sage: C1(r) (1/2, 3/2) sage: C2(r) - (1/3, 2/3) + (1/3, 2/3) sage: p = P.point((2,3), chart = C1) sage: p in C0.domain() and p in C1.domain() and p in C2.domain() @@ -328,7 +327,7 @@ def RealProjectiveSpace(dim=2): sage: p, q = P.point((2,)), P.point((0,)) sage: p in C0.domain() True - sage: p in C1.domain() + sage: p in C1.domain() True sage: q in C0.domain() True @@ -351,11 +350,11 @@ def RealProjectiveSpace(dim=2): from itertools import combinations P = Manifold(dim, "P", - structure = 'topological', + structure='topological', latex_name=f"RP^{dim}") # the trailing whitespace in the string is intentional for defining charts - names = [f'x_{i} ' for i in range(dim+1)] + names = [f'x_{i} ' for i in range(dim + 1)] # create the charts for i in range(dim+1): @@ -367,24 +366,24 @@ def RealProjectiveSpace(dim=2): P.declare_union(P.subsets()) # define the transition maps - for i,j in combinations(range(dim+1), 2): + for i, j in combinations(range(dim+1), 2): Ci, Cj = P.atlas()[i], P.atlas()[j] - gi = Ci._first_ngens(-1) # all of the generators + gi = Ci._first_ngens(-1) # all of the generators gj = Cj._first_ngens(-1) xi = gj[i] - xj = gi[j - 1] # use index j - 1 because i < j and xi is omitted from gi + xj = gi[j - 1] # use index j - 1 because i < j and xi is omitted in gi # the corresponding coordinates in k^{dim+1} d_plus_one_coords = [g/xj for g in gi[:i]] + [1/xj] + [g/xj for g in gi[i:]] cj_new_coords = d_plus_one_coords[:j] + d_plus_one_coords[j+1:] - Ci_to_Cj = Ci.transition_map(Cj, cj_new_coords, - restrictions1 = xj != 0, - restrictions2 = xi != 0) + Ci_to_Cj = Ci.transition_map(Cj, cj_new_coords, + restrictions1=xj != 0, + restrictions2=xi != 0) Cj_to_Ci = Ci_to_Cj.inverse() - return P \ No newline at end of file + return P From 11cf10d18c07c5701c7c4a1d2849795ba1d56298 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Sun, 23 Jan 2022 20:35:02 -0600 Subject: [PATCH 150/253] Add reviewer suggestions --- src/sage/manifolds/catalog.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sage/manifolds/catalog.py b/src/sage/manifolds/catalog.py index 1036a8bc7c0..414582b97e5 100644 --- a/src/sage/manifolds/catalog.py +++ b/src/sage/manifolds/catalog.py @@ -14,7 +14,7 @@ - :func:`Torus`: torus embedded in Euclidean space - :func:`Minkowski`: 4-dimensional Minkowski space - :func:`Kerr`: Kerr spacetime -- :func:`ProjectiveSpace`: projective space over a field +- :func:`RealProjectiveSpace`: `n`-dimensional real projective space AUTHORS: @@ -282,6 +282,8 @@ def RealProjectiveSpace(dim=2): sage: P = manifolds.RealProjectiveSpace(); P 2-dimensional topological manifold P + sage: latex(P) + \mathbb{RP}^2 sage: C0, C1, C2 = P.atlas()[:3] sage: p = P.point((2,0), chart = C0) @@ -351,7 +353,7 @@ def RealProjectiveSpace(dim=2): P = Manifold(dim, "P", structure='topological', - latex_name=f"RP^{dim}") + latex_name=r"\mathbb{RP}^" + str(dim)) # the trailing whitespace in the string is intentional for defining charts names = [f'x_{i} ' for i in range(dim + 1)] @@ -368,7 +370,8 @@ def RealProjectiveSpace(dim=2): # define the transition maps for i, j in combinations(range(dim+1), 2): - Ci, Cj = P.atlas()[i], P.atlas()[j] + Ci = P.atlas()[i] + Cj = P.atlas()[j] gi = Ci._first_ngens(-1) # all of the generators gj = Cj._first_ngens(-1) From 33ea2adf01e9e2ce9f1e33779f0b1ac0d9d1989c Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Mon, 24 Jan 2022 09:03:29 -0500 Subject: [PATCH 151/253] Trac #33226: update doctests for giac-1.7.0.45. We have two failing doctests with giac-1.7.0.45: one is a trivial tolerance issue, but the other is a symbolic integration result for which giac is no longer willing to return a symbolic answer. We add "abs tol" to the numeric test, and drop the symbolic one entirely. --- src/sage/functions/min_max.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/functions/min_max.py b/src/sage/functions/min_max.py index fc1837383d6..9b7d6d99f62 100644 --- a/src/sage/functions/min_max.py +++ b/src/sage/functions/min_max.py @@ -228,15 +228,15 @@ def _evalf_(self, *args, **kwds): ... TypeError: cannot evaluate symbolic expression numerically - :: + We can usually integrate these expressions, but can't + guarantee a symbolic answer in closed form:: sage: f = max_symbolic(sin(x), cos(x)) sage: r = integral(f, x, 0, 1) ... - sage: r - sqrt(2) - cos(1) - sage: r.n() + sage: r.n() # abs tol 1e-8 0.873911256504955 + """ return max_symbolic(args) From 7b6dbf0cd1211d9ab3083b6e76890d8d5b7ee876 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Mon, 24 Jan 2022 23:19:40 -0600 Subject: [PATCH 152/253] Make reviewer changes except for optimizing chart creation --- src/sage/manifolds/catalog.py | 72 +++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/src/sage/manifolds/catalog.py b/src/sage/manifolds/catalog.py index 414582b97e5..7c2fd969794 100644 --- a/src/sage/manifolds/catalog.py +++ b/src/sage/manifolds/catalog.py @@ -280,14 +280,14 @@ def RealProjectiveSpace(dim=2): EXAMPLES:: - sage: P = manifolds.RealProjectiveSpace(); P - 2-dimensional topological manifold P - sage: latex(P) - \mathbb{RP}^2 - - sage: C0, C1, C2 = P.atlas()[:3] - sage: p = P.point((2,0), chart = C0) - sage: q = P.point((0,3), chart = C0) + sage: RP2 = manifolds.RealProjectiveSpace(); RP2 + 2-dimensional topological manifold RP2 + sage: latex(RP2) + \mathbb{RP}^{2} + + sage: C0, C1, C2 = RP2.atlas()[:3] + sage: p = RP2.point((2,0), chart = C0) + sage: q = RP2.point((0,3), chart = C0) sage: p in C0.domain() True sage: p in C1.domain() @@ -305,7 +305,7 @@ def RealProjectiveSpace(dim=2): sage: C2(q) (1/3, 0) - sage: r = P.point((2,3)) + sage: r = RP2.point((2,3)) sage: r in C0.domain() and r in C1.domain() and r in C2.domain() True sage: C0(r) @@ -315,7 +315,7 @@ def RealProjectiveSpace(dim=2): sage: C2(r) (1/3, 2/3) - sage: p = P.point((2,3), chart = C1) + sage: p = RP2.point((2,3), chart = C1) sage: p in C0.domain() and p in C1.domain() and p in C2.domain() True sage: C0(p) @@ -323,10 +323,10 @@ def RealProjectiveSpace(dim=2): sage: C2(p) (2/3, 1/3) - sage: P = manifolds.RealProjectiveSpace(1); P - 1-dimensional topological manifold P - sage: C0, C1 = P.atlas()[:2] - sage: p, q = P.point((2,)), P.point((0,)) + sage: RP1 = manifolds.RealProjectiveSpace(1); RP1 + 1-dimensional topological manifold RP1 + sage: C0, C1 = RP1.atlas()[:2] + sage: p, q = RP1.point((2,)), RP1.point((0,)) sage: p in C0.domain() True sage: p in C1.domain() @@ -338,7 +338,7 @@ def RealProjectiveSpace(dim=2): sage: C1(p) (1/2,) - sage: p, q = P.point((3,), chart = C1), P.point((0,), chart = C1) + sage: p, q = RP1.point((3,), chart = C1), RP1.point((0,), chart = C1) sage: p in C0.domain() True sage: q in C0.domain() @@ -351,42 +351,48 @@ def RealProjectiveSpace(dim=2): from sage.manifolds.manifold import Manifold from itertools import combinations - P = Manifold(dim, "P", + P = Manifold(dim, f"RP{dim}", structure='topological', - latex_name=r"\mathbb{RP}^" + str(dim)) + latex_name=r"\mathbb{{RP}}^{{{}}}".format(dim)) # the trailing whitespace in the string is intentional for defining charts names = [f'x_{i} ' for i in range(dim + 1)] + charts = dict() + # create the charts for i in range(dim+1): - U = P.open_subset(f'U{i}') + U = P.open_subset(name=f'U{i}', latex_name=f'U_{i}') # The chart where we assert that x_i == 1 - C = U.chart(''.join(names[:i] + names[i+1:])) + charts[i] = U.chart(''.join(names[:i] + names[i+1:])) # this atlas is a global atlas P.declare_union(P.subsets()) # define the transition maps - for i, j in combinations(range(dim+1), 2): + for i in range(dim): + + Ci = charts[i] + gi = Ci[:] - Ci = P.atlas()[i] - Cj = P.atlas()[j] + for j in range(i, dim+1): + Cj = charts[j] + gj = Cj[:] - gi = Ci._first_ngens(-1) # all of the generators - gj = Cj._first_ngens(-1) + xi = gj[i] + xj = gi[j - 1] # use index j - 1 because i < j and xi is omitted in gi - xi = gj[i] - xj = gi[j - 1] # use index j - 1 because i < j and xi is omitted in gi + # the corresponding coordinates in R^{dim+1} + d_plus_one_coords = [g/xj for g in gi[:i]] + [1/xj] + [g/xj for g in gi[i:]] + cj_new_coords = d_plus_one_coords[:j] + d_plus_one_coords[j+1:] - # the corresponding coordinates in k^{dim+1} - d_plus_one_coords = [g/xj for g in gi[:i]] + [1/xj] + [g/xj for g in gi[i:]] - cj_new_coords = d_plus_one_coords[:j] + d_plus_one_coords[j+1:] + Ci_to_Cj = Ci.transition_map(Cj, cj_new_coords, + restrictions1=xj != 0, + restrictions2=xi != 0) - Ci_to_Cj = Ci.transition_map(Cj, cj_new_coords, - restrictions1=xj != 0, - restrictions2=xi != 0) + d_plus_one_coords = [g/xi for g in gj[:j]] + [1/xi] + [g/xi for g in gj[j:]] + ci_new_coords = d_plus_one_coords[:i] + d_plus_one_coords[i+1:] - Cj_to_Ci = Ci_to_Cj.inverse() + Cj_to_Ci = Ci_to_Cj.set_inverse(*ci_new_coords, check=False) return P From e5be551cb6e4e397fcc9b90949c17dbf7829d692 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Mon, 24 Jan 2022 23:43:18 -0600 Subject: [PATCH 153/253] Optimize creation of open subsets and charts into a single loop --- src/sage/manifolds/catalog.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/sage/manifolds/catalog.py b/src/sage/manifolds/catalog.py index 7c2fd969794..30bcb63669c 100644 --- a/src/sage/manifolds/catalog.py +++ b/src/sage/manifolds/catalog.py @@ -285,7 +285,7 @@ def RealProjectiveSpace(dim=2): sage: latex(RP2) \mathbb{RP}^{2} - sage: C0, C1, C2 = RP2.atlas()[:3] + sage: C0, C1, C2 = RP2.top_charts() sage: p = RP2.point((2,0), chart = C0) sage: q = RP2.point((0,3), chart = C0) sage: p in C0.domain() @@ -325,7 +325,7 @@ def RealProjectiveSpace(dim=2): sage: RP1 = manifolds.RealProjectiveSpace(1); RP1 1-dimensional topological manifold RP1 - sage: C0, C1 = RP1.atlas()[:2] + sage: C0, C1 = RP1.top_charts() sage: p, q = RP1.point((2,)), RP1.point((0,)) sage: p in C0.domain() True @@ -349,7 +349,6 @@ def RealProjectiveSpace(dim=2): """ from sage.manifolds.manifold import Manifold - from itertools import combinations P = Manifold(dim, f"RP{dim}", structure='topological', @@ -358,26 +357,24 @@ def RealProjectiveSpace(dim=2): # the trailing whitespace in the string is intentional for defining charts names = [f'x_{i} ' for i in range(dim + 1)] - charts = dict() + U0 = P.open_subset(name='U0', latex_name='U_0') + + charts = {0: U0.chart(''.join(names[1:]))} # create the charts - for i in range(dim+1): - U = P.open_subset(name=f'U{i}', latex_name=f'U_{i}') + for j in range(1, dim+1): + U = P.open_subset(name=f'U{j}', latex_name=f'U_{j}') + # The chart where we assert that x_i == 1 - charts[i] = U.chart(''.join(names[:i] + names[i+1:])) - - # this atlas is a global atlas - P.declare_union(P.subsets()) + Cj = U.chart(''.join(names[:j] + names[j+1:])) + gj = Cj[:] - # define the transition maps - for i in range(dim): + charts[j] = Cj - Ci = charts[i] - gi = Ci[:] + for i in range(j): - for j in range(i, dim+1): - Cj = charts[j] - gj = Cj[:] + Ci = charts[i] + gi = Ci[:] xi = gj[i] xj = gi[j - 1] # use index j - 1 because i < j and xi is omitted in gi @@ -395,4 +392,7 @@ def RealProjectiveSpace(dim=2): Cj_to_Ci = Ci_to_Cj.set_inverse(*ci_new_coords, check=False) + # this atlas is a global atlas + P.declare_union(P.subsets()) + return P From d745357be5294371512684d2a23614d358c43a7b Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Mon, 24 Jan 2022 21:43:42 -0800 Subject: [PATCH 154/253] trac 32505: fix doctests, change print representation for morphisms --- .../categories/graded_algebras_with_basis.py | 2 +- src/sage/modules/fp_graded/element.py | 30 +- src/sage/modules/fp_graded/free_element.py | 16 +- src/sage/modules/fp_graded/free_homspace.py | 42 ++- src/sage/modules/fp_graded/free_module.py | 70 +++-- src/sage/modules/fp_graded/free_morphism.py | 98 +++--- src/sage/modules/fp_graded/homspace.py | 239 ++++++++------- src/sage/modules/fp_graded/module.py | 110 +++---- src/sage/modules/fp_graded/morphism.py | 289 +++++++++--------- src/sage/structure/indexed_generators.py | 4 +- 10 files changed, 480 insertions(+), 420 deletions(-) diff --git a/src/sage/categories/graded_algebras_with_basis.py b/src/sage/categories/graded_algebras_with_basis.py index 8af922cd31b..038365bdfb6 100644 --- a/src/sage/categories/graded_algebras_with_basis.py +++ b/src/sage/categories/graded_algebras_with_basis.py @@ -117,7 +117,7 @@ def free_graded_module(self, generator_degrees, names=None): sage: Cl = CliffordAlgebra(Q) sage: M = Cl.free_graded_module((0, 2, 3)) sage: M.gens() - (g_{0}, g_{2}, g_{3}) + (g[0], g[2], g[3]) """ from sage.modules.fp_graded.free_module import FreeGradedModule return FreeGradedModule(self, generator_degrees, names) diff --git a/src/sage/modules/fp_graded/element.py b/src/sage/modules/fp_graded/element.py index f5eabaa5b44..9add5f68c2a 100755 --- a/src/sage/modules/fp_graded/element.py +++ b/src/sage/modules/fp_graded/element.py @@ -38,7 +38,7 @@ class FPElement(IndexedFreeModuleElement): sage: from sage.modules.fp_graded.module import FPModule sage: FPModule(SteenrodAlgebra(2), [0])([Sq(2)]) - Sq(2)*g_{0} + Sq(2)*g[0] """ def lift_to_free(self): r""" @@ -51,13 +51,13 @@ def lift_to_free(self): sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) sage: x = M([Sq(1), 1]) sage: x - Sq(1)*g_{0} + g_{1} + Sq(1)*g[0] + g[1] sage: x.parent() Finitely presented left module on 2 generators and 1 relation over mod 2 Steenrod algebra, milnor basis sage: x.lift_to_free() - Sq(1)*g_{0} + g_{1} + Sq(1)*g[0] + g[1] sage: x.lift_to_free().parent() - Finitely presented free left module on 2 generators over mod 2 Steenrod algebra, milnor basis + Free graded left module on 2 generators over mod 2 Steenrod algebra, milnor basis """ C = self.parent().j.codomain() return C(self.coefficients()) @@ -79,7 +79,7 @@ def degree(self): sage: x = M.an_element(7) sage: x - Sq(0,0,1)*g_{0} + Sq(3,1)*g_{1} + Sq(0,0,1)*g[0] + Sq(3,1)*g[1] sage: x.degree() 7 @@ -143,24 +143,24 @@ def _lmul_(self, a): sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) sage: M = FPModule(A2, [0,3], [[Sq(2)*Sq(4), Sq(3)]]) sage: A2.Sq(2)*M.generator(1) - Sq(2)*g_{3} + Sq(2)*g[3] sage: A2.Sq(2)*(A2.Sq(1)*A2.Sq(2)*M.generator(0) + M.generator(1)) - Sq(2,1)*g_{0} + Sq(2)*g_{3} + Sq(2,1)*g[0] + Sq(2)*g[3] TESTS:: sage: elements = [M.an_element(n) for n in range(1,10)] sage: a = A2.Sq(3) sage: [a*x for x in elements] - [Sq(1,1)*g_{0}, + [Sq(1,1)*g[0], 0, - Sq(3,1)*g_{0} + Sq(3)*g_{3}, - Sq(1,1)*g_{3}, + Sq(3,1)*g[0] + Sq(3)*g[3], + Sq(1,1)*g[3], 0, - Sq(3,2)*g_{0} + Sq(3,1)*g_{3}, - Sq(3,0,1)*g_{0} + Sq(7)*g_{3}, - Sq(1,1,1)*g_{0} + Sq(5,1)*g_{3}, - Sq(3,2)*g_{3}] + Sq(3,2)*g[0] + Sq(3,1)*g[3], + Sq(3,0,1)*g[0] + Sq(7)*g[3], + Sq(1,1,1)*g[0] + Sq(5,1)*g[3], + Sq(3,2)*g[3]] """ return self.parent()(a*self.lift_to_free()) @@ -276,7 +276,7 @@ def __eq__(self, other): sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) sage: x = M([Sq(1), 1]) sage: x - Sq(1)*g_{0} + g_{1} + Sq(1)*g[0] + g[1] sage: x == x True sage: x == M.zero() diff --git a/src/sage/modules/fp_graded/free_element.py b/src/sage/modules/fp_graded/free_element.py index 7019becd9b3..be66a0206b6 100755 --- a/src/sage/modules/fp_graded/free_element.py +++ b/src/sage/modules/fp_graded/free_element.py @@ -31,7 +31,7 @@ class FreeGradedModuleElement(IndexedFreeModuleElement): Create a module element of a finitely generated free graded left module over a connected graded algebra. - EXAMPLES:: + EXAMPLES:: sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: M = FreeGradedModule(SteenrodAlgebra(2), (0, 1)) @@ -40,13 +40,13 @@ class FreeGradedModuleElement(IndexedFreeModuleElement): 0 sage: M([1, 0]) - g_{0} + g[0] sage: M([0, 1]) - g_{1} + g[1] sage: M([Sq(1), 1]) - Sq(1)*g_{0} + g_{1} + Sq(1)*g[0] + g[1] """ def coefficients(self): @@ -81,7 +81,7 @@ def degree(self): sage: A = SteenrodAlgebra(2) sage: M = FreeGradedModule(A, (0,1)) sage: x = M.an_element(7); x - Sq(0,0,1)*g_{0} + Sq(3,1)*g_{1} + Sq(0,0,1)*g[0] + Sq(3,1)*g[1] sage: x.degree() 7 @@ -221,7 +221,7 @@ def vector_presentation(self): sage: basis = M.basis_elements(7) sage: x_ = sum( [c*b for (c,b) in zip(v, basis)] ); x_ - Sq(0,0,1)*g_{0} + Sq(3,1)*g_{1} + Sq(0,0,1)*g[0] + Sq(3,1)*g[1] sage: x == x_ True @@ -229,10 +229,10 @@ def vector_presentation(self): sage: M.zero().vector_presentation() is None True - """ + """ # We cannot represent the zero element since it does not have a degree, # and we therefore do not know which vector space it belongs to. - # + # # In this case, we could return the integer value 0 since coercion would # place it inside any vector space. However, this will not work for # homomorphisms, so we we return None to be consistent. diff --git a/src/sage/modules/fp_graded/free_homspace.py b/src/sage/modules/fp_graded/free_homspace.py index f167fa5fe1d..c5547a82723 100755 --- a/src/sage/modules/fp_graded/free_homspace.py +++ b/src/sage/modules/fp_graded/free_homspace.py @@ -11,12 +11,13 @@ sage: F2 = FreeGradedModule(A, (2,3), names='h') sage: homset = Hom(F1, F2) sage: homset - Set of Morphisms from Finitely presented free left module on 2 generators ... + Set of Morphisms from Free graded left module on 2 generators ... sage: homset([F2((Sq(1), 1)), F2((0, Sq(2)))]) - Module homomorphism of degree 2 defined by sending the generators - [g_{1}, g_{3}] - to - [Sq(1)*h_{2} + h_{3}, Sq(2)*h_{3}] + Free module morphism: + From: Free graded left module on 2 generators over mod 2 Steenrod algebra, milnor basis + To: Free graded left module on 2 generators over mod 2 Steenrod algebra, milnor basis + Defn: g[1] |--> Sq(1)*h[2] + h[3] + g[3] |--> Sq(2)*h[3] sage: TestSuite(homset).run() AUTHORS: @@ -77,13 +78,18 @@ def _element_constructor_(self, values): sage: values = (A2.Sq(4)*L.generator(0), A2.Sq(3)*L.generator(1)) sage: f = H(values); f - Module homomorphism of degree 5 defined by sending the generators - [g_{1}, g_{3}] - to - [Sq(4)*g_{2}, Sq(3)*g_{5}] + Free module morphism: + From: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + To: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Defn: g[1] |--> Sq(4)*g[2] + g[3] |--> Sq(3)*g[5] sage: H(0) - The trivial homomorphism + Free module morphism: + From: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + To: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Defn: g[1] |--> 0 + g[3] |--> 0 """ from .free_morphism import FreeGradedModuleMorphism if isinstance(values, FreeGradedModuleMorphism): @@ -106,7 +112,11 @@ def _an_element_(self): sage: L = FreeGradedModule(A2, (2,3)) sage: H = Hom(F, L) sage: H._an_element_() - The trivial homomorphism + Free module morphism: + From: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + To: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Defn: g[1] |--> 0 + g[3] |--> 0 """ return self.zero() @@ -124,7 +134,11 @@ def zero(self): sage: L = FreeGradedModule(A2, (2,3)) sage: H = Hom(F, L) sage: H.zero() - The trivial homomorphism + Free module morphism: + From: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + To: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Defn: g[1] |--> 0 + g[3] |--> 0 """ return self.element_class(self, self.codomain().zero()) @@ -140,7 +154,9 @@ def identity(self): sage: L = FreeGradedModule(A2, (2,3)) sage: H = Hom(L, L) sage: H.identity() - The identity homomorphism + Free module endomorphism of Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Defn: g[2] |--> g[2] + g[3] |--> g[3] TESTS:: diff --git a/src/sage/modules/fp_graded/free_module.py b/src/sage/modules/fp_graded/free_module.py index a104d53ea13..ffd1a856936 100755 --- a/src/sage/modules/fp_graded/free_module.py +++ b/src/sage/modules/fp_graded/free_module.py @@ -42,32 +42,32 @@ x = \sum_{i=1}^N a_i\cdot g_i\,, -where `a_i\in A_{n-\deg(g_i)}` for all `i`. The ordered set `\{a_i\}` +where `a_i\in A_{n-\deg(g_i)}` for all `i`. The ordered set `\{a_i\}` is referred to as the coefficients of `x`. Module elements are displayed by their algebra coefficients:: sage: M.an_element(n=5) - Sq(2,1)*G[0] + Sq(4)*G[1] + Sq(2,1)*g[0] + Sq(4)*g[1] sage: M.an_element(n=15) - Sq(0,0,0,1)*G[0] + Sq(1,2,1)*G[1] + Sq(0,0,0,1)*g[0] + Sq(1,2,1)*g[1] The generators are themselves elements of the module:: sage: M.generators() - (G[0], G[1]) + (g[0], g[1]) Producing elements from a given set of coefficients is possible as usual:: sage: coeffs = [Sq(5), Sq(1,1)] sage: x = M(coeffs); x - Sq(5)*G[0] + Sq(1,1)*G[1] + Sq(5)*g[0] + Sq(1,1)*g[1] The module action produces new elements:: sage: Sq(2) * x - (Sq(4,1)+Sq(7))*G[0] + Sq(3,1)*G[1] + (Sq(4,1)+Sq(7))*g[0] + Sq(3,1)*g[1] Each non-zero element has a well-defined degree:: @@ -86,9 +86,9 @@ Any two elements can be added as long as they are in the same degree:: sage: y = M.an_element(5); y - Sq(2,1)*G[0] + Sq(4)*G[1] + Sq(2,1)*g[0] + Sq(4)*g[1] sage: x + y - (Sq(2,1)+Sq(5))*G[0] + (Sq(1,1)+Sq(4))*G[1] + (Sq(2,1)+Sq(5))*g[0] + (Sq(1,1)+Sq(4))*g[1] or when at least one of them is zero:: @@ -105,7 +105,7 @@ computed:: sage: M.basis_elements(5) - (Sq(2,1)*G[0], Sq(5)*G[0], Sq(1,1)*G[1], Sq(4)*G[1]) + (Sq(2,1)*g[0], Sq(5)*g[0], Sq(1,1)*g[1], Sq(4)*g[1]) together with a corresponding vector space presentation:: @@ -122,7 +122,7 @@ sage: x_ = M.element_from_coordinates((0,1,1,0), 5) sage: x_ - Sq(5)*G[0] + Sq(1,1)*G[1] + Sq(5)*g[0] + Sq(1,1)*g[1] sage: x_ == x True @@ -157,20 +157,27 @@ domain to the `i`-th codomain value given:: sage: f - Module homomorphism of degree 4 defined by sending the generators - (G[0], G[1]) - to - (Sq(2)*c2, (Sq(0,1)+Sq(3))*c2) + Free module morphism: + From: Free graded left module on 2 generators over mod 2 Steenrod algebra, milnor basis + To: Free graded left module on 1 generator over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> Sq(2)*c2 + g[1] |--> (Sq(0,1)+Sq(3))*c2 Convenience methods exist for creating the trivial morphism:: sage: homspace.zero() - The trivial homomorphism + Free module morphism: + From: Free graded left module on 2 generators over mod 2 Steenrod algebra, milnor basis + To: Free graded left module on 1 generator over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> 0 + g[1] |--> 0 as well as the identity endomorphism:: sage: Hom(M, M).identity() - The identity homomorphism + Free module endomorphism of Free graded left module on 2 generators over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> g[0] + g[1] |--> g[1] Homomorphisms can be evaluated on elements of the domain module:: @@ -205,10 +212,11 @@ sage: f2 = homspace([Sq(2)*c2, Sq(3)*c2]) sage: f + f2 - Module homomorphism of degree 4 defined by sending the generators - (G[0], G[1]) - to - (0, Sq(0,1)*c2) + Free module morphism: + From: Free graded left module on 2 generators over mod 2 Steenrod algebra, milnor basis + To: Free graded left module on 1 generator over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> 0 + g[1] |--> Sq(0,1)*c2 or when at least one of them is zero:: @@ -217,8 +225,8 @@ Finally, additive inverses exist:: - sage: f - f - The trivial homomorphism + sage: f - f == 0 + True The restriction of a homomorphism to the vector space of `n`-dimensional module elements is a linear transformation:: @@ -315,9 +323,9 @@ class FreeGradedModule(CombinatorialFreeModule): ``names`` of generators:: sage: M.generators() - (G[-1], G[3]) + (g[-1], g[3]) sage: FreeGradedModule(E, (0, 0, 2)).generators() - (G(0, 0), G(0, 1), G(2, 0)) + (g(0, 0), g(0, 1), g(2, 0)) sage: FreeGradedModule(E, (0, 0, 2), names='x, y, z').generators() (x, y, z) sage: FreeGradedModule(E, (0, 0, 2), names='xyz').generators() @@ -354,7 +362,7 @@ def __classcall_private__(cls, algebra, generator_degrees, category=None, if names is not None and len(names) != len(generator_degrees): raise ValueError("the names do not correspond to the generators") if prefix is None: - prefix = 'G' + prefix = 'g' return super(cls, FreeGradedModule).__classcall__(cls, algebra=algebra, generator_degrees=generator_degrees, category=category, names=names, @@ -550,7 +558,7 @@ def an_element(self, n=None): sage: A = SteenrodAlgebra(2) sage: M = FreeGradedModule(A, (0,2,4)) sage: M.an_element(172) - Sq(0,0,2,0,1,0,1)*G[0] + Sq(0,4,0,0,1,0,1)*G[2] + Sq(7,1,0,0,1,0,1)*G[4] + Sq(0,0,2,0,1,0,1)*g[0] + Sq(0,4,0,0,1,0,1)*g[2] + Sq(7,1,0,0,1,0,1)*g[4] Zero is the only element in the trivial module:: @@ -650,7 +658,7 @@ def element_from_coordinates(self, coordinates, n): sage: A = SteenrodAlgebra(2) sage: M = FreeGradedModule(A, (0,1)) sage: x = M.element_from_coordinates((0,1,0,1), 5); x - Sq(5)*G[0] + Sq(4)*G[1] + Sq(5)*g[0] + Sq(4)*g[1] sage: basis = M.basis_elements(5) sage: y = 0*basis[0] + 1*basis[1] + 0*basis[2] + 1*basis[3] sage: x == y @@ -770,11 +778,11 @@ def generator(self, index): sage: A = SteenrodAlgebra(2) sage: M = FreeGradedModule(A, (0,2,4)) sage: M.generator(0) - G[0] + g[0] sage: M.generator(1) - G[2] + g[2] sage: M.generator(2) - G[4] + g[4] """ try: return self.gens()[index] @@ -796,7 +804,7 @@ def generators(self): sage: A = SteenrodAlgebra(2) sage: M = FreeGradedModule(A, (-2,1)) sage: M.generators() - (G[-2], G[1]) + (g[-2], g[1]) """ return self.gens() diff --git a/src/sage/modules/fp_graded/free_morphism.py b/src/sage/modules/fp_graded/free_morphism.py index a32e9fd6e91..be3774a3163 100755 --- a/src/sage/modules/fp_graded/free_morphism.py +++ b/src/sage/modules/fp_graded/free_morphism.py @@ -50,13 +50,14 @@ class FreeGradedModuleMorphism(Morphism): sage: F3 = FreeGradedModule(A, (2,3), names='d') sage: H1 = Hom(F1, F2) sage: H2 = Hom(F2, F3) - sage: f = H1( ( F2((Sq(4), 0)), F2((0, Sq(4))) ) ) - sage: g = H2( ( F3((Sq(2), 0)), F3((Sq(3), Sq(2))) ) ) + sage: f = H1((F2((Sq(4), 0)), F2((0, Sq(4))))) + sage: g = H2((F3((Sq(2), 0)), F3((Sq(3), Sq(2))))) sage: g*f - Module homomorphism of degree 4 defined by sending the generators - [b_{4}, b_{5}] - to - [(Sq(0,2)+Sq(3,1)+Sq(6))*d_{2}, (Sq(1,2)+Sq(7))*d_{2} + (Sq(0,2)+Sq(3,1)+Sq(6))*d_{3}] + Free module morphism: + From: Free graded left module on 2 generators over mod 2 Steenrod algebra, milnor basis + To: Free graded left module on 2 generators over mod 2 Steenrod algebra, milnor basis + Defn: b[4] |--> (Sq(0,2)+Sq(3,1)+Sq(6))*d[2] + b[5] |--> (Sq(1,2)+Sq(7))*d[2] + (Sq(0,2)+Sq(3,1)+Sq(6))*d[3] TESTS:: @@ -179,7 +180,7 @@ def values(self): sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] sage: f = homspace(values) sage: f.values() - (Sq(5)*G[2], Sq(3,1)*G[2]) + (Sq(5)*g[2], Sq(3,1)*g[2]) sage: homspace.zero().values() (0, 0) """ @@ -277,10 +278,11 @@ def _neg_(self): sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] sage: f = homspace(values) sage: f_inverse = -f; f_inverse - Module homomorphism of degree 7 defined by sending the generators - [G[0], g_{1}] - to - [Sq(5)*G[2], Sq(3,1)*G[2]] + Free module morphism: + From: Free graded left module on 2 generators over mod 2 Steenrod algebra, milnor basis + To: Free graded left module on 1 generator over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> Sq(5)*g[2] + g[1] |--> Sq(3,1)*g[2] sage: (f + f_inverse).is_zero() True """ @@ -301,8 +303,8 @@ def _sub_(self, g): sage: f = homspace(values) sage: values2 = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] sage: g = homspace(values2) - sage: f - g - The trivial homomorphism + sage: f - g == 0 + True """ return self + (-g) @@ -324,10 +326,8 @@ def __mul__(self, g): sage: values2 = [Sq(2)*M.generator(0)] sage: g = Hom(N, M)(values2) sage: fg = f * g; fg - Module homomorphism of degree 7 defined by sending the generators - [G[2]] - to - [(Sq(4,1)+Sq(7))*G[2]] + Free module endomorphism of Free graded left module on 1 generator over mod 2 Steenrod algebra, milnor basis + Defn: g[2] |--> (Sq(4,1)+Sq(7))*g[2] sage: fg.is_endomorphism() True @@ -397,9 +397,11 @@ def is_identity(self): sage: f = Hom(M, N)(values) sage: f.is_identity() False - sage: id = Hom(M, M)(M.generators()); id - The identity homomorphism - sage: id.is_identity() + sage: one = Hom(M, M)(M.generators()); one + Free module endomorphism of Free graded left module on 2 generators over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> g[0] + g[1] |--> g[1] + sage: one.is_identity() True """ return (self.parent().is_endomorphism_set() and @@ -427,9 +429,9 @@ def __call__(self, x): sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] sage: f = Hom(M, N)(values) sage: f.__call__(M.generator(0)) - Sq(5)*G[2] + Sq(5)*g[2] sage: f.__call__(M.generator(1)) - Sq(3,1)*G[2] + Sq(3,1)*g[2] """ if x.parent() != self.domain(): raise ValueError('cannot evaluate morphism on element not in the domain') @@ -440,35 +442,43 @@ def __call__(self, x): return value - def _repr_(self): - r""" - A string representation of ``self``. - - EXAMPLES:: + def _repr_type(self): + """ + TESTS:: sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: A = SteenrodAlgebra(2) sage: M = FreeGradedModule(A, (0,1)) - sage: N = FreeGradedModule(A, (2,)) - sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: f = Hom(M,M).identity() + sage: type(f) + + sage: f._repr_type() + 'Free module' + sage: f + Free module endomorphism of Free graded left module on 2 generators over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> g[0] + g[1] |--> g[1] + """ + return "Free module" - sage: Hom(M, N)(values)._repr_() - 'Module homomorphism of degree 7 defined by sending the generators\n - [G[0], g_{1}]\nto\n [Sq(5)*G[2], Sq(3,1)*G[2]]' - sage: Hom(M, N).zero()._repr_() - 'The trivial homomorphism' + def _repr_defn(self): + """ + TESTS:: - sage: Hom(M, M).identity()._repr_() - 'The identity homomorphism' + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A = SteenrodAlgebra(2) + sage: F1 = FreeGradedModule(A, (4,5), names='b') + sage: F2 = FreeGradedModule(A, (3,4), names='c') + sage: H = Hom(F1, F2) + sage: f = H((F2((Sq(4), 0)), F2((0, Sq(4))))) + sage: print(f._repr_defn()) + b[4] |--> Sq(4)*c[3] + b[5] |--> Sq(4)*c[4] """ - if self.is_zero(): - return "The trivial homomorphism" - elif self.is_identity(): - return "The identity homomorphism" - else: - r = "Module homomorphism of degree {} defined by sending the generators\n {}\nto\n {}" - return r.format(self.degree(), self.domain().generators(), self._values) + s = '\n'.join(['%s |--> %s'%(x, y) for (x, y) in + zip(self.domain().generators(), self._values)]) + return s def vector_presentation(self, n): @@ -573,7 +583,7 @@ def fp_module(self): sage: M.generator_degrees() (0,) sage: M.relations() - [Sq(2)*G[0]] + (Sq(2)*g[0],) """ from .module import FPModule return FPModule(algebra=self.base_ring(), diff --git a/src/sage/modules/fp_graded/homspace.py b/src/sage/modules/fp_graded/homspace.py index f295c8fde0b..1ec3a5bf088 100755 --- a/src/sage/modules/fp_graded/homspace.py +++ b/src/sage/modules/fp_graded/homspace.py @@ -15,20 +15,23 @@ sage: homset = Hom(F, L); homset Set of Morphisms from Finitely presented left module on 2 generators ... sage: homset.an_element() - Module homomorphism of degree 0 defined by sending the generators - [c_{1}, c_{3}] - to - [0, Sq(1)*h_{2}] + Module morphism: + From: Finitely presented left module on 2 generators and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + To: Finitely presented left module on 2 generators and 2 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Defn: c[1] |--> 0 + c[3] |--> Sq(1)*h[2] sage: homset([L((A.Sq(1), 1)), L((0, A.Sq(2)))]) - Module homomorphism of degree 2 defined by sending the generators - [c_{1}, c_{3}] - to - [Sq(1)*h_{2} + h_{3}, Sq(2)*h_{3}] + Module morphism: + From: Finitely presented left module on 2 generators and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + To: Finitely presented left module on 2 generators and 2 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Defn: c[1] |--> Sq(1)*h[2] + h[3] + c[3] |--> Sq(2)*h[3] sage: Hom(F, L) ([L((A.Sq(1), 1)), L((0, A.Sq(2)))]).kernel_inclusion() - Module homomorphism of degree 0 defined by sending the generators - [g_{3}, g_{4}] - to - (c_{3}, Sq(0,1)*c_{1}) + Module morphism: + From: Finitely presented left module on 2 generators and 1 relation over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + To: Finitely presented left module on 2 generators and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Defn: g[3] |--> c[3] + g[4] |--> Sq(0,1)*c[1] AUTHORS: @@ -92,10 +95,11 @@ def _element_constructor_(self, values): should call it implicitly using the syntax:: sage: f = homset([v1, v2]); f - Module homomorphism of degree 2 defined by sending the generators - [g_{1}, g_{3}] - to - [Sq(1)*g_{2} + g_{3}, Sq(2)*g_{3}] + Module morphism: + From: Finitely presented left module on 2 generators and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + To: Finitely presented left module on 2 generators and 2 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Defn: g[1] |--> Sq(1)*g[2] + g[3] + g[3] |--> Sq(2)*g[3] One can construct a homomorphism from another homomorhism:: @@ -105,8 +109,8 @@ def _element_constructor_(self, values): And there is a convenient way of making the trivial homomorphism:: - sage: z = homset(0); z - The trivial homomorphism + sage: homset(0) == 0 + True """ if isinstance(values, self.element_class): return values @@ -135,26 +139,22 @@ def an_element(self, n=0): sage: HZ = FPModule(A, [0], relations=[[Sq(1)]]) sage: Hom(HZ, HZ).an_element(3) - Module homomorphism of degree 3 defined by sending the generators - [g_{0}] - to - [Sq(0,1)*g_{0}] + Module endomorphism of Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> Sq(0,1)*g[0] TESTS:: sage: K = FPModule(A, [0, 0], [[Sq(2), 0]]) # Using a zero coefficient in the relations. sage: Hom(K, K).an_element(4) - Module homomorphism of degree 4 defined by sending the generators - [g_{0,0}, g_{0,1}] - to - [0, Sq(4)*g_{0,0}] + Module endomorphism of Finitely presented left module on 2 generators and 1 relation over mod 2 Steenrod algebra, milnor basis + Defn: g(0, 0) |--> 0 + g(0, 1) |--> Sq(4)*g(0, 0) sage: K = FPModule(A, [0, 0], [[Sq(2), 0], [0,0], [Sq(4), Sq(2)*Sq(2)]]) sage: Hom(K, K).an_element(n=3) - Module homomorphism of degree 3 defined by sending the generators - [g_{0,0}, g_{0,1}] - to - [0, Sq(0,1)*g_{0,0}] + Module endomorphism of Finitely presented left module on 2 generators and 2 relations over mod 2 Steenrod algebra, milnor basis + Defn: g(0, 0) |--> 0 + g(0, 1) |--> Sq(0,1)*g(0, 0) """ return self._basis_elements(n, basis=False) @@ -178,14 +178,10 @@ def basis_elements(self, n): sage: Hko = FPModule(A, [0], relations=[[Sq(2)], [Sq(1)]]) sage: Hom(Hko, Hko).basis_elements(21) - [Module homomorphism of degree 21 defined by sending the generators - [g_{0}] - to - [(Sq(0,0,3)+Sq(0,2,0,1))*g_{0}], - Module homomorphism of degree 21 defined by sending the generators - [g_{0}] - to - [Sq(8,2,1)*g_{0}]] + [Module endomorphism of Finitely presented left module on 1 generator and 2 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> (Sq(0,0,3)+Sq(0,2,0,1))*g[0], + Module endomorphism of Finitely presented left module on 1 generator and 2 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> Sq(8,2,1)*g[0]] """ return self._basis_elements(n, basis=True) @@ -201,9 +197,7 @@ def zero(self): sage: F = FPModule(A2, [1,3]) sage: L = FPModule(A2, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]) - sage: z = Hom(F, L).zero(); z - The trivial homomorphism - + sage: z = Hom(F, L).zero() sage: z(F.an_element(5)) 0 sage: z(F.an_element(23)) @@ -223,11 +217,13 @@ def identity(self): sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) sage: L = FPModule(A2, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]) - sage: id = Hom(L, L).identity(); id - The identity homomorphism + sage: one = Hom(L, L).identity(); one + Module endomorphism of Finitely presented left module on 2 generators and 2 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Defn: g[2] |--> g[2] + g[3] |--> g[3] sage: e = L.an_element(5) - sage: e == id(e) + sage: e == one(e) True It is an error to call this function when the homset is not a @@ -271,36 +267,27 @@ def _basis_elements(self, n, basis): sage: A = SteenrodAlgebra(2) sage: Hko = FPModule(A, [0], relations=[[Sq(2)], [Sq(1)]]) sage: Hom(Hko, Hko)._basis_elements(21, basis=True) - [Module homomorphism of degree 21 defined by sending the generators - [g_{0}] - to - [(Sq(0,0,3)+Sq(0,2,0,1))*g_{0}], - Module homomorphism of degree 21 defined by sending the generators - [g_{0}] - to - [Sq(8,2,1)*g_{0}]] + [Module endomorphism of Finitely presented left module on 1 generator and 2 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> (Sq(0,0,3)+Sq(0,2,0,1))*g[0], + Module endomorphism of Finitely presented left module on 1 generator and 2 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> Sq(8,2,1)*g[0]] sage: Hom(Hko, Hko)._basis_elements(21, basis=False) - Module homomorphism of degree 21 defined by sending the generators - [g_{0}] - to - [(Sq(0,0,3)+Sq(0,2,0,1))*g_{0}] + Module endomorphism of Finitely presented left module on 1 generator and 2 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> (Sq(0,0,3)+Sq(0,2,0,1))*g[0] sage: F = FPModule(A, [0]) sage: Hom(F, Hko)._basis_elements(21, basis=False) - Module homomorphism of degree 21 defined by sending the generators - [g_{0}] - to - [Sq(0,2,0,1)*g_{0}] + Module morphism: + From: Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 1 generator and 2 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> Sq(0,2,0,1)*g[0] sage: Hom(F, Hko)._basis_elements(21, basis=False) - Module homomorphism of degree 21 defined by sending the generators - [g_{0}] - to - [Sq(0,2,0,1)*g_{0}] - - Hom(FPA_Module([0], A, [[Sq(1)]]), FPA_Module([-2], A, [[Sq(1)]])).an_element(0) - The trivial homomorphism + Module morphism: + From: Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 1 generator and 2 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> Sq(0,2,0,1)*g[0] Test corner cases involving trivial modules:: @@ -308,10 +295,13 @@ def _basis_elements(self, n, basis): sage: Z0 = FPModule(A, []) # A trivial module. sage: Z1 = FPModule(A, [0], [[1]]) # A trivial module with a redundant generator and relation. - Hom(FPA_Module([-1], A), F)._basis_elements(0, basis=True) + sage: Hom(FPModule(A, [-1]), F)._basis_elements(0, basis=True) [] - Hom(FPA_Module([-1], A), F)._basis_elements(0, basis=False) - The trivial homomorphism + sage: Hom(FPModule(A, [-1]), F)._basis_elements(0, basis=False) + Module morphism: + From: Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[-1] |--> 0 sage: from itertools import product sage: for D,C in product([(F, 'Free'), (Hko, 'Hko'), (Z0, 'Trivial'), (Z1, 'Trivial with redundant generator')], repeat=2): @@ -320,109 +310,126 @@ def _basis_elements(self, n, basis): ....: print(' basis==True:\n %s' % Hom(D[0], C[0])._basis_elements(n=7, basis=True)) Hom(Free, Free): basis==False: - Module homomorphism of degree 7 defined by sending the generators - (G[0],) - to - (Sq(0,0,1)*G[0],), + Module endomorphism of Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> Sq(0,0,1)*g[0] basis==True: - [Module homomorphism of degree 7 defined by sending the generators - (G[0],) - to - (Sq(0,0,1)*G[0],), Module homomorphism of degree 7 defined by sending the generators - (G[0],) - to - (Sq(1,2)*G[0],), Module homomorphism of degree 7 defined by sending the generators - (G[0],) - to - (Sq(4,1)*G[0],), Module homomorphism of degree 7 defined by sending the generators - (G[0],) - to - (Sq(7)*G[0],)] + [Module endomorphism of Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> Sq(0,0,1)*g[0], Module endomorphism of Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> Sq(1,2)*g[0], Module endomorphism of Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> Sq(4,1)*g[0], Module endomorphism of Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> Sq(7)*g[0]] Hom(Free, Hko): basis==False: - Module homomorphism of degree 7 defined by sending the generators - [g_{0}] - to - (Sq(0,0,1)*G[0],)] + Module morphism: + From: Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 1 generator and 2 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> Sq(0,0,1)*g[0] basis==True: - [Module homomorphism of degree 7 defined by sending the generators - [g_{0}] - to - (Sq(0,0,1)*G[0],)] + [Module morphism: + From: Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 1 generator and 2 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> Sq(0,0,1)*g[0]] Hom(Free, Trivial): basis==False: - The trivial homomorphism + Module morphism: + From: Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 0 generators and 0 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> 0 basis==True: [] Hom(Free, Trivial with redundant generator): basis==False: - The trivial homomorphism + Module morphism: + From: Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> 0 basis==True: [] Hom(Hko, Free): basis==False: - The trivial homomorphism + Module morphism: + From: Finitely presented left module on 1 generator and 2 relations over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> 0 basis==True: [] Hom(Hko, Hko): basis==False: - Module homomorphism of degree 7 defined by sending the generators - (G[0],) - to - (Sq(0,0,1)*G[0],)] + Module endomorphism of Finitely presented left module on 1 generator and 2 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> Sq(0,0,1)*g[0] basis==True: - [Module homomorphism of degree 7 defined by sending the generators - (G[0],) - to - (Sq(0,0,1)*G[0],)] + [Module endomorphism of Finitely presented left module on 1 generator and 2 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> Sq(0,0,1)*g[0]] Hom(Hko, Trivial): basis==False: - The trivial homomorphism + Module morphism: + From: Finitely presented left module on 1 generator and 2 relations over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 0 generators and 0 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> 0 basis==True: [] Hom(Hko, Trivial with redundant generator): basis==False: - The trivial homomorphism + Module morphism: + From: Finitely presented left module on 1 generator and 2 relations over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> 0 basis==True: [] Hom(Trivial, Free): basis==False: - The trivial homomorphism + Module morphism: + From: Finitely presented left module on 0 generators and 0 relations over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis basis==True: [] Hom(Trivial, Hko): basis==False: - The trivial homomorphism + Module morphism: + From: Finitely presented left module on 0 generators and 0 relations over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 1 generator and 2 relations over mod 2 Steenrod algebra, milnor basis basis==True: [] Hom(Trivial, Trivial): basis==False: - The trivial homomorphism + Module endomorphism of Finitely presented left module on 0 generators and 0 relations over mod 2 Steenrod algebra, milnor basis basis==True: [] Hom(Trivial, Trivial with redundant generator): basis==False: - The trivial homomorphism + Module morphism: + From: Finitely presented left module on 0 generators and 0 relations over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis basis==True: [] Hom(Trivial with redundant generator, Free): basis==False: - The trivial homomorphism + Module morphism: + From: Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> 0 basis==True: [] Hom(Trivial with redundant generator, Hko): basis==False: - The trivial homomorphism + Module morphism: + From: Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 1 generator and 2 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> 0 basis==True: [] Hom(Trivial with redundant generator, Trivial): basis==False: - The trivial homomorphism + Module morphism: + From: Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 0 generators and 0 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> 0 basis==True: [] Hom(Trivial with redundant generator, Trivial with redundant generator): basis==False: - The trivial homomorphism + Module endomorphism of Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> 0 basis==True: [] """ diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index 6582fdd3a74..f0bd351ccb4 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -94,9 +94,9 @@ class FPModule(UniqueRepresentation, IndexedGenerators, Module): sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) sage: M = FPModule(A3, [0, 1], [[Sq(2), Sq(1)]]) sage: M.generators() - (G[0], G[1]) + (g[0], g[1]) sage: M.relations() - (Sq(2)*G[0] + Sq(1)*G[1],) + (Sq(2)*g[0] + Sq(1)*g[1],) sage: M.is_trivial() False @@ -245,7 +245,7 @@ def from_free_module_morphism(cls, morphism): sage: M.generator_degrees() (0,) sage: M.relations() - (Sq(2)*G[0],) + (Sq(2)*g[0],) """ return cls(algebra=morphism.base_ring(), generator_degrees=morphism.codomain().generator_degrees(), @@ -340,7 +340,7 @@ def _monomial(self, index): sage: from sage.modules.fp_graded.module import FPModule sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) sage: M._monomial(0) - G[0] + g[0] """ return self._from_dict({index: self.base_ring().one()}, remove_zeros=False) @@ -358,9 +358,9 @@ def monomial(self): sage: from sage.modules.fp_graded.module import FPModule sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) sage: M.monomial(0) - G[0] + g[0] sage: M.monomial(1) - G[1] + g[1] """ # Should use a real Map, as soon as combinatorial_classes are enumerated sets, and therefore parents from sage.categories.poor_man_map import PoorManMap @@ -473,7 +473,7 @@ def _repr_term(self, m): sage: A = SteenrodAlgebra(2) sage: M = FPModule(A, [0,2,4], [[Sq(4),Sq(2),0]]) sage: M._repr_term(4) - 'G[4]' + 'g[4]' """ return self._free_module()._repr_term(m) @@ -488,7 +488,7 @@ def _latex_term(self, m): sage: A = SteenrodAlgebra(2) sage: M = FPModule(A, [0,2,4], [[Sq(4),Sq(2),0]]) sage: M._latex_term(4) - 'G_{4}' + 'g_{4}' """ return self._free_module()._latex_term(m) @@ -648,16 +648,16 @@ def an_element(self, n=None): sage: M = FPModule(A2, [0,2,4], [[0, Sq(5), Sq(3)], [Sq(7), 0, Sq(2)*Sq(1)]]) sage: [M.an_element(i) for i in range(10)] - [G[0], - Sq(1)*G[0], - Sq(2)*G[0] + G[2], - Sq(0,1)*G[0] + Sq(1)*G[2], - Sq(1,1)*G[0] + Sq(2)*G[2] + G[4], - Sq(2,1)*G[0] + Sq(0,1)*G[2] + Sq(1)*G[4], - Sq(0,2)*G[0] + Sq(1,1)*G[2] + Sq(2)*G[4], - Sq(0,0,1)*G[0] + Sq(2,1)*G[2] + Sq(0,1)*G[4], - Sq(1,0,1)*G[0] + Sq(6)*G[2] + Sq(1,1)*G[4], - Sq(2,0,1)*G[0] + Sq(4,1)*G[2] + Sq(2,1)*G[4]] + [g[0], + Sq(1)*g[0], + Sq(2)*g[0] + g[2], + Sq(0,1)*g[0] + Sq(1)*g[2], + Sq(1,1)*g[0] + Sq(2)*g[2] + g[4], + Sq(2,1)*g[0] + Sq(0,1)*g[2] + Sq(1)*g[4], + Sq(0,2)*g[0] + Sq(1,1)*g[2] + Sq(2)*g[4], + Sq(0,0,1)*g[0] + Sq(2,1)*g[2] + Sq(0,1)*g[4], + Sq(1,0,1)*g[0] + Sq(6)*g[2] + Sq(1,1)*g[4], + Sq(2,0,1)*g[0] + Sq(4,1)*g[2] + Sq(2,1)*g[4]] """ a_free_element = self._free_module().an_element(n) return self(a_free_element) @@ -748,7 +748,7 @@ def element_from_coordinates(self, coordinates, n): sage: M.vector_presentation(12).dimension() 3 sage: x = M.element_from_coordinates((0,1,0), 12); x - Sq(0,4)*G[0] + Sq(0,4)*g[0] Applying the inverse function brings us back to the coordinate form:: @@ -799,7 +799,7 @@ def __getitem__(self, n): sage: M = FPModule(A, [0,2,4], [[Sq(4),Sq(2),0]]) sage: M[4] - (Sq(1,1)*G[0], Sq(4)*G[0], G[4]) + (Sq(1,1)*g[0], Sq(4)*g[0], g[4]) .. SEEALSO:: @@ -932,7 +932,7 @@ def generators(self): sage: M = FPModule(A4, [0,0,2,3]) sage: M.generators() - (g_{0,0}, g_{0,1}, g_{2,0}, g_{3,0}) + (g(0, 0), g(0, 1), g(2, 0), g(3, 0)) sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]], names='h') sage: N.generators() @@ -958,7 +958,7 @@ def generator(self, index): sage: M = FPModule(A4, [0,2,3]) sage: M.generator(0) - G[0] + g[0] sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]], names='h') sage: N.generator(1) @@ -984,7 +984,7 @@ def relations(self): sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]]) sage: N.relations() - (Sq(2)*G[0] + Sq(1)*G[1],) + (Sq(2)*g[0] + Sq(1)*g[1],) sage: Z = FPModule(A4, []) sage: Z.relations() @@ -1003,7 +1003,7 @@ def relation(self, index): sage: A4 = SteenrodAlgebra(2, profile=(4,3,2,1)) sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]]) sage: N.relation(0) - Sq(2)*G[0] + Sq(1)*G[1] + Sq(2)*g[0] + Sq(1)*g[1] """ return self.j.values()[index] @@ -1038,9 +1038,9 @@ def min_presentation(self, top_dim=None, verbose=False): There are more relations in ``M`` than in ``M_min``:: sage: M.relations() - (Sq(2)*G[0] + Sq(1)*G[1], Sq(2)*G[1], Sq(3)*G[0]) + (Sq(2)*g[0] + Sq(1)*g[1], Sq(2)*g[1], Sq(3)*g[0]) sage: M_min.relations() - (Sq(2)*G[0] + Sq(1)*G[1], Sq(2)*G[1]) + (Sq(2)*g[0] + Sq(1)*g[1], Sq(2)*g[1]) TESTS:: @@ -1078,14 +1078,14 @@ def suspension(self, t): sage: X.generator_degrees() (4,) sage: X.relations() - (Sq(1)*G[4],) + (Sq(1)*g[4],) sage: M = FPModule(A, [2,3], [[Sq(2), Sq(1)], [0, Sq(2)]]) sage: Q = M.suspension(1) sage: Q.generator_degrees() (3, 4) sage: Q.relations() - (Sq(2)*G[3] + Sq(1)*G[4], Sq(2)*G[4]) + (Sq(2)*g[3] + Sq(1)*g[4], Sq(2)*g[4]) sage: Q = M.suspension(-3) sage: Q.generator_degrees() (-1, 0) @@ -1132,7 +1132,7 @@ def submodule_inclusion(self, spanning_elements): sage: i.domain().generator_degrees() (0,) sage: i.domain().relations() - (Sq(3)*G[0],) + (Sq(3)*g[0],) """ # Create the free graded module on the set of spanning elements. degs = [x.degree() for x in spanning_elements] @@ -1179,10 +1179,11 @@ def resolution(self, k, top_dim=None, verbose=False): sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) sage: M = FPModule(A2, [0,1], [[Sq(2), Sq(1)]]) sage: M.resolution(0) - [Module homomorphism of degree 0 defined by sending the generators - [g_{0}, g_{1}] - to - (g_{0}, g_{1})] + [Module morphism: + From: Finitely presented left module on 2 generators and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + To: Finitely presented left module on 2 generators and 1 relation over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Defn: g[0] |--> g[0] + g[1] |--> g[1]] sage: res = M.resolution(4, verbose=True) Computing f_1 (1/4) Computing f_2 (2/4) @@ -1197,26 +1198,29 @@ def resolution(self, k, top_dim=None, verbose=False): sage: len(res) 5 sage: res - [Module homomorphism of degree 0 defined by sending the generators - [G[0], G[1]] - to - (G[0], G[1]), - Module homomorphism of degree 0 defined by sending the generators - [g_{2}] - to - (Sq(2)*G[0] + Sq(1)*G[1],), - Module homomorphism of degree 0 defined by sending the generators - [g_{8}] - to - (Sq(3,1)*G[2],), - Module homomorphism of degree 0 defined by sending the generators - [g_{9}, g_{10}] - to - (Sq(1)*g_{8}, Sq(2)*g_{8}), - Module homomorphism of degree 0 defined by sending the generators - [g_{10}, g_{12}] - to - (Sq(1)*g_{9}, Sq(0,1)*g_{9} + Sq(2)*g_{10})] + [Module morphism: + From: Finitely presented left module on 2 generators and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + To: Finitely presented left module on 2 generators and 1 relation over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Defn: g[0] |--> g[0] + g[1] |--> g[1], + Module morphism: + From: Finitely presented left module on 1 generator and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + To: Finitely presented left module on 2 generators and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Defn: g[2] |--> Sq(2)*g[0] + Sq(1)*g[1], + Module morphism: + From: Finitely presented left module on 1 generator and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + To: Finitely presented left module on 1 generator and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Defn: g[8] |--> Sq(3,1)*g[2], + Module morphism: + From: Finitely presented left module on 2 generators and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + To: Finitely presented left module on 1 generator and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Defn: g[9] |--> Sq(1)*g[8] + g[10] |--> Sq(2)*g[8], + Module morphism: + From: Finitely presented left module on 2 generators and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + To: Finitely presented left module on 2 generators and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Defn: g[10] |--> Sq(1)*g[9] + g[12] |--> Sq(0,1)*g[9] + Sq(2)*g[10]] sage: for i in range(len(res)-1): ....: assert (res[i]*res[i+1]).is_zero(), 'the result is not a complex' """ diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py index 3fd29252d12..caeeec2aef3 100755 --- a/src/sage/modules/fp_graded/morphism.py +++ b/src/sage/modules/fp_graded/morphism.py @@ -170,7 +170,7 @@ class FPModuleMorphism(Morphism): sage: w = Hom(Q, F)( (F((1, 0)), F((0, 1))) ) Traceback (most recent call last): ... - ValueError: relation Sq(6)*G[2] + Sq(5)*g_{3} is not sent to zero + ValueError: relation Sq(6)*g[2] + Sq(5)*g[3] is not sent to zero """ def __init__(self, parent, values): r""" @@ -228,10 +228,10 @@ def change_ring(self, algebra): sage: N = FPModule(A2, [0], relations=[[Sq(4)],[Sq(1)]]) sage: f = Hom(M,N)([A2.Sq(3)*N.generator(0)]); f - Module homomorphism of degree 3 defined by sending the generators - [G[0]] - to - [Sq(3)*G[0]] + Module morphism: + From: Finitely presented left module on 1 generator and 1 relation over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + To: Finitely presented left module on 1 generator and 2 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Defn: g[0] |--> Sq(3)*g[0] sage: f.base_ring() sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] @@ -275,7 +275,7 @@ def degree(self): Traceback (most recent call last): ... ValueError: the zero morphism does not have a well-defined degree - + TESTS:: sage: M = FPModule(SteenrodAlgebra(p=2), [7]) @@ -314,7 +314,7 @@ def values(self): sage: f = homspace(values) sage: f.values() - (Sq(5)*G[2], Sq(3,1)*G[2]) + (Sq(5)*g[2], Sq(3,1)*g[2]) sage: homspace.zero().values() (0, 0) @@ -414,10 +414,11 @@ def __neg__(self): sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] sage: f = homspace(values) sage: f_inverse = f.__neg__(); f_inverse - Module homomorphism of degree 7 defined by sending the generators - [G[0], g_{1}] - to - [Sq(5)*G[2], Sq(3,1)*G[2]] + Module morphism: + From: Finitely presented left module on 2 generators and 1 relation over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> Sq(5)*g[2] + g[1] |--> Sq(3,1)*g[2] sage: (f + f_inverse).is_zero() True """ @@ -438,18 +439,18 @@ def __sub__(self, g): sage: f = Hom(M, N)( [Sq(3)*N.generator(0)] ) sage: g = Hom(M, N)( [Sq(0,1)*N.generator(0)] ) sage: f.__sub__(g) - Module homomorphism of degree 3 defined by sending the generators - [G[0]] - to - [(Sq(0,1)+Sq(3))*G[0]] + Module morphism: + From: Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> (Sq(0,1)+Sq(3))*g[0] sage: f = Hom(M, N)( [Sq(4)*N.generator(0)] ) # the zero map sage: g = Hom(M, N)( [Sq(1,1)*N.generator(0)] ) sage: f.__sub__(g) - Module homomorphism of degree 4 defined by sending the generators - [G[0]] - to - [Sq(1,1)*G[0]] + Module morphism: + From: Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> Sq(1,1)*g[0] """ return self.__add__(g.__neg__()) @@ -467,10 +468,8 @@ def __mul__(self, g): sage: f = Hom(M, N)( [Sq(2)*N.generator(0)] ) sage: g = Hom(N, M)( [Sq(2,2)*M.generator(0)] ) sage: fg = f.__mul__(g); fg - Module homomorphism of degree 10 defined by sending the generators - [G[0]] - to - [(Sq(0,1,1)+Sq(1,3)+Sq(3,0,1))*G[0]] + Module endomorphism of Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> (Sq(0,1,1)+Sq(1,3)+Sq(3,0,1))*g[0] sage: fg.is_endomorphism() True @@ -538,10 +537,12 @@ def is_identity(self): sage: f.is_identity() False - sage: id = Hom(M, M)(M.generators()); id - The identity homomorphism + sage: one = Hom(M, M)(M.generators()); one + Module endomorphism of Finitely presented left module on 2 generators and 1 relation over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> g[0] + g[1] |--> g[1] - sage: id.is_identity() + sage: one.is_identity() True """ return (self.parent().is_endomorphism_set() and @@ -572,10 +573,10 @@ def __call__(self, x): sage: f = Hom(M, N)(values) sage: f.__call__(M.generator(0)) - Sq(5)*G[2] + Sq(5)*g[2] sage: f.__call__(M.generator(1)) - Sq(3,1)*G[2] + Sq(3,1)*g[2] """ if x.parent() != self.domain(): raise ValueError('cannot evaluate morphism on element not in domain') @@ -583,35 +584,38 @@ def __call__(self, x): return self.codomain()(self.free_morphism(x.lift_to_free())) - def _repr_(self): - r""" - A string representation of ``self``. + def _repr_type(self): + """ + TESTS:: - EXAMPLES:: + sage: from sage.modules.fp_graded.module import FPModule + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) + sage: M = FPModule(A2, [0], relations=[[Sq(1)]]) + sage: N = FPModule(A2, [0], relations=[[Sq(4)],[Sq(1)]]) + sage: f = Hom(M,N)([A2.Sq(3)*N.generator(0)]) + sage: f._repr_type() + 'Module' + """ + return "Module" - sage: from sage.modules.fp_graded.module import * - sage: A = SteenrodAlgebra(2) - sage: M = FPModule(A, [0,1], [[Sq(2), Sq(1)]]) - sage: N = FPModule(A, [2], [[Sq(4)]]) - sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] - sage: Hom(M, N)(values) - Module homomorphism of degree 7 defined by sending the generators - [G[0], g_{1}] - to - [Sq(5)*G[2], Sq(3,1)*G[2]] - sage: Hom(M, N).zero() - The trivial homomorphism - sage: Hom(M, M).identity() - The identity homomorphism + + def _repr_defn(self): """ - if self.is_zero(): - return "The trivial homomorphism" - elif self.is_identity(): - return "The identity homomorphism" - else: - return ("Module homomorphism of degree %d defined by sending " - "the generators\n %s\nto\n %s" - % (self.degree(), self.domain().generators(), self._values)) + TESTS:: + + sage: from sage.modules.fp_graded.module import FPModule + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) + sage: M = FPModule(A2, [0], relations=[[Sq(1)]]) + sage: N = FPModule(A2, [0], relations=[[Sq(4)],[Sq(1)]]) + sage: f = Hom(M,N)([A2.Sq(3)*N.generator(0)]) + sage: f._repr_defn() + 'g[0] |--> Sq(3)*g[0]' + """ + s = '\n'.join(['%s |--> %s'%(x, y) for (x, y) in + zip(self.domain().generators(), self._values)]) + return s @cached_method @@ -742,9 +746,9 @@ def solve(self, x): sage: N = FPModule(A, [0], [[Sq(2,2)]]) sage: f = Hom(M, N)( [Sq(2)*N.generator(0)] ) sage: y = Sq(1,1)*N.generator(0); y - Sq(1,1)*G[0] + Sq(1,1)*g[0] sage: x = f.solve(y); x - Sq(2)*G[0] + Sq(2)*g[0] sage: y == f(x) True @@ -810,7 +814,7 @@ def lift(self, f, verbose=False): The linear function sending `g_i` to `x_i` for every `i` is well defined if and only if the vector `x = (x_1,\ldots, x_N)` lies - in the nullspace of the coefficient matrix `R = (r_{ij})` given by the + in the nullspace of the coefficient matrix `R = (r_{ij})` given by the relations of `L`. Let `k \in \ker(f)` solve the matrix equation: @@ -819,8 +823,8 @@ def lift(self, f, verbose=False): R \cdot k = R \cdot x. - Define a module homomorphism by sending the generators of `L` to - `x_1 - k_1, \ldots, x_N - k_N`. This is well defined, and is also a + Define a module homomorphism by sending the generators of `L` to + `x_1 - k_1, \ldots, x_N - k_N`. This is well defined, and is also a lift of this homomorphism over `f`. Note that it does not matter how we choose the initial elements `x_i`: @@ -843,10 +847,10 @@ def lift(self, f, verbose=False): sage: f*f_ == k True sage: f_ - Module homomorphism of degree 1 defined by sending the generators - [G[0]] - to - [Sq(1)*G[0]] + Module morphism: + From: Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> Sq(1)*g[0] A split projection:: @@ -855,17 +859,20 @@ def lift(self, f, verbose=False): sage: q = Hom(A_plus_HZ, HZ)([HZ([1]), HZ([1])]) sage: # We can construct a splitting of `q` manually: sage: split = Hom(HZ,A_plus_HZ)([A_plus_HZ.generator(1)]) - sage: q*split - The identity homomorphism - sage: # Thus, lifting the identity homomorphism over `q` should be possible: - sage: id = Hom(HZ,HZ).identity() - sage: j = id.lift(q); j - Module homomorphism of degree 0 defined by sending the generators - [G[0]] - to - [g_{0,1}] + sage: (q*split).is_identity() + True + + Thus, lifting the identity homomorphism over `q` should be possible:: + + sage: one = Hom(HZ,HZ).identity() + sage: j = one.lift(q); j + Module morphism: + From: Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 2 generators and 1 relation over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> g(0, 1) sage: q*j - The identity homomorphism + Module endomorphism of Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> g[0] Lifting over the inclusion of the image sub module:: @@ -874,10 +881,10 @@ def lift(self, f, verbose=False): sage: f = Hom(M,M)([Sq(2)*M.generator(0)]) sage: im = f.image(top_dim=10) sage: f.lift(im) - Module homomorphism of degree 2 defined by sending the generators - [G[0]] - to - [G[2]] + Module morphism: + From: Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 1 generator and 2 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> g[2] When a lift cannot be found, the ``None`` value is returned. By setting the verbose argument to ``True``, an explanation of why @@ -897,8 +904,8 @@ def lift(self, f, verbose=False): sage: A = SteenrodAlgebra(2) sage: # The trivial map often involved in corner cases.. sage: trivial_map = Hom(FPModule(A, [0]), FPModule(A, [])).zero() - sage: trivial_map.lift(trivial_map) - The trivial homomorphism + sage: trivial_map.lift(trivial_map) == 0 + True sage: F = FPModule(A, [0]) sage: HZ = FPModule(A, [0], relations=[[Sq(1)]]) @@ -926,10 +933,10 @@ def lift(self, f, verbose=False): True sage: k = f.kernel_inclusion() # long time sage: f.lift(k) # long time - Module homomorphism of degree 21 defined by sending the generators - [G[0]] - to - [Sq(1)*g_{20}] + Module morphism: + From: Finitely presented left module on 1 generator and 2 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [2, 2, 2, 1] + To: Finitely presented left module on 3 generators and 12 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [2, 2, 2, 1] + Defn: g[0] |--> Sq(1)*g[20] Corner cases involving trivial maps:: @@ -1083,13 +1090,14 @@ def split(self, verbose=False): sage: N = FPModule(A, [0], [[Sq(1)]]) sage: p = Hom(M, N)([N.generator(0), N.generator(0)]) sage: s = p.split(); s - Module homomorphism of degree 0 defined by sending the generators - [G[0]] - to - [g_{0,1}] + Module morphism: + From: Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 2 generators and 1 relation over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> g(0, 1) sage: # Verify that `s` is a splitting: sage: p*s - The identity homomorphism + Module endomorphism of Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> g[0] TESTS:: @@ -1182,23 +1190,25 @@ def suspension(self, t): sage: F2 = FPModule(A, [5]) sage: f = Hom(F1, F2)( ( F2([Sq(4)]), F2([Sq(5)]) ) ); f - Module homomorphism of degree 5 defined by sending the generators - [g_{4}, g_{5}] - to - (Sq(4)*g_{5}, Sq(5)*g_{5}) + Module morphism: + From: Finitely presented left module on 2 generators and 0 relations over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[4] |--> Sq(4)*g[5] + g[5] |--> Sq(5)*g[5] sage: e1 = F1([1, 0]) sage: e2 = F1([0, 1]) sage: f(e1) - Sq(4)*g_{5} + Sq(4)*g[5] sage: f(e2) - Sq(5)*g_{5} + Sq(5)*g[5] sage: sf = f.suspension(4); sf - Module homomorphism of degree 5 defined by sending the generators - [g_{8}, g_{9}] - to - [Sq(4)*g_{9}, Sq(5)*g_{9}] + Module morphism: + From: Finitely presented left module on 2 generators and 0 relations over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[8] |--> Sq(4)*g[9] + g[9] |--> Sq(5)*g[9] sage: sf.domain() is f.domain().suspension(4) True @@ -1232,10 +1242,10 @@ def cokernel_projection(self): sage: r = Hom(F, M)([A1.Sq(1)*M.generator(0)]) sage: co = r.cokernel_projection(); co - Module homomorphism of degree 0 defined by sending the generators - [G[0]] - to - [G[0]] + Module morphism: + From: Finitely presented left module on 1 generator and 1 relation over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [2, 1] + To: Finitely presented left module on 1 generator and 2 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [2, 1] + Defn: g[0] |--> g[0] sage: co.domain().is_trivial() False @@ -1282,10 +1292,11 @@ def kernel_inclusion(self, top_dim=None, verbose=False): sage: H = Hom(F, L); sage: H([L((A3.Sq(1), 1)), L((0, A3.Sq(2)))]).kernel_inclusion() # long time - Module homomorphism of degree 0 defined by sending the generators - [g_{3}, g_{4}] - to - (g_{3}, Sq(0,1)*g_{1}) + Module morphism: + From: Finitely presented left module on 2 generators and 1 relation over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] + To: Finitely presented left module on 2 generators and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] + Defn: g[3] |--> g[3] + g[4] |--> Sq(0,1)*g[1] sage: M = FPModule(A3, [0,7], [[Sq(1), 0], [Sq(2), 0], [Sq(4), 0], [Sq(8), Sq(1)], [0, Sq(7)], [0, Sq(0,1,1)+Sq(4,2)]]) sage: F2 = FPModule(A3, [0], [[Sq(1)], [Sq(2)], [Sq(4)], [Sq(8)], [Sq(15)]]) @@ -1301,18 +1312,18 @@ def kernel_inclusion(self, top_dim=None, verbose=False): 7 8 9 10 11 12 13 14 15 16 17. sage: K.domain().generators() - [g_{7}] + (g[7],) sage: K.domain().relations() - [(Sq(0,1)+Sq(3))*g_{7}, - (Sq(0,0,1)+Sq(1,2)+Sq(4,1))*g_{7}, - Sq(9)*g_{7}, - (Sq(0,1,1)+Sq(4,2))*g_{7}] + ((Sq(0,1)+Sq(3))*g[7], + (Sq(0,0,1)+Sq(1,2)+Sq(4,1))*g[7], + Sq(9)*g[7], + (Sq(0,1,1)+Sq(4,2))*g[7]) sage: K - Module homomorphism of degree 0 defined by sending the generators - [g_{7}] - to - (g_{7},) + Module morphism: + From: Finitely presented left module on 1 generator and 4 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] + To: Finitely presented left module on 2 generators and 6 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] + Defn: g[7] |--> g[7] """ if verbose: print('1. Computing the generators of the kernel presentation:') @@ -1359,10 +1370,10 @@ def image(self, top_dim=None, verbose=False): sage: H = Hom(F, L); sage: H([L((A3.Sq(1), 1)), L((0, A3.Sq(2)))]).image() # long time - Module homomorphism of degree 0 defined by sending the generators - [g_{3}] - to - (Sq(1)*G[2] + g_{3},) + Module morphism: + From: Finitely presented left module on 1 generator and 1 relation over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] + To: Finitely presented left module on 2 generators and 2 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] + Defn: g[3] |--> Sq(1)*g[2] + g[3] sage: M = FPModule(A3, [0,7], [[Sq(1), 0], [Sq(2), 0], [Sq(4), 0], [Sq(8), Sq(1)], [0, Sq(7)], [0, Sq(0,1,1)+Sq(4,2)]]) sage: F2 = FPModule(A3, [0], [[Sq(1)], [Sq(2)], [Sq(4)], [Sq(8)], [Sq(15)]]) @@ -1381,7 +1392,7 @@ def image(self, top_dim=None, verbose=False): sage: K.domain().generator_degrees() (0,) sage: K.domain().relations() - [Sq(1)*G[0], Sq(2)*G[0], Sq(4)*G[0], Sq(8)*G[0]] + (Sq(1)*g[0], Sq(2)*g[0], Sq(4)*g[0], Sq(8)*g[0]) sage: K.domain().is_trivial() False @@ -1493,16 +1504,20 @@ def _resolve_kernel(self, top_dim=None, verbose=False): ... ValueError: a top dimension must be specified for this calculation to terminate sage: f._resolve_kernel(top_dim=20) - Module homomorphism of degree 0 defined by sending the generators - [g_{0,0}, g_{3,0}, g_{3,1}] - to - (g_{0,1}, Sq(0,1)*g_{0,0}, Sq(3)*g_{0,0}) + Module morphism: + From: Finitely presented left module on 3 generators and 0 relations over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 2 generators and 0 relations over mod 2 Steenrod algebra, milnor basis + Defn: g(0, 0) |--> g(0, 1) + g(3, 0) |--> Sq(0,1)*g(0, 0) + g(3, 1) |--> Sq(3)*g(0, 0) sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) sage: f.change_ring(A3)._resolve_kernel() # long time - Module homomorphism of degree 0 defined by sending the generators - [g_{0,0}, g_{3,0}, g_{3,1}] - to - (g_{0,1}, Sq(0,1)*g_{0,0}, Sq(3)*g_{0,0}) + Module morphism: + From: Finitely presented left module on 3 generators and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] + To: Finitely presented left module on 2 generators and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] + Defn: g(0, 0) |--> g(0, 1) + g(3, 0) |--> Sq(0,1)*g(0, 0) + g(3, 1) |--> Sq(3)*g(0, 0) """ # Let # @@ -1636,16 +1651,16 @@ def _resolve_image(self, top_dim=None, verbose=False): ... ValueError: a top dimension must be specified for this calculation to terminate sage: f._resolve_image(top_dim=20) - Module homomorphism of degree 0 defined by sending the generators - [G[2]] - to - (Sq(2)*g_{0,0},) + Module morphism: + From: Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis + To: Finitely presented left module on 2 generators and 2 relations over mod 2 Steenrod algebra, milnor basis + Defn: g[2] |--> Sq(2)*g(0, 0) sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) sage: f.change_ring(A3)._resolve_image() # long time - Module homomorphism of degree 0 defined by sending the generators - [G[2]] - to - (Sq(2)*g_{0,0},) + Module morphism: + From: Finitely presented left module on 1 generator and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] + To: Finitely presented left module on 2 generators and 2 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] + Defn: g[2] |--> Sq(2)*g(0, 0) """ # Let # @@ -1760,7 +1775,7 @@ def fp_module(self): sage: M.generator_degrees() (0,) sage: M.relations() - [Sq(2)*G[0]] + (Sq(2)*g[0],) sage: F3 = FPModule(A, (0,), [[Sq(4)]]) sage: pres = Hom(F1, F3)([v]) diff --git a/src/sage/structure/indexed_generators.py b/src/sage/structure/indexed_generators.py index d3cedd58330..ee42214059e 100644 --- a/src/sage/structure/indexed_generators.py +++ b/src/sage/structure/indexed_generators.py @@ -545,11 +545,11 @@ def _latex_generator(self, m): sage: F = CombinatorialFreeModule(QQ, [('a', 'b'), (0,1,2)], prefix="") sage: e = F.basis() sage: latex(2*e[(0,1,2)]) # indirect doctest - 2\left(0, 1, 2\right) + 2 \left(0, 1, 2\right) sage: F. = CombinatorialFreeModule(QQ, latex_names='x,y,z') sage: latex(a + 2*b) - x + 2y + x + 2 y """ from sage.misc.latex import latex From a73519c9f03e4b9d5f2461a55619ee8b6a09c7fb Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Mon, 24 Jan 2022 21:47:31 -0800 Subject: [PATCH 155/253] trac 32505: delete the method "__contains__" for FPModules --- src/sage/modules/fp_graded/module.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index f0bd351ccb4..cb3b6a9219c 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -287,23 +287,6 @@ def change_ring(self, algebra): return FPModule(algebra, self.generator_degrees(), relations) - def __contains__(self, x): # Probably can be removed - """ - EXAMPLES:: - - sage: from sage.modules.fp_graded.module import FPModule - sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) - sage: x = M([Sq(1), 1]) - sage: x in M - True - sage: N = FPModule(SteenrodAlgebra(2), [0], [[Sq(2)]]) - sage: y = Sq(2)*N.generator(0) - sage: y in M - False - """ - return parent(x) is self - - def _from_dict(self, d, coerce=False, remove_zeros=True): r""" Construct an element of ``self`` from an ``{index: coefficient}`` From fba70398c05016d05b0738888b196426d57ce0e7 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Tue, 25 Jan 2022 10:28:35 +0100 Subject: [PATCH 156/253] #33218 reviewer comments, further micro-optimizations --- .../rings/polynomial/polynomial_element.pyx | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index df031877a11..2bb2510b839 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -8901,37 +8901,37 @@ cdef class Polynomial(CommutativeAlgebraElement): +Infinity """ cdef int k + cdef Polynomial _p if not self: return infinity.infinity - if p is infinity.infinity: - return -self.degree() - if p is None: for k from 0 <= k <= self.degree(): if self.get_unsafe(k): return ZZ(k) if isinstance(p, Polynomial): - p = self._parent.coerce(p) + _p = self._parent.coerce(p) + elif p is infinity.infinity: + return -self.degree() elif is_Ideal(p) and p.ring() is self._parent: # eventually need to handle fractional ideals in the fraction field if self._parent.base_ring().is_field(): # common case - p = p.gen() + _p = p.gen() else: raise NotImplementedError else: from sage.rings.fraction_field import is_FractionField if is_FractionField(p.parent()) and self._parent.has_coerce_map_from(p.parent().ring()): - p = self._parent.coerce(p.parent().ring()(p)) # here we require that p be integral. + _p = self._parent.coerce(p.parent().ring()(p)) # here we require that p be integral. else: raise TypeError("The polynomial, p, must have the same parent as self.") - if p.degree() == 0: - raise ArithmeticError("The polynomial, p, must have positive degree.") + if _p.degree() == 0: + raise ArithmeticError("The polynomial, p, must be non-constant.") k = -1 - rem = self.parent().zero() + cdef Polynomial rem = self._parent.zero() while rem.is_zero(): - self, rem = self.quo_rem(p) + self, rem = self.quo_rem(_p) k += 1 return sage.rings.integer.Integer(k) From f18aa29c952e2e40c875b7c3cf541b612d6ada51 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Tue, 25 Jan 2022 08:48:42 -0600 Subject: [PATCH 157/253] Fix documentation and field import --- src/sage/manifolds/catalog.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/sage/manifolds/catalog.py b/src/sage/manifolds/catalog.py index 30bcb63669c..4c087b04a38 100644 --- a/src/sage/manifolds/catalog.py +++ b/src/sage/manifolds/catalog.py @@ -38,7 +38,6 @@ _lazy_import('sage.manifolds.differentiable.examples.real_line', 'RealLine') _lazy_import('sage.manifolds.differentiable.examples.euclidean', 'EuclideanSpace') _lazy_import('sage.manifolds.differentiable.examples.sphere', 'Sphere') -_lazy_import('sage.rings.real_mpfr','RealField_class') def Minkowski(positive_spacelike=True, names=None): """ @@ -261,11 +260,10 @@ def Torus(R=2, r=1, names=None): def RealProjectiveSpace(dim=2): r""" - Generate projective space of dimension ``dim`` over - ``field``. + Generate projective space of dimension ``dim`` over the reals. - This is the topological space of lines through the origin in `k^{d+1}` - for a field `k`. The standard atlas consists of `d+2` charts, which sends + This is the topological space of lines through the origin in + `\Bold{R}^{d+1}`. The standard atlas consists of `d+2` charts, which sends the set `U_i = \{[x_1, x_2, \ldots, x_{d+1}] : x_i \neq 0 \}` to `k^{d}` by dividing by `x_i` and omitting the `i`th coordinate `x_i/x_i = 1`. From ebcae245641d773e9a3961702345143fe757b16a Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Tue, 25 Jan 2022 10:31:20 -0800 Subject: [PATCH 158/253] trac 32505: fix a doctest --- src/sage/combinat/free_module.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index d23c7c5242c..3eddc772d7a 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -173,8 +173,9 @@ class CombinatorialFreeModule(UniqueRepresentation, Module, IndexedGenerators): sage: original_print_options = F.print_options() sage: sorted(original_print_options.items()) [('bracket', None), - ('latex_bracket', False), ('latex_prefix', None), - ('latex_scalar_mult', None), ('prefix', 'x'), + ('latex_bracket', False), ('latex_names', None), + ('latex_prefix', None), ('latex_scalar_mult', None), + ('names', None), ('prefix', 'x'), ('scalar_mult', '*'), ('sorting_key', at ...>), ('sorting_reverse', False), ('string_quotes', True), From 5d35b97f48fc303b870fbf246c4062ea7576f511 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 18 Sep 2021 13:17:27 -0700 Subject: [PATCH 159/253] WIP --- build/pkgs/texlive/spkg-configure.m4 | 15 +++ build/pkgs/texlive/spkg-install | 3 +- build/pkgs/texlive/spkg-install.py | 134 --------------------------- 3 files changed, 17 insertions(+), 135 deletions(-) create mode 100644 build/pkgs/texlive/spkg-configure.m4 delete mode 100644 build/pkgs/texlive/spkg-install.py diff --git a/build/pkgs/texlive/spkg-configure.m4 b/build/pkgs/texlive/spkg-configure.m4 new file mode 100644 index 00000000000..5a8704c19e4 --- /dev/null +++ b/build/pkgs/texlive/spkg-configure.m4 @@ -0,0 +1,15 @@ +m4_pushdef([required_latex_packages], [fontspec,xunicode,xltxtra,amssymb,amsfonts,graphicx,mathrsfs,textcomp,tikz,tikz-qtree,iftex,tkz-berge,tkz-graph,xy,babel,subfigure,hyperref,hypcap,xr]) +SAGE_SPKG_CONFIGURE([texlive], [ + sage_spkg_install_texlive=no + dnl pdflatex --version + m4_foreach([latex_package], [required_latex_packages], [ + AC_MSG_CHECKING([for latex package ]latex_package) + AS_IF([kpsewhich ]latex_package[.sty >& AS_MESSAGE_LOG_FD 2>&1], [ + AC_MSG_RESULT([yes]) + sage_spkg_install_texlive=yes + ], [ + AC_MSG_RESULT([no]) + ]) + ]) +]) +m4_popdef([required_latex_packages]) diff --git a/build/pkgs/texlive/spkg-install b/build/pkgs/texlive/spkg-install index a917196c0c4..599e0b77a66 100755 --- a/build/pkgs/texlive/spkg-install +++ b/build/pkgs/texlive/spkg-install @@ -1 +1,2 @@ -exec python3 spkg-install.py +#! /usr/bin/env bash +# Nothing to do diff --git a/build/pkgs/texlive/spkg-install.py b/build/pkgs/texlive/spkg-install.py deleted file mode 100644 index a7cd4afdc4a..00000000000 --- a/build/pkgs/texlive/spkg-install.py +++ /dev/null @@ -1,134 +0,0 @@ -import os -import sys -import glob -from subprocess import check_call, CalledProcessError - -try: - SAGE_LOCAL = os.environ['SAGE_LOCAL'] - DOT_SAGE = os.environ['DOT_SAGE'] -except KeyError: - print('You need to run this script in a Sage shell ("sage -sh")') - sys.exit(1) - - -TEXLIVE_INSTALL_UNIX_URL = \ - 'http://mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz' - -TEXLIVE_PROFILE_TEMPLATE = \ -""" -selected_scheme scheme-minimal -TEXDIR {SAGE_LOCAL}/share/texlive -TEXMFLOCAL {SAGE_LOCAL}/share/texlive/texmf-local -TEXMFSYSCONFIG {SAGE_LOCAL}/share/texlive/texmf-config -TEXMFSYSVAR {SAGE_LOCAL}/share/texlive/texmf-var -TEXMFCONFIG {DOT_SAGE}/texlive/texmf-config -TEXMFHOME {DOT_SAGE}/texlive/texmf-home -TEXMFVAR {DOT_SAGE}/texlive/texmf-var -collection-basic 1 -in_place 0 -option_adjustrepo 1 -option_autobackup 1 -option_backupdir tlpkg/backups -option_desktop_integration 1 -option_doc 1 -option_file_assocs 1 -option_fmt 1 -option_letter 0 -option_menu_integration 1 -option_path 1 -option_post_code 1 -option_src 1 -option_sys_bin {SAGE_LOCAL}/bin -option_sys_info {SAGE_LOCAL}/share/info -option_sys_man {SAGE_LOCAL}/share/man -option_w32_multi_user 1 -option_write18_restricted 1 -portable 0 -""" - - -def have_texlive(): - try: - check_call(['tlmgr', '--version']) - return True - except (OSError, CalledProcessError): - return False - - -def download_install_script(tarball): - try: - from urllib import urlretrieve - except ImportError: - from urllib.request import urlretrieve - urlretrieve(TEXLIVE_INSTALL_UNIX_URL, tarball) - - -def write_profile(filename): - profile = TEXLIVE_PROFILE_TEMPLATE.format( - SAGE_LOCAL=SAGE_LOCAL, DOT_SAGE=DOT_SAGE) - with open(filename, 'w') as f: - f.write(profile) - print('TeXlive unattended install profile: {0}'.format(filename)) - -def first_dir(glob_pattern): - """ - Return the first directory matching ``glob_pattern`` - """ - for dirent in glob.glob(glob_pattern): - if os.path.isdir(dirent): - return dirent - raise RuntimeError('no directory found: {0}'.format(glob_pattern)) - -def install_texlive(): - import tempfile - tmp_dir = tempfile.mkdtemp() - tarball = os.path.join(tmp_dir, 'install-tl-unx.tar.gz') - profile = os.path.join(tmp_dir, 'sage.profile') - download_install_script(tarball) - write_profile(profile) - - original_dir = os.getcwd() - os.chdir(tmp_dir) - check_call(['tar', '-x', '-z', '-f', tarball]) - install_dir = first_dir('install-tl-*') - os.chdir(install_dir) - - check_call([ - './install-tl', - '-profile', - profile - ]) - os.chdir(original_dir) - - -def install_packages(): - package_list_txt = os.path.join( - os.path.dirname(__file__), - 'package-list.txt' - ) - with open(package_list_txt) as f: - package_list = f.read() - packages = [] - for pkg in package_list.splitlines(): - pkg = pkg.strip() - if len(pkg) == 0: - continue - if pkg.startswith('#'): - continue - packages.append(pkg) - print('installing the following TeXlive packages:') - for pkg in packages: - print(' * ' + pkg) - check_call(['tlmgr', 'install'] + packages) - check_call(['tlmgr', 'path', 'add']) - - -if __name__ == '__main__': - if have_texlive(): - print('Using your own texlive install (see "tlmgr --version")') - else: - print('Performing minimal texlive install into {0}' - .format(SAGE_LOCAL)) - install_texlive() - install_packages() - From 9dceb3445d3c353ba42fe660dec89b98cd1d0732 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 26 Jan 2022 14:33:05 +0000 Subject: [PATCH 160/253] fix M4 bugs there was a logic error ('..=yes' in the wrong place), and also m4 variable not working as a list of values for m4_foreach. --- build/pkgs/texlive/spkg-configure.m4 | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/build/pkgs/texlive/spkg-configure.m4 b/build/pkgs/texlive/spkg-configure.m4 index 5a8704c19e4..649252c0d05 100644 --- a/build/pkgs/texlive/spkg-configure.m4 +++ b/build/pkgs/texlive/spkg-configure.m4 @@ -1,15 +1,16 @@ -m4_pushdef([required_latex_packages], [fontspec,xunicode,xltxtra,amssymb,amsfonts,graphicx,mathrsfs,textcomp,tikz,tikz-qtree,iftex,tkz-berge,tkz-graph,xy,babel,subfigure,hyperref,hypcap,xr]) SAGE_SPKG_CONFIGURE([texlive], [ - sage_spkg_install_texlive=no dnl pdflatex --version - m4_foreach([latex_package], [required_latex_packages], [ + m4_foreach([latex_package], + [fontspec,xunicode,xltxtra,amssymb,amsfonts,graphicx,mathrsfs, + textcomp,tikz,tikz-qtree,iftex,tkz-berge,tkz-graph,xy,babel, + subfigure,hyperref,hypcap,xr], + [ AC_MSG_CHECKING([for latex package ]latex_package) AS_IF([kpsewhich ]latex_package[.sty >& AS_MESSAGE_LOG_FD 2>&1], [ AC_MSG_RESULT([yes]) - sage_spkg_install_texlive=yes ], [ AC_MSG_RESULT([no]) + sage_spkg_install_texlive=yes ]) ]) ]) -m4_popdef([required_latex_packages]) From 0eb3b733173f2d1c6f09689d897eec0efdbd3344 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Wed, 26 Jan 2022 13:02:42 -0600 Subject: [PATCH 161/253] Fix documentation by adding space --- src/sage/manifolds/catalog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/manifolds/catalog.py b/src/sage/manifolds/catalog.py index 4c087b04a38..f8e2a030c35 100644 --- a/src/sage/manifolds/catalog.py +++ b/src/sage/manifolds/catalog.py @@ -274,7 +274,7 @@ def RealProjectiveSpace(dim=2): OUTPUT: - - ``P`` -- the projective space `RP^d` where `d =```dim``. + - ``P`` -- the projective space `RP^d` where `d =` ``dim``. EXAMPLES:: From 767fb8e61149a0727d4457bd8de4ee810b625d86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Wed, 26 Jan 2022 21:31:31 +0100 Subject: [PATCH 162/253] 33231: running the cmd inside of a try except clause --- src/sage/features/ffmpeg.py | 6 +++++- src/sage/features/imagemagick.py | 7 ++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/sage/features/ffmpeg.py b/src/sage/features/ffmpeg.py index 2af5b57f852..bb708478251 100644 --- a/src/sage/features/ffmpeg.py +++ b/src/sage/features/ffmpeg.py @@ -94,7 +94,11 @@ def is_functional(self): # Running the commands and reporting any issue encountered from subprocess import run for cmd in commands: - result = run(cmd, cwd=base, capture_output=True, text=True) + try: + result = run(cmd, cwd=base, capture_output=True, text=True) + except OSError as e: + return FeatureTestResult(self, False, reason='Running command "{}" ' + 'raised an OSError "{}" '.format(' '.join(cmd), e)) # If an error occurred, return False if result.returncode: diff --git a/src/sage/features/imagemagick.py b/src/sage/features/imagemagick.py index 85abdf829df..cc9ce75c485 100644 --- a/src/sage/features/imagemagick.py +++ b/src/sage/features/imagemagick.py @@ -81,7 +81,12 @@ def is_functional(self): from subprocess import run cmd = ['convert', '-dispose', 'Background', '-delay', '20', '-loop', '0', filename_png, filename_gif] - result = run(cmd, cwd=base, capture_output=True, text=True) + + try: + result = run(cmd, cwd=base, capture_output=True, text=True) + except OSError as e: + return FeatureTestResult(self, False, reason='Running command "{}" ' + 'raised an OSError "{}" '.format(' '.join(cmd), e)) # If an error occurred, return False if result.returncode: From 65d67d190815985249e00f4b760cc176e0e11cbe Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 26 Jan 2022 22:23:07 -0800 Subject: [PATCH 163/253] build/pkgs/texlive/distros: Add *.txt --- build/pkgs/texlive/distros/alpine.txt | 1 + build/pkgs/texlive/distros/cygwin.txt | 1 + build/pkgs/texlive/distros/debian.txt | 2 ++ build/pkgs/texlive/distros/fedora.txt | 2 ++ build/pkgs/texlive/distros/gentoo.txt | 2 ++ build/pkgs/texlive/distros/opensuse.txt | 1 + build/pkgs/texlive/distros/slackware.txt | 1 + build/pkgs/texlive/distros/void.txt | 1 + 8 files changed, 11 insertions(+) create mode 100644 build/pkgs/texlive/distros/alpine.txt create mode 100644 build/pkgs/texlive/distros/cygwin.txt create mode 100644 build/pkgs/texlive/distros/debian.txt create mode 100644 build/pkgs/texlive/distros/fedora.txt create mode 100644 build/pkgs/texlive/distros/gentoo.txt create mode 100644 build/pkgs/texlive/distros/opensuse.txt create mode 100644 build/pkgs/texlive/distros/slackware.txt create mode 100644 build/pkgs/texlive/distros/void.txt diff --git a/build/pkgs/texlive/distros/alpine.txt b/build/pkgs/texlive/distros/alpine.txt new file mode 100644 index 00000000000..ba0ee3a029f --- /dev/null +++ b/build/pkgs/texlive/distros/alpine.txt @@ -0,0 +1 @@ +texlive diff --git a/build/pkgs/texlive/distros/cygwin.txt b/build/pkgs/texlive/distros/cygwin.txt new file mode 100644 index 00000000000..ba0ee3a029f --- /dev/null +++ b/build/pkgs/texlive/distros/cygwin.txt @@ -0,0 +1 @@ +texlive diff --git a/build/pkgs/texlive/distros/debian.txt b/build/pkgs/texlive/distros/debian.txt new file mode 100644 index 00000000000..dbfe8d4bfa8 --- /dev/null +++ b/build/pkgs/texlive/distros/debian.txt @@ -0,0 +1,2 @@ +latexmk +texlive diff --git a/build/pkgs/texlive/distros/fedora.txt b/build/pkgs/texlive/distros/fedora.txt new file mode 100644 index 00000000000..dbfe8d4bfa8 --- /dev/null +++ b/build/pkgs/texlive/distros/fedora.txt @@ -0,0 +1,2 @@ +latexmk +texlive diff --git a/build/pkgs/texlive/distros/gentoo.txt b/build/pkgs/texlive/distros/gentoo.txt new file mode 100644 index 00000000000..9d4b10e19a4 --- /dev/null +++ b/build/pkgs/texlive/distros/gentoo.txt @@ -0,0 +1,2 @@ +dev-tex/latexmk +app-text/texlive diff --git a/build/pkgs/texlive/distros/opensuse.txt b/build/pkgs/texlive/distros/opensuse.txt new file mode 100644 index 00000000000..ba0ee3a029f --- /dev/null +++ b/build/pkgs/texlive/distros/opensuse.txt @@ -0,0 +1 @@ +texlive diff --git a/build/pkgs/texlive/distros/slackware.txt b/build/pkgs/texlive/distros/slackware.txt new file mode 100644 index 00000000000..ba0ee3a029f --- /dev/null +++ b/build/pkgs/texlive/distros/slackware.txt @@ -0,0 +1 @@ +texlive diff --git a/build/pkgs/texlive/distros/void.txt b/build/pkgs/texlive/distros/void.txt new file mode 100644 index 00000000000..ba0ee3a029f --- /dev/null +++ b/build/pkgs/texlive/distros/void.txt @@ -0,0 +1 @@ +texlive From ffe23f9485adf2aff8636345f00182ef06331803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Fri, 14 Jan 2022 12:32:55 +0100 Subject: [PATCH 164/253] 33167: adding a second check in lrs feature is_functional --- src/sage/features/lrs.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/sage/features/lrs.py b/src/sage/features/lrs.py index 4defebd069f..0ed9649cd04 100644 --- a/src/sage/features/lrs.py +++ b/src/sage/features/lrs.py @@ -43,6 +43,8 @@ def is_functional(self): FeatureTestResult('lrslib', True) """ from sage.misc.temporary_file import tmp_filename + + # Check #1 tf_name = tmp_filename() with open(tf_name, 'wb') as tf: tf.write(str_to_bytes("V-representation\nbegin\n 1 1 rational\n 1 \nend\nvolume")) @@ -62,6 +64,22 @@ def is_functional(self): command=" ".join(command), expected=" or ".join(expected_list))) + # Check #2 + # Checking whether `lrsnash` can handle the new input format + # This test is currently done in build/pkgs/lrslib/spkg-configure.m4 + tf_name = tmp_filename() + with open(tf_name, 'w') as tf: + tf.write("1 1\n \n 0\n \n 0\n") + command = ['lrsnash', tf_name] + result = subprocess.run(command, capture_output=True, text=True) + if result.returncode: + return FeatureTestResult(self, False, reason='Running command "{}" ' + 'returned non-zero exit status "{}" with stderr ' + '"{}" and stdout "{}".'.format(' '.join(result.args), + result.returncode, + result.stderr.strip(), + result.stdout.strip())) + return FeatureTestResult(self, True) From 986ed5305d3b0827da4c6699928fae87a706ae5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Fri, 14 Jan 2022 12:43:52 +0100 Subject: [PATCH 165/253] 33167: simplification of check #1 in is_functional method of lrs feature --- src/sage/features/lrs.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/sage/features/lrs.py b/src/sage/features/lrs.py index 0ed9649cd04..79decd3e175 100644 --- a/src/sage/features/lrs.py +++ b/src/sage/features/lrs.py @@ -3,11 +3,9 @@ Feature for testing the presence of ``lrslib`` """ -import os import subprocess from . import Executable, FeatureTestResult -from sage.cpython.string import str_to_bytes, bytes_to_str class Lrs(Executable): @@ -46,19 +44,17 @@ def is_functional(self): # Check #1 tf_name = tmp_filename() - with open(tf_name, 'wb') as tf: - tf.write(str_to_bytes("V-representation\nbegin\n 1 1 rational\n 1 \nend\nvolume")) - devnull = open(os.devnull, 'wb') + with open(tf_name, 'w') as tf: + tf.write("V-representation\nbegin\n 1 1 rational\n 1 \nend\nvolume") command = ['lrs', tf_name] - try: - lines = bytes_to_str(subprocess.check_output(command, stderr=devnull)) - except subprocess.CalledProcessError as e: + result = subprocess.run(command, capture_output=True, text=True) + if result.returncode: return FeatureTestResult(self, False, - reason="Call to `{command}` failed with exit code {e.returncode}.".format(command=" ".join(command), e=e)) + reason="Call to `{command}` failed with exit code {result.returncode}.".format(command=" ".join(command), result=result)) expected_list = ["Volume= 1", "Volume=1"] - if all(lines.find(expected) == -1 for expected in expected_list): - print(lines) + if all(result.stdout.find(expected) == -1 for expected in expected_list): + print(result.stdout) return FeatureTestResult(self, False, reason="Output of `{command}` did not contain the expected result {expected}.".format( command=" ".join(command), From ab57121e38ec952845da6f1d0c953001389d4883 Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Mon, 17 Jan 2022 20:59:35 +0100 Subject: [PATCH 166/253] 33167: avoid printing of output --- src/sage/features/lrs.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/features/lrs.py b/src/sage/features/lrs.py index 79decd3e175..7031982797b 100644 --- a/src/sage/features/lrs.py +++ b/src/sage/features/lrs.py @@ -54,11 +54,11 @@ def is_functional(self): expected_list = ["Volume= 1", "Volume=1"] if all(result.stdout.find(expected) == -1 for expected in expected_list): - print(result.stdout) return FeatureTestResult(self, False, - reason="Output of `{command}` did not contain the expected result {expected}.".format( + reason="Output of `{command}` did not contain the expected result {expected}; output: {result.stdout}".format( command=" ".join(command), - expected=" or ".join(expected_list))) + expected=" or ".join(expected_list), + result=result)) # Check #2 # Checking whether `lrsnash` can handle the new input format From 5733f4ebd87159d71393ae089a0f7bba0a4cb77a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 27 Jan 2022 09:13:45 -0800 Subject: [PATCH 167/253] build/pkgs/texlive/distros/debian.txt: Move texlive system packages here from build/pkgs/_recommended/distros/debian.txt --- build/pkgs/_recommended/distros/debian.txt | 12 +----------- build/pkgs/texlive/distros/debian.txt | 8 +++++++- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/build/pkgs/_recommended/distros/debian.txt b/build/pkgs/_recommended/distros/debian.txt index c7be25b851a..cb1a47333fa 100644 --- a/build/pkgs/_recommended/distros/debian.txt +++ b/build/pkgs/_recommended/distros/debian.txt @@ -1,17 +1,7 @@ # From https://wiki.sagemath.org/prerequisitesUbuntu +# - see also separate script packages texlive, pandoc, ffmpeg -# to generate pdf documentation -texlive-latex-extra -# to convert Jupyter notebooks to pdf -texlive-xetex -# to generate pdf documentation -latexmk -# to convert Jupyter notebooks to pdf -# pandoc -- this is a separate script package -# to render text with LaTeX in Matplotlib -dvipng # to run the Jmol 3D viewer from the console and generate images for 3D plots in the documentation default-jdk # to produce animations -# ffmpeg -- this is a separate script package libavdevice-dev diff --git a/build/pkgs/texlive/distros/debian.txt b/build/pkgs/texlive/distros/debian.txt index dbfe8d4bfa8..47d395e1452 100644 --- a/build/pkgs/texlive/distros/debian.txt +++ b/build/pkgs/texlive/distros/debian.txt @@ -1,2 +1,8 @@ +# to generate pdf documentation +texlive-latex-extra +# to convert Jupyter notebooks to pdf +texlive-xetex +# to generate pdf documentation latexmk -texlive +# to render text with LaTeX in Matplotlib +dvipng From 79852ce189cf641477685dacda97da5384653497 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 27 Jan 2022 09:14:35 -0800 Subject: [PATCH 168/253] src/doc/bootstrap: Add texlive to RECOMMENDED_SYSTEM_PACKAGES --- src/doc/bootstrap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/bootstrap b/src/doc/bootstrap index 8b6d072f360..5c2d27f990e 100755 --- a/src/doc/bootstrap +++ b/src/doc/bootstrap @@ -42,7 +42,7 @@ for SYSTEM in arch debian fedora cygwin homebrew conda; do *:standard) SYSTEM_PACKAGES+=" $PKG_SYSTEM_PACKAGES" ;; - _recommended:*|pandoc:*|ffmpeg:*|imagemagick:*) + _recommended:*|pandoc:*|ffmpeg:*|imagemagick:*|texlive:*) RECOMMENDED_SYSTEM_PACKAGES+=" $PKG_SYSTEM_PACKAGES" ;; *) From b1c705b73278b93aa09bae79c890df3f8f2403fc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 27 Jan 2022 12:42:49 -0800 Subject: [PATCH 169/253] build/pkgs/texlive/distros/debian.txt: Add more --- build/pkgs/texlive/distros/debian.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/pkgs/texlive/distros/debian.txt b/build/pkgs/texlive/distros/debian.txt index 47d395e1452..05553c735a9 100644 --- a/build/pkgs/texlive/distros/debian.txt +++ b/build/pkgs/texlive/distros/debian.txt @@ -6,3 +6,5 @@ texlive-xetex latexmk # to render text with LaTeX in Matplotlib dvipng +# for tgtermes.sty used in doc-pdf +tex-gyre From 1636cd3ba8d85d4dc05853a9501085d4b42920d6 Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Thu, 27 Jan 2022 21:46:18 +0100 Subject: [PATCH 170/253] 33236: fix deadlocks in map_reduce when aborting computation If the worker process is terminated while its thief thread holds a lock on the shared `_aborted` value, the lock is never released, causing the main process to deadlock. As a compromise, we remove the lock from the `_aborted` value. --- src/sage/parallel/map_reduce.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/parallel/map_reduce.py b/src/sage/parallel/map_reduce.py index 18ec7f41fe0..dbb92129caf 100644 --- a/src/sage/parallel/map_reduce.py +++ b/src/sage/parallel/map_reduce.py @@ -1121,7 +1121,9 @@ def setup_workers(self, max_proc=None, reduce_locally=True): self._results = mp.Queue() self._active_tasks = ActiveTaskCounter(self._nprocess) self._done = mp.Lock() - self._aborted = mp.Value(ctypes.c_bool, False) + # We use lock=False here, as a compromise, to avoid deadlocking when a + # subprocess holding a lock is terminated. (:trac:`33236`) + self._aborted = mp.Value(ctypes.c_bool, False, lock=False) sys.stdout.flush() sys.stderr.flush() self._workers = [RESetMapReduceWorker(self, i, reduce_locally) From 6b840715fc73c0fc528a6d48e2020dc86c682bef Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 28 Jan 2022 15:10:36 +0900 Subject: [PATCH 171/253] Adding additional print option to IndexedGenerators for iterating through keys. --- src/sage/modules/fp_graded/free_module.py | 7 ++-- src/sage/modules/fp_graded/homspace.py | 8 ++--- src/sage/modules/fp_graded/module.py | 2 +- src/sage/modules/fp_graded/morphism.py | 20 +++++------ src/sage/structure/indexed_generators.py | 42 +++++++++++++++++++++-- 5 files changed, 58 insertions(+), 21 deletions(-) diff --git a/src/sage/modules/fp_graded/free_module.py b/src/sage/modules/fp_graded/free_module.py index ffd1a856936..33181dfd240 100755 --- a/src/sage/modules/fp_graded/free_module.py +++ b/src/sage/modules/fp_graded/free_module.py @@ -325,11 +325,11 @@ class FreeGradedModule(CombinatorialFreeModule): sage: M.generators() (g[-1], g[3]) sage: FreeGradedModule(E, (0, 0, 2)).generators() - (g(0, 0), g(0, 1), g(2, 0)) + (g[0, 0], g[0, 1], g[2, 0]) sage: FreeGradedModule(E, (0, 0, 2), names='x, y, z').generators() (x, y, z) sage: FreeGradedModule(E, (0, 0, 2), names='xyz').generators() - (xyz(0, 0), xyz(0, 1), xyz(2, 0)) + (xyz[0, 0], xyz[0, 1], xyz[2, 0]) ``names`` can also be defined implicitly using Sage's ``M.<...>`` syntax:: @@ -398,8 +398,7 @@ def __init__(self, algebra, generator_degrees, category, names=None, **kwds): keys.append((i, idx)) if unique: keys = [i[0] for i in keys] - else: - kwds['bracket'] = False + kwds['iterate_key'] = True # Call the base class constructor. CombinatorialFreeModule.__init__(self, algebra, diff --git a/src/sage/modules/fp_graded/homspace.py b/src/sage/modules/fp_graded/homspace.py index 1ec3a5bf088..4a575fae33d 100755 --- a/src/sage/modules/fp_graded/homspace.py +++ b/src/sage/modules/fp_graded/homspace.py @@ -147,14 +147,14 @@ def an_element(self, n=0): sage: K = FPModule(A, [0, 0], [[Sq(2), 0]]) # Using a zero coefficient in the relations. sage: Hom(K, K).an_element(4) Module endomorphism of Finitely presented left module on 2 generators and 1 relation over mod 2 Steenrod algebra, milnor basis - Defn: g(0, 0) |--> 0 - g(0, 1) |--> Sq(4)*g(0, 0) + Defn: g[0, 0] |--> 0 + g[0, 1] |--> Sq(4)*g[0, 0] sage: K = FPModule(A, [0, 0], [[Sq(2), 0], [0,0], [Sq(4), Sq(2)*Sq(2)]]) sage: Hom(K, K).an_element(n=3) Module endomorphism of Finitely presented left module on 2 generators and 2 relations over mod 2 Steenrod algebra, milnor basis - Defn: g(0, 0) |--> 0 - g(0, 1) |--> Sq(0,1)*g(0, 0) + Defn: g[0, 0] |--> 0 + g[0, 1] |--> Sq(0,1)*g[0, 0] """ return self._basis_elements(n, basis=False) diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index cb3b6a9219c..1352ef789da 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -915,7 +915,7 @@ def generators(self): sage: M = FPModule(A4, [0,0,2,3]) sage: M.generators() - (g(0, 0), g(0, 1), g(2, 0), g(3, 0)) + (g[0, 0], g[0, 1], g[2, 0], g[3, 0]) sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]], names='h') sage: N.generators() diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py index caeeec2aef3..891b4a76fdf 100755 --- a/src/sage/modules/fp_graded/morphism.py +++ b/src/sage/modules/fp_graded/morphism.py @@ -869,7 +869,7 @@ def lift(self, f, verbose=False): Module morphism: From: Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis To: Finitely presented left module on 2 generators and 1 relation over mod 2 Steenrod algebra, milnor basis - Defn: g[0] |--> g(0, 1) + Defn: g[0] |--> g[0, 1] sage: q*j Module endomorphism of Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis Defn: g[0] |--> g[0] @@ -1093,7 +1093,7 @@ def split(self, verbose=False): Module morphism: From: Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis To: Finitely presented left module on 2 generators and 1 relation over mod 2 Steenrod algebra, milnor basis - Defn: g[0] |--> g(0, 1) + Defn: g[0] |--> g[0, 1] sage: # Verify that `s` is a splitting: sage: p*s Module endomorphism of Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis @@ -1507,17 +1507,17 @@ def _resolve_kernel(self, top_dim=None, verbose=False): Module morphism: From: Finitely presented left module on 3 generators and 0 relations over mod 2 Steenrod algebra, milnor basis To: Finitely presented left module on 2 generators and 0 relations over mod 2 Steenrod algebra, milnor basis - Defn: g(0, 0) |--> g(0, 1) - g(3, 0) |--> Sq(0,1)*g(0, 0) - g(3, 1) |--> Sq(3)*g(0, 0) + Defn: g[0, 0] |--> g[0, 1] + g[3, 0] |--> Sq(0,1)*g[0, 0] + g[3, 1] |--> Sq(3)*g[0, 0] sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) sage: f.change_ring(A3)._resolve_kernel() # long time Module morphism: From: Finitely presented left module on 3 generators and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] To: Finitely presented left module on 2 generators and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] - Defn: g(0, 0) |--> g(0, 1) - g(3, 0) |--> Sq(0,1)*g(0, 0) - g(3, 1) |--> Sq(3)*g(0, 0) + Defn: g[0, 0] |--> g[0, 1] + g[3, 0] |--> Sq(0,1)*g[0, 0] + g[3, 1] |--> Sq(3)*g[0, 0] """ # Let # @@ -1654,13 +1654,13 @@ def _resolve_image(self, top_dim=None, verbose=False): Module morphism: From: Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis To: Finitely presented left module on 2 generators and 2 relations over mod 2 Steenrod algebra, milnor basis - Defn: g[2] |--> Sq(2)*g(0, 0) + Defn: g[2] |--> Sq(2)*g[0, 0] sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) sage: f.change_ring(A3)._resolve_image() # long time Module morphism: From: Finitely presented left module on 1 generator and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] To: Finitely presented left module on 2 generators and 2 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] - Defn: g[2] |--> Sq(2)*g(0, 0) + Defn: g[2] |--> Sq(2)*g[0, 0] """ # Let # diff --git a/src/sage/structure/indexed_generators.py b/src/sage/structure/indexed_generators.py index ee42214059e..2abac83fcea 100644 --- a/src/sage/structure/indexed_generators.py +++ b/src/sage/structure/indexed_generators.py @@ -93,6 +93,10 @@ class IndexedGenerators(object): - ``string_quotes`` -- bool (default: ``True``), if ``True`` then display string indices with quotes + - ``iterate_key`` -- bool (default: ``False``) iterate through + the elements of the key and print the result as comma separated + objects for string output + .. NOTE:: These print options may also be accessed and modified using the @@ -153,7 +157,8 @@ def __init__(self, indices, prefix="x", **kwds): 'tensor_symbol': None, 'string_quotes': True, 'sorting_key': lambda x: x, - 'sorting_reverse': False} + 'sorting_reverse': False, + 'iterate_key': False} # 'bracket': its default value here is None, meaning that # the value of self._repr_option_bracket is used; the default # value of that attribute is True -- see immediately before @@ -213,6 +218,7 @@ def print_options(self, **kwds): - ``string_quotes`` - ``sorting_key`` - ``sorting_reverse`` + - ``iterate_key`` See the documentation for :class:`IndexedGenerators` for descriptions of the effects of setting each of these options. @@ -233,7 +239,7 @@ def print_options(self, **kwds): TESTS:: sage: sorted(F.print_options().items()) - [('bracket', '('), + [('bracket', '('), ('iterate_key', False), ('latex_bracket', False), ('latex_names', None), ('latex_prefix', None), ('latex_scalar_mult', None), ('names', None), ('prefix', 'x'), @@ -329,6 +335,7 @@ def _repr_generator(self, m): - ``bracket`` - ``scalar_mult`` - ``names`` + - ``iterate_key`` Alternatively, one can use the :meth:`print_options` method to achieve the same effect. To modify the bracket setting, @@ -355,6 +362,15 @@ def _repr_generator(self, m): sage: e['a'] + 2*e['b'] F[a] + 2*F[b] + sage: F = CombinatorialFreeModule(QQ, ['aa', 'bb', 'cc'], prefix="F") + sage: e = F.basis() + sage: F.print_options(iterate_key=True) + sage: e['aa'] + 2*e['bb'] + F['a', 'a'] + 2*F['b', 'b'] + sage: F.print_options(string_quotes=False) + sage: e['aa'] + 2*e['bb'] + F[a, a] + 2*F[b, b] + sage: QS3 = CombinatorialFreeModule(QQ, Permutations(3), prefix="") sage: original_print_options = QS3.print_options() sage: a = 2*QS3([1,2,3])+4*QS3([3,2,1]) @@ -373,6 +389,10 @@ def _repr_generator(self, m): sage: a # indirect doctest 2 *@* |[1, 2, 3]| + 4 *@* |[3, 2, 1]| + sage: QS3.print_options(bracket="|", scalar_mult="*", iterate_key=True) + sage: a # indirect doctest + 2*|1, 2, 3| + 4*|3, 2, 1| + sage: QS3.print_options(**original_print_options) # reset TESTS:: @@ -385,6 +405,14 @@ def _repr_generator(self, m): sage: F. = CombinatorialFreeModule(QQ) sage: a + 2*b a + 2*b + + sage: F = CombinatorialFreeModule(QQ, ZZ) + sage: e = F.basis() + sage: 3*e[1] + 2*e[-2] + 2*B[-2] + 3*B[1] + sage: F.print_options(iterate_key=True) + sage: 3*e[1] + 2*e[-2] + 2*B[-2] + 3*B[1] """ ret = self._parse_names(m, False) if ret is not None: @@ -408,7 +436,17 @@ def _repr_generator(self, m): else: left = bracket right = bracket + iterate_key = self._print_options.get('iterate_key', False) quotes = self._print_options.get('string_quotes', True) + if iterate_key: + try: + m = iter(m) + except TypeError: + pass # not iterable, so fallback to normal behavior + else: + if not quotes: + return self.prefix() + left + (', '.join(str(val) for val in m)) + right + return self.prefix() + left + (', '.join(repr(val) for val in m)) + right if not quotes and isinstance(m, str): return self.prefix() + left + m + right return self.prefix() + left + repr(m) + right # mind the (m), to accept a tuple for m From d6f67cfe115757c2415c7c4755a10e6a096ae649 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 28 Jan 2022 15:38:29 +0900 Subject: [PATCH 172/253] Fix containment issues and add some more doctests. --- src/sage/modules/fp_graded/element.py | 12 ++++++++++++ src/sage/modules/fp_graded/free_module.py | 9 +++++++++ src/sage/modules/fp_graded/module.py | 23 +++++++++++++++++++---- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/sage/modules/fp_graded/element.py b/src/sage/modules/fp_graded/element.py index 9add5f68c2a..3e86a8c2b80 100755 --- a/src/sage/modules/fp_graded/element.py +++ b/src/sage/modules/fp_graded/element.py @@ -283,6 +283,18 @@ def __eq__(self, other): False sage: x-x == M.zero() True + sage: x != x + False + + Comparing elements in different modules:: + + sage: x = Sq(2) * M.generator(0) + sage: N = FPModule(SteenrodAlgebra(2), [0], [[Sq(2)]]) + sage: y = Sq(2) * N.generator(0) + sage: x == y + False + sage: x != y + True """ try: return (self - other).is_zero() diff --git a/src/sage/modules/fp_graded/free_module.py b/src/sage/modules/fp_graded/free_module.py index 33181dfd240..fcfea50234d 100755 --- a/src/sage/modules/fp_graded/free_module.py +++ b/src/sage/modules/fp_graded/free_module.py @@ -345,6 +345,15 @@ def __classcall_private__(cls, algebra, generator_degrees, category=None, names=None, prefix=None, **kwds): """ Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: E. = ExteriorAlgebra(QQ) + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: M1 = FreeGradedModule(E, [1, 0, 2], names='a,b,c') + sage: M2. = FreeGradedModule(E, (1, 0, 2)) + sage: M1 is M2 + True """ if algebra.base_ring() not in Fields(): raise ValueError('the ground ring of the algebra must be a field') diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index 1352ef789da..d968645c957 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -141,6 +141,18 @@ def __init__(self, algebra, generator_degrees, relations=(), names=None): sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) sage: M = FPModule(A3, [0, 1], [[Sq(2), Sq(1)]]) sage: TestSuite(M).run() + + Checking containment:: + + sage: from sage.modules.fp_graded.module import FPModule + sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]]) + sage: x = M([Sq(1), 1]) + sage: x in M + True + sage: N = FPModule(SteenrodAlgebra(2), [0], [[Sq(2)]]) + sage: y = Sq(2) * N.generator(0) + sage: y in M + False """ self._relations = relations self._generator_degrees = generator_degrees @@ -385,25 +397,28 @@ def _element_constructor_(self, x): sage: A = SteenrodAlgebra(2) sage: M. = FPModule(A, [0,2,4], [[Sq(4), Sq(2), 0]]) - sage: # Creating an element from coefficients: + Creating an element from coefficients:: + sage: e = M((Sq(6), 0, Sq(2))); e Sq(6)*a0 + Sq(2)*a4 sage: e in M True - sage: # Special syntax for creating the zero element: + Creating the zero element:: + sage: z = M(0); z 0 sage: z.is_zero() True - sage: # Creating an element from another element returns a reference to itself: + Idempotent on elements belonging to the module:: + sage: M(e) Sq(6)*a0 + Sq(2)*a4 sage: e is M(e) True """ - if isinstance(x, self.element_class): + if parent(x) is self: return x if not self._generator_degrees: # the trivial module return self.zero() From 7e317b2a596acd44a68a2a8ca3f84f0b45ee11cb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 28 Jan 2022 00:15:55 -0800 Subject: [PATCH 173/253] build/pkgs/texlive/distros/debian.txt: Add texlive-fonts-recommended --- build/pkgs/texlive/distros/debian.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/pkgs/texlive/distros/debian.txt b/build/pkgs/texlive/distros/debian.txt index 05553c735a9..eb5a61bbbb9 100644 --- a/build/pkgs/texlive/distros/debian.txt +++ b/build/pkgs/texlive/distros/debian.txt @@ -8,3 +8,5 @@ latexmk dvipng # for tgtermes.sty used in doc-pdf tex-gyre +# for use of rsfs font in pdf documentation +texlive-fonts-recommended From 37d569de786f1c252f09f9aacca48540aa278680 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 28 Jan 2022 09:52:31 -0800 Subject: [PATCH 174/253] build/pkgs/texlive/distros/debian.txt: Add texlive-lang-* --- build/pkgs/texlive/distros/debian.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/build/pkgs/texlive/distros/debian.txt b/build/pkgs/texlive/distros/debian.txt index eb5a61bbbb9..4cb070139a7 100644 --- a/build/pkgs/texlive/distros/debian.txt +++ b/build/pkgs/texlive/distros/debian.txt @@ -10,3 +10,14 @@ dvipng tex-gyre # for use of rsfs font in pdf documentation texlive-fonts-recommended +# language support for the pdf documentation +texlive-lang-cyrillic +texlive-lang-english +texlive-lang-european +texlive-lang-french +texlive-lang-german +texlive-lang-italian +texlive-lang-japanese +texlive-lang-polish +texlive-lang-portuguese +texlive-lang-spanish From 1dc511c20412fd8cb914ea6d798b4c3c34096ec7 Mon Sep 17 00:00:00 2001 From: Antonio Rojas Date: Fri, 28 Jan 2022 20:11:02 +0100 Subject: [PATCH 175/253] Add Arch package info --- build/pkgs/texlive/distros/arch.txt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 build/pkgs/texlive/distros/arch.txt diff --git a/build/pkgs/texlive/distros/arch.txt b/build/pkgs/texlive/distros/arch.txt new file mode 100644 index 00000000000..4c0b568f576 --- /dev/null +++ b/build/pkgs/texlive/distros/arch.txt @@ -0,0 +1,4 @@ +texlive-core +texlive-latexextra +texlive-langjapanese +texlive-langcyrillic From f5ec2c1b87b21f4af85c95ca48d43a6c68301419 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Fri, 28 Jan 2022 13:28:00 -0800 Subject: [PATCH 176/253] trac 32505: do not use __class__(...), instead explicitly name the class --- src/sage/modules/fp_graded/free_module.py | 5 +--- src/sage/modules/fp_graded/free_morphism.py | 7 +++-- src/sage/modules/fp_graded/module.py | 19 +++++++------- src/sage/modules/fp_graded/morphism.py | 29 +++++++++++---------- 4 files changed, 29 insertions(+), 31 deletions(-) diff --git a/src/sage/modules/fp_graded/free_module.py b/src/sage/modules/fp_graded/free_module.py index fcfea50234d..ae7700b88d7 100755 --- a/src/sage/modules/fp_graded/free_module.py +++ b/src/sage/modules/fp_graded/free_module.py @@ -886,7 +886,4 @@ def as_fp_module(self): mod 2 Steenrod algebra, milnor basis """ from .module import FPModule - return FPModule(algebra=self.base_ring(), - generator_degrees=self.generator_degrees(), - relations=()) - + return FPModule(self.base_ring(), self.generator_degrees(), ()) diff --git a/src/sage/modules/fp_graded/free_morphism.py b/src/sage/modules/fp_graded/free_morphism.py index be3774a3163..5a0649df6d5 100755 --- a/src/sage/modules/fp_graded/free_morphism.py +++ b/src/sage/modules/fp_graded/free_morphism.py @@ -586,7 +586,6 @@ def fp_module(self): (Sq(2)*g[0],) """ from .module import FPModule - return FPModule(algebra=self.base_ring(), - generator_degrees=self.codomain().generator_degrees(), - relations=tuple([r.dense_coefficient_list() for r in self._values])) - + return FPModule(self.base_ring(), + self.codomain().generator_degrees(), + tuple([r.dense_coefficient_list() for r in self._values])) diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index d968645c957..c559abcf7bb 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -50,6 +50,7 @@ from sage.structure.element import parent from sage.modules.fp_graded.free_module import FreeGradedModule +from sage.modules.fp_graded.free_morphism import FreeGradedModuleMorphism from sage.modules.fp_graded.free_element import FreeGradedModuleElement from sage.modules.fp_graded.element import FPElement @@ -222,9 +223,9 @@ def from_free_module(cls, free_module): Finitely presented left module on 3 generators and 0 relations over mod 2 Steenrod algebra, milnor basis """ - return cls(algebra=free_module.base_ring(), - generator_degrees=free_module.generator_degrees(), - relations=()) + return cls(free_module.base_ring(), + free_module.generator_degrees(), + ()) @classmethod @@ -259,9 +260,9 @@ def from_free_module_morphism(cls, morphism): sage: M.relations() (Sq(2)*g[0],) """ - return cls(algebra=morphism.base_ring(), - generator_degrees=morphism.codomain().generator_degrees(), - relations=tuple([r.coefficients() for r in morphism.values()])) + return cls(morphism.base_ring(), + morphism.codomain().generator_degrees(), + tuple([r.coefficients() for r in morphism.values()])) def change_ring(self, algebra): @@ -1091,9 +1092,9 @@ def suspension(self, t): sage: Q.generator_degrees() (2, 3) """ - return FPModule(algebra=self.base_ring(), - generator_degrees=tuple([g + t for g in self._generator_degrees]), - relations=self._relations) + return FPModule(self.base_ring(), + tuple([g + t for g in self._generator_degrees]), + self._relations) def submodule_inclusion(self, spanning_elements): diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py index 891b4a76fdf..f15c779b19f 100755 --- a/src/sage/modules/fp_graded/morphism.py +++ b/src/sage/modules/fp_graded/morphism.py @@ -1519,6 +1519,7 @@ def _resolve_kernel(self, top_dim=None, verbose=False): g[3, 0] |--> Sq(0,1)*g[0, 0] g[3, 1] |--> Sq(3)*g[0, 0] """ + from .module import FPModule # Let # # 1) `j` be a homomorphism into `\ker(self)`, and @@ -1539,7 +1540,7 @@ def _resolve_kernel(self, top_dim=None, verbose=False): return epsilon # Create the trivial module F_ to start with. - F_ = self.domain().__class__(self.base_ring(), ()) + F_ = FPModule(self.base_ring(), ()) j = Hom(F_, self.domain())(()) dim = self.domain().connectivity() @@ -1588,8 +1589,8 @@ def _resolve_kernel(self, top_dim=None, verbose=False): if j.is_zero(): # The map j is not onto in degree `n` of the kernel. new_generator_degrees = tuple(kernel_n.dimension()*(n,)) - F_ = self.domain().__class__(self.base_ring(), - generator_degrees + new_generator_degrees) + F_ = FPModule(self.base_ring(), + generator_degrees + new_generator_degrees) new_values = tuple([ self.domain().element_from_coordinates(q, n) for q in kernel_n.basis()]) @@ -1602,8 +1603,8 @@ def _resolve_kernel(self, top_dim=None, verbose=False): # The map j is not onto in degree `n` of the kernel. new_generator_degrees = tuple(Q_n.dimension()*(n,)) - F_ = self.domain().__class__(self.base_ring(), - generator_degrees + new_generator_degrees) + F_ = FPModule(self.base_ring(), + generator_degrees + new_generator_degrees) new_values = tuple([ self.domain().element_from_coordinates(Q_n.lift(q), n) for q in Q_n.basis()]) @@ -1662,6 +1663,7 @@ def _resolve_image(self, top_dim=None, verbose=False): To: Finitely presented left module on 2 generators and 2 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] Defn: g[2] |--> Sq(2)*g[0, 0] """ + from .module import FPModule # Let # # 1) `j` be a homomorphism into `\im(self)`, and @@ -1675,7 +1677,7 @@ def _resolve_image(self, top_dim=None, verbose=False): # # Create the trivial module F_ to start with. - F_ = self.domain().__class__(self.base_ring(), ()) + F_ = FPModule(self.base_ring(), ()) j = Hom(F_, self.codomain())(()) dim = self.codomain().connectivity() @@ -1722,8 +1724,8 @@ def _resolve_image(self, top_dim=None, verbose=False): if j.is_zero(): # The map j is not onto in degree `n` of the image. new_generator_degrees = tuple(image_n.dimension()*(n,)) - F_ = self.domain().__class__(self.base_ring(), - generator_degrees + new_generator_degrees) + F_ = FPModule(self.base_ring(), + generator_degrees + new_generator_degrees) new_values = tuple([ self.codomain().element_from_coordinates(q, n) for q in image_n.basis()]) @@ -1738,8 +1740,8 @@ def _resolve_image(self, top_dim=None, verbose=False): # The map j is not onto in degree `n` of the image. new_generator_degrees = tuple(Q_n.dimension()*(n,)) - F_ = self.domain().__class__(self.base_ring(), - generator_degrees + new_generator_degrees) + F_ = FPModule(self.base_ring(), + generator_degrees + new_generator_degrees) new_values = tuple([ self.codomain().element_from_coordinates(Q_n.lift(q), n) for q in Q_n.basis()]) @@ -1787,7 +1789,6 @@ def fp_module(self): if self.domain().has_relations() or self.codomain().has_relations(): raise ValueError("this is not a morphism between free modules") from .module import FPModule - return FPModule(algebra=self.base_ring(), - generator_degrees=self.codomain().generator_degrees(), - relations=tuple([r.coefficients() for r in self._values])) - + return FPModule(self.base_ring(), + self.codomain().generator_degrees(), + tuple([r.coefficients() for r in self._values])) From 316dd9ec8e561479c8f3cdfa014a74a084d2285c Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Fri, 28 Jan 2022 16:29:39 -0600 Subject: [PATCH 177/253] \Bold -> \RR --- src/sage/manifolds/catalog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/manifolds/catalog.py b/src/sage/manifolds/catalog.py index f8e2a030c35..1e935e643c7 100644 --- a/src/sage/manifolds/catalog.py +++ b/src/sage/manifolds/catalog.py @@ -263,7 +263,7 @@ def RealProjectiveSpace(dim=2): Generate projective space of dimension ``dim`` over the reals. This is the topological space of lines through the origin in - `\Bold{R}^{d+1}`. The standard atlas consists of `d+2` charts, which sends + `\RR^{d+1}`. The standard atlas consists of `d+2` charts, which sends the set `U_i = \{[x_1, x_2, \ldots, x_{d+1}] : x_i \neq 0 \}` to `k^{d}` by dividing by `x_i` and omitting the `i`th coordinate `x_i/x_i = 1`. From 51f9419e13686805845b04d88b0a071bf32a8f08 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Fri, 28 Jan 2022 17:29:51 -0600 Subject: [PATCH 178/253] Make RP bold --- src/sage/manifolds/catalog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/manifolds/catalog.py b/src/sage/manifolds/catalog.py index 1e935e643c7..e6bf28b48ee 100644 --- a/src/sage/manifolds/catalog.py +++ b/src/sage/manifolds/catalog.py @@ -274,7 +274,7 @@ def RealProjectiveSpace(dim=2): OUTPUT: - - ``P`` -- the projective space `RP^d` where `d =` ``dim``. + - ``P`` -- the projective space `\Bold{RP}^d` where `d =` ``dim``. EXAMPLES:: From ca9cdf08d263d417566d20f86387c69512408034 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Fri, 28 Jan 2022 16:22:43 -0800 Subject: [PATCH 179/253] trac 32505: fix one doctest --- src/sage/combinat/free_module.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index 3eddc772d7a..aea71cef246 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -173,6 +173,7 @@ class CombinatorialFreeModule(UniqueRepresentation, Module, IndexedGenerators): sage: original_print_options = F.print_options() sage: sorted(original_print_options.items()) [('bracket', None), + ('iterate_key', False), ('latex_bracket', False), ('latex_names', None), ('latex_prefix', None), ('latex_scalar_mult', None), ('names', None), ('prefix', 'x'), From 7dc91398f34cd0f21a3a4922e8330f596454ea4d Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Fri, 28 Jan 2022 17:57:01 -0800 Subject: [PATCH 180/253] trac 32505: remove an unneeded import --- src/sage/modules/fp_graded/module.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index c559abcf7bb..8c493ba84cf 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -50,7 +50,6 @@ from sage.structure.element import parent from sage.modules.fp_graded.free_module import FreeGradedModule -from sage.modules.fp_graded.free_morphism import FreeGradedModuleMorphism from sage.modules.fp_graded.free_element import FreeGradedModuleElement from sage.modules.fp_graded.element import FPElement From b7f9179ccb50b17cf867e5b11009594a5ba6d155 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 29 Jan 2022 15:43:21 +0900 Subject: [PATCH 181/253] Adding support for morphism input. --- src/sage/modules/fp_graded/element.py | 6 +- src/sage/modules/fp_graded/free_morphism.py | 5 +- src/sage/modules/fp_graded/module.py | 89 ++++++++++++--------- src/sage/modules/fp_graded/morphism.py | 4 +- 4 files changed, 58 insertions(+), 46 deletions(-) diff --git a/src/sage/modules/fp_graded/element.py b/src/sage/modules/fp_graded/element.py index 3e86a8c2b80..fb760aea032 100755 --- a/src/sage/modules/fp_graded/element.py +++ b/src/sage/modules/fp_graded/element.py @@ -42,8 +42,8 @@ class FPElement(IndexedFreeModuleElement): """ def lift_to_free(self): r""" - A lift of this element to the free module F, - if this element is in a quotient of F. + Return the lift of ``self`` to the free module ``F``, + where ``self`` is in a quotient of ``F``. EXAMPLES:: @@ -59,7 +59,7 @@ def lift_to_free(self): sage: x.lift_to_free().parent() Free graded left module on 2 generators over mod 2 Steenrod algebra, milnor basis """ - C = self.parent().j.codomain() + C = self.parent()._j.codomain() return C(self.coefficients()) diff --git a/src/sage/modules/fp_graded/free_morphism.py b/src/sage/modules/fp_graded/free_morphism.py index 5a0649df6d5..0678a62b052 100755 --- a/src/sage/modules/fp_graded/free_morphism.py +++ b/src/sage/modules/fp_graded/free_morphism.py @@ -586,6 +586,5 @@ def fp_module(self): (Sq(2)*g[0],) """ from .module import FPModule - return FPModule(self.base_ring(), - self.codomain().generator_degrees(), - tuple([r.dense_coefficient_list() for r in self._values])) + return FPModule(self) + diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index 8c493ba84cf..48f21d71b6c 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -13,7 +13,7 @@ This package was designed with homological algebra in mind, and its API focuses on maps rather than objects. A good example of this is the kernel -function :meth:`sage.modules.fp_graded.morphism.FPModuleMorphism.kernel_inclusion` +function :meth:`sage.modules.fp_graded.morphism.FPModuleMorphism.kernel_inclusion`, which computes the kernel of a homomorphism `f: M\to N`. Its return value is not an instance of the module class, but rather an injective homomorphism `i: K\to M` with the property that `\operatorname{im}(i) = \ker(f)`. @@ -39,6 +39,7 @@ # **************************************************************************** from sage.categories.homset import Hom +from sage.categories.morphism import Morphism from sage.misc.cachefunc import cached_method from sage.rings.infinity import PlusInfinity from sage.categories.graded_modules import GradedModules @@ -63,7 +64,13 @@ class FPModule(UniqueRepresentation, IndexedGenerators, Module): INPUT: - - ``algebra`` -- the graded connected algebra over which the module is + One of the following: + + - ``arg0`` -- a morphism such that the module is the cokernel + + Otherwise: + + - ``arg0`` -- the graded connected algebra over which the module is defined; this algebra must be equipped with a graded basis - ``generator_degrees`` -- tuple of integer degrees @@ -109,7 +116,7 @@ class FPModule(UniqueRepresentation, IndexedGenerators, Module): True """ @staticmethod - def __classcall_private__(cls, algebra, generator_degrees, relations=(), names=None): + def __classcall_private__(cls, arg0, generator_degrees=None, relations=(), names=None): r""" Normalize input to ensure a unique representation. @@ -125,13 +132,28 @@ def __classcall_private__(cls, algebra, generator_degrees, relations=(), names=N if names is not None: from sage.structure.category_object import normalize_names names = normalize_names(-1, names) - return super(FPModule, cls).__classcall__(cls, - algebra=algebra, - generator_degrees=tuple(generator_degrees), - relations=tuple([tuple([algebra(x) for x in r]) for r in relations]), - names=names) - def __init__(self, algebra, generator_degrees, relations=(), names=None): + # If given a morphism, then that defines a module + if isinstance(arg0, Morphism): + return super(FPModule, cls).__classcall__(cls, arg0, names=names) + + if generator_degrees is None: + raise ValueError("the generator_degrees must be specified") + + # The free module on the generators of the module. + generator_module = FreeGradedModule(arg0, generator_degrees, names=names) + # Use the coefficients given for the relations and make module elements + # from them. Filter out the zero elements, as they are redundant. + rels = [v for v in [generator_module(r) for r in relations] if not v.is_zero()] + + # The free module for the relations of the module. + relations_module = FreeGradedModule(arg0, tuple([r.degree() for r in rels])) + + # The module we want to model is the cokernel of the following morphism + j = Hom(relations_module, generator_module)(rels) + return super(FPModule, cls).__classcall__(cls, j, names=names) + + def __init__(self, j, names): r""" Create a finitely presented module over a connected graded algebra. @@ -154,25 +176,14 @@ def __init__(self, algebra, generator_degrees, relations=(), names=None): sage: y in M False """ - self._relations = relations - self._generator_degrees = generator_degrees - - # The free module on the generators of the module. - generator_module = FreeGradedModule(algebra, generator_degrees, names=names) - # Use the coefficients given for the relations and make module elements - # from them. Filter out the zero elements, as they are redundant. - rels = [v for v in [generator_module(r) for r in relations] if not v.is_zero()] - - # The free module for the relations of the module. - relations_module = FreeGradedModule(algebra, - tuple([r.degree() for r in rels])) + self._j = j + codomain = j.codomain() - # The module we want to model is the cokernel of the - # following morphism. - self.j = Hom(relations_module, generator_module)(rels) + self._generator_degrees = codomain.generator_degrees() + algebra = codomain.base_ring() # Call the base class constructors. - keys = generator_module.basis().keys() + keys = j.codomain().basis().keys() cat = GradedModules(algebra).WithBasis().FinitelyPresented() IndexedGenerators.__init__(self, keys) Module.__init__(self, algebra, category=cat) @@ -197,7 +208,7 @@ def _free_module(self): sage: F.generators() (x, y) """ - return self.j.codomain() + return self._j.codomain() @classmethod @@ -295,7 +306,7 @@ def change_ring(self, algebra): True """ # self.relations() consists of module elements. We need to extra the coefficients. - relations = tuple(r.coefficients() for r in self.relations()) + relations = tuple(r.coefficients() for r in self._j.values()) return FPModule(algebra, self.generator_degrees(), relations) @@ -457,7 +468,7 @@ def _repr_(self): return "Finitely presented left module on %s generator%s and %s relation%s over %s"\ %(len(self._free_module().generator_degrees()), "" if len(self._free_module().generator_degrees()) == 1 else "s", - len(self.j.values()), "" if len(self.j.values()) == 1 else "s", + len(self._j.values()), "" if len(self._j.values()) == 1 else "s", self.base_ring()) @@ -532,7 +543,7 @@ def connectivity(self): """ # In case there are no relations, the connectivity is the equal to # the connectivity of the free module on the generators. - if self.j._degree is None: + if self._j._degree is None: return self._free_module().connectivity() # We must check that the generator(s) in the free generator module are @@ -544,7 +555,7 @@ def connectivity(self): for k in X: if previous is not None and k == previous: continue - if not self.j.vector_presentation(k - self.j._degree).is_surjective(): + if not self._j.vector_presentation(k - self._j._degree).is_surjective(): return k previous = k @@ -621,7 +632,7 @@ def has_relations(self): sage: N_min.has_relations() False """ - return not self.j.is_zero() + return not self._j.is_zero() def an_element(self, n=None): @@ -846,7 +857,7 @@ def vector_presentation(self, n, verbose=False): if verbose: num_total_iterations = 0 - for relation in self.j.values(): + for relation in self._j.values(): if relation.is_zero(): continue @@ -855,7 +866,7 @@ def vector_presentation(self, n, verbose=False): progress = 0 iteration_count = 0 - for relation in self.j.values(): + for relation in self._j.values(): if relation.is_zero(): continue @@ -988,7 +999,7 @@ def relations(self): sage: Z.relations() () """ - return self.j.values() + return self._j.values() def relation(self, index): @@ -1003,7 +1014,7 @@ def relation(self, index): sage: N.relation(0) Sq(2)*g[0] + Sq(1)*g[1] """ - return self.j.values()[index] + return self._j.values()[index] def min_presentation(self, top_dim=None, verbose=False): @@ -1091,9 +1102,10 @@ def suspension(self, t): sage: Q.generator_degrees() (2, 3) """ + relations = tuple([r.dense_coefficient_list() for r in self._j._values]) return FPModule(self.base_ring(), tuple([g + t for g in self._generator_degrees]), - self._relations) + relations) def submodule_inclusion(self, spanning_elements): @@ -1135,6 +1147,7 @@ def submodule_inclusion(self, spanning_elements): # Create the free graded module on the set of spanning elements. degs = [x.degree() for x in spanning_elements] F = FPModule(self.base_ring(), tuple(degs)) + #F = FreeGradedModule(self.base_ring(), tuple(degs)) # The submodule is the module generated by the spanning elements. return Hom(F, self)(spanning_elements).image() @@ -1241,8 +1254,8 @@ def _print_progress(i, k): # f_1: F_1 -> F_0 _print_progress(1, k) - F_1 = FPModule.from_free_module(self.j.domain()) - pres = Hom(F_1, F_0)(tuple([ F_0(x.coefficients()) for x in self.j.values() ])) + F_1 = FPModule.from_free_module(self._j.domain()) + pres = Hom(F_1, F_0)(tuple([ F_0(x.coefficients()) for x in self._j.values() ])) ret_complex.append(pres) diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py index f15c779b19f..1fd81b76944 100755 --- a/src/sage/modules/fp_graded/morphism.py +++ b/src/sage/modules/fp_graded/morphism.py @@ -196,7 +196,7 @@ def __init__(self, parent, values): if not isinstance(parent, FPModuleHomspace): raise TypeError('parent (=%s) must be a fp module hom space' % parent) - Homspace = Hom(parent.domain().j.codomain(), parent.codomain().j.codomain()) + Homspace = Hom(parent.domain()._j.codomain(), parent.codomain()._j.codomain()) self.free_morphism = Homspace([v.lift_to_free() for v in values]) self._values = tuple(values) @@ -1535,7 +1535,7 @@ def _resolve_kernel(self, top_dim=None, verbose=False): if self.is_zero(): # Epsilon: F_0 -> M M = self.domain() - F_0 = self.domain().j.codomain().as_fp_module() + F_0 = self.domain()._j.codomain().as_fp_module() epsilon = Hom(F_0, M)(tuple(M.generators())) return epsilon From 96c242edefed598e2747d9603e84d11ee5be6045 Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Sun, 23 Jan 2022 11:34:17 +0100 Subject: [PATCH 182/253] 33217: fix reduction for ideals in quotient polynomial rings This adds a new subclass for ideals of multivariate polynomial rings. --- src/sage/rings/morphism.pyx | 8 ++++ .../polynomial/multi_polynomial_ideal.py | 48 ++++++++++++++++++- src/sage/rings/quotient_ring.py | 7 +-- src/sage/rings/quotient_ring_element.py | 12 ++++- 4 files changed, 67 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/morphism.pyx b/src/sage/rings/morphism.pyx index b4d6596ce04..2cdd0ce4476 100644 --- a/src/sage/rings/morphism.pyx +++ b/src/sage/rings/morphism.pyx @@ -1090,6 +1090,14 @@ cdef class RingHomomorphism(RingMap): sage: h = A.hom([d^2, d^3], B) sage: h.inverse_image(d^2) a + + Check that quotient rings are handled correctly (:trac:`33217`):: + + sage: A. = QQ['X,Y,Z'].quotient('X^2+Y^2+Z^2-1') + sage: B. = QQ['T,U,V,W'].quotient(['T^2+U^2-1', 'V^2+W^2-1']) + sage: psi = A.hom([v*u, w*u, t], B) + sage: psi.inverse_image(t^2) == z^2 + True """ graph, from_B, to_A = self._graph_ideal() gens_A = graph.ring().gens()[-self.domain().ngens():] diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 2b6c9fb3670..c5a5e2cfdcb 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -4560,8 +4560,7 @@ def _contains_(self, f): Requires computation of a Groebner basis, which can be a very expensive operation. """ - g = f.reduce(self.groebner_basis()) - return self.ring()(g).is_zero() + return self.reduce(f).is_zero() def homogenize(self, var='h'): """ @@ -5165,3 +5164,48 @@ def weil_restriction(self): result = [h(*map_ideal) for h in result] return result_ring.ideal(result) + + +class MPolynomialIdeal_quotient(MPolynomialIdeal): + r""" + An ideal in a quotient of a multivariate polynomial ring. + + EXAMPLES:: + + sage: Q. = QQ['x,y,z,w'].quotient(['x*y-z^2', 'y^2-w^2']) + sage: I = ideal(x + y^2 + z - 1) + sage: I + Ideal (w^2 + x + z - 1) of Quotient of Multivariate Polynomial Ring + in x, y, z, w over Rational Field by the ideal (x*y - z^2, y^2 - w^2) + """ + + def reduce(self, f): + r""" + Reduce an element modulo a Gröbner basis for this ideal. + This returns 0 if and only if the element is in this ideal. In any + case, this reduction is unique up to monomial orders. + + EXAMPLES:: + + sage: R. = PolynomialRing(QQ, order='lex') + sage: I = R.ideal([T^2+U^2-1, V^2+W^2-1, X^2+Y^2+Z^2-1]) + sage: Q. = R.quotient(I) + sage: J = Q.ideal([u*v-x, u*w-y, t-z]) + sage: J.reduce(t^2 - z^2) + 0 + sage: J.reduce(u^2) + -z^2 + 1 + sage: t^2 - z^2 in J + True + sage: u^2 in J + False + """ + Q = self.ring() + gb = self.groebner_basis() + # In quotient rings, gb is not a Gröbner basis of self, but gb0 is + # a (possibly non-reduced) Gröbner basis of the preimage of self in + # the cover ring (see :trac:`33217`). We only use Gröbner bases of + # pre-existing ideals to potentially take advantage of caching. + gb0 = Q.defining_ideal().groebner_basis() + [g.lift() for g in gb] + f0 = f.lift().reduce(gb0) + return Q._element_constructor_from_element_class(f0, reduce=False) diff --git a/src/sage/rings/quotient_ring.py b/src/sage/rings/quotient_ring.py index 70c4afdc283..c875abcdb88 100644 --- a/src/sage/rings/quotient_ring.py +++ b/src/sage/rings/quotient_ring.py @@ -118,7 +118,6 @@ from sage.categories.commutative_rings import CommutativeRings -MPolynomialIdeal = None try: from sage.interfaces.singular import singular as singular_default, is_SingularElement except ImportError: @@ -967,10 +966,8 @@ def ideal(self, *gens, **kwds): if 'coerce' in kwds and kwds['coerce']: gens = [self(x) for x in gens] # this will even coerce from singular ideals correctly! - global MPolynomialIdeal - if MPolynomialIdeal is None: - from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal - return MPolynomialIdeal(self, gens, **kwds) + from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal_quotient + return MPolynomialIdeal_quotient(self, gens, **kwds) def _element_constructor_(self, x, coerce=True): """ diff --git a/src/sage/rings/quotient_ring_element.py b/src/sage/rings/quotient_ring_element.py index 337c22c232c..8ad337e8aa8 100644 --- a/src/sage/rings/quotient_ring_element.py +++ b/src/sage/rings/quotient_ring_element.py @@ -896,9 +896,14 @@ def reduce(self, G): INPUT: - - ``G`` - a list of quotient ring elements + .. WARNING:: + + This method is not guaranteed to return unique minimal results. + For quotients of polynomial rings, use + :meth:`~sage.rings.polynomial.multi_polynomial_ideal.MPolynomialIdeal.reduce` + on the ideal generated by ``G``, instead. EXAMPLES:: @@ -909,6 +914,11 @@ def reduce(self, G): sage: f = Q((a*b + c*d + 1)^2 + e) sage: f.reduce(I2.gens()) ebar + + Notice that the result above is not minimal:: + + sage: I2.reduce(f) + 0 """ try: G = [f.lift() for f in G] From e0d5533de4b5e4747c2848348779dee0410868aa Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Sat, 29 Jan 2022 16:53:19 +0100 Subject: [PATCH 183/253] 33217: implement richcmp for ideals in polynomial quotient rings --- .../polynomial/multi_polynomial_ideal.py | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index c5a5e2cfdcb..e02a39cbdb9 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -5209,3 +5209,78 @@ def reduce(self, f): gb0 = Q.defining_ideal().groebner_basis() + [g.lift() for g in gb] f0 = f.lift().reduce(gb0) return Q._element_constructor_from_element_class(f0, reduce=False) + + def __richcmp__(self, other, op): + """ + Compare ``self`` and ``other``. + + INPUT: + + - ``other`` -- an ideal in a quotient of a polynomial ring + + OUTPUT: + + boolean + + TESTS:: + + sage: R. = PolynomialRing(QQ, order='lex') + sage: Q. = R.quotient([T^2+U^2-1, V^2+W^2-1, X^2+Y^2+Z^2-1]) + sage: J = Q.ideal([u*v-x, u*w-y, t-z]) + sage: I1 = J + Q.ideal(t^2-z^2) + sage: I1 <= J, I1 < J, I1 == J, I1 != J + (True, False, True, False) + sage: I2 = J + Q.ideal(t-z^2) + sage: J <= I2, J < I2, J > I2, J >= I2 + (True, True, False, False) + + The ideals must belong to the same quotient ring:: + + sage: J0 = R.ideal([g.lift() for g in J.gens()]) + sage: J0 <= J + Traceback (most recent call last): + ... + AttributeError:... + sage: J <= J0 + Traceback (most recent call last): + ... + TypeError: '<=' not supported... + """ + # The implementation largely follows the superclass, but for simplicity + # does not deal with different rings or term orders. + if not isinstance(other, MPolynomialIdeal_quotient): + return NotImplemented + + if self is other: + return rich_to_bool(op, 0) + + # comparison for >= and > : swap the arguments + if op == op_GE: + return other.__richcmp__(self, op_LE) + elif op == op_GT: + return other.__richcmp__(self, op_LT) + + if other.ring() != self.ring(): + return NotImplemented + + s_gens = self.gens() + o_gens = other.gens() + try: + if (s_gens == o_gens) or (set(s_gens) == set(o_gens)): + # the first clause works in the non-hashable case + return rich_to_bool(op, 0) + except TypeError: + pass + + # comparison for <= and == and != and < + if op in [op_LE, op_EQ, op_NE, op_LT]: + contained = all(f in other for f in s_gens) + if op == op_LE: + return contained + contains = all(g in self for g in o_gens) + if op == op_EQ: + return contained and contains + elif op == op_NE: + return not (contained and contains) + else: # remaining case < + return contained and not contains From 5e021535eb5917c9b65036db7c018b66729063e3 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Sat, 29 Jan 2022 14:04:04 -0800 Subject: [PATCH 184/253] trac 32505: remove from_free_module, from_free_module_morphism --- src/sage/modules/fp_graded/element.py | 2 +- src/sage/modules/fp_graded/module.py | 102 +++++++------------------- 2 files changed, 29 insertions(+), 75 deletions(-) diff --git a/src/sage/modules/fp_graded/element.py b/src/sage/modules/fp_graded/element.py index fb760aea032..e559150d514 100755 --- a/src/sage/modules/fp_graded/element.py +++ b/src/sage/modules/fp_graded/element.py @@ -122,7 +122,7 @@ def coefficients(self): sage: y.coefficients() [0, Sq(2)] """ - return [self[i] for i in sorted(self.parent().basis().keys())] + return [self[i] for i in sorted(self.parent().indices())] def _lmul_(self, a): diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index 48f21d71b6c..63cc577ad9b 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -54,10 +54,11 @@ from sage.modules.fp_graded.free_element import FreeGradedModuleElement from sage.modules.fp_graded.element import FPElement -# These are not free modules over the algebra, but they are free as -# vector spaces. They have a distinguished set of generators over the -# algebra, and as long as the algebra has a vector space basis -# implemented in Sage, the modules will have a vector space basis as well. +# Note that some of the methods below assume that the base ring is a +# field and that the graded algebra has a chosen vector space basis in +# each degree. See for example :meth:`basis_elements`, +# :meth:`element_from_coordinates`, :meth:`__getitem__`, +# :meth:`vector_presentation`, and possibly others. class FPModule(UniqueRepresentation, IndexedGenerators, Module): r""" Create a finitely presented module over a connected graded algebra. @@ -66,7 +67,9 @@ class FPModule(UniqueRepresentation, IndexedGenerators, Module): One of the following: - - ``arg0`` -- a morphism such that the module is the cokernel + - ``arg0`` -- a morphism such that the module is the cokernel, or + a free graded module, in which case the output is the same + module, viewed as finitely presented Otherwise: @@ -114,6 +117,16 @@ class FPModule(UniqueRepresentation, IndexedGenerators, Module): () sage: Z.is_trivial() True + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: F = FreeGradedModule(E, [0, 1]) + sage: one = Hom(F, F).identity() + sage: Z = FPModule(one) + sage: Z.is_trivial() + True + + sage: FPModule(FreeGradedModule(E, [0, 1])) + Finitely presented left module on 2 generators and 0 relations over The exterior algebra of rank 2 over Rational Field """ @staticmethod def __classcall_private__(cls, arg0, generator_degrees=None, relations=(), names=None): @@ -137,6 +150,11 @@ def __classcall_private__(cls, arg0, generator_degrees=None, relations=(), names if isinstance(arg0, Morphism): return super(FPModule, cls).__classcall__(cls, arg0, names=names) + if isinstance(arg0, FreeGradedModule): + zero = FreeGradedModule(arg0.base_ring(), ()) + j = zero.Hom(arg0).zero() + return super(FPModule, cls).__classcall__(cls, j, names=names) + if generator_degrees is None: raise ValueError("the generator_degrees must be specified") @@ -184,7 +202,7 @@ def __init__(self, j, names): # Call the base class constructors. keys = j.codomain().basis().keys() - cat = GradedModules(algebra).WithBasis().FinitelyPresented() + cat = GradedModules(algebra).FinitelyPresented() IndexedGenerators.__init__(self, keys) Module.__init__(self, algebra, category=cat) @@ -211,70 +229,6 @@ def _free_module(self): return self._j.codomain() - @classmethod - def from_free_module(cls, free_module): - r""" - Initialize from a finitely generated free module. - - INPUT: - - - ``free_module`` -- a finitely generated free module - - OUTPUT: the finitely presented module having same set of generators - as ``free_module``, and no relations. - - EXAMPLES:: - - sage: from sage.modules.fp_graded.free_module import FreeGradedModule - sage: from sage.modules.fp_graded.module import FPModule - sage: A = SteenrodAlgebra(2) - sage: F = FreeGradedModule(A, (-2,2,4)) - sage: FPModule.from_free_module(F) - Finitely presented left module on 3 generators and 0 relations over - mod 2 Steenrod algebra, milnor basis - """ - return cls(free_module.base_ring(), - free_module.generator_degrees(), - ()) - - - @classmethod - def from_free_module_morphism(cls, morphism): - r""" - Create a finitely presented module from a morphism of finitely - generated free modules. - - INPUT: - - - ``morphism`` -- a morphism between finitely generated free modules - - OUTPUT: - - The finitely presented module having presentation equal to the - homomorphism ``morphism``. - - EXAMPLES:: - - sage: from sage.modules.fp_graded.free_module import FreeGradedModule - sage: from sage.modules.fp_graded.module import FPModule - sage: A = SteenrodAlgebra(2) - sage: F1 = FreeGradedModule(A, (2,)) - sage: F2 = FreeGradedModule(A, (0,)) - sage: v = F2([Sq(2)]) - sage: pres = Hom(F1, F2)([v]) - sage: M = FPModule.from_free_module_morphism(pres); M - Finitely presented left module on 1 generator and 1 relation over - mod 2 Steenrod algebra, milnor basis - sage: M.generator_degrees() - (0,) - sage: M.relations() - (Sq(2)*g[0],) - """ - return cls(morphism.base_ring(), - morphism.codomain().generator_degrees(), - tuple([r.coefficients() for r in morphism.values()])) - - def change_ring(self, algebra): r""" Change the base ring of ``self``. @@ -1245,7 +1199,7 @@ def _print_progress(i, k): ret_complex = [] # Epsilon: F_0 -> M - F_0 = FPModule.from_free_module(self._free_module()) + F_0 = FPModule(self._free_module()) epsilon = Hom(F_0, self)(self.generators()) ret_complex.append(epsilon) @@ -1254,7 +1208,7 @@ def _print_progress(i, k): # f_1: F_1 -> F_0 _print_progress(1, k) - F_1 = FPModule.from_free_module(self._j.domain()) + F_1 = FPModule(self._j.domain()) pres = Hom(F_1, F_0)(tuple([ F_0(x.coefficients()) for x in self._j.values() ])) ret_complex.append(pres) @@ -1266,8 +1220,8 @@ def _print_progress(i, k): _print_progress(i, k) f = ret_complex[i-1] - ret_complex.append(FPModuleMorphism._resolve_kernel(f, top_dim=top_dim, - verbose=verbose)) + ret_complex.append(f._resolve_kernel(top_dim=top_dim, + verbose=verbose)) return ret_complex From 72e455ea30c98e5c5408bf8fa646ea28b430a2da Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 30 Jan 2022 10:07:40 +0900 Subject: [PATCH 185/253] We do not require the base algebra's base ring to be a field. --- src/sage/modules/fp_graded/element.py | 4 +- src/sage/modules/fp_graded/free_module.py | 47 +++++++++++---------- src/sage/modules/fp_graded/free_morphism.py | 17 ++++---- src/sage/modules/fp_graded/homspace.py | 8 ++-- src/sage/modules/fp_graded/module.py | 39 +++++++++-------- src/sage/modules/fp_graded/morphism.py | 7 ++- 6 files changed, 65 insertions(+), 57 deletions(-) diff --git a/src/sage/modules/fp_graded/element.py b/src/sage/modules/fp_graded/element.py index e559150d514..87f52b759ae 100755 --- a/src/sage/modules/fp_graded/element.py +++ b/src/sage/modules/fp_graded/element.py @@ -220,10 +220,10 @@ def vector_presentation(self): True """ # We cannot represent the zero element since it does not have a degree, - # and we therefore do not know which vector space it belongs to. + # and we therefore do not know which free module it belongs to. # # In this case, we could return the integer value 0 since coercion would - # place it inside any vector space. However, this will not work for + # place it inside any free module. However, this will not work for # homomorphisms, so we return None to be consistent. try: degree = self.lift_to_free().degree() diff --git a/src/sage/modules/fp_graded/free_module.py b/src/sage/modules/fp_graded/free_module.py index ae7700b88d7..23c8fb7b1b2 100755 --- a/src/sage/modules/fp_graded/free_module.py +++ b/src/sage/modules/fp_graded/free_module.py @@ -100,14 +100,14 @@ sage: x - x 0 -For every integer `n`, the set of module elements of degree `n` form a -vector space over the ground field `k`. A basis for this vector space can be -computed:: +For every integer `n`, the set of module elements of degree `n` form +a free module over the ground ring `k`. A basis for this free module +can be computed:: sage: M.basis_elements(5) (Sq(2,1)*g[0], Sq(5)*g[0], Sq(1,1)*g[1], Sq(4)*g[1]) -together with a corresponding vector space presentation:: +together with a corresponding free module presentation:: sage: M.vector_presentation(5) Vector space of dimension 4 over Finite Field of size 2 @@ -131,7 +131,7 @@ -------------------- Homomorphisms of free graded `A`-modules `M\to N` are linear maps of their -underlying `k`-vector spaces which commute with the `A`-module structure. +underlying free `k`-module which commute with the `A`-module structure. To create a homomorphism, first create the object modelling the set of all such homomorphisms using the free function ``Hom``:: @@ -146,9 +146,9 @@ in Category of finite dimensional graded modules with basis over mod 2 Steenrod algebra, milnor basis -Just as module elements, homomorphisms are created using the ()-method -of the homspace object. The only argument is a list of module elements in the -codomain, corresponding to the module generators of the domain:: +Just as module elements, homomorphisms are created using the homspace +object. The only argument is a list of module elements in the codomain, +corresponding to the module generators of the domain:: sage: values = [Sq(2)*c2, Sq(2)*Sq(1)*c2] sage: f = homspace(values) @@ -228,8 +228,8 @@ sage: f - f == 0 True -The restriction of a homomorphism to the vector space of `n`-dimensional module -elements is a linear transformation:: +The restriction of a homomorphism to the free module of `n`-dimensional +module elements is a linear transformation:: sage: f_4 = f.vector_presentation(4); f_4 Vector space morphism represented by the matrix: @@ -274,7 +274,7 @@ # **************************************************************************** from sage.misc.cachefunc import cached_method -from sage.modules.free_module import VectorSpace +from sage.modules.free_module import FreeModule from sage.modules.fp_graded.free_element import FreeGradedModuleElement from sage.rings.infinity import PlusInfinity from sage.categories.graded_modules import GradedModules @@ -597,12 +597,13 @@ def an_element(self, n=None): @cached_method def basis_elements(self, n): r""" - Return a basis for the vector space of degree ``n`` module elements. + Return a basis for the free module of degree ``n`` module elements. .. NOTE:: - This returns a basis as a vector space over the base field, - not a basis as a free module over the algebra. + Suppose ``self`` is a module over the graded algebra `A` with + base ring `R`. This returns a basis as a free module over `R`, + not a basis as a free module over `A`. INPUT: @@ -611,7 +612,7 @@ def basis_elements(self, n): OUTPUT: A sequence of homogeneous module elements of degree ``n``, which - is a basis for the vector space of all degree ``n`` module elements. + is a basis for the free module of all degree ``n`` module elements. .. SEEALSO:: @@ -710,7 +711,7 @@ def element_from_coordinates(self, coordinates, n): def __getitem__(self, n): r""" - A vector space isomorphic to the vector space of module elements of + A free module isomorphic to the free module of module elements of degree ``n``. EXAMPLES:: @@ -733,14 +734,14 @@ def __getitem__(self, n): @cached_method def vector_presentation(self, n): r""" - Return a vector space over the ground field of the module algebra + Return a free module over the ground ring of the module algebra isomorphic to the degree ``n`` elements of ``self``. - Let `\mathcal{k}` be the ground field of the algebra over this module - is defined, and let `M_n` be the vector space of module elements of + Let `\mathcal{k}` be the ground ring of the algebra over this module + is defined, and let `M_n` be the free module of module elements of degree ``n``. - The return value of this function is the vector space + The return value of this function is the free module `\mathcal{k}^{r}` where `r = dim(M_n)`. The isomorphism between `k^{r}` and `M_n` is given by the @@ -753,8 +754,8 @@ def vector_presentation(self, n): OUTPUT: - A vector space over the ground field of the algebra over which - ``self`` is defined, isomorphic to the vector space of module + A free module over the ground field of the algebra over which + ``self`` is defined, isomorphic to the free module of module elements of degree ``n``. .. SEEALSO:: @@ -773,7 +774,7 @@ def vector_presentation(self, n): sage: [M.vector_presentation(i).dimension() for i in range(-2, 9)] [0, 0, 1, 1, 1, 2, 1, 1, 1, 0, 0] """ - return VectorSpace(self.base_ring().base_ring(), len(self.basis_elements(n))) + return FreeModule(self.base_ring().base_ring(), len(self.basis_elements(n))) def generator(self, index): diff --git a/src/sage/modules/fp_graded/free_morphism.py b/src/sage/modules/fp_graded/free_morphism.py index 0678a62b052..599a71c29e2 100755 --- a/src/sage/modules/fp_graded/free_morphism.py +++ b/src/sage/modules/fp_graded/free_morphism.py @@ -483,12 +483,13 @@ def _repr_defn(self): def vector_presentation(self, n): r""" - The restriction of ``self`` to the domain module elements of degree ``n``. + Return the restriction of ``self`` to the domain module elements + of degree ``n``. - The restriction of a non-zero module homomorphism to the vector space of - module elements of degree `n` is a linear function into the vector space - of elements of degree `n+d` belonging to the codomain. Here `d` is the - degree of this homomorphism. + The restriction of a non-zero module homomorphism to the free module + of module elements of degree `n` is a linear function into the free + module of elements of degree `n+d` belonging to the codomain. + Here `d` is the degree of this homomorphism. When this homomorphism is zero, it has no well defined degree so the function cannot be presented since we do not know the degree of its @@ -500,10 +501,10 @@ def vector_presentation(self, n): OUTPUT: - A linear function of finite dimensional vector spaces over the + A linear function of finite dimensional free moduless over the ground field of the algebra for this module. The domain is isomorphic - to the vector space of domain elements of degree ``n`` of this free - module, via the choice of basis given by + to the free module of domain elements of degree ``n`` of ``self`` + via the choice of basis given by :meth:`sage.modules.fp_graded.free_module.FreeGradedModule.basis_elements`. If the morphism is zero, an error is raised. diff --git a/src/sage/modules/fp_graded/homspace.py b/src/sage/modules/fp_graded/homspace.py index 4a575fae33d..612314b7595 100755 --- a/src/sage/modules/fp_graded/homspace.py +++ b/src/sage/modules/fp_graded/homspace.py @@ -161,7 +161,7 @@ def an_element(self, n=0): def basis_elements(self, n): r""" - Compute a basis for the vector space of degree ``n`` morphisms. + Return a basis for the free module of degree ``n`` morphisms. INPUT: @@ -243,7 +243,7 @@ def identity(self): def _basis_elements(self, n, basis): r""" - Compute a basis for the vector space of degree ``n`` homomorphisms. + Return a basis for the free module of degree ``n`` homomorphisms. This function is private for use by :meth:`basis_elements` and :meth:`an_element`. @@ -443,11 +443,11 @@ def _trivial_case(): The return value if there are no non-trivial homomorphisms. ''' if basis: - # Since the vector space of homomorphisms is trivial, the basis + # Since the free module of homomorphisms is trivial, the basis # is the empty set. return [] else: - # Since the vector space of homomorphisms is trivial, it contains + # Since the free module of homomorphisms is trivial, it contains # only The trivial homomorphism return self.zero() diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index 63cc577ad9b..e81653d038b 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -55,13 +55,13 @@ from sage.modules.fp_graded.element import FPElement # Note that some of the methods below assume that the base ring is a -# field and that the graded algebra has a chosen vector space basis in +# field and that the graded algebra has a chosen free module basis in # each degree. See for example :meth:`basis_elements`, # :meth:`element_from_coordinates`, :meth:`__getitem__`, # :meth:`vector_presentation`, and possibly others. class FPModule(UniqueRepresentation, IndexedGenerators, Module): r""" - Create a finitely presented module over a connected graded algebra. + A finitely presented module over a connected graded algebra. INPUT: @@ -629,9 +629,12 @@ def an_element(self, n=None): @cached_method def basis_elements(self, n, verbose=False): r""" - A basis for the vector space of degree ``n`` module elements. - Note that this returns a basis as a vector space over the - base field. + Return a basis for the free module of degree ``n`` module elements. + + .. NOTE:: + + Suppose ``self`` is a module over the graded algebra `A` with + base ring `R`. This returns a basis as a free module over `R`. INPUT: @@ -642,7 +645,7 @@ def basis_elements(self, n, verbose=False): OUTPUT: A list of homogeneous module elements of degree ``n`` which is - a basis for the vector space of all degree ``n`` module elements. + a basis for the free module of all degree ``n`` module elements. .. SEEALSO:: @@ -686,8 +689,8 @@ def basis_elements(self, n, verbose=False): @cached_method def element_from_coordinates(self, coordinates, n): r""" - The module element in degree ``n`` having the given coordinates with - respect to the basis returned by :meth:`basis_elements`. + Return the module element in degree ``n`` having the given coordinates + with respect to the basis returned by :meth:`basis_elements`. This function is inverse to :meth:`sage.modules.fp_graded.element.FPElement.vector_presentation`. @@ -744,7 +747,7 @@ def element_from_coordinates(self, coordinates, n): def __getitem__(self, n): r""" - A basis for the vector space of degree ``n`` module elements. + Return a basis for the free module of degree ``n`` module elements. INPUT: @@ -753,7 +756,7 @@ def __getitem__(self, n): OUTPUT: A list of homogeneous module elements of degree ``n`` which is - a basis for the vector space of all degree ``n`` module elements. + a basis for the free module of all degree ``n`` module elements. EXAMPLES:: @@ -774,8 +777,8 @@ def __getitem__(self, n): @cached_method def vector_presentation(self, n, verbose=False): r""" - A vector space isomorphic to the vector space of module elements of - degree ``n``. + Return a free module isomorphic to the free module of module + elements of degree ``n``. INPUT: @@ -870,7 +873,7 @@ def _Hom_(self, Y, category): def generator_degrees(self): r""" - The degrees of the generators for ``self``. + Return the degrees of the generators for ``self``. EXAMPLES:: @@ -886,7 +889,7 @@ def generator_degrees(self): def generators(self): r""" - The generators of ``self``. + Return the generators of ``self``. EXAMPLES:: @@ -973,7 +976,7 @@ def relation(self, index): def min_presentation(self, top_dim=None, verbose=False): r""" - A minimal presentation of ``self``. + Return a minimal presentation of ``self``. OUTPUT: @@ -1019,7 +1022,7 @@ def min_presentation(self, top_dim=None, verbose=False): def suspension(self, t): r""" - The suspension of ``self`` by degree ``t``. + Return the suspension of ``self`` by degree ``t``. INPUT: @@ -1069,7 +1072,7 @@ def submodule_inclusion(self, spanning_elements): INPUT: - - ``spanning_elements`` -- an iterable of elements + - ``spanning_elements`` -- an iterable of elements OUTPUT: @@ -1109,7 +1112,7 @@ def submodule_inclusion(self, spanning_elements): def resolution(self, k, top_dim=None, verbose=False): r""" - A resolution of this module of length ``k``. + Return a resolution of this module of length ``k``. INPUT: diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py index 1fd81b76944..f02f6377756 100755 --- a/src/sage/modules/fp_graded/morphism.py +++ b/src/sage/modules/fp_graded/morphism.py @@ -621,7 +621,8 @@ def _repr_defn(self): @cached_method def vector_presentation(self, n): r""" - The restriction of ``self`` to the domain module elements of degree ``n``. + The restriction of ``self`` to the domain module elements + of degree ``n``. The restriction of a non-zero module homomorphism to the vectorspace of module elements of degree `n` is a linear function into the vectorspace @@ -638,7 +639,7 @@ def vector_presentation(self, n): OUTPUT: - A linear function of finite dimensional vector spaces over the + A linear function of finite dimensional free modules over the ground field of the algebra for this module. The domain is isomorphic to the vectorspace of domain elements of degree ``n`` of this free module, via the choice of basis given by @@ -950,6 +951,7 @@ def lift(self, f, verbose=False): True .. SEEALSO:: + :meth:`split` """ from sage.modules.free_module_element import vector @@ -1792,3 +1794,4 @@ def fp_module(self): return FPModule(self.base_ring(), self.codomain().generator_degrees(), tuple([r.coefficients() for r in self._values])) + From 11b37258a9c3fa8989f0e7c42bd839b643014a2a Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Sat, 29 Jan 2022 17:09:54 -0800 Subject: [PATCH 186/253] trac 32505: allow the resolution to be made up of maps between instances of free modules rather than finitely presented ones. --- src/sage/modules/fp_graded/module.py | 45 ++++++++++++-- src/sage/modules/fp_graded/morphism.py | 83 ++++++++++++++++++++++---- 2 files changed, 111 insertions(+), 17 deletions(-) diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index 63cc577ad9b..acb4f20a0e1 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -1107,7 +1107,7 @@ def submodule_inclusion(self, spanning_elements): return Hom(F, self)(spanning_elements).image() - def resolution(self, k, top_dim=None, verbose=False): + def resolution(self, k, top_dim=None, verbose=False, as_free=False): r""" A resolution of this module of length ``k``. @@ -1116,6 +1116,9 @@ def resolution(self, k, top_dim=None, verbose=False): - ``k`` -- an non-negative integer - ``verbose`` -- (default: ``False``) a boolean to control if log messages should be emitted + - ``as_free`` -- (default: ``False``) if ``True``, return as + many morphisms as possible (all but the 0th one) as + morphisms between free modules OUTPUT: @@ -1141,6 +1144,33 @@ def resolution(self, k, top_dim=None, verbose=False): EXAMPLES:: sage: from sage.modules.fp_graded.module import FPModule + + sage: E. = ExteriorAlgebra(QQ) + sage: triv = FPModule(E, [0], [[x], [y]]) # trivial module + sage: triv.res(3) + [Module morphism: + From: Finitely presented left module on 1 generator and 0 relations over The exterior algebra of rank 2 over Rational Field + To: Finitely presented left module on 1 generator and 2 relations over The exterior algebra of rank 2 over Rational Field + Defn: g[0] |--> g[0], + Module morphism: + From: Finitely presented left module on 2 generators and 0 relations over The exterior algebra of rank 2 over Rational Field + To: Finitely presented left module on 1 generator and 0 relations over The exterior algebra of rank 2 over Rational Field + Defn: g[1, 0] |--> x*g[0] + g[1, 1] |--> y*g[0], + Module morphism: + From: Finitely presented left module on 3 generators and 0 relations over The exterior algebra of rank 2 over Rational Field + To: Finitely presented left module on 2 generators and 0 relations over The exterior algebra of rank 2 over Rational Field + Defn: g[2, 0] |--> x*g[1, 0] + g[2, 1] |--> y*g[1, 0] + x*g[1, 1] + g[2, 2] |--> y*g[1, 1], + Module morphism: + From: Finitely presented left module on 4 generators and 0 relations over The exterior algebra of rank 2 over Rational Field + To: Finitely presented left module on 3 generators and 0 relations over The exterior algebra of rank 2 over Rational Field + Defn: g[3, 0] |--> x*g[2, 0] + g[3, 1] |--> y*g[2, 0] + x*g[2, 1] + g[3, 2] |--> y*g[2, 1] + x*g[2, 2] + g[3, 3] |--> y*g[2, 2]] + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) sage: M = FPModule(A2, [0,1], [[Sq(2), Sq(1)]]) sage: M.resolution(0) @@ -1188,6 +1218,12 @@ def resolution(self, k, top_dim=None, verbose=False): g[12] |--> Sq(0,1)*g[9] + Sq(2)*g[10]] sage: for i in range(len(res)-1): ....: assert (res[i]*res[i+1]).is_zero(), 'the result is not a complex' + + sage: res2 = M.resolution(2, as_free=True) + sage: [type(f) for f in res] + [, + ] + ] """ def _print_progress(i, k): if verbose: @@ -1213,8 +1249,6 @@ def _print_progress(i, k): ret_complex.append(pres) - from .morphism import FPModuleMorphism - # f_i: F_i -> F_i-1, for i > 1 for i in range(2, k+1): _print_progress(i, k) @@ -1223,5 +1257,8 @@ def _print_progress(i, k): ret_complex.append(f._resolve_kernel(top_dim=top_dim, verbose=verbose)) - return ret_complex + if as_free: + return ret_complex[0:1] + [f._lift_to_free_morphism() for f in ret_complex[1:]] + else: + return ret_complex diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py index 1fd81b76944..62f6878b001 100755 --- a/src/sage/modules/fp_graded/morphism.py +++ b/src/sage/modules/fp_graded/morphism.py @@ -23,10 +23,9 @@ from sage.categories.homset import End, Hom from sage.categories.morphism import Morphism -from sage.misc.cachefunc import cached_method +from sage.misc.cachefunc import cached_method, cached_function from sage.rings.infinity import PlusInfinity - def _create_relations_matrix(module, relations, source_degs, target_degs): r""" The action by the given relations can be written as multiplication by @@ -169,7 +168,7 @@ class FPModuleMorphism(Morphism): sage: w = Hom(Q, F)( (F((1, 0)), F((0, 1))) ) Traceback (most recent call last): - ... + ... ValueError: relation Sq(6)*g[2] + Sq(5)*g[3] is not sent to zero """ def __init__(self, parent, values): @@ -1487,10 +1486,9 @@ def _resolve_kernel(self, top_dim=None, verbose=False): .. NOTE:: - If the algebra for this module is finite and has a - ``top_class`` method, then no ``top_dim`` needs to be - specified in order to ensure that this function - terminates. + If the algebra for this module is finite, then no + ``top_dim`` needs to be specified in order to ensure that + this function terminates. TESTS:: @@ -1549,14 +1547,10 @@ def _resolve_kernel(self, top_dim=None, verbose=False): print ('The domain of the morphism is trivial, so there is nothing to resolve.') return j - # TODO: - # - # Handle algebras which are finite dimensional but which have - # no top_class method, for example exterior algebras. if not self.base_ring().dimension() < PlusInfinity(): limit = PlusInfinity() else: - limit = (self.base_ring().top_class().degree() + max(self.domain().generator_degrees())) + limit = _top_dim(self.base_ring()) + max(self.domain().generator_degrees()) if top_dim is not None: limit = min(top_dim, limit) @@ -1694,7 +1688,7 @@ def _resolve_image(self, top_dim=None, verbose=False): degree_values = [0] + [v.degree() for v in self._values if v] limit = PlusInfinity() if not self.base_ring().is_finite() else\ - (self.base_ring().top_class().degree() + max(degree_values)) + (_top_dim(self.base_ring()) + max(degree_values)) if top_dim is not None: limit = min(top_dim, limit) @@ -1792,3 +1786,66 @@ def fp_module(self): return FPModule(self.base_ring(), self.codomain().generator_degrees(), tuple([r.coefficients() for r in self._values])) + + + def _lift_to_free_morphism(self): + """ + If ``self`` is a map between finitely presented modules which are + actually free, then return this morphism as a + FreeGradedModuleMorphism. Otherwise raise an error. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.module import FPModule + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: M = FPModule(A2, [0], relations=[[Sq(1)]]) + sage: N = FPModule(A2, [0], relations=[[Sq(4)],[Sq(1)]]) + sage: f = Hom(M,N)([A2.Sq(3)*N.generator(0)]) + sage: f._lift_to_free_morphism() + Traceback (most recent call last): + ... + ValueError: the domain and/or codomain are not free + sage: MF = FPModule(A2, [0, 1]) + sage: f = Hom(MF, MF)([A2.Sq(3) * MF.generator(0), A2.Sq(0, 1) * MF.generator(1)]) + sage: f._lift_to_free_morphism() + Free module endomorphism of Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Defn: g[0] |--> Sq(3)*g[0] + g[1] |--> Sq(0,1)*g[1] + """ + if self.domain().relations() or self.codomain().relations(): + raise ValueError("the domain and/or codomain are not free") + M = self.domain()._free_module() + N = self.codomain()._free_module() + return Hom(M, N)([N(v.coefficients()) for v in self.values()]) + + +@cached_function +def _top_dim(algebra): + r""" + The top dimension of ``algebra`` + + This returns ``PlusInfinity`` if the algebra is + infinite-dimensional. If the algebra has a ``top_class`` + method, then it is used in the computation; otherwise the + computation may be slow. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.morphism import _top_dim + sage: E. = ExteriorAlgebra(QQ) + sage: _top_dim(E) + 3 + + sage: _top_dim(SteenrodAlgebra(2, profile=(3,2,1))) + 23 + """ + if not algebra.dimension() < PlusInfinity(): + return PlusInfinity() + try: + alg_top_dim = algebra.top_class().degree() + except AttributeError: + # This could be very slow, but it should handle the case + # when the algebra is finite-dimensional but has no + # top_class method, e.g., exterior algebras. + alg_top_dim = max(a.degree() for a in algebra.basis()) + return alg_top_dim From 6c1ab8dc9a5f2a932297bf5256dab88dbb5f27e1 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Sat, 29 Jan 2022 19:25:19 -0800 Subject: [PATCH 187/253] trac 32505: more fixes --- .../categories/graded_algebras_with_basis.py | 13 ++-- src/sage/categories/modules.py | 2 +- src/sage/modules/fp_graded/free_module.py | 63 ++++++++++--------- src/sage/modules/fp_graded/module.py | 24 +++---- 4 files changed, 54 insertions(+), 48 deletions(-) diff --git a/src/sage/categories/graded_algebras_with_basis.py b/src/sage/categories/graded_algebras_with_basis.py index 038365bdfb6..e53bb68ce47 100644 --- a/src/sage/categories/graded_algebras_with_basis.py +++ b/src/sage/categories/graded_algebras_with_basis.py @@ -88,8 +88,6 @@ def free_graded_module(self, generator_degrees, names=None): """ Create a finitely generated free graded module over ``self`` - This is only implemented when the ground ring is a field. - INPUTS: - ``generator_degrees`` -- tuple of integers defining the @@ -99,13 +97,13 @@ def free_graded_module(self, generator_degrees, names=None): ``names`` is a comma-separated string like ``'a, b, c'``, then those will be the names. Otherwise, for example if ``names`` is ``abc``, then the names will be - ``abc_{d,i}``. + ``abc[d,i]``. By default, if all generators are in distinct degrees, then the ``names`` of the generators will have the form - ``g_{d}`` where ``d`` is the degree of the generator. If + ``g[d]`` where ``d`` is the degree of the generator. If the degrees are not distinct, then the generators will be - called ``g_{d,i}`` where ``d`` is the degree and ``i`` is + called ``g[d,i]`` where ``d`` is the degree and ``i`` is its index in the list of generators in that degree. See :mod:`sage.modules.fp_graded.free_module` for more @@ -118,9 +116,12 @@ def free_graded_module(self, generator_degrees, names=None): sage: M = Cl.free_graded_module((0, 2, 3)) sage: M.gens() (g[0], g[2], g[3]) + sage: N. = Cl.free_graded_module((1, 2)) + sage: N.generators() + (xy, z) """ from sage.modules.fp_graded.free_module import FreeGradedModule - return FreeGradedModule(self, generator_degrees, names) + return FreeGradedModule(self, generator_degrees, names=names) class ElementMethods: diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index ef425254340..342e31d0c02 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -363,7 +363,7 @@ def FinitelyPresented(self): sage: A = SteenrodAlgebra(2) sage: from sage.modules.fp_graded.module import FPModule sage: FPModule(A, [0, 1], [[Sq(2), Sq(1)]]).category() - Category of finitely presented graded modules with basis over mod 2 Steenrod algebra, milnor basis + Category of finitely presented graded modules over mod 2 Steenrod algebra, milnor basis TESTS:: diff --git a/src/sage/modules/fp_graded/free_module.py b/src/sage/modules/fp_graded/free_module.py index ae7700b88d7..c32094d652d 100755 --- a/src/sage/modules/fp_graded/free_module.py +++ b/src/sage/modules/fp_graded/free_module.py @@ -1,15 +1,22 @@ r""" Finitely generated free graded left modules over connected graded algebras -Let `p` be a prime number. The mod `p` Steenrod algebra `A_p` -is a connected algebra over the finite field of `p` elements. All modules -presented here will be defined over `A_p`, or one of its sub-Hopf algebras. -E.g.:: +Let `A` be a connected graded algebra. Some methods here require in +addition that `A` be an algebra over a field and that Sage has a +description of a basis for `A`. + +For example, let `p` be a prime number. The mod `p` Steenrod algebra +`A_p` is a connected algebra over the finite field of `p` elements. +Many of the modules presented here will be defined over `A_p`, or one +of its sub-Hopf algebras. E.g.:: sage: A = SteenrodAlgebra(p=2) -However, the current implementation can use any connected graded algebra -that has a graded basis where each graded part is finite dimensional. +However, the current implementation can use any connected graded +algebra that has a graded basis where each graded part is finite +dimensional. Another good family is the exterior algebras:: + + sage: E. = ExteriorAlgebra(QQ) A free module is defined by the graded algebra and an ordered tuple of degrees for the generators:: @@ -20,10 +27,26 @@ Free graded left module on 2 generators over mod 2 Steenrod algebra, milnor basis -The resulting free module will have generators in the degrees as specified:: + sage: F. = E.free_graded_module((0,3,6)) + sage: F + Free graded left module on 3 generators over + The exterior algebra of rank 3 over Rational Field + +The resulting free modules will have generators in the degrees as specified:: sage: M.generator_degrees() (0, 1) + sage: F.generator_degrees() + (0, 3, 6) + +The default names for the generators are ``g[degree]`` if they are in +distinct degrees, ``g[degree, i]`` otherwise. They can be given other +names, as was done when creating the module ``F``:: + + sage: M.generators() + (g[0], g[1]) + sage: F.generators() + (a, b, c) The connectivity of a module over a connected graded algebra is the minimum degree of all its module generators. Thus, if the module is non-trivial, the @@ -45,26 +68,13 @@ where `a_i\in A_{n-\deg(g_i)}` for all `i`. The ordered set `\{a_i\}` is referred to as the coefficients of `x`. -Module elements are displayed by their algebra coefficients:: - - sage: M.an_element(n=5) - Sq(2,1)*g[0] + Sq(4)*g[1] - - sage: M.an_element(n=15) - Sq(0,0,0,1)*g[0] + Sq(1,2,1)*g[1] - -The generators are themselves elements of the module:: - - sage: M.generators() - (g[0], g[1]) - -Producing elements from a given set of coefficients is possible as usual:: +You can produce module elements from a given set of coefficients:: sage: coeffs = [Sq(5), Sq(1,1)] sage: x = M(coeffs); x Sq(5)*g[0] + Sq(1,1)*g[1] -The module action produces new elements:: +You can also use the module action:: sage: Sq(2) * x (Sq(4,1)+Sq(7))*g[0] + Sq(3,1)*g[1] @@ -95,11 +105,6 @@ sage: x + zero == x True -Finally, additive inverses exist:: - - sage: x - x - 0 - For every integer `n`, the set of module elements of degree `n` form a vector space over the ground field `k`. A basis for this vector space can be computed:: @@ -112,7 +117,7 @@ sage: M.vector_presentation(5) Vector space of dimension 4 over Finite Field of size 2 -Given any element, its coordinates with resepct to this basis can be computed:: +Given any element, its coordinates with respect to this basis can be computed:: sage: v = x.vector_presentation(); v (0, 1, 1, 0) @@ -133,7 +138,7 @@ Homomorphisms of free graded `A`-modules `M\to N` are linear maps of their underlying `k`-vector spaces which commute with the `A`-module structure. -To create a homomorphism, first create the object modelling the set of all +To create a homomorphism, first create the object modeling the set of all such homomorphisms using the free function ``Hom``:: sage: M = FreeGradedModule(A, (0,1)) diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index acb4f20a0e1..87fb850bc26 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -1,14 +1,14 @@ r""" Finitely presented graded modules -Let `R` be a connected graded algebra. A finitely presented module over `R` -is isomorphic to the cokernel of an `R`-linear homomorphism `f: F_1 \to F_0` -of finitely generated free modules: The generators of `F_0` corresponds to the -generators of the module, and the generators of `F_1` corresponds to its -relations, via the map `f`. - -The class constructor of this module class is given a set of generators and -relations, and uses them to construct a presentation, using the class +Let `R` be a connected graded algebra. A finitely presented module +over `R` is a module isomorphic to the cokernel of an `R`-linear +homomorphism `f: F_1 \to F_0` of finitely generated free modules: the +generators of `F_0` correspond to the generators of the module, and +the generators of `F_1` correspond to its relations, via the map `f`. + +The class constructor of this module class takes a set of generators and +relations and uses them to construct a presentation, using the class :class:`sage.modules.fp_graded.free_morphism.FreeGradedModuleMorphism`. This package was designed with homological algebra in mind, and its API @@ -1147,7 +1147,7 @@ def resolution(self, k, top_dim=None, verbose=False, as_free=False): sage: E. = ExteriorAlgebra(QQ) sage: triv = FPModule(E, [0], [[x], [y]]) # trivial module - sage: triv.res(3) + sage: triv.resolution(3) [Module morphism: From: Finitely presented left module on 1 generator and 0 relations over The exterior algebra of rank 2 over Rational Field To: Finitely presented left module on 1 generator and 2 relations over The exterior algebra of rank 2 over Rational Field @@ -1220,10 +1220,10 @@ def resolution(self, k, top_dim=None, verbose=False, as_free=False): ....: assert (res[i]*res[i+1]).is_zero(), 'the result is not a complex' sage: res2 = M.resolution(2, as_free=True) - sage: [type(f) for f in res] + sage: [type(f) for f in res2] [, - ] - ] + , + ] """ def _print_progress(i, k): if verbose: From 2e0518f314df9371277710745ae5b8b8ffb07553 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 30 Jan 2022 12:10:19 +0900 Subject: [PATCH 188/253] Using free modules where possible and improved compatibility. --- src/sage/modules/fp_graded/free_element.py | 19 ++ src/sage/modules/fp_graded/free_homspace.py | 70 +--- src/sage/modules/fp_graded/free_module.py | 24 +- src/sage/modules/fp_graded/free_morphism.py | 311 +----------------- src/sage/modules/fp_graded/homspace.py | 48 ++- src/sage/modules/fp_graded/module.py | 98 +++--- src/sage/modules/fp_graded/morphism.py | 347 +++++++++++++++----- 7 files changed, 402 insertions(+), 515 deletions(-) diff --git a/src/sage/modules/fp_graded/free_element.py b/src/sage/modules/fp_graded/free_element.py index be66a0206b6..97c0db1978e 100755 --- a/src/sage/modules/fp_graded/free_element.py +++ b/src/sage/modules/fp_graded/free_element.py @@ -256,3 +256,22 @@ def vector_presentation(self): return vector + def lift_to_free(self): + r""" + Return the lift of ``self`` to a free module, which is ``self`` + since the parent is a free module. + + This is included for compatibility with + :class:`~sage.modules.fp_graded.element.FPElement`. + + EXAMPLES:: + + sage: from sage.modules.fp_graded.free_module import * + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: M = FreeGradedModule(A2, (0,1)) + sage: x = M.an_element(7) + sage: x.lift_to_free() is x + True + """ + return self + diff --git a/src/sage/modules/fp_graded/free_homspace.py b/src/sage/modules/fp_graded/free_homspace.py index c5547a82723..3c5be7c7e85 100755 --- a/src/sage/modules/fp_graded/free_homspace.py +++ b/src/sage/modules/fp_graded/free_homspace.py @@ -40,65 +40,16 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.categories.homset import Homset from sage.misc.cachefunc import cached_method from sage.modules.fp_graded.free_morphism import FreeGradedModuleMorphism +from sage.modules.fp_graded.homspace import FPModuleHomspace -class FreeGradedModuleHomspace(Homset): +class FreeGradedModuleHomspace(FPModuleHomspace): """ Homspace between two free graded modules. """ Element = FreeGradedModuleMorphism - def _element_constructor_(self, values): - r""" - Construct an element of ``self``. - - This function is used internally by the call method when creating - homomorphisms. - - INPUT: - - - ``values`` -- a tuple of values (i.e. elements of the - codomain for this homset) corresponding bijectively to the generators - of the domain of this homset, or the zero integer constant - - OUTPUT: - - An instance of the morphism class. The returned morphism is defined - by mapping the module generators in the domain to the given values. - - EXAMPLES:: - - sage: from sage.modules.fp_graded.free_module import FreeGradedModule - sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) - sage: F = FreeGradedModule(A2, (1,3)) - sage: L = FreeGradedModule(A2, (2,5)) - sage: H = Hom(F, L) - - sage: values = (A2.Sq(4)*L.generator(0), A2.Sq(3)*L.generator(1)) - sage: f = H(values); f - Free module morphism: - From: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] - To: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] - Defn: g[1] |--> Sq(4)*g[2] - g[3] |--> Sq(3)*g[5] - - sage: H(0) - Free module morphism: - From: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] - To: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] - Defn: g[1] |--> 0 - g[3] |--> 0 - """ - from .free_morphism import FreeGradedModuleMorphism - if isinstance(values, FreeGradedModuleMorphism): - return values - elif values == 0 or all(v.is_zero() for v in values): - return self.zero() - else: - return self.element_class(self, values) - def _an_element_(self): r""" @@ -149,23 +100,6 @@ def identity(self): EXAMPLES:: - sage: from sage.modules.fp_graded.free_module import FreeGradedModule - sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) - sage: L = FreeGradedModule(A2, (2,3)) - sage: H = Hom(L, L) - sage: H.identity() - Free module endomorphism of Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] - Defn: g[2] |--> g[2] - g[3] |--> g[3] - - TESTS:: - - sage: F = FreeGradedModule(A2, (1,3)) - sage: H = Hom(F, L) - sage: H.identity() - Traceback (most recent call last): - ... - TypeError: this homspace does not consist of endomorphisms """ if self.is_endomorphism_set(): return self.element_class(self, self.codomain().generators()) diff --git a/src/sage/modules/fp_graded/free_module.py b/src/sage/modules/fp_graded/free_module.py index 23c8fb7b1b2..7ee3605269b 100755 --- a/src/sage/modules/fp_graded/free_module.py +++ b/src/sage/modules/fp_graded/free_module.py @@ -836,6 +836,11 @@ def _Hom_(self, Y, category): over mod 2 Steenrod algebra, milnor basis in Category of finite dimensional graded modules with basis over mod 2 Steenrod algebra, milnor basis + + sage: from sage.modules.fp_graded.module import FPModule + sage: F = FPModule(A, [1,3]) + sage: Hom(M, F) + Set of Morphisms from Free graded left module on 2 generators ... """ from .free_homspace import FreeGradedModuleHomspace return FreeGradedModuleHomspace(self, Y, category) @@ -868,23 +873,20 @@ def suspension(self, t): generator_degrees=tuple([g + t for g in self.generator_degrees()])) - def as_fp_module(self): + def has_relations(self): r""" - Create a finitely presented module from ``self``. - - OUTPUT: + Return ``False`` as this has no relations. - The finitely presented module having same set of generators - as this module, no relations. + This is for compatibility with + :class:`~sage.modules.fp_graded.module.FPModule`. EXAMPLES:: sage: from sage.modules.fp_graded.free_module import FreeGradedModule sage: A = SteenrodAlgebra(2) sage: F = FreeGradedModule(A, (-2,2,4)) - sage: F.as_fp_module() - Finitely presented left module on 3 generators and 0 relations over - mod 2 Steenrod algebra, milnor basis + sage: F.has_relations() + False """ - from .module import FPModule - return FPModule(self.base_ring(), self.generator_degrees(), ()) + return False + diff --git a/src/sage/modules/fp_graded/free_morphism.py b/src/sage/modules/fp_graded/free_morphism.py index 599a71c29e2..547a0bfc9e7 100755 --- a/src/sage/modules/fp_graded/free_morphism.py +++ b/src/sage/modules/fp_graded/free_morphism.py @@ -23,15 +23,14 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from inspect import isfunction - from sage.categories.homset import Hom from sage.categories.morphism import Morphism +from sage.modules.fp_graded.morphism import FPModuleMorphism - -class FreeGradedModuleMorphism(Morphism): +class FreeGradedModuleMorphism(FPModuleMorphism): r""" - Create a homomorphism between finitely generated free graded modules. + Create a homomorphism from a finitely generated free graded module + to a graded module. INPUT: @@ -92,31 +91,20 @@ def __init__(self, parent, values): if not isinstance(parent, FreeGradedModuleHomspace): raise TypeError('the parent (%s) must be a f.p. free module homset' % parent) - # Get the values. - C = parent.codomain() - D = parent.domain() - if isfunction(values): - _values = [C(values(g)) for g in D.generators()] - elif values == 0: - _values = len(D.generator_degrees())*[C(0)] - else: - _values = [C(a) for a in values] - - # Check the homomorphism is well defined. - if len(D.generator_degrees()) != len(_values): - raise ValueError('the number of values must equal the number of ' - 'generators in the domain; invalid argument: %s' % _values) + self._free_morphism = self + FPModuleMorphism.__init__(self, parent, values, check=False) # Compute the degree. - if all(v.is_zero() for v in _values): + if all(v.is_zero() for v in self._values): # The zero homomorphism does not get a degree. degree = None else: degrees = [] - for i, value in enumerate(_values): - if not value.is_zero(): - x = value.degree() - xx = D.generator_degrees()[i] + gen_deg = parent.domain().generator_degrees() + for i, val in enumerate(self._values): + if val: + x = val.degree() + xx = gen_deg[i] degrees.append(x - xx) degree = min(degrees) @@ -124,9 +112,6 @@ def __init__(self, parent, values): raise ValueError('ill-defined homomorphism: degrees do not match') self._degree = degree - self._values = tuple(_values) - - Morphism.__init__(self, parent) def degree(self): @@ -162,64 +147,6 @@ def degree(self): return self._degree - def values(self): - r""" - The values under ``self`` corresponding to the generators of - the domain module. - - OUTPUT: - - A sequence of elements of the codomain module. - - EXAMPLES:: - - sage: from sage.modules.fp_graded.free_module import FreeGradedModule - sage: A = SteenrodAlgebra(2) - sage: homspace = Hom(FreeGradedModule(A, (0,1)), FreeGradedModule(A, (2,))) - sage: N = homspace.codomain() - sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] - sage: f = homspace(values) - sage: f.values() - (Sq(5)*g[2], Sq(3,1)*g[2]) - sage: homspace.zero().values() - (0, 0) - """ - return self._values - - - def _richcmp_(self, other, op): - r""" - Compare this homomorphism to the given homomorphism. - - EXAMPLES:: - - sage: from sage.modules.fp_graded.free_module import FreeGradedModule - sage: A = SteenrodAlgebra(2) - sage: homspace = Hom(FreeGradedModule(A, (0,1)), FreeGradedModule(A, (2,))) - sage: N = homspace.codomain() - sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] - sage: f = homspace(values) - sage: f._richcmp_(f, op=2) - True - sage: f._richcmp_(f, op=3) - False - """ - try: - same = (self - other).is_zero() - except ValueError: - return False - - # Equality - if op == 2: - return same - - # Non-equality - if op == 3: - return not same - - return False - - def _add_(self, g): r""" The pointwise sum of `self`` and ``g``. @@ -264,120 +191,6 @@ def _add_(self, g): return self.parent()(v) - def _neg_(self): - r""" - The additive inverse of ``self`` with respect to the group - structure given by pointwise sum. - - EXAMPLES:: - - sage: from sage.modules.fp_graded.free_module import FreeGradedModule - sage: A = SteenrodAlgebra(2) - sage: homspace = Hom(FreeGradedModule(A, (0,1)), FreeGradedModule(A, (2,))) - sage: N = homspace.codomain() - sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] - sage: f = homspace(values) - sage: f_inverse = -f; f_inverse - Free module morphism: - From: Free graded left module on 2 generators over mod 2 Steenrod algebra, milnor basis - To: Free graded left module on 1 generator over mod 2 Steenrod algebra, milnor basis - Defn: g[0] |--> Sq(5)*g[2] - g[1] |--> Sq(3,1)*g[2] - sage: (f + f_inverse).is_zero() - True - """ - return self.parent()([-x for x in self._values]) - - - def _sub_(self, g): - r""" - The pointwise difference between ``self`` and ``g``. - - EXAMPLES:: - - sage: from sage.modules.fp_graded.free_module import FreeGradedModule - sage: A = SteenrodAlgebra(2) - sage: homspace = Hom(FreeGradedModule(A, (0,1)), FreeGradedModule(A, (2,))) - sage: N = homspace.codomain() - sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] - sage: f = homspace(values) - sage: values2 = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] - sage: g = homspace(values2) - sage: f - g == 0 - True - """ - return self + (-g) - - - # Define __mul__ rather than _mul_, since we want to allow - # "multiplication" by morphisms from different homsets. - def __mul__(self, g): - r""" - The composition of ``g`` followed by ``self``. - - EXAMPLES:: - - sage: from sage.modules.fp_graded.free_module import FreeGradedModule - sage: A = SteenrodAlgebra(2) - sage: M = FreeGradedModule(A, (0,1)) - sage: N = FreeGradedModule(A, (2,)) - sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] - sage: f = Hom(M, N)(values) - sage: values2 = [Sq(2)*M.generator(0)] - sage: g = Hom(N, M)(values2) - sage: fg = f * g; fg - Free module endomorphism of Free graded left module on 1 generator over mod 2 Steenrod algebra, milnor basis - Defn: g[2] |--> (Sq(4,1)+Sq(7))*g[2] - sage: fg.is_endomorphism() - True - - TESTS:: - - sage: fg == f.__mul__(g) - True - sage: from sage.modules.fp_graded.free_module import FreeGradedModule - sage: A = SteenrodAlgebra(2) - sage: M = FreeGradedModule(A, (0,1)) - sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] - sage: f = Hom(M, N)(values) - sage: f * f - Traceback (most recent call last): - ... - ValueError: morphisms are not composable - """ - if self.parent().domain() != g.parent().codomain(): - raise ValueError('morphisms are not composable') - homset = Hom(g.parent().domain(), self.parent().codomain()) - return homset([self(g(x)) for x in g.domain().generators()]) - - - def is_zero(self): - r""" - Decide if ``self`` is trivial. - - OUTPUT: - - The boolean value ``True`` if this homomorphism is trivial, and - ``False`` otherwise. - - EXAMPLES:: - - sage: from sage.modules.fp_graded.free_module import FreeGradedModule - sage: A = SteenrodAlgebra(2) - sage: M = FreeGradedModule(A, (0,1)) - sage: N = FreeGradedModule(A, (2,)) - sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] - sage: f = Hom(M, N)(values) - sage: f.is_zero() - False - sage: (f-f).is_zero() - True - """ - return all(not v for v in self._values) - - __bool__ = is_zero - - def is_identity(self): r""" Return if ``self`` is the identity endomorphism. @@ -462,106 +275,6 @@ def _repr_type(self): return "Free module" - def _repr_defn(self): - """ - TESTS:: - - sage: from sage.modules.fp_graded.free_module import FreeGradedModule - sage: A = SteenrodAlgebra(2) - sage: F1 = FreeGradedModule(A, (4,5), names='b') - sage: F2 = FreeGradedModule(A, (3,4), names='c') - sage: H = Hom(F1, F2) - sage: f = H((F2((Sq(4), 0)), F2((0, Sq(4))))) - sage: print(f._repr_defn()) - b[4] |--> Sq(4)*c[3] - b[5] |--> Sq(4)*c[4] - """ - s = '\n'.join(['%s |--> %s'%(x, y) for (x, y) in - zip(self.domain().generators(), self._values)]) - return s - - - def vector_presentation(self, n): - r""" - Return the restriction of ``self`` to the domain module elements - of degree ``n``. - - The restriction of a non-zero module homomorphism to the free module - of module elements of degree `n` is a linear function into the free - module of elements of degree `n+d` belonging to the codomain. - Here `d` is the degree of this homomorphism. - - When this homomorphism is zero, it has no well defined degree so the - function cannot be presented since we do not know the degree of its - codomain. In this case, an error is raised. - - INPUT: - - - ``n`` -- an integer degree - - OUTPUT: - - A linear function of finite dimensional free moduless over the - ground field of the algebra for this module. The domain is isomorphic - to the free module of domain elements of degree ``n`` of ``self`` - via the choice of basis given by - :meth:`sage.modules.fp_graded.free_module.FreeGradedModule.basis_elements`. - If the morphism is zero, an error is raised. - - .. SEEALSO:: - - :meth:`sage.modules.fp_graded.free_module.FreeGradedModule.vector_presentation`, - :meth:`sage.modules.fp_graded.free_module.FreeGradedModule.basis_elements`. - - EXAMPLES:: - - sage: from sage.modules.fp_graded.free_module import FreeGradedModule - sage: A = SteenrodAlgebra(2) - sage: M = FreeGradedModule(A, (0,1)) - sage: N = FreeGradedModule(A, (2,)) - sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] - sage: f = Hom(M, N)(values) - sage: f.vector_presentation(0) - Vector space morphism represented by the matrix: - [0 1] - Domain: Vector space of dimension 1 over Finite Field of size 2 - Codomain: Vector space of dimension 2 over Finite Field of size 2 - sage: f.vector_presentation(1) - Vector space morphism represented by the matrix: - [0 0 0] - [0 1 0] - Domain: Vector space of dimension 2 over Finite Field of size 2 - Codomain: Vector space of dimension 3 over Finite Field of size 2 - sage: f.vector_presentation(2) - Vector space morphism represented by the matrix: - [0 0 1 1] - [0 0 0 0] - Domain: Vector space of dimension 2 over Finite Field of size 2 - Codomain: Vector space of dimension 4 over Finite Field of size 2 - - TESTS:: - - sage: F = FreeGradedModule(A, (0,)) - sage: z = Hom(F, F)([0]) - sage: z.is_zero() - True - sage: z.vector_presentation(0) - Traceback (most recent call last): - ... - ValueError: the zero map has no vector presentation - """ - # The trivial map has no degree, so we can not create the codomain - # of the linear transformation. - if self.is_zero(): - raise ValueError("the zero map has no vector presentation") - - D_n = self.domain().vector_presentation(n) - C_n = self.codomain().vector_presentation(n + self.degree()) - - values = [self(e) for e in self.domain().basis_elements(n)] - return Hom(D_n, C_n)([C_n.zero() if e.is_zero() else e.vector_presentation() - for e in values]) - def fp_module(self): r""" Create a finitely presented module from ``self``. diff --git a/src/sage/modules/fp_graded/homspace.py b/src/sage/modules/fp_graded/homspace.py index 612314b7595..f7af1770516 100755 --- a/src/sage/modules/fp_graded/homspace.py +++ b/src/sage/modules/fp_graded/homspace.py @@ -111,10 +111,32 @@ def _element_constructor_(self, values): sage: homset(0) == 0 True + + TESTS:: + + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: F = A2.free_graded_module((1,3)) + sage: L = A2.free_graded_module((2,5)) + sage: H = Hom(F, L) + + sage: values = (A2.Sq(4)*L.generator(0), A2.Sq(3)*L.generator(1)) + sage: f = H(values); f + Free module morphism: + From: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + To: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Defn: g[1] |--> Sq(4)*g[2] + g[3] |--> Sq(3)*g[5] + + sage: H(0) + Free module morphism: + From: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + To: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Defn: g[1] |--> 0 + g[3] |--> 0 """ if isinstance(values, self.element_class): return values - elif values == 0: + elif values == 0 or all(v.is_zero() for v in values): return self.zero() else: return self.element_class(self, values) @@ -209,7 +231,7 @@ def zero(self): def identity(self): r""" - Create The identity homomorphism + Return the identity homomorphism. EXAMPLES:: @@ -234,6 +256,28 @@ def identity(self): Traceback (most recent call last): ... TypeError: this homspace does not consist of endomorphisms + + An example with free graded modules:: + + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: L = A2.free_graded_module((2,3)) + sage: H = Hom(L, L) + sage: H.identity() + Free module endomorphism of Free graded left module on 2 generators + over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Defn: g[2] |--> g[2] + g[3] |--> g[3] + + TESTS:: + + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: L = A2.free_graded_module((2,3)) + sage: F = A2.free_graded_module((1,3)) + sage: H = Hom(F, L) + sage: H.identity() + Traceback (most recent call last): + ... + TypeError: this homspace does not consist of endomorphisms """ if self.is_endomorphism_set(): return self.element_class(self, self.codomain().generators()) diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index 99c6a138fa6..b0a06619bac 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -856,14 +856,18 @@ def _Hom_(self, Y, category): sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) - sage: F = FPModule(A, [1,3]); - sage: L = FPModule(A, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]); + sage: F = FPModule(A, [1,3]) + sage: L = FPModule(A, [2,3], [[Sq(2),Sq(1)], [0,Sq(2)]]) - sage: homset = Hom(F, L); homset + sage: Hom(F, L) + Set of Morphisms from Finitely presented left module on 2 generators ... + + sage: M = A.free_graded_module((2,1)) + sage: Hom(F, M) Set of Morphisms from Finitely presented left module on 2 generators ... """ from .homspace import FPModuleHomspace - if not isinstance(Y, self.__class__): + if not isinstance(Y, (FPModule, FreeGradedModule)): raise ValueError('cannot create homspace between incompatible types:\n%s ->\n%s' % (self.__class__, type(Y))) if Y.base_ring() != self.base_ring(): raise ValueError('the modules are not defined over the same base ring') @@ -1110,18 +1114,15 @@ def submodule_inclusion(self, spanning_elements): return Hom(F, self)(spanning_elements).image() - def resolution(self, k, top_dim=None, verbose=False, as_free=False): + def resolution(self, k, top_dim=None, verbose=False): r""" - Return a resolution of this module of length ``k``. + Return a free resolution of this module of length ``k``. INPUT: - ``k`` -- an non-negative integer - ``verbose`` -- (default: ``False``) a boolean to control if log messages should be emitted - - ``as_free`` -- (default: ``False``) if ``True``, return as - many morphisms as possible (all but the 0th one) as - morphisms between free modules OUTPUT: @@ -1150,25 +1151,25 @@ def resolution(self, k, top_dim=None, verbose=False, as_free=False): sage: E. = ExteriorAlgebra(QQ) sage: triv = FPModule(E, [0], [[x], [y]]) # trivial module - sage: triv.res(3) - [Module morphism: - From: Finitely presented left module on 1 generator and 0 relations over The exterior algebra of rank 2 over Rational Field + sage: triv.resolution(3) + [Free module morphism: + From: Free graded left module on 1 generator over The exterior algebra of rank 2 over Rational Field To: Finitely presented left module on 1 generator and 2 relations over The exterior algebra of rank 2 over Rational Field Defn: g[0] |--> g[0], - Module morphism: - From: Finitely presented left module on 2 generators and 0 relations over The exterior algebra of rank 2 over Rational Field - To: Finitely presented left module on 1 generator and 0 relations over The exterior algebra of rank 2 over Rational Field + Free module morphism: + From: Free graded left module on 2 generators over The exterior algebra of rank 2 over Rational Field + To: Free graded left module on 1 generator over The exterior algebra of rank 2 over Rational Field Defn: g[1, 0] |--> x*g[0] g[1, 1] |--> y*g[0], - Module morphism: - From: Finitely presented left module on 3 generators and 0 relations over The exterior algebra of rank 2 over Rational Field - To: Finitely presented left module on 2 generators and 0 relations over The exterior algebra of rank 2 over Rational Field + Free module morphism: + From: Free graded left module on 3 generators over The exterior algebra of rank 2 over Rational Field + To: Free graded left module on 2 generators over The exterior algebra of rank 2 over Rational Field Defn: g[2, 0] |--> x*g[1, 0] g[2, 1] |--> y*g[1, 0] + x*g[1, 1] g[2, 2] |--> y*g[1, 1], - Module morphism: - From: Finitely presented left module on 4 generators and 0 relations over The exterior algebra of rank 2 over Rational Field - To: Finitely presented left module on 3 generators and 0 relations over The exterior algebra of rank 2 over Rational Field + Free module morphism: + From: Free graded left module on 4 generators over The exterior algebra of rank 2 over Rational Field + To: Free graded left module on 3 generators over The exterior algebra of rank 2 over Rational Field Defn: g[3, 0] |--> x*g[2, 0] g[3, 1] |--> y*g[2, 0] + x*g[2, 1] g[3, 2] |--> y*g[2, 1] + x*g[2, 2] @@ -1177,8 +1178,8 @@ def resolution(self, k, top_dim=None, verbose=False, as_free=False): sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) sage: M = FPModule(A2, [0,1], [[Sq(2), Sq(1)]]) sage: M.resolution(0) - [Module morphism: - From: Finitely presented left module on 2 generators and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + [Free module morphism: + From: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] To: Finitely presented left module on 2 generators and 1 relation over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] Defn: g[0] |--> g[0] g[1] |--> g[1]] @@ -1196,37 +1197,41 @@ def resolution(self, k, top_dim=None, verbose=False, as_free=False): sage: len(res) 5 sage: res - [Module morphism: - From: Finitely presented left module on 2 generators and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + [Free module morphism: + From: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] To: Finitely presented left module on 2 generators and 1 relation over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] Defn: g[0] |--> g[0] g[1] |--> g[1], - Module morphism: - From: Finitely presented left module on 1 generator and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] - To: Finitely presented left module on 2 generators and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Free module morphism: + From: Free graded left module on 1 generator over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + To: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] Defn: g[2] |--> Sq(2)*g[0] + Sq(1)*g[1], - Module morphism: - From: Finitely presented left module on 1 generator and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] - To: Finitely presented left module on 1 generator and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Free module morphism: + From: Free graded left module on 1 generator over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + To: Free graded left module on 1 generator over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] Defn: g[8] |--> Sq(3,1)*g[2], - Module morphism: - From: Finitely presented left module on 2 generators and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] - To: Finitely presented left module on 1 generator and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Free module morphism: + From: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + To: Free graded left module on 1 generator over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] Defn: g[9] |--> Sq(1)*g[8] g[10] |--> Sq(2)*g[8], - Module morphism: - From: Finitely presented left module on 2 generators and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] - To: Finitely presented left module on 2 generators and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Free module morphism: + From: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + To: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] Defn: g[10] |--> Sq(1)*g[9] g[12] |--> Sq(0,1)*g[9] + Sq(2)*g[10]] sage: for i in range(len(res)-1): ....: assert (res[i]*res[i+1]).is_zero(), 'the result is not a complex' - sage: res2 = M.resolution(2, as_free=True) - sage: [type(f) for f in res] - [, - ] - ] + TESTS:: + + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: M = FPModule(A2, [0,1], [[Sq(2), Sq(1)]]) + sage: res2 = M.resolution(2) + sage: [type(f) for f in res2] + [, + , + ] """ def _print_progress(i, k): if verbose: @@ -1238,7 +1243,7 @@ def _print_progress(i, k): ret_complex = [] # Epsilon: F_0 -> M - F_0 = FPModule(self._free_module()) + F_0 = self._free_module() epsilon = Hom(F_0, self)(self.generators()) ret_complex.append(epsilon) @@ -1247,7 +1252,7 @@ def _print_progress(i, k): # f_1: F_1 -> F_0 _print_progress(1, k) - F_1 = FPModule(self._j.domain()) + F_1 = self._j.domain() pres = Hom(F_1, F_0)(tuple([ F_0(x.coefficients()) for x in self._j.values() ])) ret_complex.append(pres) @@ -1260,8 +1265,5 @@ def _print_progress(i, k): ret_complex.append(f._resolve_kernel(top_dim=top_dim, verbose=verbose)) - if as_free: - return ret_complex[0:1] + [f._lift_to_free_morphism() for f in ret_complex[1:]] - else: - return ret_complex + return ret_complex diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py index 5e23c33a96d..9cd1fab7010 100755 --- a/src/sage/modules/fp_graded/morphism.py +++ b/src/sage/modules/fp_graded/morphism.py @@ -21,10 +21,13 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +from inspect import isfunction + from sage.categories.homset import End, Hom from sage.categories.morphism import Morphism from sage.misc.cachefunc import cached_method, cached_function -from sage.rings.infinity import PlusInfinity +from sage.misc.lazy_attribute import lazy_attribute +from sage.rings.infinity import infinity def _create_relations_matrix(module, relations, source_degs, target_degs): r""" @@ -158,9 +161,11 @@ class FPModuleMorphism(Morphism): sage: A = SteenrodAlgebra(2) sage: F = FPModule(A, [2,3]) sage: Q = FPModule(A, [2,3], relations=[[Sq(6), Sq(5)]]) - sage: m = Hom(F, Q)( (F((Sq(1), 0)), F((0, 1))) ) + sage: v1 = Q((Sq(1), 0)) + sage: v2 = Q((0, 1)) + sage: m = Hom(F, Q)( (v1, v2) ) Traceback (most recent call last): - ... + ... ValueError: ill-defined homomorphism: degrees do not match Trying to map the generators of a non-free module into a @@ -171,7 +176,7 @@ class FPModuleMorphism(Morphism): ... ValueError: relation Sq(6)*g[2] + Sq(5)*g[3] is not sent to zero """ - def __init__(self, parent, values): + def __init__(self, parent, values, check=True): r""" Create a homomorphism between finitely presented graded modules. @@ -195,19 +200,61 @@ def __init__(self, parent, values): if not isinstance(parent, FPModuleHomspace): raise TypeError('parent (=%s) must be a fp module hom space' % parent) - Homspace = Hom(parent.domain()._j.codomain(), parent.codomain()._j.codomain()) - self.free_morphism = Homspace([v.lift_to_free() for v in values]) + # Get the values. + C = parent.codomain() + D = parent.domain() + if isfunction(values): + values = [C(values(g)) for g in D.generators()] + elif not values: + values = len(D.generator_degrees()) * [C.zero()] + else: + values = [C(a) for a in values] + + # Check the homomorphism is well defined. + if len(D.generator_degrees()) != len(values): + raise ValueError('the number of values must equal the number of ' + 'generators in the domain; invalid argument: %s' % values) + self._values = tuple(values) # Call the base class constructor. Morphism.__init__(self, parent) # Check that the homomorphism is well defined. - for relation in parent.domain().relations(): - # The relation is an element in the free part of the domain. - img = self.free_morphism(relation) - if parent.codomain()(img): - raise ValueError('relation %s is not sent to zero' % relation) + if check: + self._free_morphism + for relation in parent.domain().relations(): + # The relation is an element in the free part of the domain. + img = self._free_morphism(relation) + if parent.codomain()(img): + raise ValueError('relation %s is not sent to zero' % relation) + + + @lazy_attribute + def _free_morphism(self): + """ + Return the lifted morphism between free modules. + + TESTS:: + + sage: from sage.modules.fp_graded.module import FPModule + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) + sage: M = FPModule(A2, [0], relations=[[Sq(1)]]) + sage: N = FPModule(A2, [0], relations=[[Sq(4)],[Sq(1)]]) + sage: f = Hom(M,N)([A2.Sq(3)*N.generator(0)]) + sage: f._free_morphism + Free module endomorphism of Free graded left module on 1 generator + over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Defn: g[0] |--> Sq(3)*g[0] + """ + P = self.parent() + from sage.modules.fp_graded.free_module import FreeGradedModule + if isinstance(P.codomain(), FreeGradedModule): + Homspace = Hom(P.domain()._j.codomain(), P.codomain()) + return Homspace(self._values) + Homspace = Hom(P.domain()._j.codomain(), P.codomain()._j.codomain()) + return Homspace([v.lift_to_free() for v in self._values]) def change_ring(self, algebra): @@ -290,7 +337,7 @@ def degree(self): if self.is_zero(): # The zero morphism has no degree. raise ValueError("the zero morphism does not have a well-defined degree") - return self.free_morphism.degree() + return self._free_morphism.degree() def values(self): @@ -303,7 +350,7 @@ def values(self): EXAMPLES:: - sage: from sage.modules.fp_graded.module import * + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) sage: M = FPModule(A, [0,1], [[Sq(2), Sq(1)]]) sage: N = FPModule(A, [2], [[Sq(4)]]) @@ -317,6 +364,15 @@ def values(self): sage: homspace.zero().values() (0, 0) + + sage: homspace = Hom(A.free_graded_module((0,1)), A.free_graded_module((2,))) + sage: N = homspace.codomain() + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: f = homspace(values) + sage: f.values() + (Sq(5)*g[2], Sq(3,1)*g[2]) + sage: homspace.zero().values() + (0, 0) """ return self._values @@ -338,6 +394,15 @@ def _richcmp_(self, other, op): True sage: f._richcmp_(f, op=3) False + + sage: homspace = Hom(A.free_graded_module((0,1)), A.free_graded_module((2,))) + sage: N = homspace.codomain() + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: f = homspace(values) + sage: f._richcmp_(f, op=2) + True + sage: f._richcmp_(f, op=3) + False """ try: same = (self - other).is_zero() @@ -373,13 +438,14 @@ def __add__(self, g): sage: A = SteenrodAlgebra(2) sage: M = FPModule(A, [0,1], [[Sq(2), Sq(1)]]) sage: N = FPModule(A, [2], [[Sq(4)]]) + sage: v = N.generator(0) sage: homspace = Hom(M, N) - sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: values = [Sq(5)*v, Sq(3,1)*v] sage: f = homspace(values) - sage: ff = f.__add__(f) + sage: ff = f + f sage: ff.is_zero() True - sage: ff.__add__(f) == f + sage: ff + f == f True """ if self.domain() != g.domain(): @@ -405,20 +471,36 @@ def __neg__(self): EXAMPLES:: - sage: from sage.modules.fp_graded.module import * + sage: from sage.modules.fp_graded.module import FPModule sage: A = SteenrodAlgebra(2) sage: M = FPModule(A, [0,1], [[Sq(2), Sq(1)]]) sage: N = FPModule(A, [2], [[Sq(4)]]) + sage: v = N.generator(0) sage: homspace = Hom(M, N) - sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: values = [Sq(5)*v, Sq(3,1)*v] sage: f = homspace(values) - sage: f_inverse = f.__neg__(); f_inverse + sage: f_neg = -f; f_neg Module morphism: From: Finitely presented left module on 2 generators and 1 relation over mod 2 Steenrod algebra, milnor basis To: Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis Defn: g[0] |--> Sq(5)*g[2] g[1] |--> Sq(3,1)*g[2] - sage: (f + f_inverse).is_zero() + sage: (f + f_neg).is_zero() + True + + sage: N = A.free_graded_module((2,)) + sage: v = N.generator(0) + sage: homspace = Hom(A.free_graded_module((0,1)), N) + sage: N = homspace.codomain() + sage: values = [Sq(5)*v, Sq(3,1)*v] + sage: f = homspace(values) + sage: f_neg = -f; f_neg + Free module morphism: + From: Free graded left module on 2 generators over mod 2 Steenrod algebra, milnor basis + To: Free graded left module on 1 generator over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> Sq(5)*g[2] + g[1] |--> Sq(3,1)*g[2] + sage: (f + f_neg).is_zero() True """ return self.parent()([-x for x in self._values]) @@ -437,7 +519,7 @@ def __sub__(self, g): sage: N = FPModule(A, [0], [[Sq(4)]]) sage: f = Hom(M, N)( [Sq(3)*N.generator(0)] ) sage: g = Hom(M, N)( [Sq(0,1)*N.generator(0)] ) - sage: f.__sub__(g) + sage: f - g Module morphism: From: Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis To: Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis @@ -445,11 +527,21 @@ def __sub__(self, g): sage: f = Hom(M, N)( [Sq(4)*N.generator(0)] ) # the zero map sage: g = Hom(M, N)( [Sq(1,1)*N.generator(0)] ) - sage: f.__sub__(g) + sage: f - g Module morphism: From: Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis To: Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis Defn: g[0] |--> Sq(1,1)*g[0] + + sage: N = A.free_graded_module((2,)) + sage: v = N.generator(0) + sage: homspace = Hom(A.free_graded_module((0,1)), N) + sage: values = [Sq(5)*v, Sq(3,1)*v] + sage: f = homspace(values) + sage: values2 = [Sq(5)*v, Sq(3,1)*v] + sage: g = homspace(values2) + sage: f - g == 0 + True """ return self.__add__(g.__neg__()) @@ -466,12 +558,25 @@ def __mul__(self, g): sage: N = FPModule(A, [0], [[Sq(2,2)]]) sage: f = Hom(M, N)( [Sq(2)*N.generator(0)] ) sage: g = Hom(N, M)( [Sq(2,2)*M.generator(0)] ) - sage: fg = f.__mul__(g); fg + sage: fg = f * g; fg Module endomorphism of Finitely presented left module on 1 generator and 1 relation over mod 2 Steenrod algebra, milnor basis Defn: g[0] |--> (Sq(0,1,1)+Sq(1,3)+Sq(3,0,1))*g[0] sage: fg.is_endomorphism() True + sage: M = A.free_graded_module((0,1)) + sage: N = A.free_graded_module((2,)) + sage: v = N.generator(0) + sage: values = [Sq(5)*v, Sq(3,1)*v] + sage: f = Hom(M, N)(values) + sage: values2 = [Sq(2)*v] + sage: g = Hom(N, M)(values2) + sage: fg = f * g; fg + Free module endomorphism of Free graded left module on 1 generator over mod 2 Steenrod algebra, milnor basis + Defn: g[2] |--> (Sq(4,1)+Sq(7))*g[2] + sage: fg.is_endomorphism() + True + TESTS:: sage: from sage.modules.fp_graded.free_module import * @@ -479,7 +584,16 @@ def __mul__(self, g): sage: M = FPModule(A, (0,1)) sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] sage: f = Hom(M, N)(values) - sage: f.__mul__(f) + sage: f * f + Traceback (most recent call last): + ... + ValueError: morphisms not composable + + sage: M = A.free_graded_module((0,1)) + sage: N = A.free_graded_module((2,)) + sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] + sage: f = Hom(M, N)(values) + sage: f * f Traceback (most recent call last): ... ValueError: morphisms not composable @@ -513,6 +627,16 @@ def is_zero(self): sage: (f-f).is_zero() True + + sage: M = A.free_graded_module((0,1)) + sage: N = A.free_graded_module((2,)) + sage: v = N.generator(0) + sage: values = [Sq(5)*v, Sq(3,1)*v] + sage: f = Hom(M, N)(values) + sage: f.is_zero() + False + sage: (f-f).is_zero() + True """ return all(x.is_zero() for x in self._values) @@ -580,7 +704,7 @@ def __call__(self, x): if x.parent() != self.domain(): raise ValueError('cannot evaluate morphism on element not in domain') - return self.codomain()(self.free_morphism(x.lift_to_free())) + return self.codomain()(self._free_morphism(x.lift_to_free())) def _repr_type(self): @@ -611,6 +735,15 @@ def _repr_defn(self): sage: f = Hom(M,N)([A2.Sq(3)*N.generator(0)]) sage: f._repr_defn() 'g[0] |--> Sq(3)*g[0]' + + sage: A = SteenrodAlgebra(2) + sage: F1 = A.free_graded_module((4,5), names='b') + sage: F2 = A.free_graded_module((3,4), names='c') + sage: H = Hom(F1, F2) + sage: f = H((F2((Sq(4), 0)), F2((0, Sq(4))))) + sage: print(f._repr_defn()) + b[4] |--> Sq(4)*c[3] + b[5] |--> Sq(4)*c[4] """ s = '\n'.join(['%s |--> %s'%(x, y) for (x, y) in zip(self.domain().generators(), self._values)]) @@ -620,17 +753,17 @@ def _repr_defn(self): @cached_method def vector_presentation(self, n): r""" - The restriction of ``self`` to the domain module elements + Return the restriction of ``self`` to the domain module elements of degree ``n``. - The restriction of a non-zero module homomorphism to the vectorspace of - module elements of degree `n` is a linear function into the vectorspace - of elements of degree `n+d` belonging to the codomain. Here `d` is the - degree of this homomorphism. + The restriction of a non-zero module homomorphism to the free module + of module elements of degree `n` is a linear function into the free + module of elements of degree `n+d` belonging to the codomain. + Here `d` is the degree of this homomorphism. When this homomorphism is zero, it has no well defined degree so the function cannot be presented since we do not know the degree of its - codomain. In this case, the return value is ``None``. + codomain. In this case, an error is raised. INPUT: @@ -638,17 +771,19 @@ def vector_presentation(self, n): OUTPUT: - A linear function of finite dimensional free modules over the + A linear function of finite dimensional free moduless over the ground field of the algebra for this module. The domain is isomorphic - to the vectorspace of domain elements of degree ``n`` of this free - module, via the choice of basis given by + to the free module of domain elements of degree ``n`` of ``self`` + via the choice of basis given by :meth:`sage.modules.fp_graded.free_module.FreeGradedModule.basis_elements`. - If the morphism is zero, the value ``None`` is returned. + If the morphism is zero, an error is raised. .. SEEALSO:: :meth:`sage.modules.fp_graded.module.FPModule.vector_presentation`, - :meth:`sage.modules.fp_graded.module.FPModule.basis_elements`. + :meth:`sage.modules.fp_graded.module.FPModule.basis_elements`, + :meth:`sage.modules.fp_graded.free_module.FreeGradedModule.vector_presentation`, + :meth:`sage.modules.fp_graded.free_module.FreeGradedModule.basis_elements`. EXAMPLES:: @@ -700,6 +835,28 @@ def vector_presentation(self, n): [0 0 1 0] [0 0 0 1] + sage: M = A.free_graded_module((0,1)) + sage: N = A.free_graded_module((2,)) + sage: v = N.generator(0) + sage: values = [Sq(5)*v, Sq(3,1)*v] + sage: f = Hom(M, N)(values) + sage: f.vector_presentation(0) + Vector space morphism represented by the matrix: + [0 1] + Domain: Vector space of dimension 1 over Finite Field of size 2 + Codomain: Vector space of dimension 2 over Finite Field of size 2 + sage: f.vector_presentation(1) + Vector space morphism represented by the matrix: + [0 0 0] + [0 1 0] + Domain: Vector space of dimension 2 over Finite Field of size 2 + Codomain: Vector space of dimension 3 over Finite Field of size 2 + sage: f.vector_presentation(2) + Vector space morphism represented by the matrix: + [0 0 1 1] + [0 0 0 0] + Domain: Vector space of dimension 2 over Finite Field of size 2 + Codomain: Vector space of dimension 4 over Finite Field of size 2 TESTS:: @@ -708,13 +865,15 @@ def vector_presentation(self, n): sage: z = Hom(F, Q)([Sq(2)*Q.generator(0)]) sage: z.is_zero() True - sage: z.vector_presentation(0) is None - True + sage: z.vector_presentation(0) + Traceback (most recent call last): + ... + ValueError: the zero map has no vector presentation """ # The trivial map has no degree, so we can not create the codomain # of the linear transformation. if self.is_zero(): - return None + raise ValueError("the zero map has no vector presentation") D_n = self.domain().vector_presentation(n) C_n = self.codomain().vector_presentation(self.degree() + n) @@ -727,7 +886,7 @@ def vector_presentation(self, n): def solve(self, x): r""" - Find an element in the inverse image of ``x``. + Return an element in the inverse image of ``x``. INPUT: @@ -794,7 +953,7 @@ def solve(self, x): def lift(self, f, verbose=False): r""" - A lift of this homomorphism over the given homomorphism ``f``. + Return a lift of this homomorphism over the given homomorphism ``f``. INPUT: @@ -1504,22 +1663,22 @@ def _resolve_kernel(self, top_dim=None, verbose=False): ... ValueError: a top dimension must be specified for this calculation to terminate sage: f._resolve_kernel(top_dim=20) - Module morphism: - From: Finitely presented left module on 3 generators and 0 relations over mod 2 Steenrod algebra, milnor basis + Free module morphism: + From: Free graded left module on 3 generators over mod 2 Steenrod algebra, milnor basis To: Finitely presented left module on 2 generators and 0 relations over mod 2 Steenrod algebra, milnor basis Defn: g[0, 0] |--> g[0, 1] g[3, 0] |--> Sq(0,1)*g[0, 0] g[3, 1] |--> Sq(3)*g[0, 0] sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) sage: f.change_ring(A3)._resolve_kernel() # long time - Module morphism: - From: Finitely presented left module on 3 generators and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] + Free module morphism: + From: Free graded left module on 3 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] To: Finitely presented left module on 2 generators and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] Defn: g[0, 0] |--> g[0, 1] g[3, 0] |--> Sq(0,1)*g[0, 0] g[3, 1] |--> Sq(3)*g[0, 0] """ - from .module import FPModule + from .free_module import FreeGradedModule # Let # # 1) `j` be a homomorphism into `\ker(self)`, and @@ -1532,32 +1691,34 @@ def _resolve_kernel(self, top_dim=None, verbose=False): # This induction step is then repeated for all `n \leq` ``top_dim``. # + domain = self.domain() + R = self.base_ring() + if self.is_zero(): # Epsilon: F_0 -> M - M = self.domain() - F_0 = self.domain()._j.codomain().as_fp_module() - epsilon = Hom(F_0, M)(tuple(M.generators())) + F_0 = FreeGradedModule(R, domain.generator_degrees()) + epsilon = Hom(F_0, domain)(tuple(domain.generators())) return epsilon # Create the trivial module F_ to start with. - F_ = FPModule(self.base_ring(), ()) - j = Hom(F_, self.domain())(()) + F_ = FreeGradedModule(R, ()) + j = Hom(F_, domain).zero() - dim = self.domain().connectivity() - if dim == PlusInfinity(): + dim = domain.connectivity() + if dim == infinity: if verbose: print ('The domain of the morphism is trivial, so there is nothing to resolve.') return j - if not self.base_ring().dimension() < PlusInfinity(): - limit = PlusInfinity() + if not self.base_ring().dimension() < infinity: + limit = infinity else: - limit = _top_dim(self.base_ring()) + max(self.domain().generator_degrees()) + limit = _top_dim(R) + max(domain.generator_degrees()) if top_dim is not None: limit = min(top_dim, limit) - if limit == PlusInfinity(): + if limit == infinity: raise ValueError('a top dimension must be specified for this calculation to terminate') if verbose: @@ -1577,37 +1738,35 @@ def _resolve_kernel(self, top_dim=None, verbose=False): self_n = self.vector_presentation(n) kernel_n = self_n.kernel() - if kernel_n.dimension() == 0: + if not kernel_n: continue generator_degrees = tuple((x.degree() for x in F_.generators())) if j.is_zero(): # The map j is not onto in degree `n` of the kernel. - new_generator_degrees = tuple(kernel_n.dimension()*(n,)) - F_ = FPModule(self.base_ring(), - generator_degrees + new_generator_degrees) + new_generator_degrees = kernel_n.rank() * (n,) + F_ = FreeGradedModule(R, generator_degrees + new_generator_degrees) new_values = tuple([ - self.domain().element_from_coordinates(q, n) for q in kernel_n.basis()]) + domain.element_from_coordinates(q, n) for q in kernel_n.basis()]) else: Q_n = kernel_n.quotient(j.vector_presentation(n).image()) - if Q_n.dimension() == 0: + if not Q_n.rank(): continue # The map j is not onto in degree `n` of the kernel. - new_generator_degrees = tuple(Q_n.dimension()*(n,)) - F_ = FPModule(self.base_ring(), - generator_degrees + new_generator_degrees) + new_generator_degrees = Q_n.rank() * (n,) + F_ = FreeGradedModule(R, generator_degrees + new_generator_degrees) new_values = tuple([ - self.domain().element_from_coordinates(Q_n.lift(q), n) for q in Q_n.basis()]) + domain.element_from_coordinates(Q_n.lift(q), n) for q in Q_n.basis()]) # Create a new homomorphism which is surjective onto the kernel # in all degrees less than, and including `n`. - j = Hom(F_, self.domain()) (j._values + new_values) + j = Hom(F_, domain)(j._values + new_values) if verbose: print('.') @@ -1648,18 +1807,18 @@ def _resolve_image(self, top_dim=None, verbose=False): ... ValueError: a top dimension must be specified for this calculation to terminate sage: f._resolve_image(top_dim=20) - Module morphism: - From: Finitely presented left module on 1 generator and 0 relations over mod 2 Steenrod algebra, milnor basis + Free module morphism: + From: Free graded left module on 1 generator over mod 2 Steenrod algebra, milnor basis To: Finitely presented left module on 2 generators and 2 relations over mod 2 Steenrod algebra, milnor basis Defn: g[2] |--> Sq(2)*g[0, 0] sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1)) sage: f.change_ring(A3)._resolve_image() # long time - Module morphism: - From: Finitely presented left module on 1 generator and 0 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] + Free module morphism: + From: Free graded left module on 1 generator over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] To: Finitely presented left module on 2 generators and 2 relations over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [4, 3, 2, 1] Defn: g[2] |--> Sq(2)*g[0, 0] """ - from .module import FPModule + from .free_module import FreeGradedModule # Let # # 1) `j` be a homomorphism into `\im(self)`, and @@ -1673,11 +1832,13 @@ def _resolve_image(self, top_dim=None, verbose=False): # # Create the trivial module F_ to start with. - F_ = FPModule(self.base_ring(), ()) - j = Hom(F_, self.codomain())(()) + R = self.base_ring() + codomain = self.codomain() + F_ = FreeGradedModule(R, ()) + j = Hom(F_, codomain).zero() dim = self.codomain().connectivity() - if dim == PlusInfinity(): + if dim == infinity: if verbose: print ('The codomain of the morphism is trivial, so there is nothing to resolve.') return j @@ -1689,13 +1850,14 @@ def _resolve_image(self, top_dim=None, verbose=False): return j degree_values = [0] + [v.degree() for v in self._values if v] - limit = PlusInfinity() if not self.base_ring().is_finite() else\ - (_top_dim(self.base_ring()) + max(degree_values)) + # TODO: Change this to test finite dimensional (not a finite algebra)!! + limit = (infinity if not R.is_finite() else + (_top_dim(self.base_ring()) + max(degree_values))) if top_dim is not None: limit = min(top_dim, limit) - if limit == PlusInfinity(): + if limit == infinity: raise ValueError('a top dimension must be specified for this calculation to terminate') if verbose: @@ -1719,9 +1881,8 @@ def _resolve_image(self, top_dim=None, verbose=False): generator_degrees = tuple((x.degree() for x in F_.generators())) if j.is_zero(): # The map j is not onto in degree `n` of the image. - new_generator_degrees = tuple(image_n.dimension()*(n,)) - F_ = FPModule(self.base_ring(), - generator_degrees + new_generator_degrees) + new_generator_degrees = image_n.rank() * (n,) + F_ = FreeGradedModule(R, generator_degrees + new_generator_degrees) new_values = tuple([ self.codomain().element_from_coordinates(q, n) for q in image_n.basis()]) @@ -1735,9 +1896,8 @@ def _resolve_image(self, top_dim=None, verbose=False): continue # The map j is not onto in degree `n` of the image. - new_generator_degrees = tuple(Q_n.dimension()*(n,)) - F_ = FPModule(self.base_ring(), - generator_degrees + new_generator_degrees) + new_generator_degrees = Q_n.rank() * (n,) + F_ = FreeGradedModule(R, generator_degrees + new_generator_degrees) new_values = tuple([ self.codomain().element_from_coordinates(Q_n.lift(q), n) for q in Q_n.basis()]) @@ -1775,7 +1935,19 @@ def fp_module(self): sage: M.relations() (Sq(2)*g[0],) + sage: F2 = A.free_graded_module((0,)) + sage: v = F2([Sq(2)]) + sage: pres = Hom(F1, F2)([v]) + sage: M = pres.fp_module(); M + Finitely presented left module on 1 generator and 1 relation over + mod 2 Steenrod algebra, milnor basis + sage: M.generator_degrees() + (0,) + sage: M.relations() + (Sq(2)*g[0],) + sage: F3 = FPModule(A, (0,), [[Sq(4)]]) + sage: v = F3([Sq(2)]) sage: pres = Hom(F1, F3)([v]) sage: pres.fp_module() Traceback (most recent call last): @@ -1841,8 +2013,8 @@ def _top_dim(algebra): sage: _top_dim(SteenrodAlgebra(2, profile=(3,2,1))) 23 """ - if not algebra.dimension() < PlusInfinity(): - return PlusInfinity() + if not algebra.dimension() < infinity: + return infinity try: alg_top_dim = algebra.top_class().degree() except AttributeError: @@ -1851,3 +2023,4 @@ def _top_dim(algebra): # top_class method, e.g., exterior algebras. alg_top_dim = max(a.degree() for a in algebra.basis()) return alg_top_dim + From 50744642c4c07b3987729988501d7347b5286b9d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 30 Jan 2022 12:41:58 +0900 Subject: [PATCH 189/253] Some last fixes and removing redundancy. --- src/sage/modules/fp_graded/free_module.py | 4 +- src/sage/modules/fp_graded/free_morphism.py | 73 --------------------- src/sage/modules/fp_graded/module.py | 12 +++- src/sage/modules/fp_graded/morphism.py | 30 ++++++++- 4 files changed, 40 insertions(+), 79 deletions(-) diff --git a/src/sage/modules/fp_graded/free_module.py b/src/sage/modules/fp_graded/free_module.py index 705815a7dc6..1164ed264cf 100755 --- a/src/sage/modules/fp_graded/free_module.py +++ b/src/sage/modules/fp_graded/free_module.py @@ -2,8 +2,8 @@ Finitely generated free graded left modules over connected graded algebras Let `A` be a connected graded algebra. Some methods here require in -addition that `A` be an algebra over a field and that Sage has a -description of a basis for `A`. +addition that `A` be an algebra over a field or a PID and that Sage +has a description of a basis for `A`. For example, let `p` be a prime number. The mod `p` Steenrod algebra `A_p` is a connected algebra over the finite field of `p` elements. diff --git a/src/sage/modules/fp_graded/free_morphism.py b/src/sage/modules/fp_graded/free_morphism.py index 547a0bfc9e7..ff4d8453053 100755 --- a/src/sage/modules/fp_graded/free_morphism.py +++ b/src/sage/modules/fp_graded/free_morphism.py @@ -147,79 +147,6 @@ def degree(self): return self._degree - def _add_(self, g): - r""" - The pointwise sum of `self`` and ``g``. - - Pointwise addition of two homomorphisms `f` and `g` with the same - domain and codomain is given by the formula `(f+g)(x) = f(x) + g(x)` - for every `x` in the domain of `f`. - - INPUT: - - - ``g`` -- a homomorphism with the same domain and codomain as ``self`` - - EXAMPLES:: - - sage: from sage.modules.fp_graded.free_module import FreeGradedModule - sage: A = SteenrodAlgebra(2) - sage: homspace = Hom(FreeGradedModule(A, (0,1)), FreeGradedModule(A, (2,))) - sage: N = homspace.codomain() - sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] - sage: f = homspace(values) - sage: ff = f.__add__(f) - sage: ff.is_zero() - True - sage: ff.__add__(f) == f - True - sage: ff = f + f - sage: ff.is_zero() - True - """ - if self.domain() != g.domain(): - raise ValueError('morphisms do not have the same domain') - elif self.codomain() != g.codomain(): - raise ValueError('morphisms do not have the same codomain') - elif self.is_zero(): - return g - elif g.is_zero(): - return self - elif self.degree() and g.degree() and self.degree() != g.degree(): - raise ValueError('morphisms do not have the same degree') - - v = [self(x) + g(x) for x in self.domain().generators()] - return self.parent()(v) - - - def is_identity(self): - r""" - Return if ``self`` is the identity endomorphism. - - OUTPUT: - - The boolean value ``True`` if this homomorphism is the identity - and ``False`` otherwise. - - EXAMPLES:: - - sage: from sage.modules.fp_graded.free_module import FreeGradedModule - sage: A = SteenrodAlgebra(2) - sage: M = FreeGradedModule(A, (0,1)) - sage: N = FreeGradedModule(A, (2,)) - sage: values = [Sq(5)*N.generator(0), Sq(3,1)*N.generator(0)] - sage: f = Hom(M, N)(values) - sage: f.is_identity() - False - sage: one = Hom(M, M)(M.generators()); one - Free module endomorphism of Free graded left module on 2 generators over mod 2 Steenrod algebra, milnor basis - Defn: g[0] |--> g[0] - g[1] |--> g[1] - sage: one.is_identity() - True - """ - return (self.parent().is_endomorphism_set() and - self.parent().identity() == self) - def __call__(self, x): r""" Evaluate the homomorphism at the given domain element ``x``. diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index f42172dc915..7e4789c57cf 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -7,9 +7,10 @@ generators of `F_0` correspond to the generators of the module, and the generators of `F_1` correspond to its relations, via the map `f`. -The class constructor of this module class takes a set of generators and -relations and uses them to construct a presentation, using the class -:class:`sage.modules.fp_graded.free_morphism.FreeGradedModuleMorphism`. +This module class takes as input a set of generators and relations +and uses them to construct a presentation, using the class +:class:`~sage.modules.fp_graded.free_morphism.FreeGradedModuleMorphism`. +It also allows such a morphism as input. This package was designed with homological algebra in mind, and its API focuses on maps rather than objects. A good example of this is the kernel @@ -18,6 +19,11 @@ is not an instance of the module class, but rather an injective homomorphism `i: K\to M` with the property that `\operatorname{im}(i) = \ker(f)`. +.. NOTE:: + + Some methods here require in addition that `R` be an algebra over a + field or a PID and that Sage has a description of a basis for `R`. + AUTHORS: - Robert R. Bruner, Michael J. Catanzaro (2012): Initial version. diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py index 9cd1fab7010..5c7a8802701 100755 --- a/src/sage/modules/fp_graded/morphism.py +++ b/src/sage/modules/fp_graded/morphism.py @@ -447,6 +447,20 @@ def __add__(self, g): True sage: ff + f == f True + + sage: N = A.free_graded_module((2,)) + sage: v = N.generator(0) + sage: homspace = Hom(A.free_graded_module((0,1)), N) + sage: values = [Sq(5)*v, Sq(3,1)*v] + sage: f = homspace(values) + sage: ff = f + f + sage: ff.is_zero() + True + sage: ff + f == f + True + sage: ff = f + f + sage: ff.is_zero() + True """ if self.domain() != g.domain(): raise ValueError('morphisms do not have the same domain') @@ -569,7 +583,7 @@ def __mul__(self, g): sage: v = N.generator(0) sage: values = [Sq(5)*v, Sq(3,1)*v] sage: f = Hom(M, N)(values) - sage: values2 = [Sq(2)*v] + sage: values2 = [Sq(2)*M.generator(0)] sage: g = Hom(N, M)(values2) sage: fg = f * g; fg Free module endomorphism of Free graded left module on 1 generator over mod 2 Steenrod algebra, milnor basis @@ -667,6 +681,20 @@ def is_identity(self): sage: one.is_identity() True + + sage: M = A.free_graded_module((0,1)) + sage: N = A.free_graded_module((2,)) + sage: v = N.generator(0) + sage: values = [Sq(5)*v, Sq(3,1)*v] + sage: f = Hom(M, N)(values) + sage: f.is_identity() + False + sage: one = Hom(M, M)(M.generators()); one + Free module endomorphism of Free graded left module on 2 generators over mod 2 Steenrod algebra, milnor basis + Defn: g[0] |--> g[0] + g[1] |--> g[1] + sage: one.is_identity() + True """ return (self.parent().is_endomorphism_set() and self.parent().identity() == self) From ffe7179490704efe9157a6796cdbf2ae68f27c46 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Sat, 29 Jan 2022 22:13:17 -0800 Subject: [PATCH 190/253] trac 32505: replace "PlusInfinity()" with "infinity" --- src/sage/modules/fp_graded/free_module.py | 4 ++-- src/sage/modules/fp_graded/module.py | 6 +++--- src/sage/modules/fp_graded/morphism.py | 14 ++++++-------- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/sage/modules/fp_graded/free_module.py b/src/sage/modules/fp_graded/free_module.py index 1164ed264cf..b867fcb28fa 100755 --- a/src/sage/modules/fp_graded/free_module.py +++ b/src/sage/modules/fp_graded/free_module.py @@ -286,7 +286,7 @@ from sage.misc.cachefunc import cached_method from sage.modules.free_module import FreeModule from sage.modules.fp_graded.free_element import FreeGradedModuleElement -from sage.rings.infinity import PlusInfinity +from sage.rings.infinity import infinity from sage.categories.graded_modules import GradedModules from sage.categories.fields import Fields from sage.combinat.free_module import CombinatorialFreeModule @@ -510,7 +510,7 @@ def connectivity(self): sage: M.connectivity() +Infinity """ - return min(self.generator_degrees() + (PlusInfinity(),)) + return min(self.generator_degrees() + (infinity,)) def _element_constructor_(self, coefficients): diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index 7e4789c57cf..14818f8ffac 100755 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -47,7 +47,7 @@ from sage.categories.homset import Hom from sage.categories.morphism import Morphism from sage.misc.cachefunc import cached_method -from sage.rings.infinity import PlusInfinity +from sage.rings.infinity import infinity from sage.categories.graded_modules import GradedModules from sage.modules.module import Module from sage.structure.indexed_generators import IndexedGenerators @@ -519,7 +519,7 @@ def connectivity(self): return k previous = k - return PlusInfinity() + return infinity def is_trivial(self): @@ -555,7 +555,7 @@ def is_trivial(self): sage: C.is_trivial() True """ - return self.connectivity() == PlusInfinity() + return self.connectivity() == infinity def has_relations(self): diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py index 5c7a8802701..9a6e2ff4139 100755 --- a/src/sage/modules/fp_graded/morphism.py +++ b/src/sage/modules/fp_graded/morphism.py @@ -1738,7 +1738,7 @@ def _resolve_kernel(self, top_dim=None, verbose=False): print ('The domain of the morphism is trivial, so there is nothing to resolve.') return j - if not self.base_ring().dimension() < infinity: + if not R.dimension() < infinity: limit = infinity else: limit = _top_dim(R) + max(domain.generator_degrees()) @@ -1878,9 +1878,8 @@ def _resolve_image(self, top_dim=None, verbose=False): return j degree_values = [0] + [v.degree() for v in self._values if v] - # TODO: Change this to test finite dimensional (not a finite algebra)!! - limit = (infinity if not R.is_finite() else - (_top_dim(self.base_ring()) + max(degree_values))) + limit = (infinity if not R.dimension() < infinity else + (_top_dim(R) + max(degree_values))) if top_dim is not None: limit = min(top_dim, limit) @@ -2026,10 +2025,9 @@ def _top_dim(algebra): r""" The top dimension of ``algebra`` - This returns ``PlusInfinity`` if the algebra is - infinite-dimensional. If the algebra has a ``top_class`` - method, then it is used in the computation; otherwise the - computation may be slow. + This returns infinity if the algebra is infinite-dimensional. If + the algebra has a ``top_class`` method, then it is used in the + computation; otherwise the computation may be slow. EXAMPLES:: From 0cc8b67568c8df6111dfac37f4c122457da96740 Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Sun, 30 Jan 2022 10:05:18 +0100 Subject: [PATCH 191/253] 33217: revert import for modularization --- src/sage/rings/quotient_ring.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/quotient_ring.py b/src/sage/rings/quotient_ring.py index c875abcdb88..f6f54b361bd 100644 --- a/src/sage/rings/quotient_ring.py +++ b/src/sage/rings/quotient_ring.py @@ -118,6 +118,7 @@ from sage.categories.commutative_rings import CommutativeRings +MPolynomialIdeal_quotient = None try: from sage.interfaces.singular import singular as singular_default, is_SingularElement except ImportError: @@ -966,7 +967,9 @@ def ideal(self, *gens, **kwds): if 'coerce' in kwds and kwds['coerce']: gens = [self(x) for x in gens] # this will even coerce from singular ideals correctly! - from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal_quotient + global MPolynomialIdeal_quotient + if MPolynomialIdeal_quotient is None: + from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal_quotient return MPolynomialIdeal_quotient(self, gens, **kwds) def _element_constructor_(self, x, coerce=True): From 232983237e7788f9ec512b9634cff1c2538d8821 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Sun, 30 Jan 2022 19:34:04 +0800 Subject: [PATCH 192/253] PARI's ellweilpairing() only works over finite fields --- src/sage/schemes/elliptic_curves/ell_point.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_point.py b/src/sage/schemes/elliptic_curves/ell_point.py index 9ef37f9906b..436cb9f2082 100644 --- a/src/sage/schemes/elliptic_curves/ell_point.py +++ b/src/sage/schemes/elliptic_curves/ell_point.py @@ -1515,7 +1515,7 @@ def _miller_(self, Q, n): t = 1/(t*vee) return t - def weil_pairing(self, Q, n, algorithm='pari'): + def weil_pairing(self, Q, n, algorithm=None): r""" Compute the Weil pairing of this point with another point `Q` on the same curve. @@ -1527,8 +1527,10 @@ def weil_pairing(self, Q, n, algorithm='pari'): - ``n`` -- an integer `n` such that `nP = nQ = (0:1:0)`, where `P` is ``self``. - - ``algorithm`` (default: ``pari``) -- choices are ``pari`` - and ``sage``. PARI is usually significantly faster. + - ``algorithm`` (default: ``None``) -- choices are ``pari`` + and ``sage``. PARI is usually significantly faster, but it + only works over finite fields. When ``None`` is given, a + suitable algorithm is chosen automatically. OUTPUT: @@ -1620,6 +1622,12 @@ def weil_pairing(self, Q, n, algorithm='pari'): if Q.curve() is not E: raise ValueError("points must both be on the same curve") + if algorithm is None: + if E.base_field().is_finite(): + algorithm = 'pari' + else: + algorithm = 'sage' + if algorithm == 'pari': if pari.ellmul(E,P,n) != [0] or pari.ellmul(E,Q,n) != [0]: raise ValueError("points must both be n-torsion") From c79b74a34ef9b3c48431421efc5f1b872c3f44c2 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Sun, 30 Jan 2022 19:42:36 +0800 Subject: [PATCH 193/253] test is not really "long time" anymore, finishes in < 500ms --- src/sage/schemes/elliptic_curves/ell_point.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_point.py b/src/sage/schemes/elliptic_curves/ell_point.py index 436cb9f2082..2a8fc04a8db 100644 --- a/src/sage/schemes/elliptic_curves/ell_point.py +++ b/src/sage/schemes/elliptic_curves/ell_point.py @@ -1572,13 +1572,13 @@ def weil_pairing(self, Q, n, algorithm=None): An example over a number field:: - sage: P,Q = EllipticCurve('11a1').change_ring(CyclotomicField(5)).torsion_subgroup().gens() # long time (10s) - sage: P,Q = (P.element(), Q.element()) # long time - sage: (P.order(),Q.order()) # long time + sage: P,Q = EllipticCurve('11a1').change_ring(CyclotomicField(5)).torsion_subgroup().gens() + sage: P,Q = (P.element(), Q.element()) + sage: (P.order(),Q.order()) (5, 5) - sage: P.weil_pairing(Q,5) # long time + sage: P.weil_pairing(Q,5) zeta5^2 - sage: Q.weil_pairing(P,5) # long time + sage: Q.weil_pairing(P,5) zeta5^3 TESTS: From 5dd228e9da6039e372fe3c8abd8ecdc180f724eb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 30 Jan 2022 09:38:17 -0800 Subject: [PATCH 194/253] tox.ini: Remove centos-6 (packages no longer available) --- tox.ini | 3 --- 1 file changed, 3 deletions(-) diff --git a/tox.ini b/tox.ini index a34255bc42d..200ac973ca2 100644 --- a/tox.ini +++ b/tox.ini @@ -266,13 +266,10 @@ setenv = # # https://hub.docker.com/_/centos # https://quay.io/repository/centos/centos?tab=tags - # centos-6 only has autoconf 2.63 -- too old for bootstrap; download configure tarball instead. # centos: SYSTEM=fedora centos: BASE_IMAGE=centos centos: IGNORE_MISSING_SYSTEM_PACKAGES=yes - centos-6: BASE_TAG=centos6 - centos-6: BOOTSTRAP=./bootstrap -D centos-7: BASE_TAG=centos7 centos-8: BASE_TAG=centos8 centos-stream: BASE_IMAGE=quay.io/centos/centos From a50548772c74a04901c44e563c3d7cc5a47e6608 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 30 Jan 2022 09:42:07 -0800 Subject: [PATCH 195/253] build/pkgs/texlive/distros/fedora.txt: Add texlive-collection-latexextra --- build/pkgs/texlive/distros/fedora.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/build/pkgs/texlive/distros/fedora.txt b/build/pkgs/texlive/distros/fedora.txt index dbfe8d4bfa8..1097858fb79 100644 --- a/build/pkgs/texlive/distros/fedora.txt +++ b/build/pkgs/texlive/distros/fedora.txt @@ -1,2 +1,3 @@ latexmk texlive +texlive-collection-latexextra From 7daedd97d05d1820b828ae5baf3dae0c20df3f1c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 30 Jan 2022 11:49:36 -0800 Subject: [PATCH 196/253] build/pkgs/texlive/distros/fedora.txt: Add texlive-collection-lang* --- build/pkgs/texlive/distros/fedora.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/build/pkgs/texlive/distros/fedora.txt b/build/pkgs/texlive/distros/fedora.txt index 1097858fb79..e2a8ac0a702 100644 --- a/build/pkgs/texlive/distros/fedora.txt +++ b/build/pkgs/texlive/distros/fedora.txt @@ -1,3 +1,13 @@ latexmk texlive texlive-collection-latexextra +# language support for the pdf documentation +texlive-collection-langcyrillic +texlive-collection-langeuropean +texlive-collection-langfrench +texlive-collection-langgerman +texlive-collection-langitalian +texlive-collection-langjapanese +texlive-collection-langpolish +texlive-collection-langportuguese +texlive-collection-langspanish From a1a9467e95cd05a6439b4b2765e62c6aad6dc960 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Sun, 30 Jan 2022 17:11:51 -0800 Subject: [PATCH 197/253] trac 32505: remove redundant "zero" and "identity" methods --- src/sage/modules/fp_graded/free_homspace.py | 36 --------------------- src/sage/modules/fp_graded/homspace.py | 15 +++++++++ 2 files changed, 15 insertions(+), 36 deletions(-) diff --git a/src/sage/modules/fp_graded/free_homspace.py b/src/sage/modules/fp_graded/free_homspace.py index 3c5be7c7e85..cef1db86b34 100755 --- a/src/sage/modules/fp_graded/free_homspace.py +++ b/src/sage/modules/fp_graded/free_homspace.py @@ -70,39 +70,3 @@ def _an_element_(self): g[3] |--> 0 """ return self.zero() - - - @cached_method - def zero(self): - r""" - Return the trivial morphism of ``self``. - - EXAMPLES:: - - sage: from sage.modules.fp_graded.free_module import FreeGradedModule - sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) - sage: F = FreeGradedModule(A2, (1,3)) - sage: L = FreeGradedModule(A2, (2,3)) - sage: H = Hom(F, L) - sage: H.zero() - Free module morphism: - From: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] - To: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] - Defn: g[1] |--> 0 - g[3] |--> 0 - """ - return self.element_class(self, self.codomain().zero()) - - - def identity(self): - r""" - Return the identity morphism, if ``self`` is an endomorphism set. - - EXAMPLES:: - - """ - if self.is_endomorphism_set(): - return self.element_class(self, self.codomain().generators()) - else: - raise TypeError('this homspace does not consist of endomorphisms') - diff --git a/src/sage/modules/fp_graded/homspace.py b/src/sage/modules/fp_graded/homspace.py index f7af1770516..19436bbac3c 100755 --- a/src/sage/modules/fp_graded/homspace.py +++ b/src/sage/modules/fp_graded/homspace.py @@ -224,6 +224,21 @@ def zero(self): 0 sage: z(F.an_element(23)) 0 + + Example with free modules:: + + sage: from sage.modules.fp_graded.free_module import FreeGradedModule + sage: A2 = SteenrodAlgebra(2, profile=(3,2,1)) + sage: F = FreeGradedModule(A2, (1,3)) + sage: L = FreeGradedModule(A2, (2,3)) + sage: H = Hom(F, L) + sage: H.zero() + Free module morphism: + From: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + To: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + Defn: g[1] |--> 0 + g[3] |--> 0 + """ ngens = len(self.domain().generator_degrees()) return self.element_class(self, [self.codomain().zero()] * ngens) From c7626f6d209c4161c2c0abb05364cf4d9ba68c6c Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Mon, 31 Jan 2022 17:49:13 +0800 Subject: [PATCH 198/253] Returns -> Return --- src/sage/schemes/elliptic_curves/ell_point.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/schemes/elliptic_curves/ell_point.py b/src/sage/schemes/elliptic_curves/ell_point.py index 2a8fc04a8db..25992aec9d3 100644 --- a/src/sage/schemes/elliptic_curves/ell_point.py +++ b/src/sage/schemes/elliptic_curves/ell_point.py @@ -3483,7 +3483,7 @@ def _magma_init_(self, magma): def discrete_log(self, Q, ord=None): r""" - Returns the discrete logarithm of `Q` to base `P` = ``self``, + Return the discrete logarithm of `Q` to base `P` = ``self``, that is, an integer `x` such that `xP = Q`. A :class:`ValueError` is raised if there is no solution. From 868109b83081d48e0279148334c3b8ab9467e873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20Leli=C3=A8vre?= Date: Mon, 31 Jan 2022 11:04:59 +0100 Subject: [PATCH 199/253] 33248: Skip Mathematica feature detection doctest --- src/sage/features/interfaces.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/features/interfaces.py b/src/sage/features/interfaces.py index 8daa59f58e1..b77c2cc4f88 100644 --- a/src/sage/features/interfaces.py +++ b/src/sage/features/interfaces.py @@ -123,7 +123,7 @@ class Mathematica(InterfaceFeature): EXAMPLES:: sage: from sage.features.interfaces import Mathematica - sage: Mathematica().is_present() # random + sage: Mathematica().is_present() # not tested FeatureTestResult('mathematica', False) """ From 72b9c13801658b9f09b77d1e1dbaa304656dae13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 16 Jan 2022 10:11:01 +0100 Subject: [PATCH 200/253] fix E111 (indentation) in graphs and coding --- src/sage/coding/code_constructions.py | 13 +++++----- src/sage/coding/linear_code.py | 24 +++++++++---------- src/sage/coding/linear_code_no_metric.py | 6 ++--- src/sage/graphs/digraph.py | 5 ++-- .../graphs/generators/classical_geometries.py | 12 +++++----- src/sage/graphs/graph.py | 5 ++-- 6 files changed, 34 insertions(+), 31 deletions(-) diff --git a/src/sage/coding/code_constructions.py b/src/sage/coding/code_constructions.py index 2b07709d05e..8483d29637c 100644 --- a/src/sage/coding/code_constructions.py +++ b/src/sage/coding/code_constructions.py @@ -749,20 +749,21 @@ def ToricCode(P,F): - David Joyner (07-2006) """ from sage.combinat.all import Tuples - mset = [x for x in F if x!=0] + mset = [x for x in F if x != 0] d = len(P[0]) - pts = Tuples(mset,d).list() - n = len(pts) # (q-1)^d + pts = Tuples(mset, d).list() + n = len(pts) # (q-1)^d k = len(P) e = P[0] B = [] for e in P: - tmpvar = [prod([t[i]**e[i] for i in range(d)]) for t in pts] - B.append(tmpvar) + tmpvar = [prod([t[i]**e[i] for i in range(d)]) for t in pts] + B.append(tmpvar) # now B0 *should* be a full rank matrix - MS = MatrixSpace(F,k,n) + MS = MatrixSpace(F, k, n) return LinearCode(MS(B)) + def WalshCode(m): r""" Return the binary Walsh code of length `2^m`. diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index c335f04e1a9..106d9e1c91e 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -2012,14 +2012,14 @@ def zeta_polynomial(self, name="T"): r = n-d-dperp+2 P_coeffs = [] for i in range(len(b)): - if i == 0: - P_coeffs.append(b[0]) - if i == 1: - P_coeffs.append(b[1] - (q+1)*b[0]) - if i>1: - P_coeffs.append(b[i] - (q+1)*b[i-1] + q*b[i-2]) + if i == 0: + P_coeffs.append(b[0]) + if i == 1: + P_coeffs.append(b[1] - (q+1)*b[0]) + if i > 1: + P_coeffs.append(b[i] - (q+1)*b[i-1] + q*b[i-2]) P = sum([P_coeffs[i]*T**i for i in range(r+1)]) - return RT(P)/RT(P)(1) + return RT(P) / RT(P)(1) def zeta_function(self, name="T"): r""" @@ -2027,11 +2027,11 @@ def zeta_function(self, name="T"): INPUT: - - ``name`` - String, variable name (default: ``"T"``) + - ``name`` -- String, variable name (default: ``"T"``) OUTPUT: - - Element of `\QQ(T)` + Element of `\QQ(T)` EXAMPLES:: @@ -2039,9 +2039,9 @@ def zeta_function(self, name="T"): sage: C.zeta_function() (1/5*T^2 + 1/5*T + 1/10)/(T^2 - 3/2*T + 1/2) """ - P = self.zeta_polynomial() - q = (self.base_ring()).characteristic() - RT = PolynomialRing(QQ,"%s"%name) + P = self.zeta_polynomial() + q = self.base_ring().characteristic() + RT = PolynomialRing(QQ, name) T = RT.gen() return P/((1-T)*(1-q*T)) diff --git a/src/sage/coding/linear_code_no_metric.py b/src/sage/coding/linear_code_no_metric.py index 9e4b6115ad3..305442dd0de 100644 --- a/src/sage/coding/linear_code_no_metric.py +++ b/src/sage/coding/linear_code_no_metric.py @@ -943,7 +943,7 @@ def permuted_code(self, p): True """ if not hasattr(self, "_generic_constructor"): - raise NotImplementedError("Generic constructor not set for the class of codes") + raise NotImplementedError("Generic constructor not set for the class of codes") G = copy(self.generator_matrix()) G.permute_columns(p) return self._generic_constructor(G) @@ -966,10 +966,10 @@ def dual_code(self): [21, 3] linear code over GF(4) """ if not hasattr(self, "_generic_constructor"): - raise NotImplementedError("Generic constructor not set for the class of codes") + raise NotImplementedError("Generic constructor not set for the class of codes") return self._generic_constructor(self.parity_check_matrix()) - def is_self_dual(self): + def is_self_dual(self) -> bool: """ Return ``True`` if the code is self-dual (in the usual Hamming inner product) and ``False`` otherwise. diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index 77118925586..50f87ecc5fd 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -182,6 +182,7 @@ from sage.graphs.dot2tex_utils import have_dot2tex from sage.graphs.views import EdgesView + class DiGraph(GenericGraph): r""" Directed graph. @@ -652,7 +653,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if data_structure in ["sparse", "static_sparse"]: CGB = SparseGraphBackend elif data_structure == "dense": - CGB = DenseGraphBackend + CGB = DenseGraphBackend else: raise ValueError("data_structure must be equal to 'sparse', " "'static_sparse' or 'dense'") @@ -674,7 +675,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if format is None and isinstance(data, Graph): data = data.to_directed() format = 'DiGraph' - if format is None and isinstance(data,list) and \ + if format is None and isinstance(data, list) and \ len(data) >= 2 and callable(data[1]): format = 'rule' diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index 617d9b1a31c..6290002cc1b 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -685,7 +685,7 @@ def NonisotropicUnitaryPolarGraph(m, q): """ p, k = is_prime_power(q,get_data=True) if not k: - raise ValueError('q must be a prime power') + raise ValueError('q must be a prime power') from sage.libs.gap.libgap import libgap from itertools import combinations F=libgap.GF(q**2) # F_{q^2} @@ -865,7 +865,7 @@ def TaylorTwographDescendantSRG(q, clique_partition=False): """ p, k = is_prime_power(q,get_data=True) if not k or p == 2: - raise ValueError('q must be an odd prime power') + raise ValueError('q must be an odd prime power') from sage.schemes.projective.projective_space import ProjectiveSpace from sage.rings.finite_rings.integer_mod import mod Fq = FiniteField(q**2, 'a') @@ -959,7 +959,7 @@ def AhrensSzekeresGeneralizedQuadrangleGraph(q, dual=False): from sage.combinat.designs.incidence_structures import IncidenceStructure p, k = is_prime_power(q,get_data=True) if not k or p == 2: - raise ValueError('q must be an odd prime power') + raise ValueError('q must be an odd prime power') F = FiniteField(q, 'a') L = [] for a in F: @@ -1053,7 +1053,7 @@ def T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None, p, k = is_prime_power(q,get_data=True) if not k or p != 2: - raise ValueError('q must be a power of 2') + raise ValueError('q must be a power of 2') if field is None: F = FiniteField(q, 'a') else: @@ -1393,9 +1393,9 @@ def Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None, check_hyperov p, k = is_prime_power(q,get_data=True) if not k or p != 2: - raise ValueError('q must be a power of 2') + raise ValueError('q must be a power of 2') if k < 3: - raise ValueError('q must be a at least 8') + raise ValueError('q must be a at least 8') if field is None: F = FiniteField(q, 'a') else: diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 5833d463704..b7267e34378 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -430,6 +430,7 @@ from sage.misc.decorators import rename_keyword + class Graph(GenericGraph): r""" Undirected graph. @@ -9066,9 +9067,9 @@ def arboricity(self, certificate=False): from sage.matroids.constructor import Matroid P = Matroid(self).partition() if certificate: - return (len(P), [self.subgraph(edges=forest) for forest in P]) + return (len(P), [self.subgraph(edges=forest) for forest in P]) else: - return len(P) + return len(P) @doc_index("Graph properties") def is_antipodal(self): From 4f7b1405a1add69a026addc4ec7f152d3bfe7082 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20Leli=C3=A8vre?= Date: Mon, 31 Jan 2022 19:10:47 +0100 Subject: [PATCH 201/253] 33252: Upgrade to pip 22.0.2 --- build/pkgs/pip/checksums.ini | 6 +++--- build/pkgs/pip/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/pip/checksums.ini b/build/pkgs/pip/checksums.ini index 572abe42c1a..84edc5a0231 100644 --- a/build/pkgs/pip/checksums.ini +++ b/build/pkgs/pip/checksums.ini @@ -1,5 +1,5 @@ tarball=pip-VERSION.tar.gz -sha1=a243525070cf70f22a185447ebd3e1435dabb218 -md5=0d3f27f4b7fecb33fd573e4f46cc6788 -cksum=3764331442 +sha1=9b45b63bfa3abaf10235bd149959a36e98eca7f6 +md5=0449e82526e48fc5169a857193f6a63c +cksum=1661319788 upstream_url=https://pypi.io/packages/source/p/pip/pip-VERSION.tar.gz diff --git a/build/pkgs/pip/package-version.txt b/build/pkgs/pip/package-version.txt index 0fac3b01f54..95f8a283f00 100644 --- a/build/pkgs/pip/package-version.txt +++ b/build/pkgs/pip/package-version.txt @@ -1 +1 @@ -21.3.1 +22.0.2 From 6952de429b08d78f03854ce22498db3581118ebf Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 31 Jan 2022 14:52:44 -0800 Subject: [PATCH 202/253] build/pkgs/texlive/spkg-configure.m4: Check for pdflatex, latexmk, dvipng --- build/pkgs/texlive/spkg-configure.m4 | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/build/pkgs/texlive/spkg-configure.m4 b/build/pkgs/texlive/spkg-configure.m4 index 649252c0d05..18dab7e9e57 100644 --- a/build/pkgs/texlive/spkg-configure.m4 +++ b/build/pkgs/texlive/spkg-configure.m4 @@ -1,5 +1,11 @@ SAGE_SPKG_CONFIGURE([texlive], [ - dnl pdflatex --version + sage_spkg_install_texlive=no + AC_PATH_PROG([PDFLATEX], [pdflatex]) + AS_IF([test -z "$PDFLATEX"], [sage_spkg_install_texlive=yes]) + AC_PATH_PROG([LATEXMK], [latexmk]) + AS_IF([test -z "$LATEXMK"], [sage_spkg_install_texlive=yes]) + AC_PATH_PROG([DVIPNG], [dvipng]) + AS_IF([test -z "$DVIPNG"], [sage_spkg_install_texlive=yes]) m4_foreach([latex_package], [fontspec,xunicode,xltxtra,amssymb,amsfonts,graphicx,mathrsfs, textcomp,tikz,tikz-qtree,iftex,tkz-berge,tkz-graph,xy,babel, From b85356f7beea417338a64b856649251a30a1bdc6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 31 Jan 2022 14:53:04 -0800 Subject: [PATCH 203/253] build/pkgs/texlive/spkg-configure.m4: Check for tgtermes.sty --- build/pkgs/texlive/spkg-configure.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/texlive/spkg-configure.m4 b/build/pkgs/texlive/spkg-configure.m4 index 18dab7e9e57..a54c6d16d24 100644 --- a/build/pkgs/texlive/spkg-configure.m4 +++ b/build/pkgs/texlive/spkg-configure.m4 @@ -9,7 +9,7 @@ SAGE_SPKG_CONFIGURE([texlive], [ m4_foreach([latex_package], [fontspec,xunicode,xltxtra,amssymb,amsfonts,graphicx,mathrsfs, textcomp,tikz,tikz-qtree,iftex,tkz-berge,tkz-graph,xy,babel, - subfigure,hyperref,hypcap,xr], + subfigure,hyperref,hypcap,xr,tgtermes], [ AC_MSG_CHECKING([for latex package ]latex_package) AS_IF([kpsewhich ]latex_package[.sty >& AS_MESSAGE_LOG_FD 2>&1], [ From 62fbc45faba4a9e95d851f92bcb1c19d3bc50021 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 31 Jan 2022 14:53:54 -0800 Subject: [PATCH 204/253] build/pkgs/sagemath_doc_pdf/dependencies: Add texlive --- build/pkgs/sagemath_doc_pdf/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/sagemath_doc_pdf/dependencies b/build/pkgs/sagemath_doc_pdf/dependencies index 4bdc1055372..21eb5295b36 100644 --- a/build/pkgs/sagemath_doc_pdf/dependencies +++ b/build/pkgs/sagemath_doc_pdf/dependencies @@ -1 +1 @@ -sagemath_doc_html +sagemath_doc_html texlive From 8b2490e6f6aa700462a97bfc827855c80218c1b0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 31 Jan 2022 15:05:03 -0800 Subject: [PATCH 205/253] build/pkgs/texlive/spkg-configure.m4: ALso check for fncychap.sty --- build/pkgs/texlive/spkg-configure.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/texlive/spkg-configure.m4 b/build/pkgs/texlive/spkg-configure.m4 index a54c6d16d24..e16d0f7c057 100644 --- a/build/pkgs/texlive/spkg-configure.m4 +++ b/build/pkgs/texlive/spkg-configure.m4 @@ -9,7 +9,7 @@ SAGE_SPKG_CONFIGURE([texlive], [ m4_foreach([latex_package], [fontspec,xunicode,xltxtra,amssymb,amsfonts,graphicx,mathrsfs, textcomp,tikz,tikz-qtree,iftex,tkz-berge,tkz-graph,xy,babel, - subfigure,hyperref,hypcap,xr,tgtermes], + subfigure,hyperref,hypcap,xr,tgtermes,fncychap], [ AC_MSG_CHECKING([for latex package ]latex_package) AS_IF([kpsewhich ]latex_package[.sty >& AS_MESSAGE_LOG_FD 2>&1], [ From 7b97dd40a69ce62d908849a7ab9b3f5418dc0600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Tue, 1 Feb 2022 13:00:40 +1300 Subject: [PATCH 206/253] update list of gentoo packages --- build/pkgs/texlive/distros/gentoo.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/build/pkgs/texlive/distros/gentoo.txt b/build/pkgs/texlive/distros/gentoo.txt index 9d4b10e19a4..e1201c0213c 100644 --- a/build/pkgs/texlive/distros/gentoo.txt +++ b/build/pkgs/texlive/distros/gentoo.txt @@ -1,2 +1,15 @@ dev-tex/latexmk app-text/texlive +dev-texlive/texlive-langcjk +dev-texlive/texlive-langcyrillic +dev-texlive/texlive-langenglish +dev-texlive/texlive-langeuropean +dev-texlive/texlive-langfrench +dev-texlive/texlive-langgerman +dev-texlive/texlive-langitalian +dev-texlive/texlive-langjapanese +dev-texlive/texlive-langportuguese +dev-texlive/texlive-langspanish +dev-texlive/texlive-latexextra +dev-texlive/texlive-latexrecommended +dev-texlive/texlive-mathscience From 8f19cb7d809511e0cfa6961de82b934330c5f6ca Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 1 Feb 2022 14:59:27 +0900 Subject: [PATCH 207/253] Implementing general inverse for fin-dim algebra w basis. Extending and standardizing from_vector(). --- src/sage/algebras/lie_algebras/quotient.py | 3 +- .../lie_algebras/structure_coefficients.py | 6 +- src/sage/algebras/lie_algebras/subalgebra.py | 2 +- .../finite_dimensional_algebras_with_basis.py | 72 +++++++++++++++++++ .../finite_dimensional_modules_with_basis.py | 9 ++- src/sage/categories/lie_algebras.py | 2 +- .../categories/lie_algebras_with_basis.py | 2 +- src/sage/combinat/free_module.py | 10 ++- 8 files changed, 95 insertions(+), 11 deletions(-) diff --git a/src/sage/algebras/lie_algebras/quotient.py b/src/sage/algebras/lie_algebras/quotient.py index f4b7b87ecc2..aae66dd1087 100644 --- a/src/sage/algebras/lie_algebras/quotient.py +++ b/src/sage/algebras/lie_algebras/quotient.py @@ -385,7 +385,7 @@ def defining_ideal(self): """ return self._I - def from_vector(self, v): + def from_vector(self, v, order=None, coerce=False): r""" Return the element of ``self`` corresponding to the vector ``v``. @@ -418,3 +418,4 @@ def from_vector(self, v): sup = super(LieQuotient_finite_dimensional_with_basis, self) return sup.from_vector(v) + diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index cc84cac7388..91bb39d84c8 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -345,7 +345,7 @@ def term(self, k, c=None): c = self.base_ring()(c) return self.element_class(self, c * self._M.basis()[self._index_to_pos[k]]) - def from_vector(self, v): + def from_vector(self, v, order=None, coerce=True): """ Return an element of ``self`` from the vector ``v``. @@ -355,7 +355,9 @@ def from_vector(self, v): sage: L.from_vector([1, 2, -2]) x + 2*y - 2*z """ - return self.element_class(self, self._M(v)) + if coerce: + v = self._M(v) + return self.element_class(self, v) def some_elements(self): """ diff --git a/src/sage/algebras/lie_algebras/subalgebra.py b/src/sage/algebras/lie_algebras/subalgebra.py index 660dc23bba6..b9be7e5780d 100644 --- a/src/sage/algebras/lie_algebras/subalgebra.py +++ b/src/sage/algebras/lie_algebras/subalgebra.py @@ -734,7 +734,7 @@ def leading_monomials(self): return Family(self.lift(X).leading_monomial(key=self._order) for X in self.basis()) - def from_vector(self, v): + def from_vector(self, v, order=None, coerce=False): r""" Return the element of ``self`` corresponding to the vector ``v`` diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index a8922d18762..d9b1de0521e 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -1086,6 +1086,78 @@ def to_matrix(self, base_ring=None, action=operator.mul, side='left'): _matrix_ = to_matrix # For temporary backward compatibility on_left_matrix = to_matrix + def __invert__(self): + r""" + Return the inverse of ``self`` if ``self`` if it + exists, and otherwise raise an error. + + .. WARNING:: + + This always returns the inverse or fails on elements + that are not invertible when the base ring is a field. + In other cases, it may fail to find an inverse even + if one exists if we cannot solve a linear system of + equations over (the fraction field of) the base ring. + + EXAMPLES:: + + sage: QS3 = SymmetricGroupAlgebra(QQ, 3) + sage: P = Permutation + sage: a = 3 * QS3(P([1,2,3])) + QS3(P([1,3,2])) + QS3(P([2,1,3])) + sage: b = ~a; b + 9/20*[1, 2, 3] - 7/40*[1, 3, 2] - 7/40*[2, 1, 3] + + 3/40*[2, 3, 1] + 3/40*[3, 1, 2] - 1/20*[3, 2, 1] + sage: a * b + [1, 2, 3] + sage: ~b == a + True + + sage: R. = QQ[] + sage: RS3 = SymmetricGroupAlgebra(R, 3) + sage: a = RS3(P([1,2,3])) - RS3(P([1,3,2])) + RS3(P([2,1,3])); ~a + -1/2*[1, 3, 2] + 1/2*[2, 1, 3] + 1/2*[2, 3, 1] + 1/2*[3, 1, 2] + + Some examples on elements that do not have an inverse:: + + sage: c = 2 * QS3(P([1,2,3])) + QS3(P([1,3,2])) + QS3(P([2,1,3])) + sage: ~c + Traceback (most recent call last): + ... + ValueError: cannot invert self (= 2*[1, 2, 3] + [1, 3, 2] + [2, 1, 3]) + + sage: ZS3 = SymmetricGroupAlgebra(ZZ, 3) + sage: aZ = 3 * ZS3(P([1,2,3])) + ZS3(P([1,3,2])) + ZS3(P([2,1,3])) + sage: ~aZ + Traceback (most recent call last): + ... + ValueError: cannot invert self (= 3*[1, 2, 3] + [1, 3, 2] + [2, 1, 3]) + sage: x = 2 * ZS3.one() + sage: ~x + Traceback (most recent call last): + ... + ValueError: cannot invert self (= 2*[1, 2, 3]) + """ + alg = self.parent() + R = alg.base_ring() + try: + ob = alg.one_basis() + mc = self.monomial_coefficients(copy=False) + if len(mc) == 1 and ob in mc: + return alg.term(ob, R(~mc[ob])) + except AttributeError: + pass + except (ValueError, TypeError): + raise ValueError("cannot invert self (= %s)" % self) + + e = alg.one().to_vector() + A = self.to_matrix() + try: + inv = A.solve_right(e) + inv.change_ring(R) + return alg.from_vector(inv) + except (ValueError, TypeError): + raise ValueError("cannot invert self (= %s)" % self) + class Cellular(CategoryWithAxiom_over_base_ring): r""" Cellular algebras. diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index 0a88ea68233..a76958c22b3 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -265,7 +265,7 @@ def _dense_free_module(self, base_ring=None): from sage.modules.free_module import FreeModule return FreeModule(base_ring, self.dimension()) - def from_vector(self, vector, order=None): + def from_vector(self, vector, order=None, coerce=True): """ Build an element of ``self`` from a vector. @@ -283,7 +283,12 @@ def from_vector(self, vector, order=None): order = sorted(self.basis().keys()) except AttributeError: # Not a family, assume it is list-like order = range(self.dimension()) - return self._from_dict({order[i]: c for i,c in vector.iteritems()}) + if not coerce or vector.base_ring() is self.base_ring(): + return self._from_dict({order[i]: c for i,c in vector.items()}, + coerce=False) + R = self.base_ring() + return self._from_dict({order[i]: R(c) for i,c in vector.items() if R(c)}, + coerce=False, remove_zeros=False) def echelon_form(self, elements, row_reduced=False, order=None): r""" diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index b088a9cb39d..61145322e95 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -400,7 +400,7 @@ def module(self): """ @abstract_method(optional=True) - def from_vector(self, v, order=None): + def from_vector(self, v, order=None, coerce=False): """ Return the element of ``self`` corresponding to the vector ``v`` in ``self.module()``. diff --git a/src/sage/categories/lie_algebras_with_basis.py b/src/sage/categories/lie_algebras_with_basis.py index 9cc23084381..6bcbc7f7beb 100644 --- a/src/sage/categories/lie_algebras_with_basis.py +++ b/src/sage/categories/lie_algebras_with_basis.py @@ -107,7 +107,7 @@ def module(self): # Otherwise just index by the basis of ``self`` as a fallback return CombinatorialFreeModule(self.base_ring(), self.basis()) - def from_vector(self, v, order=None): + def from_vector(self, v, order=None, coerce=False): """ Return the element of ``self`` corresponding to the vector ``v`` in ``self.module()``. diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index d48f5ab055c..89324a0eb0d 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -889,7 +889,7 @@ def _order_key(self, x): """ return self._rank_basis(x) - def from_vector(self, vector, order=None): + def from_vector(self, vector, order=None, coerce=True): """ Build an element of ``self`` from a (sparse) vector. @@ -906,8 +906,12 @@ def from_vector(self, vector, order=None): """ if order is None: order = self.get_order() - return self._from_dict({order[index]: coeff - for (index, coeff) in vector.items()}) + if not coerce or vector.base_ring() is self.base_ring(): + return self._from_dict({order[i]: c for i,c in vector.items()}, + coerce=False) + R = self.base_ring() + return self._from_dict({order[i]: R(c) for i,c in vector.items() if R(c)}, + coerce=False, remove_zeros=False) def sum(self, iter_of_elements): """ From dbbcd6e580a7e96dee2a05b17c375340c95e8bfd Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Tue, 1 Feb 2022 21:49:16 +0100 Subject: [PATCH 208/253] handle partition for generic input of BipartiteGraph --- src/sage/graphs/bipartite_graph.py | 60 +++++++++++++++++------------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/src/sage/graphs/bipartite_graph.py b/src/sage/graphs/bipartite_graph.py index 94e99c621a5..72734006819 100644 --- a/src/sage/graphs/bipartite_graph.py +++ b/src/sage/graphs/bipartite_graph.py @@ -310,6 +310,17 @@ def __init__(self, data=None, partition=None, check=True, *args, **kwds): sage: partition = [list(range(5)), list(range(5, 10))] sage: B = BipartiteGraph(P, partition, check=False) + TESTS: + + Check that :trac:`33249` is fixed:: + + sage: G = BipartiteGraph({2:[1], 3:[1], 4:[5]}, partition=([2,3,4],[1,5])) + sage: print(G.left, G.right) + {2, 3, 4} {1, 5} + sage: G = BipartiteGraph({2:[1], 3:[1]}, partition=([1,2],[3]), check=True) + Traceback (most recent call last): + ... + TypeError: input graph is not bipartite with respect to the given partition """ if kwds is None: kwds = {'loops': False} @@ -379,33 +390,15 @@ def __init__(self, data=None, partition=None, check=True, *args, **kwds): for jj in range(nrows): if data[jj, ii]: self.add_edge((ii, jj + ncols)) - elif isinstance(data, GenericGraph) and partition is not None: - left, right = set(partition[0]), set(partition[1]) - verts = left | right - if set(data) != verts: - data = data.subgraph(verts) - Graph.__init__(self, data, *args, **kwds) - if check: - if (any(left.intersection(data.neighbor_iterator(a)) for a in left) or - any(right.intersection(data.neighbor_iterator(a)) for a in right)): - raise TypeError("input graph is not bipartite with " - "respect to the given partition") - else: - for a in left: - a_nbrs = left.intersection(data.neighbor_iterator(a)) - if a_nbrs: - self.delete_edges((a, b) for b in a_nbrs) - for a in right: - a_nbrs = right.intersection(data.neighbor_iterator(a)) - if a_nbrs: - self.delete_edges((a, b) for b in a_nbrs) - self.left, self.right = left, right - elif isinstance(data, GenericGraph): - Graph.__init__(self, data, *args, **kwds) - self._upgrade_from_graph() else: - import networkx + if partition is not None: + left, right = set(partition[0]), set(partition[1]) + if isinstance(data, GenericGraph): + verts = left | right + if set(data) != verts: + data = data.subgraph(verts) Graph.__init__(self, data, *args, **kwds) + import networkx if isinstance(data, (networkx.MultiGraph, networkx.Graph)): if hasattr(data, "node_type"): # Assume the graph is bipartite @@ -420,6 +413,23 @@ def __init__(self, data=None, partition=None, check=True, *args, **kwds): raise TypeError( "NetworkX node_type defies bipartite " "assumption (is not 'Top' or 'Bottom')") + elif partition: + if check: + if (any(left.intersection(self.neighbor_iterator(a)) for a in left) or + any(right.intersection(self.neighbor_iterator(a)) for a in right)): + raise TypeError("input graph is not bipartite with " + "respect to the given partition") + else: + for a in left: + a_nbrs = left.intersection(data.neighbor_iterator(a)) + if a_nbrs: + self.delete_edges((a, b) for b in a_nbrs) + for a in right: + a_nbrs = right.intersection(data.neighbor_iterator(a)) + if a_nbrs: + self.delete_edges((a, b) for b in a_nbrs) + self.left, self.right = left, right + # make sure we found a bipartition if not (hasattr(self, "left") and hasattr(self, "right")): self._upgrade_from_graph() From c2e9d6a72f6dc61fc4a9d78d8bce1979d1a6cbc2 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Tue, 1 Feb 2022 22:14:36 +0100 Subject: [PATCH 209/253] some error checking --- src/sage/graphs/bipartite_graph.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/sage/graphs/bipartite_graph.py b/src/sage/graphs/bipartite_graph.py index 72734006819..ad901e18136 100644 --- a/src/sage/graphs/bipartite_graph.py +++ b/src/sage/graphs/bipartite_graph.py @@ -321,6 +321,14 @@ def __init__(self, data=None, partition=None, check=True, *args, **kwds): Traceback (most recent call last): ... TypeError: input graph is not bipartite with respect to the given partition + sage: G = BipartiteGraph({2:[1], 3:[1], 4:[5]}, partition=([2,3,4],[1])) + Traceback (most recent call last): + ... + ValueError: not all vertices appear in partition + sage: G = BipartiteGraph({2:[1], 3:[1], 4:[5]}, partition=([2,3,4],[1, 2])) + Traceback (most recent call last): + ... + ValueError: the parts are not disjoint """ if kwds is None: kwds = {'loops': False} @@ -398,6 +406,13 @@ def __init__(self, data=None, partition=None, check=True, *args, **kwds): if set(data) != verts: data = data.subgraph(verts) Graph.__init__(self, data, *args, **kwds) + if partition is not None: + # Some error checking. + if left & right: + raise ValueError("the parts are not disjoint") + if len(left) + len(right) != self.num_verts(): + raise ValueError("not all vertices appear in partition") + import networkx if isinstance(data, (networkx.MultiGraph, networkx.Graph)): if hasattr(data, "node_type"): From db1c09a8698851a381cea737cacbc8baf27840a7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 1 Feb 2022 13:54:40 -0800 Subject: [PATCH 210/253] build/pkgs/pip/patches/10574.patch: Remove --- build/pkgs/pip/patches/10574.patch | 544 ----------------------------- 1 file changed, 544 deletions(-) delete mode 100644 build/pkgs/pip/patches/10574.patch diff --git a/build/pkgs/pip/patches/10574.patch b/build/pkgs/pip/patches/10574.patch deleted file mode 100644 index 365b5a9edf0..00000000000 --- a/build/pkgs/pip/patches/10574.patch +++ /dev/null @@ -1,544 +0,0 @@ -Backported by deleting changes to file tests/unit/resolution_resolvelib/test_resolver.py - -From af383922b226f7caeac79f98d7a2991be86ab904 Mon Sep 17 00:00:00 2001 -From: Maurits van Rees -Date: Tue, 12 Oct 2021 10:36:35 +0200 -Subject: [PATCH 01/13] Simplify graph in get_topological_weights. - -Fixes https://github.com/pypa/pip/issues/10557 where the resolver spends too much time calculating the weights. - -Also, do not let `get_installation_order` calculate these weights at all when there is nothing left to install. ---- - news/10557.bugfix.rst | 1 + - .../resolution/resolvelib/resolver.py | 41 ++++++++++++++++++- - .../resolution_resolvelib/test_resolver.py | 2 +- - 3 files changed, 42 insertions(+), 2 deletions(-) - create mode 100644 news/10557.bugfix.rst - -diff --git a/news/10557.bugfix.rst b/news/10557.bugfix.rst -new file mode 100644 -index 00000000000..d902cea3c3d ---- /dev/null -+++ b/news/10557.bugfix.rst -@@ -0,0 +1 @@ -+Simplify the graph when calculating weights for the installation order. -diff --git a/src/pip/_internal/resolution/resolvelib/resolver.py b/src/pip/_internal/resolution/resolvelib/resolver.py -index 12f96702024..8e35c3dc838 100644 ---- a/src/pip/_internal/resolution/resolvelib/resolver.py -+++ b/src/pip/_internal/resolution/resolvelib/resolver.py -@@ -177,6 +177,10 @@ def get_installation_order( - """ - assert self._result is not None, "must call resolve() first" - -+ if not req_set.requirements: -+ # Nothing is left to install, so we do not need an order. -+ return [] -+ - graph = self._result.graph - weights = get_topological_weights( - graph, -@@ -213,6 +217,35 @@ def get_topological_weights( - path: Set[Optional[str]] = set() - weights: Dict[Optional[str], int] = {} - -+ # Make a copy of the graph and edit the copy, -+ # instead of changing the original. -+ cgraph: "DirectedGraph[Optional[str]]" = graph.copy() -+ -+ def simplify_graph(): -+ # In the first pass, we iterate over the original graph, -+ # looking for any keys that have no dependencies themselves. -+ # Use a large weight for them. -+ # Actually, maybe not. -+ leaves = set() -+ for key in cgraph: -+ if not cgraph._forwards[key] and key is not None: -+ leaves.add(key) -+ if not leaves: -+ # We are done simplifying. -+ return -+ # Calculate the weight for the leaves. -+ weight = len(cgraph) - 1 -+ if weight == 0: -+ # Precaution against dividing by zero. We are done. -+ return -+ for leave in leaves: -+ weights[leave] = weight -+ # Remove the leaves from the copy of the graph, making the copy simpler. -+ for leave in leaves: -+ cgraph.remove(leave) -+ # Now that we have a simpler graph, try to simplify it again. -+ simplify_graph() -+ - def visit(node: Optional[str]) -> None: - if node in path: - # We hit a cycle, so we'll break it here. -@@ -220,13 +253,19 @@ def visit(node: Optional[str]) -> None: - - # Time to visit the children! - path.add(node) -- for child in graph.iter_children(node): -+ for child in cgraph.iter_children(node): - visit(child) - path.remove(node) - - last_known_parent_count = weights.get(node, 0) - weights[node] = max(last_known_parent_count, len(path)) - -+ # Recursively simplify the graph, pruning leaves that have no dependencies. -+ # This is needed for large graphs (say over 200 packages) because the -+ # `visit` function is exponentially slower then, taking minutes. -+ # See https://github.com/pypa/pip/issues/10557 -+ simplify_graph() -+ # Visit the remaining graph. - # `None` is guaranteed to be the root node by resolvelib. - visit(None) - -From 3983756b43dc321d6f6a1c8ab58acd8dcd16db23 Mon Sep 17 00:00:00 2001 -From: Maurits van Rees -Date: Tue, 12 Oct 2021 13:11:53 +0200 -Subject: [PATCH 02/13] fix mypy - ---- - src/pip/_internal/resolution/resolvelib/resolver.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/pip/_internal/resolution/resolvelib/resolver.py b/src/pip/_internal/resolution/resolvelib/resolver.py -index 8e35c3dc838..0ff54e677d7 100644 ---- a/src/pip/_internal/resolution/resolvelib/resolver.py -+++ b/src/pip/_internal/resolution/resolvelib/resolver.py -@@ -221,7 +221,7 @@ def get_topological_weights( - # instead of changing the original. - cgraph: "DirectedGraph[Optional[str]]" = graph.copy() - -- def simplify_graph(): -+ def simplify_graph() -> None: - # In the first pass, we iterate over the original graph, - # looking for any keys that have no dependencies themselves. - # Use a large weight for them. - -From 9a973209149ea0ce6bf46a911cbc42ea21969e6c Mon Sep 17 00:00:00 2001 -From: Maurits van Rees -Date: Tue, 12 Oct 2021 13:13:24 +0200 -Subject: [PATCH 03/13] Removed outdated comment and no longer needed code. - ---- - src/pip/_internal/resolution/resolvelib/resolver.py | 7 ------- - 1 file changed, 7 deletions(-) - -diff --git a/src/pip/_internal/resolution/resolvelib/resolver.py b/src/pip/_internal/resolution/resolvelib/resolver.py -index 0ff54e677d7..ebab591c639 100644 ---- a/src/pip/_internal/resolution/resolvelib/resolver.py -+++ b/src/pip/_internal/resolution/resolvelib/resolver.py -@@ -222,10 +222,6 @@ def get_topological_weights( - cgraph: "DirectedGraph[Optional[str]]" = graph.copy() - - def simplify_graph() -> None: -- # In the first pass, we iterate over the original graph, -- # looking for any keys that have no dependencies themselves. -- # Use a large weight for them. -- # Actually, maybe not. - leaves = set() - for key in cgraph: - if not cgraph._forwards[key] and key is not None: -@@ -235,9 +231,6 @@ def simplify_graph() -> None: - return - # Calculate the weight for the leaves. - weight = len(cgraph) - 1 -- if weight == 0: -- # Precaution against dividing by zero. We are done. -- return - for leave in leaves: - weights[leave] = weight - # Remove the leaves from the copy of the graph, making the copy simpler. - -From 7e53097bb35cd284d52c0f6580e692ee5c91849a Mon Sep 17 00:00:00 2001 -From: Maurits van Rees -Date: Tue, 12 Oct 2021 14:18:29 +0200 -Subject: [PATCH 04/13] Fixed another mypy warning, about DiGraph having no - attr _forwards. - -I am not used to mypy and did not have pre-commit installed yet. ---- - src/pip/_internal/resolution/resolvelib/resolver.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/pip/_internal/resolution/resolvelib/resolver.py b/src/pip/_internal/resolution/resolvelib/resolver.py -index ebab591c639..c68deb5562c 100644 ---- a/src/pip/_internal/resolution/resolvelib/resolver.py -+++ b/src/pip/_internal/resolution/resolvelib/resolver.py -@@ -224,7 +224,7 @@ def get_topological_weights( - def simplify_graph() -> None: - leaves = set() - for key in cgraph: -- if not cgraph._forwards[key] and key is not None: -+ if not list(cgraph.iter_children(key)) and key is not None: - leaves.add(key) - if not leaves: - # We are done simplifying. - -From a6b930b2263529940320c1909c60361f62f031ac Mon Sep 17 00:00:00 2001 -From: Maurits van Rees -Date: Mon, 25 Oct 2021 09:58:46 +0200 -Subject: [PATCH 05/13] get_topological_weights: minor improvements from - reviews. - ---- - .../resolution/resolvelib/resolver.py | 22 +++++++++---------- - 1 file changed, 10 insertions(+), 12 deletions(-) - -diff --git a/src/pip/_internal/resolution/resolvelib/resolver.py b/src/pip/_internal/resolution/resolvelib/resolver.py -index c68deb5562c..cda2ffc443c 100644 ---- a/src/pip/_internal/resolution/resolvelib/resolver.py -+++ b/src/pip/_internal/resolution/resolvelib/resolver.py -@@ -217,25 +217,23 @@ def get_topological_weights( - path: Set[Optional[str]] = set() - weights: Dict[Optional[str], int] = {} - -- # Make a copy of the graph and edit the copy, -- # instead of changing the original. -- cgraph: "DirectedGraph[Optional[str]]" = graph.copy() -- - def simplify_graph() -> None: - leaves = set() -- for key in cgraph: -- if not list(cgraph.iter_children(key)) and key is not None: -+ for key in graph: -+ if key is None: -+ continue -+ if next(graph.iter_children(key), None) is not None: - leaves.add(key) - if not leaves: - # We are done simplifying. - return - # Calculate the weight for the leaves. -- weight = len(cgraph) - 1 -- for leave in leaves: -- weights[leave] = weight -+ weight = len(graph) - 1 -+ for leaf in leaves: -+ weights[leaf] = weight - # Remove the leaves from the copy of the graph, making the copy simpler. -- for leave in leaves: -- cgraph.remove(leave) -+ for leaf in leaves: -+ graph.remove(leaf) - # Now that we have a simpler graph, try to simplify it again. - simplify_graph() - -@@ -246,7 +244,7 @@ def visit(node: Optional[str]) -> None: - - # Time to visit the children! - path.add(node) -- for child in cgraph.iter_children(node): -+ for child in graph.iter_children(node): - visit(child) - path.remove(node) - - -From 11ce17e84a59dcf3af32c48ca27b9d151caa0170 Mon Sep 17 00:00:00 2001 -From: Maurits van Rees -Date: Mon, 25 Oct 2021 10:48:29 +0200 -Subject: [PATCH 06/13] get_topological_weights: fixed condition. - -After minor refactoring, the condition was the wrong way around. ---- - src/pip/_internal/resolution/resolvelib/resolver.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/pip/_internal/resolution/resolvelib/resolver.py b/src/pip/_internal/resolution/resolvelib/resolver.py -index cda2ffc443c..2f27badc069 100644 ---- a/src/pip/_internal/resolution/resolvelib/resolver.py -+++ b/src/pip/_internal/resolution/resolvelib/resolver.py -@@ -222,7 +222,7 @@ def simplify_graph() -> None: - for key in graph: - if key is None: - continue -- if next(graph.iter_children(key), None) is not None: -+ if next(graph.iter_children(key), None) is None: - leaves.add(key) - if not leaves: - # We are done simplifying. - -From 6145342ba71d8e9521984a0fe4c0eed32166f205 Mon Sep 17 00:00:00 2001 -From: Maurits van Rees -Date: Mon, 25 Oct 2021 11:56:45 +0200 -Subject: [PATCH 07/13] get_topological_weights: iterate instead of calling - next. - -'next' gives mypy errors. ---- - src/pip/_internal/resolution/resolvelib/resolver.py | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/src/pip/_internal/resolution/resolvelib/resolver.py b/src/pip/_internal/resolution/resolvelib/resolver.py -index 2f27badc069..bc99d5ad733 100644 ---- a/src/pip/_internal/resolution/resolvelib/resolver.py -+++ b/src/pip/_internal/resolution/resolvelib/resolver.py -@@ -222,7 +222,11 @@ def simplify_graph() -> None: - for key in graph: - if key is None: - continue -- if next(graph.iter_children(key), None) is None: -+ for _child in graph.iter_children(key): -+ # This means we have at least one child -+ break -+ else: -+ # No child. - leaves.add(key) - if not leaves: - # We are done simplifying. - -From b5c0b82c8276c8e8262a87121ff0c6812339afa4 Mon Sep 17 00:00:00 2001 -From: Maurits van Rees -Date: Tue, 16 Nov 2021 18:33:54 +0100 -Subject: [PATCH 08/13] Replace the recursive simplify_graph function with a - while loop. - -This is easier to wrap your head around. ---- - .../resolution/resolvelib/resolver.py | 44 +++++++++---------- - 1 file changed, 21 insertions(+), 23 deletions(-) - -diff --git a/src/pip/_internal/resolution/resolvelib/resolver.py b/src/pip/_internal/resolution/resolvelib/resolver.py -index bc99d5ad733..a0f9acaeca9 100644 ---- a/src/pip/_internal/resolution/resolvelib/resolver.py -+++ b/src/pip/_internal/resolution/resolvelib/resolver.py -@@ -217,7 +217,26 @@ def get_topological_weights( - path: Set[Optional[str]] = set() - weights: Dict[Optional[str], int] = {} - -- def simplify_graph() -> None: -+ def visit(node: Optional[str]) -> None: -+ if node in path: -+ # We hit a cycle, so we'll break it here. -+ return -+ -+ # Time to visit the children! -+ path.add(node) -+ for child in graph.iter_children(node): -+ visit(child) -+ path.remove(node) -+ -+ last_known_parent_count = weights.get(node, 0) -+ weights[node] = max(last_known_parent_count, len(path)) -+ -+ # Simplify the graph, pruning leaves that have no dependencies. -+ # This is needed for large graphs (say over 200 packages) because the -+ # `visit` function is exponentially slower then, taking minutes. -+ # See https://github.com/pypa/pip/issues/10557 -+ # We will loop until we explicitly break the loop. -+ while True: - leaves = set() - for key in graph: - if key is None: -@@ -230,7 +249,7 @@ def simplify_graph() -> None: - leaves.add(key) - if not leaves: - # We are done simplifying. -- return -+ break - # Calculate the weight for the leaves. - weight = len(graph) - 1 - for leaf in leaves: -@@ -238,28 +257,7 @@ def simplify_graph() -> None: - # Remove the leaves from the copy of the graph, making the copy simpler. - for leaf in leaves: - graph.remove(leaf) -- # Now that we have a simpler graph, try to simplify it again. -- simplify_graph() - -- def visit(node: Optional[str]) -> None: -- if node in path: -- # We hit a cycle, so we'll break it here. -- return -- -- # Time to visit the children! -- path.add(node) -- for child in graph.iter_children(node): -- visit(child) -- path.remove(node) -- -- last_known_parent_count = weights.get(node, 0) -- weights[node] = max(last_known_parent_count, len(path)) -- -- # Recursively simplify the graph, pruning leaves that have no dependencies. -- # This is needed for large graphs (say over 200 packages) because the -- # `visit` function is exponentially slower then, taking minutes. -- # See https://github.com/pypa/pip/issues/10557 -- simplify_graph() - # Visit the remaining graph. - # `None` is guaranteed to be the root node by resolvelib. - visit(None) - -From 9408cad47390e60a18e56b041748e90defdb3d7e Mon Sep 17 00:00:00 2001 -From: Maurits van Rees -Date: Wed, 17 Nov 2021 10:49:34 +0100 -Subject: [PATCH 09/13] Update news/10557.bugfix.rst - -Co-authored-by: Tzu-ping Chung ---- - news/10557.bugfix.rst | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/news/10557.bugfix.rst b/news/10557.bugfix.rst -index d902cea3c3d..2381ea90310 100644 ---- a/news/10557.bugfix.rst -+++ b/news/10557.bugfix.rst -@@ -1 +1 @@ --Simplify the graph when calculating weights for the installation order. -+Optimize installation order calculation to improve performance when installing requirements that form a complex depedency graph with a large amount of edges. - -From d07cc8cbd762ef1e795bed3948802c6cc5bcd1d0 Mon Sep 17 00:00:00 2001 -From: Maurits van Rees -Date: Wed, 17 Nov 2021 10:50:19 +0100 -Subject: [PATCH 10/13] Fixed typo in news snippet. - ---- - news/10557.bugfix.rst | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/news/10557.bugfix.rst b/news/10557.bugfix.rst -index 2381ea90310..5a6a4ef26a9 100644 ---- a/news/10557.bugfix.rst -+++ b/news/10557.bugfix.rst -@@ -1 +1 @@ --Optimize installation order calculation to improve performance when installing requirements that form a complex depedency graph with a large amount of edges. -+Optimize installation order calculation to improve performance when installing requirements that form a complex dependency graph with a large amount of edges. - -From 43d94346b6363421ce8837be74bb81d71e5e2584 Mon Sep 17 00:00:00 2001 -From: Maurits van Rees -Date: Wed, 17 Nov 2021 20:59:55 +0100 -Subject: [PATCH 11/13] Fixed comment that still talked about a copy of the - graph. - ---- - src/pip/_internal/resolution/resolvelib/resolver.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/pip/_internal/resolution/resolvelib/resolver.py b/src/pip/_internal/resolution/resolvelib/resolver.py -index a0f9acaeca9..c84c697db4c 100644 ---- a/src/pip/_internal/resolution/resolvelib/resolver.py -+++ b/src/pip/_internal/resolution/resolvelib/resolver.py -@@ -254,7 +254,7 @@ def visit(node: Optional[str]) -> None: - weight = len(graph) - 1 - for leaf in leaves: - weights[leaf] = weight -- # Remove the leaves from the copy of the graph, making the copy simpler. -+ # Remove the leaves from the graph, making it simpler. - for leaf in leaves: - graph.remove(leaf) - - -From 39ce7b5f241c7c6d0c2cebdb903bd9aacdd5abd4 Mon Sep 17 00:00:00 2001 -From: Maurits van Rees -Date: Wed, 17 Nov 2021 22:36:11 +0100 -Subject: [PATCH 12/13] Updated docstring of get_installation_order and - get_topological_weights. - ---- - .../resolution/resolvelib/resolver.py | 19 +++++++++++++++---- - 1 file changed, 15 insertions(+), 4 deletions(-) - -diff --git a/src/pip/_internal/resolution/resolvelib/resolver.py b/src/pip/_internal/resolution/resolvelib/resolver.py -index c84c697db4c..2877d7552e7 100644 ---- a/src/pip/_internal/resolution/resolvelib/resolver.py -+++ b/src/pip/_internal/resolution/resolvelib/resolver.py -@@ -171,9 +171,11 @@ def get_installation_order( - get installed one-by-one. - - The current implementation creates a topological ordering of the -- dependency graph, while breaking any cycles in the graph at arbitrary -- points. We make no guarantees about where the cycle would be broken, -- other than they would be broken. -+ dependency graph, giving more weight to packages with less -+ or no dependencies, while breaking any cycles in the graph at -+ arbitrary points. -+ We make no guarantees about where the cycle would be broken, -+ other than it *would* be broken. - """ - assert self._result is not None, "must call resolve() first" - -@@ -203,13 +205,22 @@ def get_topological_weights( - This implementation may change at any point in the future without prior - notice. - -+ We first simplify the dependency graph by pruning any leaves -+ and giving them the highest weight: a package without any dependencies -+ should be installed first. -+ We simplify again and again in the same way, giving ever less weight -+ to the newly found leaves. -+ This stops when no leaves are left: all remaining packages have at least -+ one dependency left in the graph. -+ -+ Then we continue with the remaining graph. - We take the length for the longest path to any node from root, ignoring any - paths that contain a single node twice (i.e. cycles). This is done through - a depth-first search through the graph, while keeping track of the path to - the node. - - Cycles in the graph result would result in node being revisited while also -- being it's own path. In this case, take no action. This helps ensure we -+ being on it's own path. In this case, take no action. This helps ensure we - don't get stuck in a cycle. - - When assigning weight, the longer path (i.e. larger length) is preferred. - -From 69b71caea18e47db5f3491ae0b86d6cb37d09bdc Mon Sep 17 00:00:00 2001 -From: Tzu-ping Chung -Date: Thu, 18 Nov 2021 15:21:59 +0800 -Subject: [PATCH 13/13] Reflow and fix typo in docstrings - ---- - .../resolution/resolvelib/resolver.py | 28 ++++++++----------- - 1 file changed, 12 insertions(+), 16 deletions(-) - -diff --git a/src/pip/_internal/resolution/resolvelib/resolver.py b/src/pip/_internal/resolution/resolvelib/resolver.py -index 2877d7552e7..8ee36d377d8 100644 ---- a/src/pip/_internal/resolution/resolvelib/resolver.py -+++ b/src/pip/_internal/resolution/resolvelib/resolver.py -@@ -173,9 +173,8 @@ def get_installation_order( - The current implementation creates a topological ordering of the - dependency graph, giving more weight to packages with less - or no dependencies, while breaking any cycles in the graph at -- arbitrary points. -- We make no guarantees about where the cycle would be broken, -- other than it *would* be broken. -+ arbitrary points. We make no guarantees about where the cycle -+ would be broken, other than it *would* be broken. - """ - assert self._result is not None, "must call resolve() first" - -@@ -205,22 +204,19 @@ def get_topological_weights( - This implementation may change at any point in the future without prior - notice. - -- We first simplify the dependency graph by pruning any leaves -- and giving them the highest weight: a package without any dependencies -- should be installed first. -- We simplify again and again in the same way, giving ever less weight -- to the newly found leaves. -- This stops when no leaves are left: all remaining packages have at least -- one dependency left in the graph. -+ We first simplify the dependency graph by pruning any leaves and giving them -+ the highest weight: a package without any dependencies should be installed -+ first. This is done again and again in the same way, giving ever less weight -+ to the newly found leaves. The loop stops when no leaves are left: all -+ remaining packages have at least one dependency left in the graph. - -- Then we continue with the remaining graph. -- We take the length for the longest path to any node from root, ignoring any -- paths that contain a single node twice (i.e. cycles). This is done through -- a depth-first search through the graph, while keeping track of the path to -- the node. -+ Then we continue with the remaining graph, by taking the length for the -+ longest path to any node from root, ignoring any paths that contain a single -+ node twice (i.e. cycles). This is done through a depth-first search through -+ the graph, while keeping track of the path to the node. - - Cycles in the graph result would result in node being revisited while also -- being on it's own path. In this case, take no action. This helps ensure we -+ being on its own path. In this case, take no action. This helps ensure we - don't get stuck in a cycle. - - When assigning weight, the longer path (i.e. larger length) is preferred. From 9982f9c4df14bf2a91fbf2e8a8075e9edfa34eaf Mon Sep 17 00:00:00 2001 From: dcoudert Date: Wed, 2 Feb 2022 08:28:56 +0100 Subject: [PATCH 211/253] trac #33249: review commit --- src/sage/graphs/bipartite_graph.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/graphs/bipartite_graph.py b/src/sage/graphs/bipartite_graph.py index ad901e18136..27b0e35ea0f 100644 --- a/src/sage/graphs/bipartite_graph.py +++ b/src/sage/graphs/bipartite_graph.py @@ -329,6 +329,10 @@ def __init__(self, data=None, partition=None, check=True, *args, **kwds): Traceback (most recent call last): ... ValueError: the parts are not disjoint + sage: G = BipartiteGraph({2:[1], 3:[1], 4:[5]}, partition=([2, 3, 4], [1, 7])) + Traceback (most recent call last): + ... + LookupError: vertex (7) is not a vertex of the graph """ if kwds is None: kwds = {'loops': False} From 5b309aac974be15cd4344889b4487c7dff149b40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 2 Feb 2022 09:09:45 +0100 Subject: [PATCH 212/253] more fixes about obsolete L suffix for long --- src/sage/arith/multi_modular.pyx | 5 ++--- src/sage/geometry/polyhedron/backend_normaliz.py | 3 +-- src/sage/modular/modsym/p1list.pyx | 12 ++++-------- src/sage/symbolic/pynac_impl.pxi | 7 ++++--- 4 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/sage/arith/multi_modular.pyx b/src/sage/arith/multi_modular.pyx index 342a07b2614..3b79d3bd6fc 100644 --- a/src/sage/arith/multi_modular.pyx +++ b/src/sage/arith/multi_modular.pyx @@ -686,7 +686,7 @@ cdef class MultiModularBasis_base(object): return z def precomputation_list(self): - """ + r""" Return a list of the precomputed coefficients `\prod_j=1^{i-1} m_j^{-1} (mod m_i)` where `m_i` are the prime moduli. @@ -822,8 +822,7 @@ cdef class MultiModularBasis_base(object): sage: from sage.arith.multi_modular import MultiModularBasis_base sage: mm = MultiModularBasis_base([10007, 10009]) sage: mm[1] - 10009 # 64-bit - 10009L # 32-bit + 10009 sage: mm[-1] Traceback (most recent call last): ... diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index e4c249d48a9..e5f3ebef2fc 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -12,7 +12,6 @@ - Matthias Köppe (2016-12): initial version - Jean-Philippe Labbé (2019-04): Expose normaliz features and added functionalities """ - # **************************************************************************** # Copyright (C) 2016 Matthias Köppe # @@ -398,7 +397,7 @@ def _cone_from_normaliz_data(self, data, verbose=False): 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]] + [[-1, 2, 0], [0, 0, 1], [2, -1, 0]] """ if verbose: if isinstance(verbose, str): diff --git a/src/sage/modular/modsym/p1list.pyx b/src/sage/modular/modsym/p1list.pyx index 5d427fdc089..8fee1838aab 100644 --- a/src/sage/modular/modsym/p1list.pyx +++ b/src/sage/modular/modsym/p1list.pyx @@ -30,24 +30,21 @@ ctypedef long long llong cdef int c_p1_normalize_int(int N, int u, int v, int* uu, int* vv, int* ss, int compute_s) except -1: - """ + r""" Computes the canonical representative of `\mathbb{P}^1(\ZZ/N\ZZ)` equivalent to `(u,v)` along with a transforming scalar. INPUT: - - ``N`` - an integer - ``u`` - an integer - ``v`` - an integer - OUTPUT: If gcd(u,v,N) = 1, then returns - - ``uu`` - an integer - ``vv`` - an integer @@ -1277,8 +1274,7 @@ def lift_to_sl2z_llong(llong c, llong d, int N): sage: from sage.modular.modsym.p1list import lift_to_sl2z_llong sage: lift_to_sl2z_llong(2,6,11) - [1L, 8L, 2L, 17L] # 32-bit - [1, 8, 2, 17] # 64-bit + [1, 8, 2, 17] sage: m=Matrix(Integers(),2,2,lift_to_sl2z_llong(2,6,11)) sage: m [ 1 8] @@ -1330,6 +1326,7 @@ def lift_to_sl2z_llong(llong c, llong d, int N): return [z2, -z1, c, d] + def lift_to_sl2z(c, d, N): r""" Return a list of Python ints `[a,b,c',d']` that are the entries of a @@ -1345,8 +1342,7 @@ def lift_to_sl2z(c, d, N): sage: lift_to_sl2z(2,3,6) [1, 1, 2, 3] sage: lift_to_sl2z(2,3,6000000) - [1L, 1L, 2L, 3L] # 32-bit - [1, 1, 2, 3] # 64-bit + [1, 1, 2, 3] You will get a ValueError exception if the input is invalid. Note that here gcd(15,6,24)=3:: diff --git a/src/sage/symbolic/pynac_impl.pxi b/src/sage/symbolic/pynac_impl.pxi index 8a00839f6b3..dceb5be4d8c 100644 --- a/src/sage/symbolic/pynac_impl.pxi +++ b/src/sage/symbolic/pynac_impl.pxi @@ -29,7 +29,7 @@ Pynac interface # 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 cpython cimport * @@ -214,6 +214,7 @@ cdef paramset_to_PyTuple(const_paramset_ref s): itr.inc() return res + def paramset_from_Expression(Expression e): """ EXAMPLES:: @@ -221,11 +222,11 @@ def paramset_from_Expression(Expression e): sage: from sage.symbolic.expression import paramset_from_Expression sage: f = function('f') sage: paramset_from_Expression(f(x).diff(x)) - [0L] # 32-bit - [0] # 64-bit + [0] """ return paramset_to_PyTuple(ex_to_fderivative(e._gobj).get_parameter_set()) + cdef int GINAC_FN_SERIAL = 0 cdef set_ginac_fn_serial(): From 855314d5d2a9ccaa612b50baacab2cdf4e7e802a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 2 Feb 2022 11:07:58 -0800 Subject: [PATCH 213/253] src/doc/bootstrap: Get recommended spkg from build/pkgs/_recommended/dependencies --- build/pkgs/_recommended/dependencies | 1 + src/doc/bootstrap | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 build/pkgs/_recommended/dependencies diff --git a/build/pkgs/_recommended/dependencies b/build/pkgs/_recommended/dependencies new file mode 100644 index 00000000000..d3fc241be46 --- /dev/null +++ b/build/pkgs/_recommended/dependencies @@ -0,0 +1 @@ +pandoc ffmpeg imagemagick texlive diff --git a/src/doc/bootstrap b/src/doc/bootstrap index 5c2d27f990e..da8977c23a2 100755 --- a/src/doc/bootstrap +++ b/src/doc/bootstrap @@ -25,6 +25,8 @@ mkdir -p "$OUTPUT_DIR" shopt -s extglob +RECOMMENDED_SPKG_PATTERN="@(_recommended$(for a in $(head -n 1 build/pkgs/_recommended/dependencies); do echo -n "|"$a; done))" + for SYSTEM in arch debian fedora cygwin homebrew conda; do SYSTEM_PACKAGES= OPTIONAL_SYSTEM_PACKAGES= @@ -42,7 +44,7 @@ for SYSTEM in arch debian fedora cygwin homebrew conda; do *:standard) SYSTEM_PACKAGES+=" $PKG_SYSTEM_PACKAGES" ;; - _recommended:*|pandoc:*|ffmpeg:*|imagemagick:*|texlive:*) + $RECOMMENDED_SPKG_PATTERN:*) RECOMMENDED_SYSTEM_PACKAGES+=" $PKG_SYSTEM_PACKAGES" ;; *) @@ -89,7 +91,7 @@ for SYSTEM in arch debian fedora cygwin homebrew conda; do done else if [ "${BOOTSTRAP_QUIET}" = "no" ]; then - echo >&2 $0:$LINENO: installing "$OUTPUT_DIR"/$SYSTEM.txt and "$OUTPUT_DIR"/$SYSTEM-optional.txt + echo >&2 $0:$LINENO: installing "$OUTPUT_DIR"/$SYSTEM"*.txt" fi echo "$(sage-print-system-package-command $SYSTEM --prompt --sudo install $(echo $(echo $SYSTEM_PACKAGES | xargs -n 1 echo | sort)))" > "$OUTPUT_DIR"/$SYSTEM.txt echo "$(sage-print-system-package-command $SYSTEM --prompt --sudo install $(echo $(echo $OPTIONAL_SYSTEM_PACKAGES | xargs -n 1 echo | sort)))" > "$OUTPUT_DIR"/$SYSTEM-optional.txt From b084001eb44acfa97b8c8729d4f764329572d344 Mon Sep 17 00:00:00 2001 From: sheerluck Date: Wed, 2 Feb 2022 21:45:13 +0100 Subject: [PATCH 214/253] 33269: Fix build/pkgs/tox/distros/gentoo.txt --- build/pkgs/tox/distros/gentoo.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/tox/distros/gentoo.txt b/build/pkgs/tox/distros/gentoo.txt index 053148f8486..4a5071844ed 100644 --- a/build/pkgs/tox/distros/gentoo.txt +++ b/build/pkgs/tox/distros/gentoo.txt @@ -1 +1 @@ -tox +dev-python/tox From 14dada9eb29575049f6ff12232e7082ed9fea1a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20Leli=C3=A8vre?= Date: Wed, 2 Feb 2022 21:46:49 +0100 Subject: [PATCH 215/253] 33269: Remove tox Cygwin package name --- build/pkgs/tox/distros/cygwin.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 build/pkgs/tox/distros/cygwin.txt diff --git a/build/pkgs/tox/distros/cygwin.txt b/build/pkgs/tox/distros/cygwin.txt deleted file mode 100644 index 053148f8486..00000000000 --- a/build/pkgs/tox/distros/cygwin.txt +++ /dev/null @@ -1 +0,0 @@ -tox From b6c8b76ce7e2e6fe18d72184200f6cf1b951975a Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Thu, 18 Nov 2021 09:34:52 +0100 Subject: [PATCH 216/253] update flint to 2.8.4 --- build/pkgs/flint/checksums.ini | 6 +++--- build/pkgs/flint/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/flint/checksums.ini b/build/pkgs/flint/checksums.ini index 04b3653585a..2f51fa9932d 100644 --- a/build/pkgs/flint/checksums.ini +++ b/build/pkgs/flint/checksums.ini @@ -1,5 +1,5 @@ tarball=flint-VERSION.tar.gz -sha1=0e095e667ed4424e2280c49a9e6a513d12622823 -md5=05a5f77732a05b590972d2349e6f6bb0 -cksum=2043627147 +sha1=d17a245bddec753c6eb5841b28d0322ba0c9e2b6 +md5=484e62dd7326a4af6e2072f4edbc769f +cksum=1002348409 upstream_url=http://flintlib.org/flint-VERSION.tar.gz diff --git a/build/pkgs/flint/package-version.txt b/build/pkgs/flint/package-version.txt index da323e3f838..2701a226a2f 100644 --- a/build/pkgs/flint/package-version.txt +++ b/build/pkgs/flint/package-version.txt @@ -1 +1 @@ -2.7.1.p0 +2.8.4 From f9357e9858742f6aceda6d1c8c09c6f4aeac0f7f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 2 Feb 2022 15:36:03 -0800 Subject: [PATCH 217/253] build/pkgs/arb: Update to 2.22.1 --- build/pkgs/arb/checksums.ini | 6 +++--- build/pkgs/arb/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/arb/checksums.ini b/build/pkgs/arb/checksums.ini index 3352a346073..e5efd63346d 100644 --- a/build/pkgs/arb/checksums.ini +++ b/build/pkgs/arb/checksums.ini @@ -1,5 +1,5 @@ tarball=arb-VERSION.tar.gz -sha1=33c069505b30d1668f5d873499e290e517d92c74 -md5=0a60ab546a8ad3d8d46ad9f040aeca98 -cksum=1430425209 +sha1=b49978d7a54febbc408297683085f3252b5a3281 +md5=6521245e826eb337eddedd6159eabcb8 +cksum=3488846289 upstream_url=https://github.com/fredrik-johansson/arb/archive/VERSION.tar.gz diff --git a/build/pkgs/arb/package-version.txt b/build/pkgs/arb/package-version.txt index 0d13ee7427e..d93847fab5f 100644 --- a/build/pkgs/arb/package-version.txt +++ b/build/pkgs/arb/package-version.txt @@ -1 +1 @@ -2.19.0.p0 +2.22.1 From 45f4984776ff410bc507244bc8628452c3d67502 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 2 Feb 2022 16:03:25 -0800 Subject: [PATCH 218/253] build/pkgs/arb/patches/arb-flint-2.8-compatibility-b6c8032e2da1b19eb7c5a5f5c2f3372643e3d170.patch: Remove --- ...032e2da1b19eb7c5a5f5c2f3372643e3d170.patch | 46 ------------------- 1 file changed, 46 deletions(-) delete mode 100644 build/pkgs/arb/patches/arb-flint-2.8-compatibility-b6c8032e2da1b19eb7c5a5f5c2f3372643e3d170.patch diff --git a/build/pkgs/arb/patches/arb-flint-2.8-compatibility-b6c8032e2da1b19eb7c5a5f5c2f3372643e3d170.patch b/build/pkgs/arb/patches/arb-flint-2.8-compatibility-b6c8032e2da1b19eb7c5a5f5c2f3372643e3d170.patch deleted file mode 100644 index 5e5e1b0d19f..00000000000 --- a/build/pkgs/arb/patches/arb-flint-2.8-compatibility-b6c8032e2da1b19eb7c5a5f5c2f3372643e3d170.patch +++ /dev/null @@ -1,46 +0,0 @@ -From b6c8032e2da1b19eb7c5a5f5c2f3372643e3d170 Mon Sep 17 00:00:00 2001 -From: fredrik -Date: Mon, 15 Mar 2021 11:56:24 +0100 -Subject: [PATCH] compatibility fix for latest flint - ---- - acb_modular/epsilon_arg.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/acb_modular/epsilon_arg.c b/acb_modular/epsilon_arg.c -index e1332725..b42a64ad 100644 ---- a/acb_modular/epsilon_arg.c -+++ b/acb_modular/epsilon_arg.c -@@ -12,7 +12,7 @@ - #include "acb_modular.h" - - static int --fmpz_kronecker(const fmpz_t a, const fmpz_t b) -+fmpz_kronecker1(const fmpz_t a, const fmpz_t b) - { - if (fmpz_sgn(b) < 0) - { -@@ -20,7 +20,7 @@ fmpz_kronecker(const fmpz_t a, const fmpz_t b) - fmpz_t t; - fmpz_init(t); - fmpz_neg(t, b); -- r = fmpz_kronecker(a, t); -+ r = fmpz_kronecker1(a, t); - fmpz_clear(t); - return r; - } -@@ -58,12 +58,12 @@ acb_modular_epsilon_arg(const psl2z_t g) - - if (cc % 2 == 1) - { -- u = fmpz_kronecker(a, c); -+ u = fmpz_kronecker1(a, c); - aa = aa*bb + 2*aa*cc - 3*cc + cc*dd*(1-aa*aa); - } - else - { -- u = fmpz_kronecker(c, a); -+ u = fmpz_kronecker1(c, a); - aa = aa*bb - aa*cc + 3*aa - 3 + cc*dd*(1-aa*aa); - } - From ed2a3d4d17e004d5f2ebc40d64f8f5c74e7628f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Thu, 27 Jan 2022 09:54:33 +0100 Subject: [PATCH 219/253] 33167: add try except clause to catch OSError during run --- src/sage/features/lrs.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/sage/features/lrs.py b/src/sage/features/lrs.py index 7031982797b..f6a4d922bd0 100644 --- a/src/sage/features/lrs.py +++ b/src/sage/features/lrs.py @@ -47,7 +47,12 @@ def is_functional(self): with open(tf_name, 'w') as tf: tf.write("V-representation\nbegin\n 1 1 rational\n 1 \nend\nvolume") command = ['lrs', tf_name] - result = subprocess.run(command, capture_output=True, text=True) + try: + result = subprocess.run(command, capture_output=True, text=True) + except OSError as e: + return FeatureTestResult(self, False, reason='Running command "{}" ' + 'raised an OSError "{}" '.format(' '.join(command), e)) + if result.returncode: return FeatureTestResult(self, False, reason="Call to `{command}` failed with exit code {result.returncode}.".format(command=" ".join(command), result=result)) @@ -67,7 +72,11 @@ def is_functional(self): with open(tf_name, 'w') as tf: tf.write("1 1\n \n 0\n \n 0\n") command = ['lrsnash', tf_name] - result = subprocess.run(command, capture_output=True, text=True) + try: + result = subprocess.run(command, capture_output=True, text=True) + except OSError as e: + return FeatureTestResult(self, False, reason='Running command "{}" ' + 'raised an OSError "{}" '.format(' '.join(command), e)) if result.returncode: return FeatureTestResult(self, False, reason='Running command "{}" ' 'returned non-zero exit status "{}" with stderr ' From 16e1b241bff8e0485f773c7b420fd7b2fc4defa5 Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Mon, 17 Jan 2022 21:15:27 +0100 Subject: [PATCH 220/253] 33167: add comment about polymake's use of lrslib --- build/pkgs/lrslib/spkg-configure.m4 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/pkgs/lrslib/spkg-configure.m4 b/build/pkgs/lrslib/spkg-configure.m4 index 0297f7118e3..752dcfe8fbf 100644 --- a/build/pkgs/lrslib/spkg-configure.m4 +++ b/build/pkgs/lrslib/spkg-configure.m4 @@ -1,4 +1,7 @@ SAGE_SPKG_CONFIGURE([lrslib], [ + dnl Although lrs and lrsnash binaries are the only interfaces to lrslib that + dnl sagelib uses, the optional polymake package uses lrslib as a library, so + dnl the following DEPCHECK is needed. dnl System lrslib may already be 7.x, which may be compiled with FLINT SAGE_SPKG_DEPCHECK([gmp flint], [ AC_CHECK_PROGS([LRSNASH], [lrsnash]) From d0c30c0b1b871d024629c306bd0d297f7456e11e Mon Sep 17 00:00:00 2001 From: Peter Bruin Date: Thu, 3 Feb 2022 11:56:55 +0100 Subject: [PATCH 221/253] Trac 32209: additional check --- src/sage/schemes/affine/affine_morphism.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/schemes/affine/affine_morphism.py b/src/sage/schemes/affine/affine_morphism.py index 5e282e56237..b86767c779c 100644 --- a/src/sage/schemes/affine/affine_morphism.py +++ b/src/sage/schemes/affine/affine_morphism.py @@ -262,7 +262,7 @@ def __call__(self, x, check=True): """ from sage.schemes.affine.affine_point import SchemeMorphism_point_affine if check: - if not isinstance(x, SchemeMorphism_point_affine): + if not isinstance(x, SchemeMorphism_point_affine) or self.domain() != x.codomain(): try: x = self.domain()(x) except (TypeError, NotImplementedError): From a2e1b289b5c24297e2668a9e623e2895c7e0568c Mon Sep 17 00:00:00 2001 From: Friedrich Wiemer Date: Thu, 3 Feb 2022 23:00:53 +0100 Subject: [PATCH 222/253] rename internal S-box list to resolve name clash --- src/sage/crypto/sbox.pyx | 44 ++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/sage/crypto/sbox.pyx b/src/sage/crypto/sbox.pyx index 3eb68a47b70..bb75ef50c8e 100644 --- a/src/sage/crypto/sbox.pyx +++ b/src/sage/crypto/sbox.pyx @@ -115,7 +115,7 @@ cdef class SBox(SageObject): - [BKLPPRSV2007]_ - [CDL2015]_ """ - cdef list _S + cdef list _S_list cdef object _ring cdef Py_ssize_t m cdef Py_ssize_t n @@ -195,16 +195,16 @@ cdef class SBox(SageObject): else: raise TypeError("no lookup table provided") - _S = [] + _S_list = [] for e in S: if is_FiniteFieldElement(e): e = e.polynomial().change_ring(ZZ).subs(e.parent().characteristic()) - _S.append(e) - S = _S + _S_list.append(e) + S = _S_list if not ZZ(len(S)).is_power_of(2): raise TypeError("lookup table length is not a power of 2") - self._S = S + self._S_list = S self.m = ZZ(len(S)).exact_log(2) self.n = ZZ(max(S)).nbits() @@ -254,7 +254,7 @@ cdef class SBox(SageObject): raise NotImplemented cdef SBox other = rhs - return (self._S == other._S) and (self._big_endian == self._big_endian) + return (self._S_list == other._S_list) and (self._big_endian == self._big_endian) def __ne__(self, other): """ @@ -433,11 +433,11 @@ cdef class SBox(SageObject): """ # Handle integer inputs if type(X) == int: - return self._S[ X] + return self._S_list[ X] if isinstance(X, Integer): - return self._S[ X] + return self._S_list[ X] if isinstance(X, integer_types): - return self._S[ZZ(X)] + return self._S_list[ZZ(X)] # Handle non-integer inputs: vectors, finite field elements to-integer-coercible elements #cdef int i @@ -446,7 +446,7 @@ cdef class SBox(SageObject): if K.base_ring().characteristic() != 2: try: X = ZZ(X) - return K(self._S[ X]) + return K(self._S_list[ X]) except TypeError: raise TypeError("cannot apply SBox to %s" % (X,)) raise TypeError("the characteristic of the base field must be 2") @@ -455,7 +455,7 @@ cdef class SBox(SageObject): V = K.vector_space(map=False) except AttributeError: try: - return self._S[ZZ(X)] + return self._S_list[ZZ(X)] except TypeError: pass except TypeError: @@ -480,7 +480,7 @@ cdef class SBox(SageObject): if self._big_endian: X = list(reversed(X)) X = ZZ(X, 2) - out = self.to_bits(self._S[X], self.n) + out = self.to_bits(self._S_list[X], self.n) if K is not None: return K(out) # NOTE: Parts of the code assume that when a list is passed @@ -550,7 +550,7 @@ cdef class SBox(SageObject): return False cdef Py_ssize_t m = self.m cdef Py_ssize_t i - return len(set([self._S[i] for i in range(1 << m)])) == 1 << m + return len(set([self._S_list[i] for i in range(1 << m)])) == 1 << m def __iter__(self): """ @@ -563,7 +563,7 @@ cdef class SBox(SageObject): """ cdef Py_ssize_t i for i in range(1 << self.m): - yield self._S[i] + yield self._S_list[i] def derivative(self, u): r""" @@ -651,9 +651,9 @@ cdef class SBox(SageObject): cdef list L = [0]*(nrows*ncols) for i in range(nrows): - si = self._S[i] + si = self._S_list[i] for di in range(nrows): - L[di*nrows + si ^ self._S[i ^ di]] += 1 + L[di*nrows + si ^ self._S_list[i ^ di]] += 1 A = matrix(ZZ, nrows, ncols, L) A.set_immutable() @@ -782,7 +782,7 @@ cdef class SBox(SageObject): for i in range(ncols): for j in range(nrows): - temp[i*nrows + j] = 1 - ((hamming_weight(i & self._S[j]) & 1) << 1) + temp[i*nrows + j] = 1 - ((hamming_weight(i & self._S_list[j]) & 1) << 1) walsh_hadamard(&temp[i*nrows], m) cdef list L = [temp[i*nrows + j] for j in range(nrows) for i in range(ncols)] @@ -1301,7 +1301,7 @@ cdef class SBox(SageObject): raise TypeError("cannot handle input argument %s" % (b,)) cdef Py_ssize_t x - ret = BooleanFunction([ZZ(b & self._S[x]).popcount() & 1 for x in range(1 << m)]) + ret = BooleanFunction([ZZ(b & self._S_list[x]).popcount() & 1 for x in range(1 << m)]) return ret @@ -1389,7 +1389,7 @@ cdef class SBox(SageObject): for b in range(1 << n): if a != b: x = a ^ b - y = self._S[a] ^ self._S[b] + y = self._S_list[a] ^ self._S_list[b] w = hamming_weight(x) + hamming_weight(y) if w < ret: ret = w @@ -1522,7 +1522,7 @@ cdef class SBox(SageObject): for delta_in in range(ncols): table = [[] for _ in range(ncols)] for x in range(nrows): - table[x ^ self._S[Si._S[x] ^ delta_in]].append(x) + table[x ^ self._S_list[Si._S_list[x] ^ delta_in]].append(x) row = [0]*ncols for l in table: @@ -1743,7 +1743,7 @@ cdef class SBox(SageObject): [0, 1] """ cdef Py_ssize_t i - return [i for i in range(1 << self.m) if i == self._S[i]] + return [i for i in range(1 << self.m) if i == self._S_list[i]] def inverse(self): """ @@ -1764,7 +1764,7 @@ cdef class SBox(SageObject): raise TypeError("S-Box must be a permutation") cdef Py_ssize_t i - cdef list L = [self._S[i] for i in range(1 << self.m)] + cdef list L = [self._S_list[i] for i in range(1 << self.m)] return SBox([L.index(i) for i in range(1 << self.m)], big_endian=self._big_endian) From 3164fff57cc72a83b5ce6f7177e7bfa4e4ad82b4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 4 Feb 2022 17:10:12 -0800 Subject: [PATCH 223/253] build/pkgs/_recommended/dependencies: Add git --- build/pkgs/_recommended/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/_recommended/dependencies b/build/pkgs/_recommended/dependencies index d3fc241be46..6400b71fe7d 100644 --- a/build/pkgs/_recommended/dependencies +++ b/build/pkgs/_recommended/dependencies @@ -1 +1 @@ -pandoc ffmpeg imagemagick texlive +pandoc ffmpeg imagemagick texlive git From 16f019703d97d6d72c306786990c3771f7377463 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 26 Jan 2022 14:36:04 -0800 Subject: [PATCH 224/253] tox.ini: New packages factor 'recommended' --- tox.ini | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tox.ini b/tox.ini index 825e2639c6c..2b924a69c75 100644 --- a/tox.ini +++ b/tox.ini @@ -128,6 +128,7 @@ skipsdist = true [testenv] passenv = EXTRA_CONFIGURE_ARGS + EXTRA_SAGE_PACKAGES TARGETS_PRE TARGETS_OPTIONAL docker: EXTRA_DOCKER_BUILD_ARGS @@ -168,6 +169,7 @@ setenv = maximal: IGNORE_MISSING_SYSTEM_PACKAGES=yes # What system packages should be installed. Default: All standard packages with spkg-configure. SAGE_PACKAGE_LIST_ARGS=--has-file=spkg-configure.m4 :standard: + recommended: EXTRA_SAGE_PACKAGES_3=_recommended $(head -n 1 build/pkgs/_recommended/dependencies) minimal: SAGE_PACKAGE_LIST_ARGS=_prereq maximal: SAGE_PACKAGE_LIST_ARGS=:standard: :optional: conda-environment: SAGE_PACKAGE_LIST_ARGS=_prereq @@ -535,7 +537,7 @@ setenv = # # Resulting EXTRA_SAGE_PACKAGES # - EXTRA_SAGE_PACKAGES={env:EXTRA_SAGE_PACKAGES_0:} {env:EXTRA_SAGE_PACKAGES_1:} {env:EXTRA_SAGE_PACKAGES_2:} + ALL_EXTRA_SAGE_PACKAGES={env:EXTRA_SAGE_PACKAGES_0:} {env:EXTRA_SAGE_PACKAGES_1:} {env:EXTRA_SAGE_PACKAGES_2:} {env:EXTRA_SAGE_PACKAGES_3:} {env:EXTRA_SAGE_PACKAGES:} # environment will be skipped if regular expression does not match against the sys.platform string platform = @@ -558,7 +560,7 @@ commands = # # https://docs.brew.sh/Installation homebrew: bash -c 'if [ ! -x {env:HOMEBREW}/bin/brew ]; then mkdir -p {env:HOMEBREW} && cd {env:HOMEBREW} && curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 ; fi' - homebrew: bash -c 'case "{env:SKIP_SYSTEM_PKG_INSTALL:}" in 1|y*|Y*);; *) PACKAGES=$(build/bin/sage-get-system-packages homebrew $(PATH=build/bin:$PATH build/bin/sage-package list {env:SAGE_PACKAGE_LIST_ARGS}) {env:EXTRA_SAGE_PACKAGES}); {env:HOMEBREW}/bin/brew install $PACKAGES; {env:HOMEBREW}/bin/brew upgrade $PACKAGES;; esac' + homebrew: bash -c 'case "{env:SKIP_SYSTEM_PKG_INSTALL:}" in 1|y*|Y*);; *) PACKAGES=$(build/bin/sage-get-system-packages homebrew $(PATH=build/bin:$PATH build/bin/sage-package list {env:SAGE_PACKAGE_LIST_ARGS}) {env:ALL_EXTRA_SAGE_PACKAGES}); {env:HOMEBREW}/bin/brew install $PACKAGES; {env:HOMEBREW}/bin/brew upgrade $PACKAGES;; esac' # # local-conda # @@ -571,7 +573,7 @@ commands = local-conda: bash -c 'cat {env:USE_CONDARC} >> {env:CONDA_PREFIX}/.condarc' local-conda: bash -c 'if [ ! -x {env:CONDA_PREFIX}/bin/conda ]; then mkdir {env:CONDA_PREFIX}/conda-meta && curl -L {env:CONDA_INSTALLER_URL_BASE}{env:CONDA_INSTALLER_FILE} -C - -o {env:SHARED_CACHE_DIR}/{env:CONDA_INSTALLER_FILE} && bash {env:SHARED_CACHE_DIR}/{env:CONDA_INSTALLER_FILE} -b -f -p {env:CONDA_PREFIX}; fi' local-conda: bash -c 'case "{env:SKIP_SYSTEM_PKG_INSTALL:}" in 1|y*|Y*);; *) {env:SETENV} && {env:CONDA_PREFIX}/bin/conda update -n base --yes conda;; esac' - local-conda: bash -c 'PACKAGES=$(build/bin/sage-get-system-packages conda $(PATH=build/bin:$PATH build/bin/sage-package list {env:SAGE_PACKAGE_LIST_ARGS}) {env:EXTRA_SAGE_PACKAGES}); {env:SETENV} && {env:CONDA_PREFIX}/bin/conda install --yes --quiet $PACKAGES' + local-conda: bash -c 'PACKAGES=$(build/bin/sage-get-system-packages conda $(PATH=build/bin:$PATH build/bin/sage-package list {env:SAGE_PACKAGE_LIST_ARGS}) {env:ALL_EXTRA_SAGE_PACKAGES}); {env:SETENV} && {env:CONDA_PREFIX}/bin/conda install --yes --quiet $PACKAGES' # # local-cygwin-choco: Use choco to install cygwin packages # @@ -581,7 +583,7 @@ commands = # local-sudo: Use sudo to run the system package commands as root # local-{root,sudo}: bash -c 'case "{env:SKIP_SYSTEM_PKG_INSTALL:}" in 1|y*|Y*);; *) eval $(build/bin/sage-print-system-package-command {env:SYSTEM} {env:__SUDO:} update) ;; esac' - local-{root,sudo}: bash -c 'case "{env:SKIP_SYSTEM_PKG_INSTALL:}" in 1|y*|Y*);; *) PACKAGES=$(build/bin/sage-get-system-packages {env:SYSTEM} $(PATH=build/bin:$PATH build/bin/sage-package list {env:SAGE_PACKAGE_LIST_ARGS}) {env:EXTRA_SAGE_PACKAGES}); eval $(build/bin/sage-print-system-package-command {env:SYSTEM} {env:__SUDO:} --yes --no-install-recommends install $PACKAGES) || [ "$IGNORE_MISSING_SYSTEM_PACKAGES" = yes ] && echo "(ignoring errors)" ;; esac' + local-{root,sudo}: bash -c 'case "{env:SKIP_SYSTEM_PKG_INSTALL:}" in 1|y*|Y*);; *) PACKAGES=$(build/bin/sage-get-system-packages {env:SYSTEM} $(PATH=build/bin:$PATH build/bin/sage-package list {env:SAGE_PACKAGE_LIST_ARGS}) {env:ALL_EXTRA_SAGE_PACKAGES}); eval $(build/bin/sage-print-system-package-command {env:SYSTEM} {env:__SUDO:} --yes --no-install-recommends install $PACKAGES) || [ "$IGNORE_MISSING_SYSTEM_PACKAGES" = yes ] && echo "(ignoring errors)" ;; esac' # # All "local" environments # @@ -591,7 +593,7 @@ commands = local: bash -c 'if [ ! -d prefix -o -L prefix ]; then rm -f prefix; ln -sf {env:PREFIX:{envdir}/local} prefix; fi' ##commands = - docker: bash -c 'build/bin/write-dockerfile.sh {env:SYSTEM} "{env:SAGE_PACKAGE_LIST_ARGS:}" {env:WITH_SYSTEM_SPKG} {env:IGNORE_MISSING_SYSTEM_PACKAGES} "{env:EXTRA_SAGE_PACKAGES}" > {envdir}/Dockerfile' + docker: bash -c 'build/bin/write-dockerfile.sh {env:SYSTEM} "{env:SAGE_PACKAGE_LIST_ARGS:}" {env:WITH_SYSTEM_SPKG} {env:IGNORE_MISSING_SYSTEM_PACKAGES} "{env:ALL_EXTRA_SAGE_PACKAGES}" > {envdir}/Dockerfile' # From https://hub.docker.com/r/multiarch/ubuntu-core/ # configure binfmt-support on the Docker host (works locally or remotely, i.e: using boot2docker) docker-{arm64,armhf}: docker run --rm --privileged multiarch/qemu-user-static:register --reset From 41231160aa29f8774ff6c9ba41db7f288d13341c Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sat, 5 Feb 2022 23:14:26 +0100 Subject: [PATCH 225/253] Add continuous deployment of docs --- .github/workflows/doc-build.yml | 43 +++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 .github/workflows/doc-build.yml diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml new file mode 100644 index 00000000000..e8514a97bbf --- /dev/null +++ b/.github/workflows/doc-build.yml @@ -0,0 +1,43 @@ +name: Build documentation + +on: + push: + workflow_dispatch: + # Allow to run manually + +concurrency: + # Cancel previous runs of this workflow for the same branch + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + container: ghcr.io/sagemath/sage/sage-docker-ubuntu-focal-standard-with-targets:9.5 + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Prepare + run: | + # Reuse built SAGE_LOCAL contained in the Docker image + ./bootstrap + ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv + + - name: Build + run: make doc-html + env: + MAKE: make -j2 + SAGE_NUM_THREADS: 2 + + - name: Deploy to Netlify + uses: nwtgck/actions-netlify@v1.2 + with: + publish-dir: './local/share/doc/sage/html/en' + production-branch: master + github-token: ${{ secrets.GITHUB_TOKEN }} + enable-pull-request-comment: false # We don't have github pull-requests + alias: ${{ github.ref_name }} + env: + NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} + NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} From 2b989cecf3c2099140c9bfa3565c348f4d6139b2 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sat, 5 Feb 2022 23:23:53 +0100 Subject: [PATCH 226/253] Why are you not showing up? --- .github/workflows/doc-build.yml | 46 ++++++++++++++++----------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index e8514a97bbf..dddeb34e32a 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -11,33 +11,33 @@ concurrency: cancel-in-progress: true jobs: - build: + build-docs: runs-on: ubuntu-latest - container: ghcr.io/sagemath/sage/sage-docker-ubuntu-focal-standard-with-targets:9.5 + # container: ghcr.io/sagemath/sage/sage-docker-ubuntu-focal-standard-with-targets:9.5 steps: - name: Checkout uses: actions/checkout@v2 - - name: Prepare - run: | - # Reuse built SAGE_LOCAL contained in the Docker image - ./bootstrap - ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv + # - name: Prepare + # run: | + # # Reuse built SAGE_LOCAL contained in the Docker image + # ./bootstrap + # ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv - - name: Build - run: make doc-html - env: - MAKE: make -j2 - SAGE_NUM_THREADS: 2 + # - name: Build + # run: make doc-html + # env: + # MAKE: make -j2 + # SAGE_NUM_THREADS: 2 - - name: Deploy to Netlify - uses: nwtgck/actions-netlify@v1.2 - with: - publish-dir: './local/share/doc/sage/html/en' - production-branch: master - github-token: ${{ secrets.GITHUB_TOKEN }} - enable-pull-request-comment: false # We don't have github pull-requests - alias: ${{ github.ref_name }} - env: - NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} - NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} + # - name: Deploy to Netlify + # uses: nwtgck/actions-netlify@v1.2 + # with: + # publish-dir: './local/share/doc/sage/html/en' + # production-branch: master + # github-token: ${{ secrets.GITHUB_TOKEN }} + # enable-pull-request-comment: false # We don't have github pull-requests + # alias: ${{ github.ref_name }} + # env: + # NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} + # NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} From 361c95bd43fd6865ddfb6c35f41152e3bab9cfc6 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sat, 5 Feb 2022 23:29:20 +0100 Subject: [PATCH 227/253] Back to full workflow Github actions have problems right now --- .github/workflows/doc-build.yml | 44 ++++++++++++++++----------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index dddeb34e32a..a56b057ba05 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -13,31 +13,31 @@ concurrency: jobs: build-docs: runs-on: ubuntu-latest - # container: ghcr.io/sagemath/sage/sage-docker-ubuntu-focal-standard-with-targets:9.5 + container: ghcr.io/sagemath/sage/sage-docker-ubuntu-focal-standard-with-targets:9.5 steps: - name: Checkout uses: actions/checkout@v2 - # - name: Prepare - # run: | - # # Reuse built SAGE_LOCAL contained in the Docker image - # ./bootstrap - # ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv + - name: Prepare + run: | + # Reuse built SAGE_LOCAL contained in the Docker image + ./bootstrap + ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv - # - name: Build - # run: make doc-html - # env: - # MAKE: make -j2 - # SAGE_NUM_THREADS: 2 + - name: Build + run: make doc-html + env: + MAKE: make -j2 + SAGE_NUM_THREADS: 2 - # - name: Deploy to Netlify - # uses: nwtgck/actions-netlify@v1.2 - # with: - # publish-dir: './local/share/doc/sage/html/en' - # production-branch: master - # github-token: ${{ secrets.GITHUB_TOKEN }} - # enable-pull-request-comment: false # We don't have github pull-requests - # alias: ${{ github.ref_name }} - # env: - # NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} - # NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} + - name: Deploy to Netlify + uses: nwtgck/actions-netlify@v1.2 + with: + publish-dir: './local/share/doc/sage/html/en' + production-branch: master + github-token: ${{ secrets.GITHUB_TOKEN }} + enable-pull-request-comment: false # We don't have github pull-requests + alias: ${{ github.ref_name }} + env: + NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} + NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} From 0847118f8e759082efdb4da22605d74de72fc305 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sun, 6 Feb 2022 00:53:23 +0100 Subject: [PATCH 228/253] Fix path to build docs --- .github/workflows/doc-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index a56b057ba05..6afeb5f5866 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -33,7 +33,7 @@ jobs: - name: Deploy to Netlify uses: nwtgck/actions-netlify@v1.2 with: - publish-dir: './local/share/doc/sage/html/en' + publish-dir: './sage/local/share/doc/sage/html/en' production-branch: master github-token: ${{ secrets.GITHUB_TOKEN }} enable-pull-request-comment: false # We don't have github pull-requests From 97b43477092da5b416d705a9fe99f973bb1be5ab Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 30 Jan 2022 17:05:08 -0800 Subject: [PATCH 229/253] build/pkgs/ffmpeg/distros/fedora.txt: Remove ffmpeg - it is not in the standard repo --- build/pkgs/ffmpeg/distros/fedora.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build/pkgs/ffmpeg/distros/fedora.txt b/build/pkgs/ffmpeg/distros/fedora.txt index 20645e64124..2034a7b9f77 100644 --- a/build/pkgs/ffmpeg/distros/fedora.txt +++ b/build/pkgs/ffmpeg/distros/fedora.txt @@ -1 +1,3 @@ -ffmpeg +# ffmpeg is not in the standard Fedora repository +# Need "RPM Fusion Free" +#ffmpeg From 915da279b926b8b61ee4d94fa5b93710517261f0 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sun, 6 Feb 2022 10:21:03 +0100 Subject: [PATCH 230/253] Trigger build again --- .github/workflows/doc-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 6afeb5f5866..4d331b8182f 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -37,7 +37,7 @@ jobs: production-branch: master github-token: ${{ secrets.GITHUB_TOKEN }} enable-pull-request-comment: false # We don't have github pull-requests - alias: ${{ github.ref_name }} + alias: ${{ github.ref_name }} # Base deploy URL on branch name env: NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} From f5c91d8d5ecd7152112354d139fc140aca7e72ff Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sun, 6 Feb 2022 11:47:24 +0100 Subject: [PATCH 231/253] Absolute path not relative... --- .github/workflows/doc-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 4d331b8182f..24e237e3a22 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -33,7 +33,7 @@ jobs: - name: Deploy to Netlify uses: nwtgck/actions-netlify@v1.2 with: - publish-dir: './sage/local/share/doc/sage/html/en' + publish-dir: '/sage/local/share/doc/sage/html/en' production-branch: master github-token: ${{ secrets.GITHUB_TOKEN }} enable-pull-request-comment: false # We don't have github pull-requests From d3b2756fc378808df62a13b934180699c122a7d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 6 Feb 2022 11:55:14 +0100 Subject: [PATCH 232/253] replace trait_names by __dir__ for tab-completion --- src/doc/it/faq/faq-usage.rst | 7 ------- src/sage/combinat/sloane_functions.py | 18 ++++++++--------- src/sage/databases/symbolic_data.py | 23 +++++++++++----------- src/sage/interfaces/tab_completion.py | 4 ---- src/sage/libs/singular/function_factory.py | 20 +++++++++---------- src/sage/misc/object_multiplexer.py | 9 ++++----- src/sage/repl/rich_output/backend_base.py | 2 +- src/sage/sat/solvers/satsolver.pyx | 21 ++++++++++---------- 8 files changed, 46 insertions(+), 58 deletions(-) diff --git a/src/doc/it/faq/faq-usage.rst b/src/doc/it/faq/faq-usage.rst index 51a13b207fb..c1362a1e840 100644 --- a/src/doc/it/faq/faq-usage.rst +++ b/src/doc/it/faq/faq-usage.rst @@ -687,13 +687,6 @@ come questo. $ BROWSER='open -a Firefox %s' ./sage --notebook jupyter $ BROWSER='open -a Google\ Chrome %s' ./sage --notebook jupyter - Con il vecchio notebook SageNB: - - .. CODE-BLOCK:: shell-session - - $ BROWSER='open -a Firefox' ./sage --notebook - $ BROWSER='open -a Google\ Chrome' ./sage --notebook - Dov'è il codice sorgente di ````? """"""""""""""""""""""""""""""""""""""""""" diff --git a/src/sage/combinat/sloane_functions.py b/src/sage/combinat/sloane_functions.py index 93349075c17..38e3709a06e 100644 --- a/src/sage/combinat/sloane_functions.py +++ b/src/sage/combinat/sloane_functions.py @@ -50,7 +50,7 @@ We agree with the online database:: - sage: for t in sloane.trait_names(): # long time; optional -- internet; known bug + sage: for t in sloane.__dir__(): # long time; optional -- internet; known bug ....: online_list = list(oeis(t).first_terms()) ....: L = max(2, len(online_list) // 2) ....: sage_list = sloane.__getattribute__(t).list(L) @@ -9131,12 +9131,12 @@ class Sloane(SageObject): Ensure we have lots of entries:: - sage: len(sloane.trait_names()) > 100 + sage: len(sloane.__dir__()) > 100 True Ensure none are being incorrectly returned:: - sage: [ None for n in sloane.trait_names() if not n.startswith('A') ] + sage: [ None for n in sloane.__dir__() if not n.startswith('A') ] [] Ensure we can access dynamic constructions and cache correctly:: @@ -9154,7 +9154,7 @@ class Sloane(SageObject): - Nick Alexander """ - def trait_names(self): + def __dir__(self): r""" List Sloane generating functions for tab-completion. @@ -9167,16 +9167,16 @@ def trait_names(self): EXAMPLES:: - sage: type(sloane.trait_names()) + sage: type(sloane.__dir__()) """ try: - return self.__trait_names + return self.__stored_dir except AttributeError: xs = inspect.getmembers(sys.modules[__name__], inspect.isclass) - self.__trait_names = [n for n, c in xs - if n.startswith('A') and issubclass(c, SloaneSequence)] - return self.__trait_names + self.__stored_dir = [n for n, c in xs + if n.startswith('A') and issubclass(c, SloaneSequence)] + return self.__stored_dir def __getattribute__(self, name): r""" diff --git a/src/sage/databases/symbolic_data.py b/src/sage/databases/symbolic_data.py index ccd7fb3eadc..7703a2216e5 100644 --- a/src/sage/databases/symbolic_data.py +++ b/src/sage/databases/symbolic_data.py @@ -122,7 +122,7 @@ def _dom2ideal(node): """ l = [] - if str(node.nodeName) in ['vars','poly']: + if str(node.nodeName) in ['vars', 'poly']: l.append(_getTextFromNode(node)) for c in node.childNodes: @@ -131,7 +131,7 @@ def _dom2ideal(node): return l orig_name = name - name = name.replace('__','.') + name = name.replace('__', '.') try: name = self.__intpath + name + ".xml" @@ -141,17 +141,16 @@ def _dom2ideal(node): name = self.__genpath + name + ".xml" open(name) except IOError: - raise AttributeError("No ideal matching '%s' found in database."%orig_name) + raise AttributeError("No ideal matching '%s' found in database." % orig_name) dom = parse(name) res = _dom2ideal(dom) - variables, polys = res[0].replace("_",""), [p.replace("_","") for p in res[1:]] + variables, polys = res[0].replace("_", ""), [p.replace("_", "") for p in res[1:]] P = PolynomialRing(base_ring, len(variables.split(",")), variables) I = P.ideal([P(f) for f in polys]) return I - def __repr__(self): """ EXAMPLES:: @@ -160,10 +159,10 @@ def __repr__(self): SymbolicData with 372 ideals """ try: - l = len(self.trait_names()) + l = len(self.__dir__()) except AttributeError: l = 0 - return "SymbolicData with %d ideals"%l + return "SymbolicData with %d ideals" % l def __getattr__(self, name): """ @@ -184,12 +183,12 @@ def __getattr__(self, name): """ return self.get_ideal(name) - def trait_names(self): + def __dir__(self): """ EXAMPLES:: sage: sd = SymbolicData() # optional - database_symbolic_data - sage: sorted(sd.trait_names())[:10] # optional - database_symbolic_data + sage: sorted(sd.__dir__())[:10] # optional - database_symbolic_data ['Bjoerk_8', 'Bronstein-86', 'Buchberger-87', @@ -201,11 +200,11 @@ def trait_names(self): 'Curves__curve10_20', 'Curves__curve10_30'] """ - if hasattr(self,"__ideals"): + if hasattr(self, "__ideals"): return self.__ideals try: - __ideals = [s.replace('.xml','') for s in os.listdir(self.__intpath)] - __ideals += [s.replace('.xml','') for s in os.listdir(self.__genpath)] + __ideals = [s.replace('.xml', '') for s in os.listdir(self.__intpath)] + __ideals += [s.replace('.xml', '') for s in os.listdir(self.__genpath)] self.__ideals = [s.replace('.', '__') for s in __ideals] return self.__ideals except OSError: diff --git a/src/sage/interfaces/tab_completion.py b/src/sage/interfaces/tab_completion.py index f3fd8539fca..0182e4c1d6d 100644 --- a/src/sage/interfaces/tab_completion.py +++ b/src/sage/interfaces/tab_completion.py @@ -93,10 +93,6 @@ def completions(s, globs): try: O = eval(obj, globs) D = dir(O) - try: - D += O.trait_names() - except (AttributeError, TypeError): - pass if not method: v = [obj + '.' + x for x in D if x and x[0] != '_'] else: diff --git a/src/sage/libs/singular/function_factory.py b/src/sage/libs/singular/function_factory.py index cc7ac9c6cac..c3ba54dd371 100644 --- a/src/sage/libs/singular/function_factory.py +++ b/src/sage/libs/singular/function_factory.py @@ -4,17 +4,17 @@ AUTHORS: - Martin Albrecht (2010-01): initial version - """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010 Martin Albrecht # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.libs.singular.function import singular_function, lib, list_of_functions + class SingularFunctionFactory(object): """ A convenient interface to libsingular functions. @@ -34,27 +34,27 @@ def __getattr__(self, name): primdecSY (singular function) """ if name.startswith("_"): - raise AttributeError("Singular Function Factory has no attribute '%s'"%name) + raise AttributeError("Singular Function Factory has no attribute '%s'" % name) try: return singular_function(name) except NameError: if name.endswith("__lib"): name = name[:-5] - lib(name+".lib") + lib(name + ".lib") return SingularFunctionFactory() else: - raise NameError("function or package '%s' unknown."%(name)) + raise NameError("function or package '%s' unknown." % (name)) - def trait_names(self): + def __dir__(self): """ EXAMPLES:: sage: import sage.libs.singular.function_factory - sage: "groebner" in sage.libs.singular.function_factory.ff.trait_names() + sage: "groebner" in sage.libs.singular.function_factory.ff.__dir__() True - """ return list_of_functions() + ff = SingularFunctionFactory() diff --git a/src/sage/misc/object_multiplexer.py b/src/sage/misc/object_multiplexer.py index e9669c3c066..dcb482b8df2 100644 --- a/src/sage/misc/object_multiplexer.py +++ b/src/sage/misc/object_multiplexer.py @@ -54,8 +54,7 @@ def __call__(self, *args, **kwds): l.append(getattr(child, self.name)(*args, **kwds)) if all(e is None for e in l): return None - else: - return tuple(l) + return tuple(l) class Multiplex(object): @@ -83,11 +82,11 @@ def __getattr__(self, name): sage: m = Multiplex(1,1/2) sage: m.str - sage: m.trait_names + sage: m.__bork__ Traceback (most recent call last): ... - AttributeError: 'Multiplex' has no attribute 'trait_names' + AttributeError: 'Multiplex' has no attribute '__bork__' """ - if name.startswith("__") or name == "trait_names": + if name.startswith("__"): raise AttributeError("'Multiplex' has no attribute '%s'" % name) return MultiplexFunction(self, name) diff --git a/src/sage/repl/rich_output/backend_base.py b/src/sage/repl/rich_output/backend_base.py index bd89fb9774c..48ec1868950 100644 --- a/src/sage/repl/rich_output/backend_base.py +++ b/src/sage/repl/rich_output/backend_base.py @@ -2,7 +2,7 @@ r""" Base Class for Backends -The display backends are the commandline, the SageNB notebook, the +The display backends are the commandline, the IPython notebook, the Emacs sage mode, the Sage doctester, .... All of these have different capabilities for what they can display. diff --git a/src/sage/sat/solvers/satsolver.pyx b/src/sage/sat/solvers/satsolver.pyx index 9ce831636a6..3f7b7224a51 100644 --- a/src/sage/sat/solvers/satsolver.pyx +++ b/src/sage/sat/solvers/satsolver.pyx @@ -7,7 +7,7 @@ All SAT solvers must inherit from this class. Our SAT solver interfaces are 1-based, i.e., literals start at 1. This is consistent with the popular DIMACS format for SAT - solving but not with Pythion's 0-based convention. However, this + solving but not with Python's 0-based convention. However, this also allows to construct clauses using simple integers. AUTHORS: @@ -167,7 +167,7 @@ cdef class SatSolver: else: line = line.split(" ") clause = [int(e) for e in line if e] - clause = clause[:-1] # strip trailing zero + clause = clause[:-1] # strip trailing zero self.add_clause(clause) def __call__(self, assumptions=None): @@ -287,28 +287,29 @@ cdef class SatSolver: sage: from sage.sat.solvers.satsolver import SatSolver sage: solver = SatSolver() - sage: solver.gens() # __getattr__ points this to clauses + sage: solver.gens() # __getattr__ points this to clauses Traceback (most recent call last): ... NotImplementedError """ if name == "gens": return self.clauses - else: - raise AttributeError("'%s' object has no attribute '%s'"%(self.__class__.__name__,name)) + raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, name)) - def trait_names(self): + def __dir__(self): """ - Allow alias to appear in tab completion. + Custom dir for tab-completion. EXAMPLES:: sage: from sage.sat.solvers.satsolver import SatSolver sage: solver = SatSolver() - sage: solver.trait_names() - ['gens'] + sage: 'gens' in solver.__dir__() + True """ - return ["gens"] + return ['add_clause', 'clauses', 'conflict_clause', 'gens', + 'learnt_clauses', 'nvars', 'read', 'var'] + def SAT(solver=None, *args, **kwds): r""" From a8db26733707b5158d5666119026c02695ebbe84 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sun, 6 Feb 2022 14:36:09 +0100 Subject: [PATCH 233/253] Don't comment on commit --- .github/workflows/doc-build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 24e237e3a22..330aff21bb4 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -37,6 +37,7 @@ jobs: production-branch: master github-token: ${{ secrets.GITHUB_TOKEN }} enable-pull-request-comment: false # We don't have github pull-requests + enable-commit-comment: false # Don't comment on commit to reduce noise alias: ${{ github.ref_name }} # Base deploy URL on branch name env: NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} From 442134217d16e61e6ccdc97f76f0718ec37d3e39 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sun, 6 Feb 2022 16:10:02 +0100 Subject: [PATCH 234/253] Use netlify deploy cli over api --- .github/workflows/doc-build.yml | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 330aff21bb4..1a976b39846 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -31,14 +31,11 @@ jobs: SAGE_NUM_THREADS: 2 - name: Deploy to Netlify - uses: nwtgck/actions-netlify@v1.2 + uses: jsmrcaga/action-netlify-deploy@v1.7.2 with: - publish-dir: '/sage/local/share/doc/sage/html/en' - production-branch: master - github-token: ${{ secrets.GITHUB_TOKEN }} - enable-pull-request-comment: false # We don't have github pull-requests - enable-commit-comment: false # Don't comment on commit to reduce noise - alias: ${{ github.ref_name }} # Base deploy URL on branch name - env: + build_directory: '/sage/local/share/doc/sage/html/en' + install_command: 'echo "Install"' + build_command: 'echo "Build"' + deploy_alias: ${{ github.ref_name }} # Base deploy URL on branch name NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} From a94d1e8700f822f197481529c819b024cc1bbfac Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sun, 6 Feb 2022 20:55:35 +0100 Subject: [PATCH 235/253] Copy docs before deployment --- .github/workflows/doc-build.yml | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 1a976b39846..46bb600e160 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -23,19 +23,25 @@ jobs: # Reuse built SAGE_LOCAL contained in the Docker image ./bootstrap ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv - + - name: Build run: make doc-html env: MAKE: make -j2 SAGE_NUM_THREADS: 2 + - name: Copy docs + run: | + # For some reason the deploy step below cannot find /sage/... + # So copy everything from there to local folder + mkdir -p ./docs + cp -r /sage/local/share/doc/sage/html/en ./docs + - name: Deploy to Netlify - uses: jsmrcaga/action-netlify-deploy@v1.7.2 - with: - build_directory: '/sage/local/share/doc/sage/html/en' - install_command: 'echo "Install"' - build_command: 'echo "Build"' - deploy_alias: ${{ github.ref_name }} # Base deploy URL on branch name + uses: netlify/actions/cli@master + with: + args: deploy --dir=docs --alias="${NETLIFY_ALIAS}" + env: + NETLIFY_ALIAS: ${{ github.ref_name }} NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} From 5adae47a1318c77be483b3c961623ce6025268ff Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 6 Feb 2022 15:09:45 -0800 Subject: [PATCH 236/253] src/sage/misc/package_dir.py: Fix pycodestyle warning --- src/sage/misc/package_dir.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/misc/package_dir.py b/src/sage/misc/package_dir.py index 11f83a06f73..c1927ebdb3b 100644 --- a/src/sage/misc/package_dir.py +++ b/src/sage/misc/package_dir.py @@ -1,10 +1,11 @@ """ Recognizing package directories """ -import os, glob +import os +import glob def is_package_or_sage_namespace_package_dir(path): - """ + r""" Return whether ``path`` is a directory that contains a Python package. Ordinary Python packages are recognized by the presence of `__init__.py`. From b7948d6a344ba6d87adfab65bb1c6e623633d208 Mon Sep 17 00:00:00 2001 From: Simon Brandhorst Date: Mon, 7 Feb 2022 08:20:55 +0100 Subject: [PATCH 237/253] formatting --- ...free_quadratic_module_integer_symmetric.py | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index a6943afac36..6b2f5b21653 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -1050,7 +1050,7 @@ def maximal_overlattice(self, p=None): # https://arxiv.org/abs/1208.2481 # and trac:11940 if not self.is_even() and (p is None or p==2): - raise ValueError("This lattice must be even to admit an even overlattice") + raise ValueError("this lattice must be even to admit an even overlattice") from sage.rings.finite_rings.finite_field_constructor import GF L = self if p is None: @@ -1389,7 +1389,7 @@ def quadratic_form(self): [ 2 -2 ] [ * 2 ] """ - return QuadraticForm(2*self.gram_matrix()) + return QuadraticForm(2 * self.gram_matrix()) @cached_method def minimum(self): @@ -1409,8 +1409,8 @@ def minimum(self): -Infinity """ p, n = self.signature_pair() - if self.rank()==0: - raise ValueError("The empty set does not have a minimum") + if self.rank() == 0: + raise ValueError("the empty set does not have a minimum") if n != 0: from sage.rings.infinity import MinusInfinity return MinusInfinity() @@ -1434,8 +1434,8 @@ def maximum(self): sage: L.twist(-1).maximum() -2 """ - if self.rank()==0: - raise ValueError("The empty set does not have a maximum.") + if self.rank() == 0: + raise ValueError("the empty set does not have a maximum") p, n = self.signature_pair() if p != 0: from sage.rings.infinity import PlusInfinity @@ -1443,7 +1443,6 @@ def maximum(self): mpari = (-self.gram_matrix()).__pari__().qfminim(None, 0)[1] return -mpari - min = minimum max = maximum @@ -1458,14 +1457,14 @@ def LLL(self): True sage: G = matrix(ZZ,3,[0,1,0, 1,0,0, 0,0,7]) sage: V = matrix(ZZ,3,[-14,-15,-15, -4,1,16, -5,-5,-4]) - sage: L = IntegralLattice(V*G*V.T) + sage: L = IntegralLattice(V * G * V.T) sage: L.lll().gram_matrix() [0 0 1] [0 7 0] [1 0 0] """ p, n = self.signature_pair() - if p*n != 0: + if p * n != 0: from sage.env import SAGE_EXTCODE from sage.interfaces.gp import gp from sage.libs.pari import pari @@ -1474,14 +1473,13 @@ def LLL(self): m = gp.eval('qflllgram_indefgoon(%s)'%m) # convert the output string to sage G, U = pari(m).sage() - assert G == U.T*self.gram_matrix()*U U = U.T else: e = 1 if n != 0: e = -1 - U = (e*self.gram_matrix().change_ring(ZZ)).LLL_gram().T - return self.sublattice(U*self.basis_matrix()) + U = (e * self.gram_matrix().change_ring(ZZ)).LLL_gram().T + return self.sublattice(U * self.basis_matrix()) lll = LLL @@ -1508,14 +1506,14 @@ def short_vectors(self, n, **kwargs): [[(0, 0)], [], [(1, 1), (0, 1), (1, 0)]] """ p, m = self.signature_pair() - if p*m != 0: - raise NotImplementedError("The lattice has to be positive definite.") - e = 1 + if p * m != 0: + raise NotImplementedError("the lattice has to be positive definite") + e = 2 if m != 0: - e = -1 - q = QuadraticForm(e*2*self.gram_matrix()) + e = -2 + q = QuadraticForm(e * self.gram_matrix()) short = q.short_vector_list_up_to_length(n, *kwargs) - return [[self(v*self.basis_matrix()) for v in L] for L in short] + return [[self(v * self.basis_matrix()) for v in L] for L in short] def twist(self, s, discard_basis=False): r""" From e0bac5f18f19a8f4460f9063501b7e47189ef48a Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 7 Feb 2022 19:02:19 +0100 Subject: [PATCH 238/253] Replace symlinks --- .github/workflows/doc-build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 46bb600e160..c4d7e9bbdef 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -34,8 +34,9 @@ jobs: run: | # For some reason the deploy step below cannot find /sage/... # So copy everything from there to local folder + # We also need to replace the symlinks because netlify is not following them mkdir -p ./docs - cp -r /sage/local/share/doc/sage/html/en ./docs + cp -r -L /sage/local/share/doc/sage/html/en ./docs - name: Deploy to Netlify uses: netlify/actions/cli@master From e7c8e4662f84ce7d74bfeb9a56e0960cfffa2ec3 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 7 Feb 2022 19:09:02 +0100 Subject: [PATCH 239/253] Don't use alias for now due to various netlify bugs --- .github/workflows/doc-build.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index c4d7e9bbdef..7e0a97bc64c 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -40,8 +40,14 @@ jobs: - name: Deploy to Netlify uses: netlify/actions/cli@master - with: - args: deploy --dir=docs --alias="${NETLIFY_ALIAS}" + with: + # We could use --alias="${NETLIFY_ALIAS}" to fix the deploy url to the branch name. + # However, netlify currently doesn't support updates to a deploy with alias + # https://github.com/netlify/cli/issues/948 + # https://github.com/netlify/cli/issues/1984 + # Note that even if this feature is implemented, one would also need to first process the branch name + # to workaround the bug https://github.com/netlify/cli/issues/969. + args: deploy --dir=docs env: NETLIFY_ALIAS: ${{ github.ref_name }} NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} From 5f7086fffb80f397c043ac7ab6c4a63161c1972e Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 7 Feb 2022 20:10:04 +0100 Subject: [PATCH 240/253] Print url in action overview --- .github/workflows/doc-build.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 7e0a97bc64c..74eba1325d3 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -39,6 +39,7 @@ jobs: cp -r -L /sage/local/share/doc/sage/html/en ./docs - name: Deploy to Netlify + id: deploy-neflify uses: netlify/actions/cli@master with: # We could use --alias="${NETLIFY_ALIAS}" to fix the deploy url to the branch name. @@ -52,3 +53,7 @@ jobs: NETLIFY_ALIAS: ${{ github.ref_name }} NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} + + - name: Report deployment url + run: | + echo "::notice::The documentation has being automatically deployed to Netlify.\n\n✅ Preview: ${{ steps.deploy-neflify.outputs.NETLIFY_URL }}" From 870745e4a407c8b9f1381611eb36cfd5c9adce41 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 7 Feb 2022 20:22:36 +0100 Subject: [PATCH 241/253] Copy only contents of folder not the folder itself --- .github/workflows/doc-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 74eba1325d3..8141e40b2d0 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -36,7 +36,7 @@ jobs: # So copy everything from there to local folder # We also need to replace the symlinks because netlify is not following them mkdir -p ./docs - cp -r -L /sage/local/share/doc/sage/html/en ./docs + cp -r -L /sage/local/share/doc/sage/html/en/* ./docs - name: Deploy to Netlify id: deploy-neflify From b88ed5ea81b18496edfa28fd8ee00ddfe504cbcd Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 7 Feb 2022 20:37:55 +0100 Subject: [PATCH 242/253] Deploy to production on push to master --- .github/workflows/doc-build.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 8141e40b2d0..3c472db6904 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -38,8 +38,9 @@ jobs: mkdir -p ./docs cp -r -L /sage/local/share/doc/sage/html/en/* ./docs - - name: Deploy to Netlify + - name: Deploy to Netlify preview id: deploy-neflify + if: github.ref != 'refs/heads/master' uses: netlify/actions/cli@master with: # We could use --alias="${NETLIFY_ALIAS}" to fix the deploy url to the branch name. @@ -54,6 +55,16 @@ jobs: NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} + - name: Deploy to Netlify production + id: deploy-neflify + if: github.ref == 'refs/heads/master' + uses: netlify/actions/cli@master + with: + args: deploy --dir=docs --prod + env: + NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} + NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} + - name: Report deployment url run: | echo "::notice::The documentation has being automatically deployed to Netlify.\n\n✅ Preview: ${{ steps.deploy-neflify.outputs.NETLIFY_URL }}" From 67b410575baad55e302045726c2ab9fb7a86a943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 7 Feb 2022 20:45:53 +0100 Subject: [PATCH 243/253] fix tab completion for maxima wrapper --- src/sage/symbolic/maxima_wrapper.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/sage/symbolic/maxima_wrapper.py b/src/sage/symbolic/maxima_wrapper.py index d29318beccd..34ece429e00 100644 --- a/src/sage/symbolic/maxima_wrapper.py +++ b/src/sage/symbolic/maxima_wrapper.py @@ -31,6 +31,7 @@ def __call__(self, *args, **kwds): return super(MaximaFunctionElementWrapper, self).__call__(*args, **kwds).sage() + class MaximaWrapper(SageObject): def __init__(self, exp): """ @@ -89,12 +90,15 @@ def __getattr__(self, s): self._maxima_exp = self._exp._maxima_() if s[0] == '_': return getattr(self._maxima_exp, s) - if s == 'trait_names': # SageNB backward compatibility - return self._maxima_()._tab_completion - else: - # add a wrapper function which converts the result back to - # a Sage expression - return MaximaFunctionElementWrapper(self._maxima_exp, s) + # add a wrapper function which converts the result back to + # a Sage expression + return MaximaFunctionElementWrapper(self._maxima_exp, s) + + def __dir__(self): + """ + Enable the tab completions. + """ + return self._maxima_()._tab_completion() def sage(self): """ From 2035054f3fa3c0a7e6901b74c4ca199f4236ecd4 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 7 Feb 2022 22:28:27 +0100 Subject: [PATCH 244/253] Specify line break in message in the correct format --- .github/workflows/doc-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 3c472db6904..a965ca12436 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -67,4 +67,4 @@ jobs: - name: Report deployment url run: | - echo "::notice::The documentation has being automatically deployed to Netlify.\n\n✅ Preview: ${{ steps.deploy-neflify.outputs.NETLIFY_URL }}" + echo "::notice::The documentation has being automatically deployed to Netlify.%0A%0A✅ Preview: ${{ steps.deploy-neflify.outputs.NETLIFY_URL }}" From 17287820443c64e1b24e462d8c446c9db8f21c62 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 7 Feb 2022 22:34:47 +0100 Subject: [PATCH 245/253] Correct spelling of netlify --- .github/workflows/doc-build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index a965ca12436..c9be14c6cba 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -39,7 +39,7 @@ jobs: cp -r -L /sage/local/share/doc/sage/html/en/* ./docs - name: Deploy to Netlify preview - id: deploy-neflify + id: deploy-netlify if: github.ref != 'refs/heads/master' uses: netlify/actions/cli@master with: @@ -56,7 +56,7 @@ jobs: NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} - name: Deploy to Netlify production - id: deploy-neflify + id: deploy-netlify if: github.ref == 'refs/heads/master' uses: netlify/actions/cli@master with: @@ -67,4 +67,4 @@ jobs: - name: Report deployment url run: | - echo "::notice::The documentation has being automatically deployed to Netlify.%0A%0A✅ Preview: ${{ steps.deploy-neflify.outputs.NETLIFY_URL }}" + echo "::notice::The documentation has being automatically deployed to Netlify.%0A%0A✅ Preview: ${{ steps.deploy-netlify.outputs.NETLIFY_URL }}" From 81e7a2ebec91b975ca779a8531ee54f1c64c51d5 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 7 Feb 2022 23:15:05 +0100 Subject: [PATCH 246/253] Fix workflow --- .github/workflows/doc-build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index c9be14c6cba..e2738e60df4 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -39,7 +39,7 @@ jobs: cp -r -L /sage/local/share/doc/sage/html/en/* ./docs - name: Deploy to Netlify preview - id: deploy-netlify + id: preview-netlify if: github.ref != 'refs/heads/master' uses: netlify/actions/cli@master with: @@ -67,4 +67,4 @@ jobs: - name: Report deployment url run: | - echo "::notice::The documentation has being automatically deployed to Netlify.%0A%0A✅ Preview: ${{ steps.deploy-netlify.outputs.NETLIFY_URL }}" + echo "::notice::The documentation has being automatically deployed to Netlify.%0A%0A✅ Preview: ${{ steps.preview-netlify.outputs.NETLIFY_URL || steps.deploy-netlify.outputs.NETLIFY_URL }}" From 836a681d50bdec21082818fe57c30944ef957732 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 8 Feb 2022 09:17:13 +0900 Subject: [PATCH 247/253] Fixes for one_basis() of DescentAlgebra and other misc changes --- .../finite_dimensional_algebras_with_basis.py | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index d9b1de0521e..2893f425369 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -1088,8 +1088,8 @@ def to_matrix(self, base_ring=None, action=operator.mul, side='left'): def __invert__(self): r""" - Return the inverse of ``self`` if ``self`` if it - exists, and otherwise raise an error. + Return the inverse of ``self`` if it exists, and + otherwise raise an error. .. WARNING:: @@ -1112,6 +1112,15 @@ def __invert__(self): sage: ~b == a True + sage: a = 3 * QS3.one() + sage: b = ~a + sage: b * a == QS3.one() + True + sage: b == 1/3 * QS3.one() + True + sage: ~b == a + True + sage: R. = QQ[] sage: RS3 = SymmetricGroupAlgebra(R, 3) sage: a = RS3(P([1,2,3])) - RS3(P([1,3,2])) + RS3(P([2,1,3])); ~a @@ -1136,18 +1145,30 @@ def __invert__(self): Traceback (most recent call last): ... ValueError: cannot invert self (= 2*[1, 2, 3]) + + TESTS: + + An algebra that does not define ``one_basis()``:: + + sage: I = DescentAlgebra(QQ, 3).I() + sage: a = 3 * I.one() + sage: ~a == 1/3 * I.one() + True """ alg = self.parent() R = alg.base_ring() + ob = None try: ob = alg.one_basis() + except (AttributeError, TypeError, ValueError): + pass + if ob is not None: mc = self.monomial_coefficients(copy=False) if len(mc) == 1 and ob in mc: - return alg.term(ob, R(~mc[ob])) - except AttributeError: - pass - except (ValueError, TypeError): - raise ValueError("cannot invert self (= %s)" % self) + try: + return alg.term(ob, R(~mc[ob])) + except (ValueError, TypeError): + raise ValueError("cannot invert self (= %s)" % self) e = alg.one().to_vector() A = self.to_matrix() From e5e43ccba2c6ff9da86b0bf1f0171e76fb232f1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 8 Feb 2022 09:01:47 +0100 Subject: [PATCH 248/253] add missing doc --- src/sage/symbolic/maxima_wrapper.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sage/symbolic/maxima_wrapper.py b/src/sage/symbolic/maxima_wrapper.py index 34ece429e00..8fc3a840ca9 100644 --- a/src/sage/symbolic/maxima_wrapper.py +++ b/src/sage/symbolic/maxima_wrapper.py @@ -97,6 +97,13 @@ def __getattr__(self, s): def __dir__(self): """ Enable the tab completions. + + EXAMPLES:: + + sage: t = sin(x) + cos(x) + sage: u = t.maxima_methods() + sage: 'zeta' in u.__dir__() + True """ return self._maxima_()._tab_completion() From 7a1a1fe20f22e08e4b7ea76db0a5d516ebb5e793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Tue, 8 Feb 2022 21:41:48 +1300 Subject: [PATCH 249/253] add dvipng to gentoo list of texlive related packages --- build/pkgs/texlive/distros/gentoo.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/build/pkgs/texlive/distros/gentoo.txt b/build/pkgs/texlive/distros/gentoo.txt index e1201c0213c..fe1229d1fd5 100644 --- a/build/pkgs/texlive/distros/gentoo.txt +++ b/build/pkgs/texlive/distros/gentoo.txt @@ -1,5 +1,6 @@ dev-tex/latexmk app-text/texlive +app-text/dvipng dev-texlive/texlive-langcjk dev-texlive/texlive-langcyrillic dev-texlive/texlive-langenglish From 3b11cd9b7f2e4677b01db834f1477a7779f02f0d Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Tue, 8 Feb 2022 17:35:45 +0100 Subject: [PATCH 250/253] Deploy to production for develop branch not master --- .github/workflows/doc-build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index e2738e60df4..b88adde6df8 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -40,7 +40,7 @@ jobs: - name: Deploy to Netlify preview id: preview-netlify - if: github.ref != 'refs/heads/master' + if: github.ref != 'refs/heads/develop' uses: netlify/actions/cli@master with: # We could use --alias="${NETLIFY_ALIAS}" to fix the deploy url to the branch name. @@ -57,7 +57,7 @@ jobs: - name: Deploy to Netlify production id: deploy-netlify - if: github.ref == 'refs/heads/master' + if: github.ref == 'refs/heads/develop' uses: netlify/actions/cli@master with: args: deploy --dir=docs --prod @@ -67,4 +67,4 @@ jobs: - name: Report deployment url run: | - echo "::notice::The documentation has being automatically deployed to Netlify.%0A%0A✅ Preview: ${{ steps.preview-netlify.outputs.NETLIFY_URL || steps.deploy-netlify.outputs.NETLIFY_URL }}" + echo "::notice::The documentation has being automatically deployed to Netlify. %0A ✅ Preview: ${{ steps.preview-netlify.outputs.NETLIFY_URL || steps.deploy-netlify.outputs.NETLIFY_URL }}" From 2c97b7cca224932d58920f0958cf2a829e556cb2 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Wed, 9 Feb 2022 00:28:38 +0100 Subject: [PATCH 251/253] Only run in sagetrac-mirror repo --- .github/workflows/doc-build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index b88adde6df8..5bd8bab7c95 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -14,6 +14,7 @@ jobs: build-docs: runs-on: ubuntu-latest container: ghcr.io/sagemath/sage/sage-docker-ubuntu-focal-standard-with-targets:9.5 + if: github.repository == 'sagemath/sagetrac-mirror' steps: - name: Checkout uses: actions/checkout@v2 From 31665def57b107136a67bd3708f1c2e641cdf2de Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Thu, 10 Feb 2022 14:27:56 +0100 Subject: [PATCH 252/253] Use commit sha for url --- .github/workflows/doc-build.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 5bd8bab7c95..d5c6986272e 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -44,15 +44,16 @@ jobs: if: github.ref != 'refs/heads/develop' uses: netlify/actions/cli@master with: - # We could use --alias="${NETLIFY_ALIAS}" to fix the deploy url to the branch name. - # However, netlify currently doesn't support updates to a deploy with alias + args: deploy --dir=docs --alias="${NETLIFY_ALIAS}" + env: + # Set deployment url to commit hash to easily link from the trac. + # We could also set NETLIFY_ALIAS to the branch name. + # However, netlify currently doesn't support updates to a deployment with the same alias # https://github.com/netlify/cli/issues/948 # https://github.com/netlify/cli/issues/1984 # Note that even if this feature is implemented, one would also need to first process the branch name # to workaround the bug https://github.com/netlify/cli/issues/969. - args: deploy --dir=docs - env: - NETLIFY_ALIAS: ${{ github.ref_name }} + NETLIFY_ALIAS: ${{ github.sha }} NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} From 826061adbb03db0d3140a38f798b4e267d960e56 Mon Sep 17 00:00:00 2001 From: Release Manager Date: Sun, 13 Feb 2022 11:43:46 +0100 Subject: [PATCH 253/253] Updated SageMath version to 9.6.beta1 --- .zenodo.json | 8 ++++---- VERSION.txt | 2 +- build/pkgs/configure/checksums.ini | 6 +++--- build/pkgs/configure/package-version.txt | 2 +- build/pkgs/sagelib/package-version.txt | 2 +- src/VERSION.txt | 2 +- src/bin/sage-version.sh | 6 +++--- src/sage/version.py | 6 +++--- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.zenodo.json b/.zenodo.json index 69cf838ad33..9bf8ff1a686 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -1,10 +1,10 @@ { "description": "Mirror of the Sage https://sagemath.org/ source tree", "license": "other-open", - "title": "sagemath/sage: 9.6.beta0", - "version": "9.6.beta0", + "title": "sagemath/sage: 9.6.beta1", + "version": "9.6.beta1", "upload_type": "software", - "publication_date": "2022-02-06", + "publication_date": "2022-02-13", "creators": [ { "affiliation": "SageMath.org", @@ -15,7 +15,7 @@ "related_identifiers": [ { "scheme": "url", - "identifier": "https://github.com/sagemath/sage/tree/9.6.beta0", + "identifier": "https://github.com/sagemath/sage/tree/9.6.beta1", "relation": "isSupplementTo" }, { diff --git a/VERSION.txt b/VERSION.txt index cff01409a82..75735813865 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 9.6.beta0, Release Date: 2022-02-06 +SageMath version 9.6.beta1, Release Date: 2022-02-13 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 01e2481eb3b..4e50c8ddd05 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=e015a30e5c7857e45ae5baf519415eba69736e1c -md5=b0085dbf9c6fc50fc5f30201088557d8 -cksum=702064197 +sha1=8e164215068f39fcaa971350baa69da13b9b5cff +md5=7b3d1f477ac6491f55ebee7b575963e0 +cksum=506943323 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 36d4c13df4d..46c3dac3b7a 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -d800b05b302eb6e943ef94146abf607595cb46ac +33dd1c9955f5509472380e5ac6ca07ea8618fb2f diff --git a/build/pkgs/sagelib/package-version.txt b/build/pkgs/sagelib/package-version.txt index 84891528bce..5faace0c2a4 100644 --- a/build/pkgs/sagelib/package-version.txt +++ b/build/pkgs/sagelib/package-version.txt @@ -1 +1 @@ -9.6.beta0 +9.6.beta1 diff --git a/src/VERSION.txt b/src/VERSION.txt index 84891528bce..5faace0c2a4 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -9.6.beta0 +9.6.beta1 diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index dd91a5f5d2c..63794e57060 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.6.beta0' -SAGE_RELEASE_DATE='2022-02-06' -SAGE_VERSION_BANNER='SageMath version 9.6.beta0, Release Date: 2022-02-06' +SAGE_VERSION='9.6.beta1' +SAGE_RELEASE_DATE='2022-02-13' +SAGE_VERSION_BANNER='SageMath version 9.6.beta1, Release Date: 2022-02-13' diff --git a/src/sage/version.py b/src/sage/version.py index 9df213893d6..a4a1de6a819 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.6.beta0' -date = '2022-02-06' -banner = 'SageMath version 9.6.beta0, Release Date: 2022-02-06' +version = '9.6.beta1' +date = '2022-02-13' +banner = 'SageMath version 9.6.beta1, Release Date: 2022-02-13'