From 98dc756161108b5d01280c54d7b475ab4dd59489 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 21 Oct 2015 14:36:07 -0500 Subject: [PATCH 001/300] Improvements to submodules. --- src/sage/categories/modules_with_basis.py | 32 +++++++++++++++++++--- src/sage/modules/with_basis/subquotient.py | 25 +++++++++++------ 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 282b6fc7fa9..7951664e939 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -622,7 +622,8 @@ def echelon_form(self, elements): return [self.from_vector(vec) for vec in mat if vec] def submodule(self, gens, - check=True, already_echelonized=False, category=None): + check=True, already_echelonized=False, + support_order=None, category=None, *args, **opts): r""" The submodule spanned by a finite set of elements. @@ -631,11 +632,15 @@ def submodule(self, gens, - ``gens`` -- a list or family of elements of ``self`` - ``check`` -- (default: ``True``) whether to verify that the - elements of ``gens`` are in ``self``. + elements of ``gens`` are in ``self`` - ``already_echelonized`` -- (default: ``False``) whether the elements of ``gens`` are already in (not necessarily - reduced) echelon form. + reduced) echelon form + + - ``support_order`` -- (optional) either an instance of class + with an ``index`` method (ex. a list), which returns an index + of an element in `\ZZ`, or a comparison function If ``already_echelonized`` is ``False``, then the generators are put in reduced echelon form using @@ -748,6 +753,15 @@ def submodule(self, gens, sage: center = S3A.center() + We now construct a (finite-dimensional) submodule of an + infinite-dimensional free module. Due to current implementation + limitations, we must pass an echelonized basis:: + + sage: A = GradedModulesWithBasis(ZZ).example() + sage: M = A.submodule(list(A.basis(3)), already_echelonized=True) + sage: [A(b) for b in M.basis()] + [P[3], P[2, 1], P[1, 1, 1]] + TESTS:: sage: TestSuite(Y).run() @@ -755,8 +769,18 @@ def submodule(self, gens, """ if not already_echelonized: gens = self.echelon_form(gens) + if support_order is None: + try: + support_order = self.get_order() + except NotImplementedError: + support_order = list(reduce( lambda x,y: x.union(y.support()), + gens, set() )) + elif not hasattr(support_order, 'index') and callable(support_order): + support_order = sorted(cmp=support_order) from sage.modules.with_basis.subquotient import SubmoduleWithBasis - return SubmoduleWithBasis(gens, ambient=self, category=category) + return SubmoduleWithBasis(gens, ambient=self, + support_order=support_order, + category=category, *args, **opts) def tensor(*parents): """ diff --git a/src/sage/modules/with_basis/subquotient.py b/src/sage/modules/with_basis/subquotient.py index 50e0560a162..1f22242c932 100644 --- a/src/sage/modules/with_basis/subquotient.py +++ b/src/sage/modules/with_basis/subquotient.py @@ -173,6 +173,9 @@ class SubmoduleWithBasis(CombinatorialFreeModule): :class:`module with basis ` `V`, or data that can be converted into such a family + - ``support_order`` -- an ordering of the support of ``basis`` + expressed in ``ambient`` + - ``ambient`` -- the ambient space `V` - ``category`` -- a category @@ -190,7 +193,8 @@ class SubmoduleWithBasis(CombinatorialFreeModule): """ @staticmethod - def __classcall_private__(cls, basis, ambient=None, category=None, *args, **opts): + def __classcall_private__(cls, basis, support_order, ambient=None, + category=None, *args, **opts): r""" Normalize the input. @@ -198,8 +202,8 @@ def __classcall_private__(cls, basis, ambient=None, category=None, *args, **opts sage: from sage.modules.with_basis.subquotient import SubmoduleWithBasis sage: X = CombinatorialFreeModule(QQ, range(3)); x = X.basis() - sage: Y1 = SubmoduleWithBasis((x[0]-x[1], x[1]-x[2]), X) - sage: Y2 = SubmoduleWithBasis([x[0]-x[1], x[1]-x[2]], X) + sage: Y1 = SubmoduleWithBasis((x[0]-x[1], x[1]-x[2]), [0,1,2], X) + sage: Y2 = SubmoduleWithBasis([x[0]-x[1], x[1]-x[2]], (0,1,2), X) sage: Y1 is Y2 True """ @@ -209,9 +213,9 @@ def __classcall_private__(cls, basis, ambient=None, category=None, *args, **opts default_category = ModulesWithBasis(ambient.category().base_ring()).Subobjects() category = default_category.or_subcategory(category, join=True) return super(SubmoduleWithBasis, cls).__classcall__( - cls, basis, ambient, category, *args, **opts) + cls, basis, tuple(support_order), ambient, category, *args, **opts) - def __init__(self, basis, ambient, category): + def __init__(self, basis, support_order, ambient, category, *args, **opts): r""" Initialization. @@ -220,7 +224,7 @@ def __init__(self, basis, ambient, category): sage: from sage.modules.with_basis.subquotient import SubmoduleWithBasis sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x"); x = X.basis() sage: ybas = (x[0]-x[1], x[1]-x[2]) - sage: Y = SubmoduleWithBasis(ybas, X) + sage: Y = SubmoduleWithBasis(ybas, [0, 1, 2], X) sage: Y.print_options(prefix='y') sage: Y.basis().list() [y[0], y[1]] @@ -231,10 +235,13 @@ def __init__(self, basis, ambient, category): import operator ring = ambient.base_ring() CombinatorialFreeModule.__init__(self, ring, basis.keys(), - category=category.Subobjects()) + category=category.Subobjects(), + *args, **opts) self._ambient = ambient self._basis = basis + self._support_order = support_order self.lift_on_basis = self._basis.__getitem__ + self.lift.register_as_coercion() def ambient(self): """ @@ -267,10 +274,12 @@ def lift(self): sage: (y[0] + y[1]).lift() x[0] - x[2] """ + support_cmp = lambda x,y: cmp(self._support_order.index(x), + self._support_order.index(y)) return self.module_morphism(self.lift_on_basis, codomain=self.ambient(), triangular="lower", - cmp=self.ambient().get_order_cmp(), + cmp=support_cmp, inverse_on_support="compute") @lazy_attribute From d4838df190198c014f700c8dfea4062c7cf82a62 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 9 Jun 2017 09:03:01 -0500 Subject: [PATCH 002/300] Removing cmp for key. --- src/sage/modules/with_basis/subquotient.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/sage/modules/with_basis/subquotient.py b/src/sage/modules/with_basis/subquotient.py index 33a3fa47146..3ee0982e263 100644 --- a/src/sage/modules/with_basis/subquotient.py +++ b/src/sage/modules/with_basis/subquotient.py @@ -8,6 +8,7 @@ # http://www.gnu.org/licenses/ #****************************************************************************** +from sage.misc.cachefunc import cached_method from sage.sets.family import Family from sage.combinat.free_module import CombinatorialFreeModule from sage.misc.lazy_attribute import lazy_attribute @@ -261,6 +262,21 @@ def ambient(self): """ return self._ambient + @cached_method + def _support_key(self, x): + """ + Return a key corresponding to the index ``x`` for ordering the + basis of ``self``. + + EXAMPLES:: + + sage: A = GradedModulesWithBasis(ZZ).example() + sage: M = A.submodule(list(A.basis(3)), already_echelonized=True) + sage: [M._support_key(x) for x in M._support_order] + [0, 1, 2] + """ + return self._support_order.index(x) + @lazy_attribute def lift(self): r""" @@ -283,7 +299,7 @@ def lift(self): codomain=self.ambient(), triangular="lower", unitriangular=self._unitriangular, - key=self.ambient().get_order_key(), + key=self._support_key, inverse_on_support="compute") @lazy_attribute @@ -369,3 +385,4 @@ def is_submodule(self, other): except ValueError: return False return True + From e09a7bbdfc09f69aa9d648b64315aebdc05bf6f4 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Wed, 23 May 2018 21:29:45 +0100 Subject: [PATCH 003/300] This is the initial commit for the project on Path Tableaux --- src/sage/categories/pathtableaux.py | 437 ++++++++++++++++++++++++++++ src/sage/combinat/catalan.py | 292 +++++++++++++++++++ src/sage/combinat/semistandard.py | 182 ++++++++++++ 3 files changed, 911 insertions(+) create mode 100644 src/sage/categories/pathtableaux.py create mode 100644 src/sage/combinat/catalan.py create mode 100644 src/sage/combinat/semistandard.py diff --git a/src/sage/categories/pathtableaux.py b/src/sage/categories/pathtableaux.py new file mode 100644 index 00000000000..25416420f32 --- /dev/null +++ b/src/sage/categories/pathtableaux.py @@ -0,0 +1,437 @@ +""" +This is a category for using local rules to construct rectification +and the action of the cactus group. This is an effective version +of the Henriques-Kamnitzer construction of the action of the cactus +group on tensor powers of a crystal. This is a generalisation of +the Fomin growth rules which are an effective version of the operations +on standard tableaux which were previously constructed using jeu-de-taquin. + +The basic operations are rectification, evacuation and promotion. +Rectification of standard skew tableaux agrees with the rectification +by jeu-de-taquin as does evacuation. Promotion agrees with promotion +by jeu-de-taquin on rectangular tableaux but in general they are different. + +AUTHORS: + +- Bruce Westbury (2018): initial version + +#***************************************************************************** +# Copyright (C) 2018 Bruce Westbury , +# +# 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/ +#***************************************************************************** + + +""" + + +from sage.misc.abstract_method import abstract_method +from sage.categories.category import Category +from sage.categories.sets_cat import Sets + +class PathTableaux(Category): + """ + This defines the category of PathTableaux. + """ + def super_categories(self): + return [Sets()] + + class ElementMethods: + """ + These methods are not called directly. Instead, when a Element class + for this Category is created these methods are automatically added + to the class methods. + """ + +############################ Abstract Methods ################################# + + @abstract_method(optional=False) + def check(self): + """ + This is an abstract method. It must be overwritten in any + Element class for this Category. Typically an instance of + an Element class is a sequence of partitions with conditions + on adjacent partitions in the sequence. This function checks + that these conditions are met. + """ + + @abstract_method(optional=False) + def _rule(self,p): + """ + This is an abstract method. It must be overwritten in any + Element class for this Category. This rule provides the + functionality for this Category. It is called in local_rule. + + An instance of an Element class of this Category is a list + of objects of some type. This function takes a list of length + three of objects of this type and returns an object of this type. + + The key property is that the following operation on lists + of length three is an involution: apply the rule to a list + and replace the middle term with the output. + """ + +################################# Book Keeping ################################ + def size(self): + """ + Returns the size or length. + """ + return len(self) + + def initial_shape(self): + """ + Returns the initial shape. + """ + return self[0] + + def final_shape(self): + """ + Returns the final shape. + """ + return self[-1] + +############################# Jeu de taquin ################################### + + def local_rule(self,i): + """ + This is the local that is used for the remaining constructions. + This has input a list of objects. This method first takes + the list of objects of length three consisting of the $(i-1)$-st, + $i$-th and $(i+1)$-term and applies the rule. It then replaces + the $i$-th object by the object returned by the rule. + """ + if not (i > 0 and i < len(self) ): + raise ValueError("%d is not a valid integer." % i) + + result = list(self) + result[i] = self._rule(self[i-1:i+2]) + + return self.parent()(result) + + def promotion(self): + """ + The promotion operator. This is given by a two row diagram. + """ + result = list(self) + for i in range(1,len(result)-1): + result[i] = self._rule(result[i-1:i+2]) + return self.parent()(result) + + def evacuation(self): + """ + The evacuation operator. This is given by a triangular diagram. + """ + if self.size() < 3: + return self + + T = self + L = list(T) + result = [] + for i in range(len(self)): + T = self.parent()(L).promotion() + L = list(T) + result.append( L.pop() ) + result.reverse() + return self.parent()(result) + + def commutor(self,other): + """ + This constructs the commutor of a pair of tableau. + This is given by a rectangular diagram. + """ + n = len(self) + m = len(other) + + row = list(self) + col = list(other) + for i in range(1,m): + row[0] = self._rule([col[i-1],row[0],row[1]]) + for j in range(1,n): + row[j] = self._rule(row[i-1:i+2]) + + return self.parent()(result) # Result is not defined. + + + def cactus(self,i,j): + """ + This constructs the action of the generators of the cactus group. + These generators are involutions and are usually denoted by + $s_{i,\,j$}$. + """ + if not 0 < i < j < self.size(): + raise ValueError("Integers out of bounds.") + + if i == j: + return self + + if i == 1: + h = list(self)[:j-1] + t = list(self)[j-1:] + T = self.parent()(h) + L = list(T.evacuation()) + t + return self.parent()(L) + + return self.cactus(1,j).cactus(1,j-i).cactus(1,j) + +########################### Visualisation and checking ######################## + + def cylindrical_diagram(self): + """ + This constructs the cylindrical growth diagram. This provides + a visual summary of several operations simultaneously. The + operations which can be read off directly from this diagram + are the powers of the promotion operator (which form the rows) + and the cactus group operators $s_{1,\,j$}$ (which form the + first half of the columns). + """ + n = len(self) + result = [[None]*(2*n-1)]*n + T = self + for i in range(n): + result[i] = [None]*i + list(T) + T = T.promotion() + + return result + + def check_involution_rule(self): + """ + This is to check that the local rule gives an involution. + This is crucial. + """ + for i in range(self.size()): + if self.local_rule(i+1).self.local_rule(i+1) != self: + return False + return True + + def check_involution_cactus(self): + """ + This is to check that the cactus group generators are + involutions.. + """ + return all([ self.cactus(1,i).cactus(1,i) == self for i in range(2,self.size() ) ]) + + def check_promotion(self): + """ + Promotion can be expressed in terms of the cactus generators. + Here we check this relation. + """ + n = self.size() + lhs = self.promotion() + rhs = self.cactus(1,n).cactus(2,n) + return lhs == rhs + + def check_commutation(self): + """ + This is to check the commutation relations in the presentation + of the cactus group. + """ + from itertools import combinations + + n = self.size() + for i,j,r,s in combinations(range(n),4): + lhs = self.cactus(i,j).cactus(r,s) + rhs = self.cactus(r,s).cactus(i,j) + if lhs != rhs: + return False + return True + + def check_coboundary(self): + """ + This is to check the coboundary relations in the presentation + of the cactus group. + """ + from itertools import combinations + + n = self.size() + for i,j,r,s in combinations(range(n),4): + lhs = self.cactus(i,s).cactus(j,r) + rhs = self.cactus(i+s-r,i+s-j).cactus(i,s) + if lhs != rhs: + return False + return True + + def check_consistent(self): + """ + This checks that two different constructions of the + operators $s_{1,\,i}$ give the same result. The first + construction is the direct construction which uses + evacuation. The second method reads this off the + cylindrical diagram; which is constructed using promotion. + """ + d = self.cylindrical_diagram() + for i in range(1,n): + t = [ d[i][i-j] for j in range(i-1) ] + x = self.parent()(t+d[0][i:]) + if x != self.cactus(1,i): + return False + return True + + + def orbit(self): + """ + Constructs the orbit under the action of the cactus group. + """ + n = self.size() + orb = set([]) + rec = set([self]) + new = set([]) + while rec != set([]): + for a in rec: + for i in range(self.size()): + b = a.cactus(1,i+1) + if b not in orb and b not in rec: + new.add(b) + orbit.join(new) + rec = copy(new) + new = set([]) + + return orb + + def dual_equivalence_graph(self): + """ + This constructs the graph with vertices the orbit of self + and edges given by the action of the cactus group generators. + + In most implementations the generators $s_{i,\,i+1}$ will act + as the identity operators. The usual dual equivalence graphs + are given by replacing the label $i,i+2$ by $i$ and removing + edges with other labels. + """ + from sage.graphs.graph import Graph + from itertools import combinations + + G = Graph() + orb = orbit(self) + + for a in orb: + for i,j in combinations(range(self.size(),2)): + b = a.cactus(i+1,j+1) + if a != b: + G.add_edge(a,b,"%d,%d" % (i,j)) + return G + + def csp(self): + import sage.combinat.cyclic_sieving_phenomenon + +#### These functions don't belong here but I don't have a home for them. #### + + def drawL(self): + """ + This assumes we have a sequence of partitions. + This is the default case but need not always be the case. + + This draws a plot of the sequence of partitions. + """ + + gap = 1 + + def draw_partition(p,origin): + + global gap + + if p == Partition([]): + return point(origin,axes=False,size=60) + + r = origin[0] + s = origin[1] + + u = p.to_dyck_word() + u = u[u.index(0):] + u.reverse() + u = u[u.index(1):] + u.reverse() + x = u.count(0) + y = u.count(1) + + gap = max(x,gap) + n = len(u) + + edge = [] + edge.append([r,-y+s]) + for i in range(n): + v = copy(edge[i]) + if u[i] == 1: + v[1] += 1 + else: + v[0] += 1 + edge.append(v) + + G = Graphics() + G += line([(r,-y+s),(r,s),(r+x,s)],axes=False,thickness=2) + G += line(edge,color='red',axes=False,thickness=3) + + for i, a in enumerate(p[1:]): + G += line([(r,s-i-1),(r+a,s-i-1)],color='green') + + for i, a in enumerate(p.conjugate()[1:]): + G += line([(r+i+1,s),(r+i+1,s-a)],color='green') + + return G + + G = Graphics() + + for i, x in enumerate(self): + G += draw_partition(x, (i*gap+1.5*i,0)) + + G.set_aspect_ratio(1) + + return G + + def drawC(self): + """ + This assumes we have a sequence of partitions. + This is the default case but need not always be the case. + + This draws a plot of the sequence of partitions. + """ + + def draw_partition(p): + + if p == Partition([]): + return point((0,0),axes=False,size=60) + + u = p.to_dyck_word() + u = u[u.index(0):] + u.reverse() + u = u[u.index(1):] + u.reverse() + x = u.count(0) + y = u.count(1) + + n = len(u) + + edge = [] + edge.append([0,-y]) + for i in range(n): + v = copy(edge[i]) + if u[i] == 1: + v[1] += 1 + else: + v[0] += 1 + edge.append(v) + + return line(edge,color='red',axes=False,thickness=3) + + p = self.final_shape() + + G = line([(0,-len(p)),(0,0),(p[0],0)],axes=False) + + for i, a in enumerate(p[1:]): + G += line([(0,-i-1),(a,-i-1)],color='green') + + for i, a in enumerate(p.conjugate()[1:]): + G += line([(i+1,0),(i+1,-a)],color='green') + + for i, x in enumerate(self): + G += draw_partition(x) + + for p in self: + G += draw_partition(p) + + G.set_aspect_ratio(1) + + return G \ No newline at end of file diff --git a/src/sage/combinat/catalan.py b/src/sage/combinat/catalan.py new file mode 100644 index 00000000000..aade224ddea --- /dev/null +++ b/src/sage/combinat/catalan.py @@ -0,0 +1,292 @@ +#!/usr/bin/env python2 +# -*- coding: utf-8 -*- +""" +This is an implementation of the Category PathTableaux. +This is the simplest implementation of PathTableaux and is included to +provide a convenient test case and for pedagogical purposes. + +In this implementation we have sequences of nonnegative integers. These +are required to be the heights Dyck words (except that we do not require +the sequence to start or end at height zero). These are in bijection +with skew standard tableaux with at most two rows. Sequences which start +and end at height zero are in bijection with noncrossing perfect matchings. + +AUTHORS: + +- Bruce Westbury (2018): initial version + +#***************************************************************************** +# Copyright (C) 2018 Bruce Westbury , +# +# 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/ +#***************************************************************************** + + +""" + +from six import add_metaclass + +from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.list_clone import ClonableArray +from sage.structure.parent import Parent + +from pathtableaux import PathTableaux +from sage.categories.sets_cat import Sets + + +############################################################################### + +@add_metaclass(InheritComparisonClasscallMetaclass) +class CatalanTableau(ClonableArray): + """ + An instance is the sequence of nonnegative + integers given by the heights of a Dyck word. The acceptable inputs + are: + - a sequence of nonnegative integers + - a two row standard skew tableau + - a Dyck word + - a noncrossing perfect matching + + EXAMPLES: + + sage: CatalanTableau([0,1,2,1,0]) + [0, 1, 2, 1, 0] + + sage: w = DyckWord([1,1,0,0]) + sage: CatalanTableau(w) + [0, 1, 2, 1, 0] + + sage: p = PerfectMatching([(1,2),(3,4)]) + sage: CatalanTableau(p) + /home/bruce/sage-8.1/src/bin/sage-ipython:76: DeprecationWarning: is_non_crossing is deprecated. Please use is_noncrossing instead. + See http://trac.sagemath.org/23982 for details. + [1, 0, 1, 0] + + sage: t = SkewTableau([[1,2],[3,4]]) + sage: CatalanTableau(t) + [1, 1, 0, 0] + + + """ + @staticmethod + def __classcall_private__(self, ot): + + w = None + + if isinstance(ot,DyckWord): + w = ot.heights() + + if isinstance(ot,PerfectMatching): + if ot.is_non_crossing(): + w = [1]*ot.size() + for a in ot.arcs(): + w[a[1]-1] = 0 + else: + raise ValueError("The perfect matching must be non crossing.") + + if isinstance(ot,SkewTableau): + if len(ot) == 2: + if ot.is_standard(): + w = [1]*ot.size() + for i in ot[1]: + w[i-1] = 0 + else: + raise ValueError("The tableau must be standard.") + else: + raise ValueError("The tableau must have two rows.") + + if isinstance(ot,(list,tuple)): + try: + w = tuple([ Integer(a) for a in ot ]) + except TypeError: + raise ValueError("%s is not a sequence of integers." % str(ot) ) + + if w == None: + raise ValueError( "Sorry, not sorry; I don't know what to do with %s." % str(ot) ) + + return CatalanTableaux()(w) + + def check(self): + """ + This overwrites the abstract method. + + This checks that heights are nonnegative and that succesive heights + differ by +1 or -1. + + EXAMPLES: + sage: CatalanTableau([0,1,2,3,2,3]) + [0, 1, 2, 3, 2, 3] + + sage: CatalanTableau([0,1,0,-1,0]) + ValueError: [0, 1, 0, -1, 0] has a negative entry. + + sage: CatalanTableau([0,1,3,3,2,3]) + ValueError: [0, 1, 3, 3, 2, 3] is not a Dyck path. + + """ + n = len(self) + if any([ a < 0 for a in self]): + raise ValueError( "%s has a negative entry." % (str(self)) ) + for i in range(n-1): + if abs(self[i+1]-self[i]) > 1: + raise ValueError( "%s is not a Dyck path." % (str(self)) ) + + @staticmethod + def _rule(x): + """ + This overwrites the abstract method. + """ + return abs(x[0]-x[1]+x[2]) + + def is_skew(self): + """ + Returns True if Tableau is skew and False if not. + + EXAMPLES: + sage: CatalanTableau([0,1,2,1]).is_skew() + False + sage: CatalanTableau([1,0,1,2,1]).is_skew() + True + + """ + return self[0] != 0 + + def descents(self): + """ + Returns the descent set. + + EXAMPLE: + + sage: CatalanTableau([0,1,2,1,2,1,0,1,0]).descents() + {3, 6} + + """ + result = set() + + for i in range(1,len(self)-1): + if self[i] < self[i-1] and self[i] < self[i+1]: + result.add(i) + + return result + + def to_word(self): + """ + Converts to a word in the alphabet 0,1 + + EXAMPLE: + + sage: CatalanTableau([1,0,1,2,1]).to_word() + [0, 1, 1, 0] + + """ + return [ (self[i+1]-self[i]+1)/2 for i in range(self.size()-1) ] + + def to_dyck_word(self): + """ + This converts to a Dyck path. + + EXAMPLE: + + sage: CatalanTableau([1,0,1,2,1]).to_dyck_word() + [0, 1, 1, 0] + + """ + return DyckWord(self.to_word()) + + def to_perfect_matching(self): + """ + This converts to a perfect matching. + + EXAMPLE: + + sage: CatalanTableau([0,1,2,1,2,1,0,1,0]).to_perfect_matching() + [(0, 5), (1, 2), (3, 4), (6, 7)] + + """ + w = self.to_word() + y = DyckWord(w) + pairs = set() + for i, a in enumerate(y): + c = y.associated_parenthesis(i) + if i < c: + pairs.add((i,c)) + return PerfectMatching(pairs) + + def to_tableau(self): + """ + Converts to a skew tableau. + """ + top = [ i for i, a in enumerate(self) if a == 1 ] + bot = [ i for i, a in enumerate(self) if a == 0 ] + return SkewTableau([[None]*self[0]+top,bot]) + + def draw(self): + """ + This draws the Dyck path. + """ + return line([ (i,a) for i, a in enumerate(self)]) + +""" + +Here we illustrate the slogan that promotion = rotation. + +sage: t = CatalanTableau([0,1,2,3,2,1,0]) +sage: t.to_perfect_matching() +[(0, 5), (1, 4), (2, 3)] +sage: t = t.promotion() +sage: t.to_perfect_matching() +[(0, 3), (1, 2), (4, 5)] +sage: t = t.promotion() +sage: t.to_perfect_matching() +[(0, 1), (2, 5), (3, 4)] +sage: t = t.promotion() +sage: t.to_perfect_matching() +[(0, 5), (1, 4), (2, 3)] + +Here we test the Category methods. + +sage: t = CatalanTableau([0,1,2,3,2,1,0]) +sage: SkewTableau(t.cylindrical_diagram()).pp() + 0 1 2 3 2 1 0 + . 0 1 2 1 0 1 0 + . . 0 1 0 1 2 1 0 + . . . 0 1 2 3 2 1 0 + . . . . 0 1 2 1 0 1 0 + . . . . . 0 1 0 1 2 1 0 + . . . . . . 0 1 2 3 2 1 0 + + + +""" +############################################################################### + +class CatalanTableaux(UniqueRepresentation,Parent): + """ + This constructs the Parent class. + """ + @staticmethod + def __classcall_private__(cls): + return super(CatalanTableaux, cls).__classcall__(cls) + + def __init__(self): + + Parent.__init__(self, category=PathTableaux()) + + def __contains__(self, ot): + + return isinstance(ot, (list, tuple, CatalanTableau)) + + def _element_constructor_(self, ot, check=True): + + if isinstance(ot, CatalanTableaux) and ot.parent() == self: + return ot + + return self.element_class(self, list(ot)) + + Element = CatalanTableau + diff --git a/src/sage/combinat/semistandard.py b/src/sage/combinat/semistandard.py new file mode 100644 index 00000000000..3dce239faba --- /dev/null +++ b/src/sage/combinat/semistandard.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python2 +# -*- coding: utf-8 -*- +""" +This is an impementation of the Category PathTableaux. + +In this implementation we have sequences of partitions. These are in +bijection with dual semistandard tableaux. This gives an effective +version of operations on tableaux constructed using jeu-de-taquin. +In the standard constructions of these operations one usually assumes +the tableau is standard. + +For rectification and evacuation the operations here +agree with the standard construction. For promotion the construction +here agrees with the standard construction on rectangular standard +tableaux, but, in general, they are different. + +The operations here also give the Bender-Knuth involutions and +dual equivalence graphs. + +AUTHORS: + +- Bruce Westbury (2018): initial version + +#***************************************************************************** +# Copyright (C) 2018 Bruce Westbury , +# +# 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/ +#***************************************************************************** + + +""" + +from six import add_metaclass + +from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.list_clone import ClonableArray +from sage.structure.parent import Parent + +from pathtableaux import PathTableaux + + +@add_metaclass(InheritComparisonClasscallMetaclass) +class DualSemistandardTableau(ClonableArray): + """ + An instance is the sequence of partitions correspond to the + chain of partitions of a dual semistandard skew tableau. + + The acceptable inputs are: + - a sequence such that each term defines a partition + - a semistandard skew tableau + + EXAMPLES: + + sage: DualSemistandardTableau([[],[1],[2],[2,1]]) + [[], [1], [2], [2, 1]] + + sage: t = SkewTableau([[None,None,None,4,4,5,6,7],[None,2,4,6,7,7,7],[None,4,5,8,8,9],[None,6,7,10],[None,8,8,11],[None],[4]]) + sage: DualSemistandardTableau(t) + [[6, 1, 1], [6, 1, 1], [6, 2, 1], [6, 2, 1], [7, 3, 2, 1, 1], [7, 3, 3, 1, 1, 1], [7, 4, 3, 2, 1, 1, 1], [7, 4, 4, 2, 2, 2, 2, 1], [7, 5, 5, 3, 3, 2, 2, 1], [7, 5, 5, 3, 3, 3, 2, 1], [7, 5, 5, 4, 3, 3, 2, 1], [7, 5, 5, 5, 3, 3, 2, 1]] + + """ + @staticmethod + def __classcall_private__(self, ot): + + w = None + + if isinstance(ot,(SkewTableau,SemistandardTableau)): + w = ot.conjugate().to_chain() + + if isinstance(ot,(list,tuple)): + try: + w = tuple([ Partition(a) for a in ot ]) + except TypeError: + raise ValueError("%s is not a sequence of partitions." % str(ot) ) + + if w == None: + raise ValueError( "Sorry, not sorry; I don't know what to do with %s." % str(ot) ) + + return DualSemistandardTableaux()(w) + + def _hash_(self): + return hash(tuple(map(tuple, self))) + + def check(self): + n = len(self) + for i in range(n-1): + h = self[i] + t = self[i+1] + if not t.contains(h): + raise ValueError( "%s must contain %s" % (str(t),str(h)) ) + for r, s in zip(h,t): + if s > r+1: + raise ValueError( "%s / %s is not a vertical strip" % (str(t),str(h)) ) + for a in t[len(h):]: + if a > 1: + raise ValueError( "%s / %s is not a vertical strip" % (str(t),str(h)) ) + @staticmethod + def _rule(x): + y = map(list,x) + m = max([ len(u) for u in y ]) + z = map( lambda u: vector(u + [0]*(m-len(u)) ), y ) + result = list(z[0]-z[1]+z[2]) + result.sort(reverse=true) + return Partition(result) + + def evaluation(self): + z = [ p.size() for p in self ] + return [ z[i+1] - z[i] for i in range(len(self)-1) ] + + def to_tableau(self): + """ + Returns the conjugate skew tableau. This will be semistandard. + """ + ch = [ p.conjugate() for p in self] + try: + return SkewTableau(chain=ch) + except TypeError: + return SemistandardTableau(chain=ch) + + def is_skew(self): + """ + Returns True if Tableau is skew and False if not. + + EXAMPLE: + sage: T = OscillatingTableau([[],[1],[2],[1],[]]) + sage: T.is_skew() + False + """ + return self[0] != Partition([]) + + def rectify(self): + pass + + def check_bender_knuth(self,i): + lhs = self.local_rule(i).to_tableau() + rhs = self.to_tableau().bender_knuth_involution(i) + return lhs == rhs + + def check_rectify(self): + lhs = self.rectify().to_tableau() + rhs = self.to_tableau().rectify() + return lhs == rhs + + def check_evacuation(self): + lhs = self.evacuation().to_tableau() + rhs = self.to_tableau().evacuation() + return lhs == rhs +""" +I wanted to put in checks of the claims I made. However SkewTableaux +does not have the operations of promotion or evacuation + +""" +############################################################################### + +class DualSemistandardTableaux(UniqueRepresentation,Parent): + + @staticmethod + def __classcall_private__(cls): + return super(DualSemistandardTableaux, cls).__classcall__(cls) + + def __init__(self): + + Parent.__init__(self, category=PathTableaux()) + + def __contains__(self, ot): + + return isinstance(ot, (list, tuple, DualSemistandardTableau)) + + def _element_constructor_(self, ot, check=True): + + if isinstance(ot, DualSemistandardTableaux) and ot.parent() == self: + return ot + + return self.element_class(self, list(ot)) + + Element = DualSemistandardTableau + From 934c0152d8b4af95508e038305dbba0ad365d58d Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Thu, 24 May 2018 08:29:08 +0100 Subject: [PATCH 004/300] Corrected path --- src/sage/combinat/catalan.py | 2 +- src/sage/combinat/semistandard.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/catalan.py b/src/sage/combinat/catalan.py index aade224ddea..447ad0f19db 100644 --- a/src/sage/combinat/catalan.py +++ b/src/sage/combinat/catalan.py @@ -35,7 +35,7 @@ from sage.structure.list_clone import ClonableArray from sage.structure.parent import Parent -from pathtableaux import PathTableaux +from sage.categories.pathtableaux import PathTableaux from sage.categories.sets_cat import Sets diff --git a/src/sage/combinat/semistandard.py b/src/sage/combinat/semistandard.py index 3dce239faba..d5c2551b960 100644 --- a/src/sage/combinat/semistandard.py +++ b/src/sage/combinat/semistandard.py @@ -41,7 +41,7 @@ from sage.structure.list_clone import ClonableArray from sage.structure.parent import Parent -from pathtableaux import PathTableaux +from sage.categories.pathtableaux import PathTableaux @add_metaclass(InheritComparisonClasscallMetaclass) From 7157b1fd2fa111a0e71a23d550ff5b76d995cb4b Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Thu, 24 May 2018 08:47:56 +0100 Subject: [PATCH 005/300] Edited a couple of doc tests --- src/sage/combinat/semistandard.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/semistandard.py b/src/sage/combinat/semistandard.py index d5c2551b960..41438d0b4e9 100644 --- a/src/sage/combinat/semistandard.py +++ b/src/sage/combinat/semistandard.py @@ -127,8 +127,8 @@ def is_skew(self): Returns True if Tableau is skew and False if not. EXAMPLE: - sage: T = OscillatingTableau([[],[1],[2],[1],[]]) - sage: T.is_skew() + sage: t = DualSemistandardTableau([[],[1],[2],[2,1]]) + sage: t.is_skew() False """ return self[0] != Partition([]) From 3090a75ec766aa05f83ee6046cabed79b7abe369 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Wed, 30 May 2018 17:51:05 +0100 Subject: [PATCH 006/300] A few trivial changes. --- src/sage/combinat/all.py | 2 ++ src/sage/combinat/catalan.py | 25 ++++++++++++------------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 345fb2a9ca8..85d5f8bca00 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -218,3 +218,5 @@ 'GrowthDiagramRSK', 'GrowthDiagramBurge', 'GrowthDiagramBinWord', 'GrowthDiagramDomino', 'GrowthDiagramYoungFibonacci', 'GrowthDiagramSylvester']) + +lazy_import('sage.combinat.catalan', ['PathTableau','PathTableaux']) \ No newline at end of file diff --git a/src/sage/combinat/catalan.py b/src/sage/combinat/catalan.py index 447ad0f19db..78d090ee1c8 100644 --- a/src/sage/combinat/catalan.py +++ b/src/sage/combinat/catalan.py @@ -14,7 +14,7 @@ AUTHORS: - Bruce Westbury (2018): initial version - +""" #***************************************************************************** # Copyright (C) 2018 Bruce Westbury , # @@ -25,9 +25,6 @@ # http://www.gnu.org/licenses/ #***************************************************************************** - -""" - from six import add_metaclass from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass @@ -36,7 +33,9 @@ from sage.structure.parent import Parent from sage.categories.pathtableaux import PathTableaux -from sage.categories.sets_cat import Sets +#from sage.categories.sets_cat import Sets +#from sage.combinat.catalan import CatalanTableau +#from sage.combinat.catalan import CatalanTableaux ############################################################################### @@ -51,12 +50,12 @@ class CatalanTableau(ClonableArray): - a two row standard skew tableau - a Dyck word - a noncrossing perfect matching - + EXAMPLES: sage: CatalanTableau([0,1,2,1,0]) [0, 1, 2, 1, 0] - + sage: w = DyckWord([1,1,0,0]) sage: CatalanTableau(w) [0, 1, 2, 1, 0] @@ -70,14 +69,14 @@ class CatalanTableau(ClonableArray): sage: t = SkewTableau([[1,2],[3,4]]) sage: CatalanTableau(t) [1, 1, 0, 0] - - + + """ @staticmethod def __classcall_private__(self, ot): w = None - + if isinstance(ot,DyckWord): w = ot.heights() @@ -107,8 +106,8 @@ def __classcall_private__(self, ot): raise ValueError("%s is not a sequence of integers." % str(ot) ) if w == None: - raise ValueError( "Sorry, not sorry; I don't know what to do with %s." % str(ot) ) - + raise ValueError( "Sorry, not sorry; I don't know what to do with %s." % str(ot) ) + return CatalanTableaux()(w) def check(self): @@ -224,7 +223,7 @@ def to_tableau(self): top = [ i for i, a in enumerate(self) if a == 1 ] bot = [ i for i, a in enumerate(self) if a == 0 ] return SkewTableau([[None]*self[0]+top,bot]) - + def draw(self): """ This draws the Dyck path. From a89516ed725a144291757abf0908da85e65d9c9c Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Wed, 30 May 2018 18:07:19 +0100 Subject: [PATCH 007/300] Changed all.py --- src/sage/combinat/all.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 85d5f8bca00..118c6490669 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -219,4 +219,4 @@ 'GrowthDiagramBinWord', 'GrowthDiagramDomino', 'GrowthDiagramYoungFibonacci', 'GrowthDiagramSylvester']) -lazy_import('sage.combinat.catalan', ['PathTableau','PathTableaux']) \ No newline at end of file +from .catalan import CatalanTableau, CatalanTableaux \ No newline at end of file From 8944c6e6c854148d2f884346663c305a7c6990f5 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Wed, 30 May 2018 20:00:13 +0100 Subject: [PATCH 008/300] Fixed imports so doc tests now run. --- src/sage/combinat/all.py | 2 +- src/sage/combinat/catalan.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 118c6490669..655dc674d6c 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -219,4 +219,4 @@ 'GrowthDiagramBinWord', 'GrowthDiagramDomino', 'GrowthDiagramYoungFibonacci', 'GrowthDiagramSylvester']) -from .catalan import CatalanTableau, CatalanTableaux \ No newline at end of file +lazy_import('sage.combinat.catalan', ['CatalanTableaux','CatalanTableau']) diff --git a/src/sage/combinat/catalan.py b/src/sage/combinat/catalan.py index 78d090ee1c8..87d72955e5a 100644 --- a/src/sage/combinat/catalan.py +++ b/src/sage/combinat/catalan.py @@ -32,6 +32,11 @@ from sage.structure.list_clone import ClonableArray from sage.structure.parent import Parent +from sage.combinat.dyck_word import DyckWord +from sage.combinat.perfect_matching import PerfectMatching +from sage.combinat.skew_tableau import SkewTableau +from sage.rings.integer import Integer + from sage.categories.pathtableaux import PathTableaux #from sage.categories.sets_cat import Sets #from sage.combinat.catalan import CatalanTableau From 7d6fef08c58ddce1e3dea7b52ff4081ead34c245 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Wed, 30 May 2018 21:44:22 +0100 Subject: [PATCH 009/300] Imports into semistandard.py fixed --- src/sage/categories/pathtableaux.py | 20 +++++++++---------- src/sage/combinat/all.py | 3 +++ src/sage/combinat/semistandard.py | 31 ++++++++++++++--------------- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/src/sage/categories/pathtableaux.py b/src/sage/categories/pathtableaux.py index 25416420f32..c226eb07512 100644 --- a/src/sage/categories/pathtableaux.py +++ b/src/sage/categories/pathtableaux.py @@ -48,7 +48,7 @@ class ElementMethods: """ ############################ Abstract Methods ################################# - + @abstract_method(optional=False) def check(self): """ @@ -95,7 +95,7 @@ def final_shape(self): return self[-1] ############################# Jeu de taquin ################################### - + def local_rule(self,i): """ This is the local that is used for the remaining constructions. @@ -127,7 +127,7 @@ def evacuation(self): """ if self.size() < 3: return self - + T = self L = list(T) result = [] @@ -161,10 +161,10 @@ def cactus(self,i,j): This constructs the action of the generators of the cactus group. These generators are involutions and are usually denoted by $s_{i,\,j$}$. - """ + """ if not 0 < i < j < self.size(): raise ValueError("Integers out of bounds.") - + if i == j: return self @@ -178,7 +178,7 @@ def cactus(self,i,j): return self.cactus(1,j).cactus(1,j-i).cactus(1,j) ########################### Visualisation and checking ######################## - + def cylindrical_diagram(self): """ This constructs the cylindrical growth diagram. This provides @@ -223,7 +223,7 @@ def check_promotion(self): lhs = self.promotion() rhs = self.cactus(1,n).cactus(2,n) return lhs == rhs - + def check_commutation(self): """ This is to check the commutation relations in the presentation @@ -316,9 +316,9 @@ def dual_equivalence_graph(self): def csp(self): import sage.combinat.cyclic_sieving_phenomenon - + #### These functions don't belong here but I don't have a home for them. #### - + def drawL(self): """ This assumes we have a sequence of partitions. @@ -434,4 +434,4 @@ def draw_partition(p): G.set_aspect_ratio(1) - return G \ No newline at end of file + return G diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 655dc674d6c..2473b3307a4 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -220,3 +220,6 @@ 'GrowthDiagramYoungFibonacci', 'GrowthDiagramSylvester']) lazy_import('sage.combinat.catalan', ['CatalanTableaux','CatalanTableau']) + +lazy_import('sage.combinat.semistandard', ['DualSemistandardTableaux','DualSemistandardTableau']) + diff --git a/src/sage/combinat/semistandard.py b/src/sage/combinat/semistandard.py index 41438d0b4e9..aadd48412f6 100644 --- a/src/sage/combinat/semistandard.py +++ b/src/sage/combinat/semistandard.py @@ -20,7 +20,7 @@ AUTHORS: - Bruce Westbury (2018): initial version - +""" #***************************************************************************** # Copyright (C) 2018 Bruce Westbury , # @@ -31,9 +31,6 @@ # http://www.gnu.org/licenses/ #***************************************************************************** - -""" - from six import add_metaclass from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass @@ -42,20 +39,22 @@ from sage.structure.parent import Parent from sage.categories.pathtableaux import PathTableaux - +from sage.combinat.skew_tableau import SkewTableau +from sage.combinat.tableau import SemistandardTableau +from sage.combinat.partition import Partition @add_metaclass(InheritComparisonClasscallMetaclass) class DualSemistandardTableau(ClonableArray): """ An instance is the sequence of partitions correspond to the chain of partitions of a dual semistandard skew tableau. - + The acceptable inputs are: - a sequence such that each term defines a partition - a semistandard skew tableau EXAMPLES: - + sage: DualSemistandardTableau([[],[1],[2],[2,1]]) [[], [1], [2], [2, 1]] @@ -66,12 +65,12 @@ class DualSemistandardTableau(ClonableArray): """ @staticmethod def __classcall_private__(self, ot): - + w = None if isinstance(ot,(SkewTableau,SemistandardTableau)): w = ot.conjugate().to_chain() - + if isinstance(ot,(list,tuple)): try: w = tuple([ Partition(a) for a in ot ]) @@ -79,8 +78,8 @@ def __classcall_private__(self, ot): raise ValueError("%s is not a sequence of partitions." % str(ot) ) if w == None: - raise ValueError( "Sorry, not sorry; I don't know what to do with %s." % str(ot) ) - + raise ValueError( "Sorry, not sorry; I don't know what to do with %s." % str(ot) ) + return DualSemistandardTableaux()(w) def _hash_(self): @@ -111,7 +110,7 @@ def _rule(x): def evaluation(self): z = [ p.size() for p in self ] return [ z[i+1] - z[i] for i in range(len(self)-1) ] - + def to_tableau(self): """ Returns the conjugate skew tableau. This will be semistandard. @@ -121,7 +120,7 @@ def to_tableau(self): return SkewTableau(chain=ch) except TypeError: return SemistandardTableau(chain=ch) - + def is_skew(self): """ Returns True if Tableau is skew and False if not. @@ -135,17 +134,17 @@ def is_skew(self): def rectify(self): pass - + def check_bender_knuth(self,i): lhs = self.local_rule(i).to_tableau() rhs = self.to_tableau().bender_knuth_involution(i) return lhs == rhs - + def check_rectify(self): lhs = self.rectify().to_tableau() rhs = self.to_tableau().rectify() return lhs == rhs - + def check_evacuation(self): lhs = self.evacuation().to_tableau() rhs = self.to_tableau().evacuation() From bfcfc84ed86f6ab70b4576d4ef0da2816642141c Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Thu, 31 May 2018 15:41:48 +0100 Subject: [PATCH 010/300] Added doc tests --- src/sage/categories/pathtableaux.py | 4 ++-- src/sage/combinat/catalan.py | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/pathtableaux.py b/src/sage/categories/pathtableaux.py index c226eb07512..d19a94422c5 100644 --- a/src/sage/categories/pathtableaux.py +++ b/src/sage/categories/pathtableaux.py @@ -202,8 +202,8 @@ def check_involution_rule(self): This is to check that the local rule gives an involution. This is crucial. """ - for i in range(self.size()): - if self.local_rule(i+1).self.local_rule(i+1) != self: + for i in range(self.size()-2): + if self.local_rule(i+1).local_rule(i+1) != self: return False return True diff --git a/src/sage/combinat/catalan.py b/src/sage/combinat/catalan.py index 87d72955e5a..ba7aa45b372 100644 --- a/src/sage/combinat/catalan.py +++ b/src/sage/combinat/catalan.py @@ -266,6 +266,20 @@ def draw(self): +""" + +""" +sage: t = CatalanTableau([0,1,2,3,2,1,0]) +sage: t.evacuation() +[0, 1, 0, 1, 2] +sage: t.cactus(1,6) +[0, 1, 0, 1, 2, 1, 0] +sage: t.cactus(1,5) +[0, 1, 2, 3, 2, 1, 0] +sage: t == t.cactus(1,5).cactus(1,6).promotion() +True + + """ ############################################################################### From 391ffd0c447336a2459b2a87265bb246372bd71d Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Thu, 31 May 2018 17:39:01 +0100 Subject: [PATCH 011/300] More doc testing --- src/sage/categories/pathtableaux.py | 44 +++++++++++++++-------------- src/sage/combinat/catalan.py | 29 +++++++++++++++---- 2 files changed, 47 insertions(+), 26 deletions(-) diff --git a/src/sage/categories/pathtableaux.py b/src/sage/categories/pathtableaux.py index d19a94422c5..ed208098c76 100644 --- a/src/sage/categories/pathtableaux.py +++ b/src/sage/categories/pathtableaux.py @@ -162,20 +162,20 @@ def cactus(self,i,j): These generators are involutions and are usually denoted by $s_{i,\,j$}$. """ - if not 0 < i < j < self.size(): + if not 0 < i < j <= self.size(): raise ValueError("Integers out of bounds.") if i == j: return self if i == 1: - h = list(self)[:j-1] - t = list(self)[j-1:] + h = list(self)[:j] + t = list(self)[j:] T = self.parent()(h) L = list(T.evacuation()) + t return self.parent()(L) - return self.cactus(1,j).cactus(1,j-i).cactus(1,j) + return self.cactus(1,j).cactus(1,j-i+1).cactus(1,j) ########################### Visualisation and checking ######################## @@ -212,17 +212,15 @@ def check_involution_cactus(self): This is to check that the cactus group generators are involutions.. """ - return all([ self.cactus(1,i).cactus(1,i) == self for i in range(2,self.size() ) ]) + return all([ self.cactus(1,i).cactus(1,i) == self for i in range(2,self.size()+1 ) ]) def check_promotion(self): """ Promotion can be expressed in terms of the cactus generators. Here we check this relation. """ - n = self.size() - lhs = self.promotion() - rhs = self.cactus(1,n).cactus(2,n) - return lhs == rhs + n = self.size()-1 + return self == self.cactus(1,n-1).cactus(1,n).promotion() def check_commutation(self): """ @@ -232,7 +230,9 @@ def check_commutation(self): from itertools import combinations n = self.size() - for i,j,r,s in combinations(range(n),4): + if n < 5: + return True + for i,j,r,s in combinations(range(1,n+1),4): lhs = self.cactus(i,j).cactus(r,s) rhs = self.cactus(r,s).cactus(i,j) if lhs != rhs: @@ -247,9 +247,11 @@ def check_coboundary(self): from itertools import combinations n = self.size() - for i,j,r,s in combinations(range(n),4): - lhs = self.cactus(i,s).cactus(j,r) - rhs = self.cactus(i+s-r,i+s-j).cactus(i,s) + if n < 4: + return True + for i,j,r,s in combinations(range(1,n+3),4): + lhs = self.cactus(i,s-2).cactus(j-1,r-1) + rhs = self.cactus(i+s-r-1,i+s-j-1).cactus(i,s-2) if lhs != rhs: return False return True @@ -281,12 +283,12 @@ def orbit(self): new = set([]) while rec != set([]): for a in rec: - for i in range(self.size()): - b = a.cactus(1,i+1) - if b not in orb and b not in rec: + for i in range(2,self.size()): + b = a.cactus(1,i) + if (b not in orb) and (b not in rec): new.add(b) - orbit.join(new) - rec = copy(new) + orb = orb.union(rec) + rec = new.copy() new = set([]) return orb @@ -305,11 +307,11 @@ def dual_equivalence_graph(self): from itertools import combinations G = Graph() - orb = orbit(self) + orb = self.orbit() for a in orb: - for i,j in combinations(range(self.size(),2)): - b = a.cactus(i+1,j+1) + for i,j in combinations(range(1,self.size()+1),2): + b = a.cactus(i,j) if a != b: G.add_edge(a,b,"%d,%d" % (i,j)) return G diff --git a/src/sage/combinat/catalan.py b/src/sage/combinat/catalan.py index ba7aa45b372..10e65402aa3 100644 --- a/src/sage/combinat/catalan.py +++ b/src/sage/combinat/catalan.py @@ -271,13 +271,32 @@ def draw(self): """ sage: t = CatalanTableau([0,1,2,3,2,1,0]) sage: t.evacuation() -[0, 1, 0, 1, 2] -sage: t.cactus(1,6) -[0, 1, 0, 1, 2, 1, 0] -sage: t.cactus(1,5) [0, 1, 2, 3, 2, 1, 0] -sage: t == t.cactus(1,5).cactus(1,6).promotion() +sage: t.cactus(1,5) +[0, 1, 0, 1, 2, 1, 0] +sage: t.cactus(1,6) +[0, 1, 2, 1, 0, 1, 0] +sage: t.cactus(1,7) == t.evacuation() +True +sage: t.cactus(1,7).cactus(1,6) == t.promotion() True +sage: t.check_involution_rule() +True +sage: t.check_involution_cactus() +True +sage: t.check_promotion() +True +sage: t.check_involution_cactus() +True +sage: t.check_commutation() +True +sage: t.orbit() +{[0, 1, 0, 1, 0, 1, 0], + [0, 1, 0, 1, 2, 1, 0], + [0, 1, 2, 1, 0, 1, 0], + [0, 1, 2, 1, 2, 1, 0], + [0, 1, 2, 3, 2, 1, 0]} + """ From f9abd6b957346e8c844522aacd40ef23a38a054e Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 1 Jun 2018 15:33:29 +0100 Subject: [PATCH 012/300] Started doc testing semistandard.py --- src/sage/combinat/catalan.py | 23 +++++++---------------- src/sage/combinat/semistandard.py | 26 +++++++++++++++++++++----- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/sage/combinat/catalan.py b/src/sage/combinat/catalan.py index 10e65402aa3..a1971a4fc1e 100644 --- a/src/sage/combinat/catalan.py +++ b/src/sage/combinat/catalan.py @@ -29,7 +29,7 @@ from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.list_clone import ClonableArray +from sage.structure.list_clone import ClonableList from sage.structure.parent import Parent from sage.combinat.dyck_word import DyckWord @@ -46,7 +46,7 @@ ############################################################################### @add_metaclass(InheritComparisonClasscallMetaclass) -class CatalanTableau(ClonableArray): +class CatalanTableau(ClonableList): """ An instance is the sequence of nonnegative integers given by the heights of a Dyck word. The acceptable inputs @@ -67,8 +67,7 @@ class CatalanTableau(ClonableArray): sage: p = PerfectMatching([(1,2),(3,4)]) sage: CatalanTableau(p) - /home/bruce/sage-8.1/src/bin/sage-ipython:76: DeprecationWarning: is_non_crossing is deprecated. Please use is_noncrossing instead. - See http://trac.sagemath.org/23982 for details. + ... [1, 0, 1, 0] sage: t = SkewTableau([[1,2],[3,4]]) @@ -127,9 +126,11 @@ def check(self): [0, 1, 2, 3, 2, 3] sage: CatalanTableau([0,1,0,-1,0]) + ... ValueError: [0, 1, 0, -1, 0] has a negative entry. sage: CatalanTableau([0,1,3,3,2,3]) + ... ValueError: [0, 1, 3, 3, 2, 3] is not a Dyck path. """ @@ -190,18 +191,6 @@ def to_word(self): """ return [ (self[i+1]-self[i]+1)/2 for i in range(self.size()-1) ] - def to_dyck_word(self): - """ - This converts to a Dyck path. - - EXAMPLE: - - sage: CatalanTableau([1,0,1,2,1]).to_dyck_word() - [0, 1, 1, 0] - - """ - return DyckWord(self.to_word()) - def to_perfect_matching(self): """ This converts to a perfect matching. @@ -290,6 +279,8 @@ def draw(self): True sage: t.check_commutation() True +sage: t.check_coboundary() +True sage: t.orbit() {[0, 1, 0, 1, 0, 1, 0], [0, 1, 0, 1, 2, 1, 0], diff --git a/src/sage/combinat/semistandard.py b/src/sage/combinat/semistandard.py index aadd48412f6..ed3014be061 100644 --- a/src/sage/combinat/semistandard.py +++ b/src/sage/combinat/semistandard.py @@ -35,16 +35,17 @@ from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.list_clone import ClonableArray +from sage.structure.list_clone import ClonableList from sage.structure.parent import Parent from sage.categories.pathtableaux import PathTableaux from sage.combinat.skew_tableau import SkewTableau from sage.combinat.tableau import SemistandardTableau from sage.combinat.partition import Partition +from sage.modules.free_module_element import vector @add_metaclass(InheritComparisonClasscallMetaclass) -class DualSemistandardTableau(ClonableArray): +class DualSemistandardTableau(ClonableList): """ An instance is the sequence of partitions correspond to the chain of partitions of a dual semistandard skew tableau. @@ -104,7 +105,7 @@ def _rule(x): m = max([ len(u) for u in y ]) z = map( lambda u: vector(u + [0]*(m-len(u)) ), y ) result = list(z[0]-z[1]+z[2]) - result.sort(reverse=true) + result.sort(reverse=True) return Partition(result) def evaluation(self): @@ -150,8 +151,23 @@ def check_evacuation(self): rhs = self.to_tableau().evacuation() return lhs == rhs """ -I wanted to put in checks of the claims I made. However SkewTableaux -does not have the operations of promotion or evacuation + +sage: T = DualSemistandardTableau([[],[1],[2],[2,1]]) +sage: T.evacuation() +[[], [1], [1, 1], [2, 1]] + +sage: Tableau([[1,2],[3]]).evacuation() +[[1, 3], [2]] + +sage: ST = SemistandardTableaux([5,3,3,2,1],[2,1,4,2,2,2,1]) +sage: ST.cardinality() +84 +sage: t = ST.an_element() +sage: s = DualSemistandardTableau(t.conjugate().to_chain()) +sage: v = Tableau(list(SkewTableau(chain=s.evacuation()))) +sage: v.conjugate() == t.evacuation() +True + """ ############################################################################### From 0d1e91f80005f4e21570b7a4d1bd3977b2f0402a Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sat, 2 Jun 2018 16:13:17 +0100 Subject: [PATCH 013/300] Added rectify and multiply --- src/sage/categories/pathtableaux.py | 23 ++++--- src/sage/combinat/semistandard.py | 99 +++++++++++++++++++++++++++-- 2 files changed, 107 insertions(+), 15 deletions(-) diff --git a/src/sage/categories/pathtableaux.py b/src/sage/categories/pathtableaux.py index ed208098c76..793a8ebd55a 100644 --- a/src/sage/categories/pathtableaux.py +++ b/src/sage/categories/pathtableaux.py @@ -145,16 +145,23 @@ def commutor(self,other): """ n = len(self) m = len(other) - - row = list(self) - col = list(other) + if n == 0 or m == 0: + raise ValueError("This requires nonempty lists.") + if n == 1 or m == 1: + return (other,self) + + row = list(other) + col = list(self) + if col[-1] != row[0]: + raise ValueError("%s is not a composable pair." % (self,other)) + + path = col + row[1:] for i in range(1,m): - row[0] = self._rule([col[i-1],row[0],row[1]]) - for j in range(1,n): - row[j] = self._rule(row[i-1:i+2]) - - return self.parent()(result) # Result is not defined. + for j in range(n): + path = path.local_rule(i-j) + + return (self.parent()(path[:n]),self.parent()(path[n-1:])) def cactus(self,i,j): """ diff --git a/src/sage/combinat/semistandard.py b/src/sage/combinat/semistandard.py index ed3014be061..0ec464791dc 100644 --- a/src/sage/combinat/semistandard.py +++ b/src/sage/combinat/semistandard.py @@ -117,11 +117,12 @@ def to_tableau(self): Returns the conjugate skew tableau. This will be semistandard. """ ch = [ p.conjugate() for p in self] - try: - return SkewTableau(chain=ch) - except TypeError: - return SemistandardTableau(chain=ch) - + s = SkewTableau(chain=ch) + if self.is_skew(): + return s + else: + return SemistandardTableau(list(s)) + def is_skew(self): """ Returns True if Tableau is skew and False if not. @@ -134,9 +135,51 @@ def is_skew(self): return self[0] != Partition([]) def rectify(self): - pass - + """ + This is the same function as skew_tableau.rectify + """ + p = self[0].conjugate() + path = [[]] + for i in range(len(p)): + path += p[:i+1] + + return DualSemistandardTableau(path).commutor(self)[0] + + def multiply(self,other): + """ + This is the same function as tableau.slide_multiply and tableau.bump_multiply. + """ + + left = list(self) + right = list(other) + + m = max([len(a) for a in right]) + n = max([ a[0] for a in left]) + + right = [a+[0]*(m-len(a)) for a in right] + + p = max(len(left),len(right)) + left = left + left[-1]*(p-len(left)) + right = right + right[-1]*(p-len(right)) + + result = [Partition([a+n for a in y]+x) for x,y in zip(left,right)] + + return DualSemistandardTableau(result).rectify() + def check_bender_knuth(self,i): + """ + Check that the i-th Bender-Knuth move on the conjugate + tableau is the i-th local rule. + + sage: ST = SemistandardTableaux([5,3,3,2,1],[2,1,4,2,2,2,1]) + sage: s = DualSemistandardTableau(ST.an_element()) + sage: s.check_bender_knuth(5) + True + sage: s.check_bender_knuth(4) + True + + """" + lhs = self.local_rule(i).to_tableau() rhs = self.to_tableau().bender_knuth_involution(i) return lhs == rhs @@ -147,6 +190,16 @@ def check_rectify(self): return lhs == rhs def check_evacuation(self): + """ + Check that jdt-evacuation on the conjugate tableaux + is the evacuation defined here. + + sage: ST = SemistandardTableaux([5,3,3,2,1],[2,1,4,2,2,2,1]) + sage: s = DualSemistandardTableau(ST.an_element()) + sage: s.check_evacuation() + True + + """ lhs = self.evacuation().to_tableau() rhs = self.to_tableau().evacuation() return lhs == rhs @@ -168,6 +221,38 @@ def check_evacuation(self): sage: v.conjugate() == t.evacuation() True +sage: ST = SemistandardTableaux([5,3,3,2,1],[2,1,4,2,2,2,1]) +sage: s = DualSemistandardTableau(ST.an_element()) +sage: s.check_involution_cactus() +True +sage: s.check_commutation() +True +sage: s.check_coboundary() +True + +sage: ST = StandardTableaux([3,3,3]) +sage: ST.cardinality() +42 +sage: t = ST.an_element() +sage: t.promotion() +[[1, 2, 5], [3, 6, 8], [4, 7, 9]] + + +sage: ST = StandardTableaux([3,3,3]) +sage: t = ST.an_element() +sage: s = DualSemistandardTableau(t.to_chain()) +sage: u = StandardTableau(list(SkewTableau(chain=s.promotion()))) +sage: u.promotion() == t +True + +sage: ST.cardinality() +42 +sage: t = ST.an_element() +sage: s = DualSemistandardTableau(t.to_chain()) +sage: len(s.orbit()) +42 + + """ ############################################################################### From 16c04c43e726fe41005c3346e672503a9702277d Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Mon, 4 Jun 2018 16:48:27 +0100 Subject: [PATCH 014/300] Added rectify --- src/sage/categories/pathtableaux.py | 17 ++++++++++++----- src/sage/combinat/semistandard.py | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/sage/categories/pathtableaux.py b/src/sage/categories/pathtableaux.py index 793a8ebd55a..e448d4ca4d4 100644 --- a/src/sage/categories/pathtableaux.py +++ b/src/sage/categories/pathtableaux.py @@ -138,10 +138,13 @@ def evacuation(self): result.reverse() return self.parent()(result) - def commutor(self,other): + def path_rule(self,other,display=False): """ This constructs the commutor of a pair of tableau. This is given by a rectangular diagram. + + If display=True then the function will print + the rectangle. """ n = len(self) m = len(other) @@ -156,12 +159,16 @@ def commutor(self,other): raise ValueError("%s is not a composable pair." % (self,other)) path = col + row[1:] - for i in range(1,m): - for j in range(n): - path = path.local_rule(i-j) + if display: + print row + for i in range(1:n): + for j in range(m-1): + path = path.local_rule(n+j-i) + if display: + print path[n-i:n+m-i-2] - return (self.parent()(path[:n]),self.parent()(path[n-1:])) + return (self.parent()(path[:m]),self.parent()(path[n-1:])) def cactus(self,i,j): """ diff --git a/src/sage/combinat/semistandard.py b/src/sage/combinat/semistandard.py index 0ec464791dc..b006af41640 100644 --- a/src/sage/combinat/semistandard.py +++ b/src/sage/combinat/semistandard.py @@ -143,7 +143,7 @@ def rectify(self): for i in range(len(p)): path += p[:i+1] - return DualSemistandardTableau(path).commutor(self)[0] + return DualSemistandardTableau(path).path_rule(self)[0] def multiply(self,other): """ From e5cb8617c06746325523d815a6c28728a225e4a1 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sun, 10 Jun 2018 14:37:04 +0100 Subject: [PATCH 015/300] Rectify added --- src/sage/categories/pathtableaux.py | 17 ++++++------ src/sage/combinat/catalan.py | 8 ++++-- src/sage/combinat/semistandard.py | 43 +++++++++++++++++------------ 3 files changed, 39 insertions(+), 29 deletions(-) diff --git a/src/sage/categories/pathtableaux.py b/src/sage/categories/pathtableaux.py index e448d4ca4d4..fbd4cee1e8b 100644 --- a/src/sage/categories/pathtableaux.py +++ b/src/sage/categories/pathtableaux.py @@ -156,19 +156,20 @@ def path_rule(self,other,display=False): row = list(other) col = list(self) if col[-1] != row[0]: - raise ValueError("%s is not a composable pair." % (self,other)) + raise ValueError("%s,%s is not a composable pair." % (self,other)) - path = col + row[1:] - if display: - print row - for i in range(1:n): + path = self.parent()(col + row[1:]) + + for i in range(1,n): + if display: + print path[n-i:n+m-i] for j in range(m-1): path = path.local_rule(n+j-i) - if display: - print path[n-i:n+m-i-2] + if display: + print path[:m] - return (self.parent()(path[:m]),self.parent()(path[n-1:])) + return (self.parent()(path[:m]),self.parent()(path[m-1:])) def cactus(self,i,j): """ diff --git a/src/sage/combinat/catalan.py b/src/sage/combinat/catalan.py index a1971a4fc1e..13802960167 100644 --- a/src/sage/combinat/catalan.py +++ b/src/sage/combinat/catalan.py @@ -35,6 +35,7 @@ from sage.combinat.dyck_word import DyckWord from sage.combinat.perfect_matching import PerfectMatching from sage.combinat.skew_tableau import SkewTableau +from sage.combinat.tableau import Tableau from sage.rings.integer import Integer from sage.categories.pathtableaux import PathTableaux @@ -92,12 +93,13 @@ def __classcall_private__(self, ot): else: raise ValueError("The perfect matching must be non crossing.") - if isinstance(ot,SkewTableau): + if isinstance(ot,Tableau): if len(ot) == 2: if ot.is_standard(): - w = [1]*ot.size() + u = [1]*ot.size() for i in ot[1]: - w[i-1] = 0 + u[i-1] = 0 + w = DyckWord(u).heights() else: raise ValueError("The tableau must be standard.") else: diff --git a/src/sage/combinat/semistandard.py b/src/sage/combinat/semistandard.py index b006af41640..df69f494cbe 100644 --- a/src/sage/combinat/semistandard.py +++ b/src/sage/combinat/semistandard.py @@ -122,7 +122,7 @@ def to_tableau(self): return s else: return SemistandardTableau(list(s)) - + def is_skew(self): """ Returns True if Tableau is skew and False if not. @@ -134,51 +134,58 @@ def is_skew(self): """ return self[0] != Partition([]) - def rectify(self): + def rectify(self,display=False): """ This is the same function as skew_tableau.rectify + + sage: t = SkewTableau([[None,None,2,4],[1,3,5]]) + sage: s = DualSemistandardTableau(t.to_chain()) + sage: s.rectify(display=True) + [[2], [2, 1], [3, 1], [3, 2], [4, 2], [4, 3]] + [[1], [1, 1], [2, 1], [2, 2], [3, 2], [3, 3]] + [[], [1], [2], [2, 1], [3, 1], [3, 2]] + [[], [1], [2], [2, 1], [3, 1], [3, 2]] """ p = self[0].conjugate() path = [[]] for i in range(len(p)): - path += p[:i+1] - - return DualSemistandardTableau(path).path_rule(self)[0] + path += [Partition(p[:i+1]).conjugate()] + + return DualSemistandardTableau(path).path_rule(self,display=display)[0] def multiply(self,other): """ This is the same function as tableau.slide_multiply and tableau.bump_multiply. """ - + left = list(self) right = list(other) - + m = max([len(a) for a in right]) n = max([ a[0] for a in left]) - + right = [a+[0]*(m-len(a)) for a in right] - + p = max(len(left),len(right)) left = left + left[-1]*(p-len(left)) right = right + right[-1]*(p-len(right)) - + result = [Partition([a+n for a in y]+x) for x,y in zip(left,right)] - + return DualSemistandardTableau(result).rectify() - + def check_bender_knuth(self,i): """ Check that the i-th Bender-Knuth move on the conjugate tableau is the i-th local rule. - sage: ST = SemistandardTableaux([5,3,3,2,1],[2,1,4,2,2,2,1]) + sage: ST = SemistandardTableaux([5,3,3,2,1],[2,1,4,2,2,2,1]) sage: s = DualSemistandardTableau(ST.an_element()) sage: s.check_bender_knuth(5) True sage: s.check_bender_knuth(4) True - - """" + """ lhs = self.local_rule(i).to_tableau() rhs = self.to_tableau().bender_knuth_involution(i) @@ -191,10 +198,10 @@ def check_rectify(self): def check_evacuation(self): """ - Check that jdt-evacuation on the conjugate tableaux + Check that jdt-evacuation on the conjugate tableaux is the evacuation defined here. - - sage: ST = SemistandardTableaux([5,3,3,2,1],[2,1,4,2,2,2,1]) + + sage: ST = SemistandardTableaux([5,3,3,2,1],[2,1,4,2,2,2,1]) sage: s = DualSemistandardTableau(ST.an_element()) sage: s.check_evacuation() True From 0ae66fe9d4bdf4c90b3ccc1211baa692f66a3311 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Tue, 12 Jun 2018 11:53:14 +0100 Subject: [PATCH 016/300] Corrected formatting of doctests --- src/sage/categories/pathtableaux.py | 12 +- src/sage/combinat/catalan.py | 208 +++++++++++++++------------- src/sage/combinat/semistandard.py | 172 ++++++++++++----------- 3 files changed, 206 insertions(+), 186 deletions(-) diff --git a/src/sage/categories/pathtableaux.py b/src/sage/categories/pathtableaux.py index fbd4cee1e8b..589019c3416 100644 --- a/src/sage/categories/pathtableaux.py +++ b/src/sage/categories/pathtableaux.py @@ -14,6 +14,7 @@ AUTHORS: - Bruce Westbury (2018): initial version +""" #***************************************************************************** # Copyright (C) 2018 Bruce Westbury , @@ -26,9 +27,6 @@ #***************************************************************************** -""" - - from sage.misc.abstract_method import abstract_method from sage.categories.category import Category from sage.categories.sets_cat import Sets @@ -142,7 +140,7 @@ def path_rule(self,other,display=False): """ This constructs the commutor of a pair of tableau. This is given by a rectangular diagram. - + If display=True then the function will print the rectangle. """ @@ -152,12 +150,12 @@ def path_rule(self,other,display=False): raise ValueError("This requires nonempty lists.") if n == 1 or m == 1: return (other,self) - + row = list(other) col = list(self) if col[-1] != row[0]: raise ValueError("%s,%s is not a composable pair." % (self,other)) - + path = self.parent()(col + row[1:]) for i in range(1,n): @@ -167,7 +165,7 @@ def path_rule(self,other,display=False): path = path.local_rule(n+j-i) if display: print path[:m] - + return (self.parent()(path[:m]),self.parent()(path[m-1:])) diff --git a/src/sage/combinat/catalan.py b/src/sage/combinat/catalan.py index 13802960167..f1e8942b00c 100644 --- a/src/sage/combinat/catalan.py +++ b/src/sage/combinat/catalan.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python2 -# -*- coding: utf-8 -*- + """ This is an implementation of the Category PathTableaux. This is the simplest implementation of PathTableaux and is included to @@ -46,6 +45,84 @@ ############################################################################### +""" + +Here we illustrate the slogan that promotion = rotation. + +EXAMPLE:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t.to_perfect_matching() + [(0, 5), (1, 4), (2, 3)] + + sage: t = t.promotion() + sage: t.to_perfect_matching() + [(0, 3), (1, 2), (4, 5)] + + sage: t = t.promotion() + sage: t.to_perfect_matching() + [(0, 1), (2, 5), (3, 4)] + + sage: t = t.promotion() + sage: t.to_perfect_matching() + [(0, 5), (1, 4), (2, 3)] + +EXAMPLE:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: SkewTableau(t.cylindrical_diagram()).pp() + 0 1 2 3 2 1 0 + . 0 1 2 1 0 1 0 + . . 0 1 0 1 2 1 0 + . . . 0 1 2 3 2 1 0 + . . . . 0 1 2 1 0 1 0 + . . . . . 0 1 0 1 2 1 0 + . . . . . . 0 1 2 3 2 1 0 + + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t.evacuation() + [0, 1, 2, 3, 2, 1, 0] + + sage: t.cactus(1,5) + [0, 1, 0, 1, 2, 1, 0] + + sage: t.cactus(1,6) + [0, 1, 2, 1, 0, 1, 0] + + sage: t.cactus(1,7) == t.evacuation() + True + + sage: t.cactus(1,7).cactus(1,6) == t.promotion() + True + + sage: t.check_involution_rule() + True + + sage: t.check_involution_cactus() + True + + sage: t.check_promotion() + True + + sage: t.check_involution_cactus() + True + + sage: t.check_commutation() + True + + sage: t.check_coboundary() + True + + sage: t.orbit() + {[0, 1, 0, 1, 0, 1, 0], + [0, 1, 0, 1, 2, 1, 0], + [0, 1, 2, 1, 0, 1, 0], + [0, 1, 2, 1, 2, 1, 0], + [0, 1, 2, 3, 2, 1, 0]} + +""" + @add_metaclass(InheritComparisonClasscallMetaclass) class CatalanTableau(ClonableList): """ @@ -57,7 +134,7 @@ class CatalanTableau(ClonableList): - a Dyck word - a noncrossing perfect matching - EXAMPLES: + EXAMPLES:: sage: CatalanTableau([0,1,2,1,0]) [0, 1, 2, 1, 0] @@ -71,10 +148,9 @@ class CatalanTableau(ClonableList): ... [1, 0, 1, 0] - sage: t = SkewTableau([[1,2],[3,4]]) + sage: t = Tableau([[1,2],[3,4]]) sage: CatalanTableau(t) - [1, 1, 0, 0] - + [0, 1, 2, 1, 0] """ @staticmethod @@ -86,7 +162,7 @@ def __classcall_private__(self, ot): w = ot.heights() if isinstance(ot,PerfectMatching): - if ot.is_non_crossing(): + if ot.is_noncrossing(): w = [1]*ot.size() for a in ot.arcs(): w[a[1]-1] = 0 @@ -112,7 +188,7 @@ def __classcall_private__(self, ot): raise ValueError("%s is not a sequence of integers." % str(ot) ) if w == None: - raise ValueError( "Sorry, not sorry; I don't know what to do with %s." % str(ot) ) + raise ValueError( "Sorry; I don't know what to do with %s." % str(ot) ) return CatalanTableaux()(w) @@ -123,17 +199,18 @@ def check(self): This checks that heights are nonnegative and that succesive heights differ by +1 or -1. - EXAMPLES: - sage: CatalanTableau([0,1,2,3,2,3]) - [0, 1, 2, 3, 2, 3] + EXAMPLES:: - sage: CatalanTableau([0,1,0,-1,0]) - ... - ValueError: [0, 1, 0, -1, 0] has a negative entry. + sage: CatalanTableau([0,1,2,3,2,3]) + [0, 1, 2, 3, 2, 3] - sage: CatalanTableau([0,1,3,3,2,3]) - ... - ValueError: [0, 1, 3, 3, 2, 3] is not a Dyck path. + sage: CatalanTableau([0,1,0,-1,0]) + ... + ValueError: [0, 1, 0, -1, 0] has a negative entry. + + sage: CatalanTableau([0,1,3,3,2,3]) + ... + ValueError: [0, 1, 3, 3, 2, 3] is not a Dyck path. """ n = len(self) @@ -154,11 +231,13 @@ def is_skew(self): """ Returns True if Tableau is skew and False if not. - EXAMPLES: - sage: CatalanTableau([0,1,2,1]).is_skew() - False - sage: CatalanTableau([1,0,1,2,1]).is_skew() - True + EXAMPLES:: + + sage: CatalanTableau([0,1,2,1]).is_skew() + False + + sage: CatalanTableau([1,0,1,2,1]).is_skew() + True """ return self[0] != 0 @@ -167,10 +246,10 @@ def descents(self): """ Returns the descent set. - EXAMPLE: + EXAMPLE:: - sage: CatalanTableau([0,1,2,1,2,1,0,1,0]).descents() - {3, 6} + sage: CatalanTableau([0,1,2,1,2,1,0,1,0]).descents() + {3, 6} """ result = set() @@ -185,10 +264,10 @@ def to_word(self): """ Converts to a word in the alphabet 0,1 - EXAMPLE: + EXAMPLE:: - sage: CatalanTableau([1,0,1,2,1]).to_word() - [0, 1, 1, 0] + sage: CatalanTableau([1,0,1,2,1]).to_word() + [0, 1, 1, 0] """ return [ (self[i+1]-self[i]+1)/2 for i in range(self.size()-1) ] @@ -197,10 +276,10 @@ def to_perfect_matching(self): """ This converts to a perfect matching. - EXAMPLE: + EXAMPLE:: - sage: CatalanTableau([0,1,2,1,2,1,0,1,0]).to_perfect_matching() - [(0, 5), (1, 2), (3, 4), (6, 7)] + sage: CatalanTableau([0,1,2,1,2,1,0,1,0]).to_perfect_matching() + [(0, 5), (1, 2), (3, 4), (6, 7)] """ w = self.to_word() @@ -226,73 +305,6 @@ def draw(self): """ return line([ (i,a) for i, a in enumerate(self)]) -""" - -Here we illustrate the slogan that promotion = rotation. - -sage: t = CatalanTableau([0,1,2,3,2,1,0]) -sage: t.to_perfect_matching() -[(0, 5), (1, 4), (2, 3)] -sage: t = t.promotion() -sage: t.to_perfect_matching() -[(0, 3), (1, 2), (4, 5)] -sage: t = t.promotion() -sage: t.to_perfect_matching() -[(0, 1), (2, 5), (3, 4)] -sage: t = t.promotion() -sage: t.to_perfect_matching() -[(0, 5), (1, 4), (2, 3)] - -Here we test the Category methods. - -sage: t = CatalanTableau([0,1,2,3,2,1,0]) -sage: SkewTableau(t.cylindrical_diagram()).pp() - 0 1 2 3 2 1 0 - . 0 1 2 1 0 1 0 - . . 0 1 0 1 2 1 0 - . . . 0 1 2 3 2 1 0 - . . . . 0 1 2 1 0 1 0 - . . . . . 0 1 0 1 2 1 0 - . . . . . . 0 1 2 3 2 1 0 - - - -""" - -""" -sage: t = CatalanTableau([0,1,2,3,2,1,0]) -sage: t.evacuation() -[0, 1, 2, 3, 2, 1, 0] -sage: t.cactus(1,5) -[0, 1, 0, 1, 2, 1, 0] -sage: t.cactus(1,6) -[0, 1, 2, 1, 0, 1, 0] -sage: t.cactus(1,7) == t.evacuation() -True -sage: t.cactus(1,7).cactus(1,6) == t.promotion() -True -sage: t.check_involution_rule() -True -sage: t.check_involution_cactus() -True -sage: t.check_promotion() -True -sage: t.check_involution_cactus() -True -sage: t.check_commutation() -True -sage: t.check_coboundary() -True -sage: t.orbit() -{[0, 1, 0, 1, 0, 1, 0], - [0, 1, 0, 1, 2, 1, 0], - [0, 1, 2, 1, 0, 1, 0], - [0, 1, 2, 1, 2, 1, 0], - [0, 1, 2, 3, 2, 1, 0]} - - - -""" ############################################################################### class CatalanTableaux(UniqueRepresentation,Parent): diff --git a/src/sage/combinat/semistandard.py b/src/sage/combinat/semistandard.py index df69f494cbe..ea88cbff301 100644 --- a/src/sage/combinat/semistandard.py +++ b/src/sage/combinat/semistandard.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python2 -# -*- coding: utf-8 -*- """ This is an impementation of the Category PathTableaux. @@ -44,6 +42,61 @@ from sage.combinat.partition import Partition from sage.modules.free_module_element import vector +""" +EXAMPLES:: + + sage: T = DualSemistandardTableau([[],[1],[2],[2,1]]) + sage: T.evacuation() + [[], [1], [1, 1], [2, 1]] + + sage: Tableau([[1,2],[3]]).evacuation() + [[1, 3], [2]] + + sage: ST = SemistandardTableaux([5,3,3,2,1],[2,1,4,2,2,2,1]) + sage: ST.cardinality() + 84 + + sage: t = ST.an_element() + sage: s = DualSemistandardTableau(t.conjugate().to_chain()) + sage: v = Tableau(list(SkewTableau(chain=s.evacuation()))) + sage: v.conjugate() == t.evacuation() + True + + sage: ST = SemistandardTableaux([5,3,3,2,1],[2,1,4,2,2,2,1]) + sage: s = DualSemistandardTableau(ST.an_element()) + sage: s.check_involution_cactus() + True + + sage: s.check_commutation() + True + + sage: s.check_coboundary() + True + + sage: ST = StandardTableaux([3,3,3]) + sage: ST.cardinality() + 42 + + sage: t = ST.an_element() + sage: t.promotion() + [[1, 2, 5], [3, 6, 8], [4, 7, 9]] + + sage: ST = StandardTableaux([3,3,3]) + sage: t = ST.an_element() + sage: s = DualSemistandardTableau(t.to_chain()) + sage: u = StandardTableau(list(SkewTableau(chain=s.promotion()))) + sage: u.promotion() == t + True + + sage: ST.cardinality() + 42 + sage: t = ST.an_element() + sage: s = DualSemistandardTableau(t.to_chain()) + sage: len(s.orbit()) + 42 + +""" + @add_metaclass(InheritComparisonClasscallMetaclass) class DualSemistandardTableau(ClonableList): """ @@ -54,14 +107,14 @@ class DualSemistandardTableau(ClonableList): - a sequence such that each term defines a partition - a semistandard skew tableau - EXAMPLES: + EXAMPLES:: - sage: DualSemistandardTableau([[],[1],[2],[2,1]]) - [[], [1], [2], [2, 1]] + sage: DualSemistandardTableau([[],[1],[2],[2,1]]) + [[], [1], [2], [2, 1]] - sage: t = SkewTableau([[None,None,None,4,4,5,6,7],[None,2,4,6,7,7,7],[None,4,5,8,8,9],[None,6,7,10],[None,8,8,11],[None],[4]]) - sage: DualSemistandardTableau(t) - [[6, 1, 1], [6, 1, 1], [6, 2, 1], [6, 2, 1], [7, 3, 2, 1, 1], [7, 3, 3, 1, 1, 1], [7, 4, 3, 2, 1, 1, 1], [7, 4, 4, 2, 2, 2, 2, 1], [7, 5, 5, 3, 3, 2, 2, 1], [7, 5, 5, 3, 3, 3, 2, 1], [7, 5, 5, 4, 3, 3, 2, 1], [7, 5, 5, 5, 3, 3, 2, 1]] + sage: t = SkewTableau([[None,None,None,4,4,5,6,7],[None,2,4,6,7,7,7],[None,4,5,8,8,9],[None,6,7,10],[None,8,8,11],[None],[4]]) + sage: DualSemistandardTableau(t) + [[6, 1, 1], [6, 1, 1], [6, 2, 1], [6, 2, 1], [7, 3, 2, 1, 1], [7, 3, 3, 1, 1, 1], [7, 4, 3, 2, 1, 1, 1], [7, 4, 4, 2, 2, 2, 2, 1], [7, 5, 5, 3, 3, 2, 2, 1], [7, 5, 5, 3, 3, 3, 2, 1], [7, 5, 5, 4, 3, 3, 2, 1], [7, 5, 5, 5, 3, 3, 2, 1]] """ @staticmethod @@ -127,24 +180,27 @@ def is_skew(self): """ Returns True if Tableau is skew and False if not. - EXAMPLE: - sage: t = DualSemistandardTableau([[],[1],[2],[2,1]]) - sage: t.is_skew() - False + EXAMPLE:: + sage: t = DualSemistandardTableau([[],[1],[2],[2,1]]) + sage: t.is_skew() + False """ return self[0] != Partition([]) def rectify(self,display=False): """ This is the same function as skew_tableau.rectify - - sage: t = SkewTableau([[None,None,2,4],[1,3,5]]) - sage: s = DualSemistandardTableau(t.to_chain()) - sage: s.rectify(display=True) - [[2], [2, 1], [3, 1], [3, 2], [4, 2], [4, 3]] - [[1], [1, 1], [2, 1], [2, 2], [3, 2], [3, 3]] - [[], [1], [2], [2, 1], [3, 1], [3, 2]] - [[], [1], [2], [2, 1], [3, 1], [3, 2]] + + EXAMPLE:: + + sage: t = SkewTableau([[None,None,2,4],[1,3,5]]) + sage: s = DualSemistandardTableau(t.to_chain()) + sage: s.rectify(display=True) + [[2], [2, 1], [3, 1], [3, 2], [4, 2], [4, 3]] + [[1], [1, 1], [2, 1], [2, 2], [3, 2], [3, 3]] + [[], [1], [2], [2, 1], [3, 1], [3, 2]] + [[], [1], [2], [2, 1], [3, 1], [3, 2]] + """ p = self[0].conjugate() path = [[]] @@ -179,12 +235,15 @@ def check_bender_knuth(self,i): Check that the i-th Bender-Knuth move on the conjugate tableau is the i-th local rule. - sage: ST = SemistandardTableaux([5,3,3,2,1],[2,1,4,2,2,2,1]) - sage: s = DualSemistandardTableau(ST.an_element()) - sage: s.check_bender_knuth(5) - True - sage: s.check_bender_knuth(4) - True + EXAMPLE:: + + sage: ST = SemistandardTableaux([5,3,3,2,1],[2,1,4,2,2,2,1]) + sage: s = DualSemistandardTableau(ST.an_element()) + sage: s.check_bender_knuth(5) + True + sage: s.check_bender_knuth(4) + True + """ lhs = self.local_rule(i).to_tableau() @@ -201,67 +260,18 @@ def check_evacuation(self): Check that jdt-evacuation on the conjugate tableaux is the evacuation defined here. - sage: ST = SemistandardTableaux([5,3,3,2,1],[2,1,4,2,2,2,1]) - sage: s = DualSemistandardTableau(ST.an_element()) - sage: s.check_evacuation() - True + EXAMPLE:: + + sage: ST = SemistandardTableaux([5,3,3,2,1],[2,1,4,2,2,2,1]) + sage: s = DualSemistandardTableau(ST.an_element()) + sage: s.check_evacuation() + True """ lhs = self.evacuation().to_tableau() rhs = self.to_tableau().evacuation() return lhs == rhs -""" - -sage: T = DualSemistandardTableau([[],[1],[2],[2,1]]) -sage: T.evacuation() -[[], [1], [1, 1], [2, 1]] - -sage: Tableau([[1,2],[3]]).evacuation() -[[1, 3], [2]] - -sage: ST = SemistandardTableaux([5,3,3,2,1],[2,1,4,2,2,2,1]) -sage: ST.cardinality() -84 -sage: t = ST.an_element() -sage: s = DualSemistandardTableau(t.conjugate().to_chain()) -sage: v = Tableau(list(SkewTableau(chain=s.evacuation()))) -sage: v.conjugate() == t.evacuation() -True - -sage: ST = SemistandardTableaux([5,3,3,2,1],[2,1,4,2,2,2,1]) -sage: s = DualSemistandardTableau(ST.an_element()) -sage: s.check_involution_cactus() -True -sage: s.check_commutation() -True -sage: s.check_coboundary() -True - -sage: ST = StandardTableaux([3,3,3]) -sage: ST.cardinality() -42 -sage: t = ST.an_element() -sage: t.promotion() -[[1, 2, 5], [3, 6, 8], [4, 7, 9]] - - -sage: ST = StandardTableaux([3,3,3]) -sage: t = ST.an_element() -sage: s = DualSemistandardTableau(t.to_chain()) -sage: u = StandardTableau(list(SkewTableau(chain=s.promotion()))) -sage: u.promotion() == t -True - -sage: ST.cardinality() -42 -sage: t = ST.an_element() -sage: s = DualSemistandardTableau(t.to_chain()) -sage: len(s.orbit()) -42 - - -""" ############################################################################### class DualSemistandardTableaux(UniqueRepresentation,Parent): From cdef4c8244107e9fee3c3067664f0ff86df8bb9e Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Tue, 12 Jun 2018 13:46:12 +0100 Subject: [PATCH 017/300] Corrections to doctests with ellipsis --- src/sage/combinat/catalan.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/catalan.py b/src/sage/combinat/catalan.py index f1e8942b00c..84b164930d1 100644 --- a/src/sage/combinat/catalan.py +++ b/src/sage/combinat/catalan.py @@ -205,16 +205,18 @@ def check(self): [0, 1, 2, 3, 2, 3] sage: CatalanTableau([0,1,0,-1,0]) + Traceback (most recent call last): ... ValueError: [0, 1, 0, -1, 0] has a negative entry. sage: CatalanTableau([0,1,3,3,2,3]) + Traceback (most recent call last): ... ValueError: [0, 1, 3, 3, 2, 3] is not a Dyck path. """ n = len(self) - if any([ a < 0 for a in self]): + if any(a < 0 for a in self): raise ValueError( "%s has a negative entry." % (str(self)) ) for i in range(n-1): if abs(self[i+1]-self[i]) > 1: From d5622463ac055afec1f2968209bc8b4373d5c8ff Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Tue, 12 Jun 2018 13:53:11 +0100 Subject: [PATCH 018/300] Files moved to new directory --- src/sage/combinat/{ => tableau}/catalan.py | 0 src/sage/{categories => combinat/tableau}/pathtableaux.py | 0 src/sage/combinat/{ => tableau}/semistandard.py | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename src/sage/combinat/{ => tableau}/catalan.py (100%) rename src/sage/{categories => combinat/tableau}/pathtableaux.py (100%) rename src/sage/combinat/{ => tableau}/semistandard.py (100%) diff --git a/src/sage/combinat/catalan.py b/src/sage/combinat/tableau/catalan.py similarity index 100% rename from src/sage/combinat/catalan.py rename to src/sage/combinat/tableau/catalan.py diff --git a/src/sage/categories/pathtableaux.py b/src/sage/combinat/tableau/pathtableaux.py similarity index 100% rename from src/sage/categories/pathtableaux.py rename to src/sage/combinat/tableau/pathtableaux.py diff --git a/src/sage/combinat/semistandard.py b/src/sage/combinat/tableau/semistandard.py similarity index 100% rename from src/sage/combinat/semistandard.py rename to src/sage/combinat/tableau/semistandard.py From 8d0191a3651a4a6e716e9421384ca1331835ed62 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Tue, 12 Jun 2018 14:16:32 +0100 Subject: [PATCH 019/300] Edited and added files all.py --- src/sage/combinat/all.py | 3 -- src/sage/combinat/tableau/all.py | 6 +++ src/sage/combinat/tableau/catalan.py | 6 +-- src/sage/combinat/tableau/pathtableaux.py | 48 +++-------------------- src/sage/combinat/tableau/semistandard.py | 8 ++-- 5 files changed, 17 insertions(+), 54 deletions(-) create mode 100644 src/sage/combinat/tableau/all.py diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 2473b3307a4..a91f3ad5111 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -219,7 +219,4 @@ 'GrowthDiagramBinWord', 'GrowthDiagramDomino', 'GrowthDiagramYoungFibonacci', 'GrowthDiagramSylvester']) -lazy_import('sage.combinat.catalan', ['CatalanTableaux','CatalanTableau']) - -lazy_import('sage.combinat.semistandard', ['DualSemistandardTableaux','DualSemistandardTableau']) diff --git a/src/sage/combinat/tableau/all.py b/src/sage/combinat/tableau/all.py new file mode 100644 index 00000000000..05d7d86f4f9 --- /dev/null +++ b/src/sage/combinat/tableau/all.py @@ -0,0 +1,6 @@ +from __future__ import absolute_import +from sage.misc.lazy_import import lazy_import + +lazy_import('sage.combinat.tableau.pathtableaux', 'PathTableau') +lazy_import('sage.combinat.tableau.catalan', 'CatalanTableau') +lazy_import('sage.combinat.tableau.semistandard', 'DualSemistandardTableau') diff --git a/src/sage/combinat/tableau/catalan.py b/src/sage/combinat/tableau/catalan.py index 84b164930d1..4268a9b5a20 100644 --- a/src/sage/combinat/tableau/catalan.py +++ b/src/sage/combinat/tableau/catalan.py @@ -27,10 +27,8 @@ from six import add_metaclass from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass -from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.list_clone import ClonableList -from sage.structure.parent import Parent +from sage.combinat.tableau.pathtableaux import PathTableau from sage.combinat.dyck_word import DyckWord from sage.combinat.perfect_matching import PerfectMatching from sage.combinat.skew_tableau import SkewTableau @@ -124,7 +122,7 @@ """ @add_metaclass(InheritComparisonClasscallMetaclass) -class CatalanTableau(ClonableList): +class CatalanTableau(PathTableau): """ An instance is the sequence of nonnegative integers given by the heights of a Dyck word. The acceptable inputs diff --git a/src/sage/combinat/tableau/pathtableaux.py b/src/sage/combinat/tableau/pathtableaux.py index 589019c3416..d90de100faf 100644 --- a/src/sage/combinat/tableau/pathtableaux.py +++ b/src/sage/combinat/tableau/pathtableaux.py @@ -1,5 +1,5 @@ """ -This is a category for using local rules to construct rectification +This is an abstract base class for using local rules to construct rectification and the action of the cactus group. This is an effective version of the Henriques-Kamnitzer construction of the action of the cactus group on tensor powers of a crystal. This is a generalisation of @@ -28,24 +28,9 @@ from sage.misc.abstract_method import abstract_method -from sage.categories.category import Category -from sage.categories.sets_cat import Sets +from sage.structure.list_clone import ClonableList -class PathTableaux(Category): - """ - This defines the category of PathTableaux. - """ - def super_categories(self): - return [Sets()] - - class ElementMethods: - """ - These methods are not called directly. Instead, when a Element class - for this Category is created these methods are automatically added - to the class methods. - """ - -############################ Abstract Methods ################################# +class PathTableau(ClonableList): @abstract_method(optional=False) def check(self): @@ -60,13 +45,8 @@ def check(self): @abstract_method(optional=False) def _rule(self,p): """ - This is an abstract method. It must be overwritten in any - Element class for this Category. This rule provides the - functionality for this Category. It is called in local_rule. - - An instance of an Element class of this Category is a list - of objects of some type. This function takes a list of length - three of objects of this type and returns an object of this type. + This is an abstract method. It must be overwritten. + This rule provides the functionality. It is called in local_rule. The key property is that the following operation on lists of length three is an involution: apply the rule to a list @@ -74,6 +54,7 @@ def _rule(self,p): """ ################################# Book Keeping ################################ + def size(self): """ Returns the size or length. @@ -269,23 +250,6 @@ def check_coboundary(self): return False return True - def check_consistent(self): - """ - This checks that two different constructions of the - operators $s_{1,\,i}$ give the same result. The first - construction is the direct construction which uses - evacuation. The second method reads this off the - cylindrical diagram; which is constructed using promotion. - """ - d = self.cylindrical_diagram() - for i in range(1,n): - t = [ d[i][i-j] for j in range(i-1) ] - x = self.parent()(t+d[0][i:]) - if x != self.cactus(1,i): - return False - return True - - def orbit(self): """ Constructs the orbit under the action of the cactus group. diff --git a/src/sage/combinat/tableau/semistandard.py b/src/sage/combinat/tableau/semistandard.py index ea88cbff301..a3d29e170be 100644 --- a/src/sage/combinat/tableau/semistandard.py +++ b/src/sage/combinat/tableau/semistandard.py @@ -32,11 +32,9 @@ from six import add_metaclass from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass -from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.list_clone import ClonableList -from sage.structure.parent import Parent -from sage.categories.pathtableaux import PathTableaux + +from sage.combinat.tableau.pathtableaux import PathTableau from sage.combinat.skew_tableau import SkewTableau from sage.combinat.tableau import SemistandardTableau from sage.combinat.partition import Partition @@ -98,7 +96,7 @@ """ @add_metaclass(InheritComparisonClasscallMetaclass) -class DualSemistandardTableau(ClonableList): +class DualSemistandardTableau(PathTableau): """ An instance is the sequence of partitions correspond to the chain of partitions of a dual semistandard skew tableau. From 18aaf9331201f17df44fd6342754cba74e769269 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Tue, 12 Jun 2018 14:22:59 +0100 Subject: [PATCH 020/300] File __init__.py added --- src/sage/combinat/tableau/__init__.py | 1 + src/sage/combinat/tableau/catalan.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 src/sage/combinat/tableau/__init__.py diff --git a/src/sage/combinat/tableau/__init__.py b/src/sage/combinat/tableau/__init__.py new file mode 100644 index 00000000000..0c12d5e2879 --- /dev/null +++ b/src/sage/combinat/tableau/__init__.py @@ -0,0 +1 @@ +from . import pathtableaux \ No newline at end of file diff --git a/src/sage/combinat/tableau/catalan.py b/src/sage/combinat/tableau/catalan.py index 4268a9b5a20..cf33520c7ce 100644 --- a/src/sage/combinat/tableau/catalan.py +++ b/src/sage/combinat/tableau/catalan.py @@ -35,7 +35,7 @@ from sage.combinat.tableau import Tableau from sage.rings.integer import Integer -from sage.categories.pathtableaux import PathTableaux +#from sage.categories.pathtableaux import PathTableaux #from sage.categories.sets_cat import Sets #from sage.combinat.catalan import CatalanTableau #from sage.combinat.catalan import CatalanTableaux From 5aa14e11073115603e701cd132ff9a744d123836 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Tue, 12 Jun 2018 14:38:27 +0100 Subject: [PATCH 021/300] Moved directory from tableau to pathtableau --- .../{tableau => pathtableau}/__init__.py | 0 .../combinat/{tableau => pathtableau}/all.py | 2 ++ .../{tableau => pathtableau}/catalan.py | 29 +------------------ .../{tableau => pathtableau}/pathtableaux.py | 0 .../{tableau => pathtableau}/semistandard.py | 25 ---------------- 5 files changed, 3 insertions(+), 53 deletions(-) rename src/sage/combinat/{tableau => pathtableau}/__init__.py (100%) rename src/sage/combinat/{tableau => pathtableau}/all.py (82%) rename src/sage/combinat/{tableau => pathtableau}/catalan.py (91%) rename src/sage/combinat/{tableau => pathtableau}/pathtableaux.py (100%) rename src/sage/combinat/{tableau => pathtableau}/semistandard.py (92%) diff --git a/src/sage/combinat/tableau/__init__.py b/src/sage/combinat/pathtableau/__init__.py similarity index 100% rename from src/sage/combinat/tableau/__init__.py rename to src/sage/combinat/pathtableau/__init__.py diff --git a/src/sage/combinat/tableau/all.py b/src/sage/combinat/pathtableau/all.py similarity index 82% rename from src/sage/combinat/tableau/all.py rename to src/sage/combinat/pathtableau/all.py index 05d7d86f4f9..b28fe038a79 100644 --- a/src/sage/combinat/tableau/all.py +++ b/src/sage/combinat/pathtableau/all.py @@ -1,6 +1,8 @@ from __future__ import absolute_import from sage.misc.lazy_import import lazy_import +lazy_import('sage.combinat.tableau',['Tableau','Tableaux']) + lazy_import('sage.combinat.tableau.pathtableaux', 'PathTableau') lazy_import('sage.combinat.tableau.catalan', 'CatalanTableau') lazy_import('sage.combinat.tableau.semistandard', 'DualSemistandardTableau') diff --git a/src/sage/combinat/tableau/catalan.py b/src/sage/combinat/pathtableau/catalan.py similarity index 91% rename from src/sage/combinat/tableau/catalan.py rename to src/sage/combinat/pathtableau/catalan.py index cf33520c7ce..3606b747cc0 100644 --- a/src/sage/combinat/tableau/catalan.py +++ b/src/sage/combinat/pathtableau/catalan.py @@ -32,7 +32,7 @@ from sage.combinat.dyck_word import DyckWord from sage.combinat.perfect_matching import PerfectMatching from sage.combinat.skew_tableau import SkewTableau -from sage.combinat.tableau import Tableau +from sage.combinat.tableau import Tableau, Tableaux from sage.rings.integer import Integer #from sage.categories.pathtableaux import PathTableaux @@ -305,30 +305,3 @@ def draw(self): """ return line([ (i,a) for i, a in enumerate(self)]) -############################################################################### - -class CatalanTableaux(UniqueRepresentation,Parent): - """ - This constructs the Parent class. - """ - @staticmethod - def __classcall_private__(cls): - return super(CatalanTableaux, cls).__classcall__(cls) - - def __init__(self): - - Parent.__init__(self, category=PathTableaux()) - - def __contains__(self, ot): - - return isinstance(ot, (list, tuple, CatalanTableau)) - - def _element_constructor_(self, ot, check=True): - - if isinstance(ot, CatalanTableaux) and ot.parent() == self: - return ot - - return self.element_class(self, list(ot)) - - Element = CatalanTableau - diff --git a/src/sage/combinat/tableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py similarity index 100% rename from src/sage/combinat/tableau/pathtableaux.py rename to src/sage/combinat/pathtableau/pathtableaux.py diff --git a/src/sage/combinat/tableau/semistandard.py b/src/sage/combinat/pathtableau/semistandard.py similarity index 92% rename from src/sage/combinat/tableau/semistandard.py rename to src/sage/combinat/pathtableau/semistandard.py index a3d29e170be..56610d2e50a 100644 --- a/src/sage/combinat/tableau/semistandard.py +++ b/src/sage/combinat/pathtableau/semistandard.py @@ -270,28 +270,3 @@ def check_evacuation(self): rhs = self.to_tableau().evacuation() return lhs == rhs -############################################################################### - -class DualSemistandardTableaux(UniqueRepresentation,Parent): - - @staticmethod - def __classcall_private__(cls): - return super(DualSemistandardTableaux, cls).__classcall__(cls) - - def __init__(self): - - Parent.__init__(self, category=PathTableaux()) - - def __contains__(self, ot): - - return isinstance(ot, (list, tuple, DualSemistandardTableau)) - - def _element_constructor_(self, ot, check=True): - - if isinstance(ot, DualSemistandardTableaux) and ot.parent() == self: - return ot - - return self.element_class(self, list(ot)) - - Element = DualSemistandardTableau - From f20a5d192e219d7a3420431da6002a95fd303a27 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Tue, 12 Jun 2018 16:13:06 +0100 Subject: [PATCH 022/300] Parent classes added --- src/sage/combinat/all.py | 5 ++++- src/sage/combinat/pathtableau/__init__.py | 6 +++++- src/sage/combinat/pathtableau/all.py | 8 ++++---- src/sage/combinat/pathtableau/catalan.py | 20 +++++++++++-------- src/sage/combinat/pathtableau/pathtableaux.py | 10 ++++++++++ src/sage/combinat/pathtableau/semistandard.py | 5 ++++- 6 files changed, 39 insertions(+), 15 deletions(-) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index a91f3ad5111..816a9ec2cef 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -219,4 +219,7 @@ 'GrowthDiagramBinWord', 'GrowthDiagramDomino', 'GrowthDiagramYoungFibonacci', 'GrowthDiagramSylvester']) - +# Path tableaux +lazy_import('sage.combinat.pathtableau.pathtableaux',['PathTableau','PathTableaux']) +lazy_import('sage.combinat.pathtableau.catalan',['CatalanTableau','CatalanTableaux']) +lazy_import('sage.combinat.pathtableau.semistandard',['DualSemistandardTableau','DualSemistandardTableaux']) diff --git a/src/sage/combinat/pathtableau/__init__.py b/src/sage/combinat/pathtableau/__init__.py index 0c12d5e2879..f53f3e00bed 100644 --- a/src/sage/combinat/pathtableau/__init__.py +++ b/src/sage/combinat/pathtableau/__init__.py @@ -1 +1,5 @@ -from . import pathtableaux \ No newline at end of file +from __future__ import absolute_import + +from .pathtableaux import PathTableau +from .catalan import CatalanTableau +from .semistandard import DualSemistandardTableau \ No newline at end of file diff --git a/src/sage/combinat/pathtableau/all.py b/src/sage/combinat/pathtableau/all.py index b28fe038a79..9a0fa4d5d75 100644 --- a/src/sage/combinat/pathtableau/all.py +++ b/src/sage/combinat/pathtableau/all.py @@ -1,8 +1,8 @@ from __future__ import absolute_import from sage.misc.lazy_import import lazy_import -lazy_import('sage.combinat.tableau',['Tableau','Tableaux']) +#lazy_import('sage.combinat.tableau',['Tableau','Tableaux']) -lazy_import('sage.combinat.tableau.pathtableaux', 'PathTableau') -lazy_import('sage.combinat.tableau.catalan', 'CatalanTableau') -lazy_import('sage.combinat.tableau.semistandard', 'DualSemistandardTableau') +lazy_import('sage.combinat.pathtableau.pathtableaux', ['PathTableau','PathTableaux']) +lazy_import('sage.combinat.pathtableau.catalan', ['CatalanTableau','CatalanTableaux']) +lazy_import('sage.combinat.pathtableau.semistandard', ['DualSemistandardTableau','DualSemistandardTableaux']) diff --git a/src/sage/combinat/pathtableau/catalan.py b/src/sage/combinat/pathtableau/catalan.py index 3606b747cc0..ffe5ad63fe8 100644 --- a/src/sage/combinat/pathtableau/catalan.py +++ b/src/sage/combinat/pathtableau/catalan.py @@ -24,11 +24,12 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from six import add_metaclass +#from six import add_metaclass -from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass +#from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass -from sage.combinat.tableau.pathtableaux import PathTableau +from sage.combinat.pathtableau.pathtableaux import PathTableau +#from sage.combinat.pathtableau.catalan import CatalanTableau from sage.combinat.dyck_word import DyckWord from sage.combinat.perfect_matching import PerfectMatching from sage.combinat.skew_tableau import SkewTableau @@ -121,7 +122,7 @@ """ -@add_metaclass(InheritComparisonClasscallMetaclass) +#@add_metaclass(InheritComparisonClasscallMetaclass) class CatalanTableau(PathTableau): """ An instance is the sequence of nonnegative @@ -151,8 +152,8 @@ class CatalanTableau(PathTableau): [0, 1, 2, 1, 0] """ - @staticmethod - def __classcall_private__(self, ot): + + def __init__(self, ot): w = None @@ -188,8 +189,8 @@ def __classcall_private__(self, ot): if w == None: raise ValueError( "Sorry; I don't know what to do with %s." % str(ot) ) - return CatalanTableaux()(w) - + Parent.__init__(self,category=Sets()) + def check(self): """ This overwrites the abstract method. @@ -305,3 +306,6 @@ def draw(self): """ return line([ (i,a) for i, a in enumerate(self)]) +class CatalanTableaux(PathTableaux): + + Element = CatalanTableau \ No newline at end of file diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index d90de100faf..92d3e342e6f 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -414,3 +414,13 @@ def draw_partition(p): G.set_aspect_ratio(1) return G + +class PathTableaux(UniqueRepresentation,Parent): + + def __init__(self): + Parent.__init__(self, category = Sets()) + + def _element_constructor_(self, *args, **keywords): + return self.element_class(self, *args, **keywords) + + Element = PathTableau diff --git a/src/sage/combinat/pathtableau/semistandard.py b/src/sage/combinat/pathtableau/semistandard.py index 56610d2e50a..bf9df9cb69d 100644 --- a/src/sage/combinat/pathtableau/semistandard.py +++ b/src/sage/combinat/pathtableau/semistandard.py @@ -34,7 +34,7 @@ from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass -from sage.combinat.tableau.pathtableaux import PathTableau +from sage.combinat.pathtableau.pathtableaux import PathTableau from sage.combinat.skew_tableau import SkewTableau from sage.combinat.tableau import SemistandardTableau from sage.combinat.partition import Partition @@ -270,3 +270,6 @@ def check_evacuation(self): rhs = self.to_tableau().evacuation() return lhs == rhs +class DualSemistandardTableaux(PathTableaux): + + Element = DualSemistandardTableau \ No newline at end of file From 4adad87c4e9a9bd635848798050a366baff2df2d Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Wed, 13 Jun 2018 15:52:20 +0100 Subject: [PATCH 023/300] All tests passed! --- src/sage/combinat/pathtableau/__init__.py | 5 - src/sage/combinat/pathtableau/catalan.py | 47 +- src/sage/combinat/pathtableau/pathtableaux.py | 677 +++++++++--------- src/sage/combinat/pathtableau/semistandard.py | 8 +- 4 files changed, 378 insertions(+), 359 deletions(-) delete mode 100644 src/sage/combinat/pathtableau/__init__.py diff --git a/src/sage/combinat/pathtableau/__init__.py b/src/sage/combinat/pathtableau/__init__.py deleted file mode 100644 index f53f3e00bed..00000000000 --- a/src/sage/combinat/pathtableau/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import absolute_import - -from .pathtableaux import PathTableau -from .catalan import CatalanTableau -from .semistandard import DualSemistandardTableau \ No newline at end of file diff --git a/src/sage/combinat/pathtableau/catalan.py b/src/sage/combinat/pathtableau/catalan.py index ffe5ad63fe8..e3924dd7197 100644 --- a/src/sage/combinat/pathtableau/catalan.py +++ b/src/sage/combinat/pathtableau/catalan.py @@ -24,24 +24,21 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -#from six import add_metaclass -#from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass +from six import add_metaclass +from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass +from sage.misc.abstract_method import abstract_method +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.parent import Parent +from sage.categories.sets_cat import Sets -from sage.combinat.pathtableau.pathtableaux import PathTableau -#from sage.combinat.pathtableau.catalan import CatalanTableau +from sage.combinat.pathtableau.pathtableaux import PathTableau, PathTableaux from sage.combinat.dyck_word import DyckWord from sage.combinat.perfect_matching import PerfectMatching from sage.combinat.skew_tableau import SkewTableau from sage.combinat.tableau import Tableau, Tableaux from sage.rings.integer import Integer -#from sage.categories.pathtableaux import PathTableaux -#from sage.categories.sets_cat import Sets -#from sage.combinat.catalan import CatalanTableau -#from sage.combinat.catalan import CatalanTableaux - - ############################################################################### """ @@ -122,7 +119,7 @@ """ -#@add_metaclass(InheritComparisonClasscallMetaclass) +@add_metaclass(InheritComparisonClasscallMetaclass) class CatalanTableau(PathTableau): """ An instance is the sequence of nonnegative @@ -153,7 +150,8 @@ class CatalanTableau(PathTableau): """ - def __init__(self, ot): + @staticmethod + def __classcall_private__(cls, ot): w = None @@ -187,10 +185,10 @@ def __init__(self, ot): raise ValueError("%s is not a sequence of integers." % str(ot) ) if w == None: - raise ValueError( "Sorry; I don't know what to do with %s." % str(ot) ) + raise NotImplementedError( "Sorry; I don't know what to do with %s." % str(ot) ) - Parent.__init__(self,category=Sets()) - + return CatalanTableaux()(w) + def check(self): """ This overwrites the abstract method. @@ -218,7 +216,7 @@ def check(self): if any(a < 0 for a in self): raise ValueError( "%s has a negative entry." % (str(self)) ) for i in range(n-1): - if abs(self[i+1]-self[i]) > 1: + if abs(self[i+1]-self[i]) != 1: raise ValueError( "%s is not a Dyck path." % (str(self)) ) @staticmethod @@ -296,8 +294,9 @@ def to_tableau(self): """ Converts to a skew tableau. """ - top = [ i for i, a in enumerate(self) if a == 1 ] - bot = [ i for i, a in enumerate(self) if a == 0 ] + w = self.to_word() + top = [ i for i, a in enumerate(w) if a == 1 ] + bot = [ i for i, a in enumerate(w) if a == 0 ] return SkewTableau([[None]*self[0]+top,bot]) def draw(self): @@ -306,6 +305,16 @@ def draw(self): """ return line([ (i,a) for i, a in enumerate(self)]) +#class PathTableaux(UniqueRepresentation,Parent): +# +# def __init__(self): +# Parent.__init__(self, category = Sets()) +# +# def _element_constructor_(self, *args, **keywords): +# return self.element_class(self, *args, **keywords) +# +# Element = PathTableau + class CatalanTableaux(PathTableaux): - + Element = CatalanTableau \ No newline at end of file diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index 92d3e342e6f..1e06239fdb5 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -26,401 +26,414 @@ # http://www.gnu.org/licenses/ #***************************************************************************** - +from six import add_metaclass +from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.misc.abstract_method import abstract_method from sage.structure.list_clone import ClonableList +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.parent import Parent +from sage.categories.sets_cat import Sets +@add_metaclass(InheritComparisonClasscallMetaclass) class PathTableau(ClonableList): - @abstract_method(optional=False) - def check(self): - """ - This is an abstract method. It must be overwritten in any - Element class for this Category. Typically an instance of - an Element class is a sequence of partitions with conditions - on adjacent partitions in the sequence. This function checks - that these conditions are met. - """ - - @abstract_method(optional=False) - def _rule(self,p): - """ - This is an abstract method. It must be overwritten. - This rule provides the functionality. It is called in local_rule. - - The key property is that the following operation on lists - of length three is an involution: apply the rule to a list - and replace the middle term with the output. - """ + @staticmethod + def __classcall_private__(cls, t): + + if isinstance(t, cls): + return t + + raise NotImplementedError("This needs to be overwritten.") + + @abstract_method(optional=False) + def check(self): + """ + This is an abstract method. It must be overwritten + Typically an instance of + an Element class is a sequence of partitions with conditions + on adjacent partitions in the sequence. This function checks + that these conditions are met. + """ + + @abstract_method(optional=False) + def _rule(self,p): + """ + This is an abstract method. It must be overwritten. + This rule provides the functionality. It is called in local_rule. + + The key property is that the following operation on lists + of length three is an involution: apply the rule to a list + and replace the middle term with the output. + """ ################################# Book Keeping ################################ - - def size(self): - """ - Returns the size or length. - """ - return len(self) - - def initial_shape(self): - """ - Returns the initial shape. - """ - return self[0] - - def final_shape(self): - """ - Returns the final shape. - """ - return self[-1] + + def size(self): + """ + Returns the size or length. + """ + return len(self) + + def initial_shape(self): + """ + Returns the initial shape. + """ + return self[0] + + def final_shape(self): + """ + Returns the final shape. + """ + return self[-1] ############################# Jeu de taquin ################################### - def local_rule(self,i): - """ - This is the local that is used for the remaining constructions. - This has input a list of objects. This method first takes - the list of objects of length three consisting of the $(i-1)$-st, - $i$-th and $(i+1)$-term and applies the rule. It then replaces - the $i$-th object by the object returned by the rule. - """ - if not (i > 0 and i < len(self) ): - raise ValueError("%d is not a valid integer." % i) - - result = list(self) - result[i] = self._rule(self[i-1:i+2]) - - return self.parent()(result) - - def promotion(self): - """ - The promotion operator. This is given by a two row diagram. - """ - result = list(self) - for i in range(1,len(result)-1): - result[i] = self._rule(result[i-1:i+2]) - return self.parent()(result) - - def evacuation(self): - """ - The evacuation operator. This is given by a triangular diagram. - """ - if self.size() < 3: - return self - - T = self + def local_rule(self,i): + """ + This is the local that is used for the remaining constructions. + This has input a list of objects. This method first takes + the list of objects of length three consisting of the $(i-1)$-st, + $i$-th and $(i+1)$-term and applies the rule. It then replaces + the $i$-th object by the object returned by the rule. + """ + if not (i > 0 and i < len(self) ): + raise ValueError("%d is not a valid integer." % i) + + result = list(self) + result[i] = self._rule(self[i-1:i+2]) + + return self.parent()(result) + + def promotion(self): + """ + The promotion operator. This is given by a two row diagram. + """ + result = list(self) + for i in range(1,len(result)-1): + result[i] = self._rule(result[i-1:i+2]) + return self.parent()(result) + + def evacuation(self): + """ + The evacuation operator. This is given by a triangular diagram. + """ + if self.size() < 3: + return self + + T = self + L = list(T) + result = [] + for i in range(len(self)): + T = self.parent()(L).promotion() L = list(T) - result = [] - for i in range(len(self)): - T = self.parent()(L).promotion() - L = list(T) - result.append( L.pop() ) - result.reverse() - return self.parent()(result) - - def path_rule(self,other,display=False): - """ - This constructs the commutor of a pair of tableau. - This is given by a rectangular diagram. - - If display=True then the function will print - the rectangle. - """ - n = len(self) - m = len(other) - if n == 0 or m == 0: - raise ValueError("This requires nonempty lists.") - if n == 1 or m == 1: - return (other,self) - - row = list(other) - col = list(self) - if col[-1] != row[0]: - raise ValueError("%s,%s is not a composable pair." % (self,other)) - - path = self.parent()(col + row[1:]) - - for i in range(1,n): - if display: - print path[n-i:n+m-i] - for j in range(m-1): - path = path.local_rule(n+j-i) + result.append( L.pop() ) + result.reverse() + return self.parent()(result) + + def path_rule(self,other,display=False): + """ + This constructs the commutor of a pair of tableau. + This is given by a rectangular diagram. + + If display=True then the function will print + the rectangle. + """ + n = len(self) + m = len(other) + if n == 0 or m == 0: + raise ValueError("This requires nonempty lists.") + if n == 1 or m == 1: + return (other,self) + + row = list(other) + col = list(self) + if col[-1] != row[0]: + raise ValueError("%s,%s is not a composable pair." % (self,other)) + + path = self.parent()(col + row[1:]) + + for i in range(1,n): if display: - print path[:m] + print path[n-i:n+m-i] + for j in range(m-1): + path = path.local_rule(n+j-i) + if display: + print path[:m] - return (self.parent()(path[:m]),self.parent()(path[m-1:])) + return (self.parent()(path[:m]),self.parent()(path[m-1:])) - def cactus(self,i,j): - """ - This constructs the action of the generators of the cactus group. - These generators are involutions and are usually denoted by - $s_{i,\,j$}$. - """ - if not 0 < i < j <= self.size(): - raise ValueError("Integers out of bounds.") + def cactus(self,i,j): + """ + This constructs the action of the generators of the cactus group. + These generators are involutions and are usually denoted by + $s_{i,\,j$}$. + """ + if not 0 < i < j <= self.size(): + raise ValueError("Integers out of bounds.") - if i == j: - return self + if i == j: + return self - if i == 1: - h = list(self)[:j] - t = list(self)[j:] - T = self.parent()(h) - L = list(T.evacuation()) + t - return self.parent()(L) + if i == 1: + h = list(self)[:j] + t = list(self)[j:] + T = self.parent()(h) + L = list(T.evacuation()) + t + return self.parent()(L) - return self.cactus(1,j).cactus(1,j-i+1).cactus(1,j) + return self.cactus(1,j).cactus(1,j-i+1).cactus(1,j) ########################### Visualisation and checking ######################## - def cylindrical_diagram(self): - """ - This constructs the cylindrical growth diagram. This provides - a visual summary of several operations simultaneously. The - operations which can be read off directly from this diagram - are the powers of the promotion operator (which form the rows) - and the cactus group operators $s_{1,\,j$}$ (which form the - first half of the columns). - """ - n = len(self) - result = [[None]*(2*n-1)]*n - T = self - for i in range(n): - result[i] = [None]*i + list(T) - T = T.promotion() - - return result - - def check_involution_rule(self): - """ - This is to check that the local rule gives an involution. - This is crucial. - """ - for i in range(self.size()-2): - if self.local_rule(i+1).local_rule(i+1) != self: - return False + def cylindrical_diagram(self): + """ + This constructs the cylindrical growth diagram. This provides + a visual summary of several operations simultaneously. The + operations which can be read off directly from this diagram + are the powers of the promotion operator (which form the rows) + and the cactus group operators $s_{1,\,j$}$ (which form the + first half of the columns). + """ + n = len(self) + result = [[None]*(2*n-1)]*n + T = self + for i in range(n): + result[i] = [None]*i + list(T) + T = T.promotion() + + return result + + def check_involution_rule(self): + """ + This is to check that the local rule gives an involution. + This is crucial. + """ + for i in range(self.size()-2): + if self.local_rule(i+1).local_rule(i+1) != self: + return False + return True + + def check_involution_cactus(self): + """ + This is to check that the cactus group generators are + involutions.. + """ + return all([ self.cactus(1,i).cactus(1,i) == self for i in range(2,self.size()+1 ) ]) + + def check_promotion(self): + """ + Promotion can be expressed in terms of the cactus generators. + Here we check this relation. + """ + n = self.size()-1 + return self == self.cactus(1,n-1).cactus(1,n).promotion() + + def check_commutation(self): + """ + This is to check the commutation relations in the presentation + of the cactus group. + """ + from itertools import combinations + + n = self.size() + if n < 5: return True - - def check_involution_cactus(self): - """ - This is to check that the cactus group generators are - involutions.. - """ - return all([ self.cactus(1,i).cactus(1,i) == self for i in range(2,self.size()+1 ) ]) - - def check_promotion(self): - """ - Promotion can be expressed in terms of the cactus generators. - Here we check this relation. - """ - n = self.size()-1 - return self == self.cactus(1,n-1).cactus(1,n).promotion() - - def check_commutation(self): - """ - This is to check the commutation relations in the presentation - of the cactus group. - """ - from itertools import combinations - - n = self.size() - if n < 5: - return True - for i,j,r,s in combinations(range(1,n+1),4): - lhs = self.cactus(i,j).cactus(r,s) - rhs = self.cactus(r,s).cactus(i,j) - if lhs != rhs: - return False + for i,j,r,s in combinations(range(1,n+1),4): + lhs = self.cactus(i,j).cactus(r,s) + rhs = self.cactus(r,s).cactus(i,j) + if lhs != rhs: + return False + return True + + def check_coboundary(self): + """ + This is to check the coboundary relations in the presentation + of the cactus group. + """ + from itertools import combinations + + n = self.size() + if n < 4: return True - - def check_coboundary(self): - """ - This is to check the coboundary relations in the presentation - of the cactus group. - """ - from itertools import combinations - - n = self.size() - if n < 4: - return True - for i,j,r,s in combinations(range(1,n+3),4): - lhs = self.cactus(i,s-2).cactus(j-1,r-1) - rhs = self.cactus(i+s-r-1,i+s-j-1).cactus(i,s-2) - if lhs != rhs: - return False - return True - - def orbit(self): - """ - Constructs the orbit under the action of the cactus group. - """ - n = self.size() - orb = set([]) - rec = set([self]) + for i,j,r,s in combinations(range(1,n+3),4): + lhs = self.cactus(i,s-2).cactus(j-1,r-1) + rhs = self.cactus(i+s-r-1,i+s-j-1).cactus(i,s-2) + if lhs != rhs: + return False + return True + + def orbit(self): + """ + Constructs the orbit under the action of the cactus group. + """ + n = self.size() + orb = set([]) + rec = set([self]) + new = set([]) + while rec != set([]): + for a in rec: + for i in range(2,self.size()): + b = a.cactus(1,i) + if (b not in orb) and (b not in rec): + new.add(b) + orb = orb.union(rec) + rec = new.copy() new = set([]) - while rec != set([]): - for a in rec: - for i in range(2,self.size()): - b = a.cactus(1,i) - if (b not in orb) and (b not in rec): - new.add(b) - orb = orb.union(rec) - rec = new.copy() - new = set([]) - - return orb - - def dual_equivalence_graph(self): - """ - This constructs the graph with vertices the orbit of self - and edges given by the action of the cactus group generators. - - In most implementations the generators $s_{i,\,i+1}$ will act - as the identity operators. The usual dual equivalence graphs - are given by replacing the label $i,i+2$ by $i$ and removing - edges with other labels. - """ - from sage.graphs.graph import Graph - from itertools import combinations - - G = Graph() - orb = self.orbit() - - for a in orb: - for i,j in combinations(range(1,self.size()+1),2): - b = a.cactus(i,j) - if a != b: - G.add_edge(a,b,"%d,%d" % (i,j)) - return G - def csp(self): - import sage.combinat.cyclic_sieving_phenomenon + return orb -#### These functions don't belong here but I don't have a home for them. #### + def dual_equivalence_graph(self): + """ + This constructs the graph with vertices the orbit of self + and edges given by the action of the cactus group generators. + + In most implementations the generators $s_{i,\,i+1}$ will act + as the identity operators. The usual dual equivalence graphs + are given by replacing the label $i,i+2$ by $i$ and removing + edges with other labels. + """ + from sage.graphs.graph import Graph + from itertools import combinations - def drawL(self): - """ - This assumes we have a sequence of partitions. - This is the default case but need not always be the case. + G = Graph() + orb = self.orbit() - This draws a plot of the sequence of partitions. - """ + for a in orb: + for i,j in combinations(range(1,self.size()+1),2): + b = a.cactus(i,j) + if a != b: + G.add_edge(a,b,"%d,%d" % (i,j)) + return G - gap = 1 + def csp(self): + import sage.combinat.cyclic_sieving_phenomenon - def draw_partition(p,origin): +#### These functions don't belong here but I don't have a home for them. #### - global gap + def drawL(self): + """ + This assumes we have a sequence of partitions. + This is the default case but need not always be the case. - if p == Partition([]): - return point(origin,axes=False,size=60) + This draws a plot of the sequence of partitions. + """ - r = origin[0] - s = origin[1] + gap = 1 - u = p.to_dyck_word() - u = u[u.index(0):] - u.reverse() - u = u[u.index(1):] - u.reverse() - x = u.count(0) - y = u.count(1) + def draw_partition(p,origin): - gap = max(x,gap) - n = len(u) + global gap - edge = [] - edge.append([r,-y+s]) - for i in range(n): - v = copy(edge[i]) - if u[i] == 1: - v[1] += 1 - else: - v[0] += 1 - edge.append(v) + if p == Partition([]): + return point(origin,axes=False,size=60) - G = Graphics() - G += line([(r,-y+s),(r,s),(r+x,s)],axes=False,thickness=2) - G += line(edge,color='red',axes=False,thickness=3) + r = origin[0] + s = origin[1] - for i, a in enumerate(p[1:]): - G += line([(r,s-i-1),(r+a,s-i-1)],color='green') + u = p.to_dyck_word() + u = u[u.index(0):] + u.reverse() + u = u[u.index(1):] + u.reverse() + x = u.count(0) + y = u.count(1) - for i, a in enumerate(p.conjugate()[1:]): - G += line([(r+i+1,s),(r+i+1,s-a)],color='green') + gap = max(x,gap) + n = len(u) - return G + edge = [] + edge.append([r,-y+s]) + for i in range(n): + v = copy(edge[i]) + if u[i] == 1: + v[1] += 1 + else: + v[0] += 1 + edge.append(v) G = Graphics() + G += line([(r,-y+s),(r,s),(r+x,s)],axes=False,thickness=2) + G += line(edge,color='red',axes=False,thickness=3) - for i, x in enumerate(self): - G += draw_partition(x, (i*gap+1.5*i,0)) + for i, a in enumerate(p[1:]): + G += line([(r,s-i-1),(r+a,s-i-1)],color='green') - G.set_aspect_ratio(1) + for i, a in enumerate(p.conjugate()[1:]): + G += line([(r+i+1,s),(r+i+1,s-a)],color='green') return G - def drawC(self): - """ - This assumes we have a sequence of partitions. - This is the default case but need not always be the case. + G = Graphics() - This draws a plot of the sequence of partitions. - """ + for i, x in enumerate(self): + G += draw_partition(x, (i*gap+1.5*i,0)) - def draw_partition(p): + G.set_aspect_ratio(1) - if p == Partition([]): - return point((0,0),axes=False,size=60) + return G - u = p.to_dyck_word() - u = u[u.index(0):] - u.reverse() - u = u[u.index(1):] - u.reverse() - x = u.count(0) - y = u.count(1) + def drawC(self): + """ + This assumes we have a sequence of partitions. + This is the default case but need not always be the case. - n = len(u) + This draws a plot of the sequence of partitions. + """ - edge = [] - edge.append([0,-y]) - for i in range(n): - v = copy(edge[i]) - if u[i] == 1: - v[1] += 1 - else: - v[0] += 1 - edge.append(v) + def draw_partition(p): - return line(edge,color='red',axes=False,thickness=3) + if p == Partition([]): + return point((0,0),axes=False,size=60) - p = self.final_shape() + u = p.to_dyck_word() + u = u[u.index(0):] + u.reverse() + u = u[u.index(1):] + u.reverse() + x = u.count(0) + y = u.count(1) - G = line([(0,-len(p)),(0,0),(p[0],0)],axes=False) + n = len(u) - for i, a in enumerate(p[1:]): - G += line([(0,-i-1),(a,-i-1)],color='green') + edge = [] + edge.append([0,-y]) + for i in range(n): + v = copy(edge[i]) + if u[i] == 1: + v[1] += 1 + else: + v[0] += 1 + edge.append(v) - for i, a in enumerate(p.conjugate()[1:]): - G += line([(i+1,0),(i+1,-a)],color='green') + return line(edge,color='red',axes=False,thickness=3) - for i, x in enumerate(self): - G += draw_partition(x) + p = self.final_shape() - for p in self: - G += draw_partition(p) + G = line([(0,-len(p)),(0,0),(p[0],0)],axes=False) - G.set_aspect_ratio(1) + for i, a in enumerate(p[1:]): + G += line([(0,-i-1),(a,-i-1)],color='green') - return G + for i, a in enumerate(p.conjugate()[1:]): + G += line([(i+1,0),(i+1,-a)],color='green') -class PathTableaux(UniqueRepresentation,Parent): - - def __init__(self): - Parent.__init__(self, category = Sets()) + for i, x in enumerate(self): + G += draw_partition(x) + + for p in self: + G += draw_partition(p) + G.set_aspect_ratio(1) + + return G + +class PathTableaux(UniqueRepresentation,Parent): +# +# def __init__(self): +# Parent.__init__(self, category = Sets()) +# def _element_constructor_(self, *args, **keywords): return self.element_class(self, *args, **keywords) - - Element = PathTableau +# +# Element = PathTableau diff --git a/src/sage/combinat/pathtableau/semistandard.py b/src/sage/combinat/pathtableau/semistandard.py index bf9df9cb69d..b46304675ee 100644 --- a/src/sage/combinat/pathtableau/semistandard.py +++ b/src/sage/combinat/pathtableau/semistandard.py @@ -30,11 +30,13 @@ #***************************************************************************** from six import add_metaclass - from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass +from sage.misc.abstract_method import abstract_method +from sage.structure.list_clone import ClonableList +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.parent import Parent - -from sage.combinat.pathtableau.pathtableaux import PathTableau +from sage.combinat.pathtableau.pathtableaux import PathTableau, PathTableaux from sage.combinat.skew_tableau import SkewTableau from sage.combinat.tableau import SemistandardTableau from sage.combinat.partition import Partition From 9c0cd75f314c958b0df9841d43358f6a01b283c7 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Wed, 13 Jun 2018 18:16:18 +0100 Subject: [PATCH 024/300] PathTableau_partitions added and more doctests --- src/sage/combinat/pathtableau/all.py | 8 -- src/sage/combinat/pathtableau/catalan.py | 8 +- src/sage/combinat/pathtableau/pathtableaux.py | 95 ++++++++++++++----- src/sage/combinat/pathtableau/semistandard.py | 40 ++++---- 4 files changed, 99 insertions(+), 52 deletions(-) delete mode 100644 src/sage/combinat/pathtableau/all.py diff --git a/src/sage/combinat/pathtableau/all.py b/src/sage/combinat/pathtableau/all.py deleted file mode 100644 index 9a0fa4d5d75..00000000000 --- a/src/sage/combinat/pathtableau/all.py +++ /dev/null @@ -1,8 +0,0 @@ -from __future__ import absolute_import -from sage.misc.lazy_import import lazy_import - -#lazy_import('sage.combinat.tableau',['Tableau','Tableaux']) - -lazy_import('sage.combinat.pathtableau.pathtableaux', ['PathTableau','PathTableaux']) -lazy_import('sage.combinat.pathtableau.catalan', ['CatalanTableau','CatalanTableaux']) -lazy_import('sage.combinat.pathtableau.semistandard', ['DualSemistandardTableau','DualSemistandardTableaux']) diff --git a/src/sage/combinat/pathtableau/catalan.py b/src/sage/combinat/pathtableau/catalan.py index e3924dd7197..e1763b49ecd 100644 --- a/src/sage/combinat/pathtableau/catalan.py +++ b/src/sage/combinat/pathtableau/catalan.py @@ -149,7 +149,7 @@ class CatalanTableau(PathTableau): [0, 1, 2, 1, 0] """ - + @staticmethod def __classcall_private__(cls, ot): @@ -188,7 +188,7 @@ def __classcall_private__(cls, ot): raise NotImplementedError( "Sorry; I don't know what to do with %s." % str(ot) ) return CatalanTableaux()(w) - + def check(self): """ This overwrites the abstract method. @@ -306,7 +306,7 @@ def draw(self): return line([ (i,a) for i, a in enumerate(self)]) #class PathTableaux(UniqueRepresentation,Parent): -# +# # def __init__(self): # Parent.__init__(self, category = Sets()) # @@ -316,5 +316,5 @@ def draw(self): # Element = PathTableau class CatalanTableaux(PathTableaux): - + Element = CatalanTableau \ No newline at end of file diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index 1e06239fdb5..3d539368aeb 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -32,7 +32,9 @@ from sage.structure.list_clone import ClonableList from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent -from sage.categories.sets_cat import Sets +from sage.combinat.partition import Partition +from sage.modules.free_module_element import vector + @add_metaclass(InheritComparisonClasscallMetaclass) class PathTableau(ClonableList): @@ -44,11 +46,11 @@ def __classcall_private__(cls, t): return t raise NotImplementedError("This needs to be overwritten.") - + @abstract_method(optional=False) def check(self): """ - This is an abstract method. It must be overwritten + This is an abstract method. It must be overwritten Typically an instance of an Element class is a sequence of partitions with conditions on adjacent partitions in the sequence. This function checks @@ -67,7 +69,7 @@ def _rule(self,p): """ ################################# Book Keeping ################################ - + def size(self): """ Returns the size or length. @@ -292,6 +294,14 @@ def dual_equivalence_graph(self): as the identity operators. The usual dual equivalence graphs are given by replacing the label $i,i+2$ by $i$ and removing edges with other labels. + + PLOT:: + + sage: t = SkewTableau([[None,1,1],[2,2]]) + sage: s = DualSemistandardTableau(t) + sage: s.dual_equivalence_graph().show() + Launched png viewer for Graphics object consisting of 4 graphics primitives + """ from sage.graphs.graph import Graph from itertools import combinations @@ -311,14 +321,53 @@ def csp(self): #### These functions don't belong here but I don't have a home for them. #### - def drawL(self): - """ - This assumes we have a sequence of partitions. - This is the default case but need not always be the case. + +class PathTableaux(UniqueRepresentation,Parent): +# +# def __init__(self): +# Parent.__init__(self, category = Sets()) +# + def _element_constructor_(self, *args, **keywords): + return self.element_class(self, *args, **keywords) +# +# Element = PathTableau + +class PathTableau_partitions(PathTableau): + """ + This is an abstract base class. This class assumes that we have + a sequence of partitions. The main examples are the minuscule + representations of classical groups. + """ + + @staticmethod + def _rule(x): + y = map(list,x) + m = max([ len(u) for u in y ]) + z = map( lambda u: vector(u + [0]*(m-len(u)) ), y ) + result = list(z[0]-z[1]+z[2]) + result.sort(reverse=True) + return Partition(result) + + def _plotL(self): + """ This draws a plot of the sequence of partitions. + This plot assumes we do not have a chain of partitions + and plots the partitions in a line. + + PLOT:: + + sage: t = SkewTableau([[None,1,1],[2,2]]) + sage: s = DualSemistandardTableau(t) + sage: s._plotL() + Launched png viewer for Graphics object consisting of 11 graphics primitives + """ + from sage.plot.graphics import Graphics + from sage.plot.line import line + from copy import copy + global gap gap = 1 def draw_partition(p,origin): @@ -373,13 +422,23 @@ def draw_partition(p,origin): return G - def drawC(self): + def _plotC(self): """ - This assumes we have a sequence of partitions. - This is the default case but need not always be the case. - This draws a plot of the sequence of partitions. + This plot assumes the sequence is not a chain and so + plots the sequence. + + PLOT:: + + sage: t = SkewTableau([[None,1,1],[2,2]]) + sage: s = DualSemistandardTableau(t) + sage: s._plotC() + Launched png viewer for Graphics object consisting of 10 graphics primitives + """ + from sage.plot.graphics import Graphics + from sage.plot.line import line + from copy import copy def draw_partition(p): @@ -426,14 +485,4 @@ def draw_partition(p): G.set_aspect_ratio(1) - return G - -class PathTableaux(UniqueRepresentation,Parent): -# -# def __init__(self): -# Parent.__init__(self, category = Sets()) -# - def _element_constructor_(self, *args, **keywords): - return self.element_class(self, *args, **keywords) -# -# Element = PathTableau + return G \ No newline at end of file diff --git a/src/sage/combinat/pathtableau/semistandard.py b/src/sage/combinat/pathtableau/semistandard.py index b46304675ee..fe03b10c96f 100644 --- a/src/sage/combinat/pathtableau/semistandard.py +++ b/src/sage/combinat/pathtableau/semistandard.py @@ -31,16 +31,10 @@ from six import add_metaclass from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass -from sage.misc.abstract_method import abstract_method -from sage.structure.list_clone import ClonableList -from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.parent import Parent - -from sage.combinat.pathtableau.pathtableaux import PathTableau, PathTableaux +from sage.combinat.pathtableau.pathtableaux import PathTableau_partitions, PathTableaux from sage.combinat.skew_tableau import SkewTableau from sage.combinat.tableau import SemistandardTableau from sage.combinat.partition import Partition -from sage.modules.free_module_element import vector """ EXAMPLES:: @@ -98,7 +92,7 @@ """ @add_metaclass(InheritComparisonClasscallMetaclass) -class DualSemistandardTableau(PathTableau): +class DualSemistandardTableau(PathTableau_partitions): """ An instance is the sequence of partitions correspond to the chain of partitions of a dual semistandard skew tableau. @@ -152,14 +146,6 @@ def check(self): for a in t[len(h):]: if a > 1: raise ValueError( "%s / %s is not a vertical strip" % (str(t),str(h)) ) - @staticmethod - def _rule(x): - y = map(list,x) - m = max([ len(u) for u in y ]) - z = map( lambda u: vector(u + [0]*(m-len(u)) ), y ) - result = list(z[0]-z[1]+z[2]) - result.sort(reverse=True) - return Partition(result) def evaluation(self): z = [ p.size() for p in self ] @@ -251,6 +237,14 @@ def check_bender_knuth(self,i): return lhs == rhs def check_rectify(self): + """ + Check that jdt-rectification on the conjugate tableaux + is the rectification defined here. + + EXAMPLE:: + + """ + lhs = self.rectify().to_tableau() rhs = self.to_tableau().rectify() return lhs == rhs @@ -272,6 +266,18 @@ def check_evacuation(self): rhs = self.to_tableau().evacuation() return lhs == rhs + def plot(self): + """ + This provides a plot of the dual semistandard tableau. + PLOT:: + + sage: t = SkewTableau([[None,None,2,2],[3,4,4],[4]]) + sage: DualSemistandardTableau(t).plot() + Graphics object consisting of 16 graphics primitives + + """ + return self._plotC() + class DualSemistandardTableaux(PathTableaux): - + Element = DualSemistandardTableau \ No newline at end of file From f4d341fc2d6ffa8a224aa16e9eb610922cec2650 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Wed, 13 Jun 2018 19:14:45 +0100 Subject: [PATCH 025/300] multiply doctest added --- src/sage/combinat/pathtableau/semistandard.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/pathtableau/semistandard.py b/src/sage/combinat/pathtableau/semistandard.py index fe03b10c96f..1ae2829c25d 100644 --- a/src/sage/combinat/pathtableau/semistandard.py +++ b/src/sage/combinat/pathtableau/semistandard.py @@ -198,6 +198,13 @@ def rectify(self,display=False): def multiply(self,other): """ This is the same function as tableau.slide_multiply and tableau.bump_multiply. + + EXAMPLE:: + + sage: t = DualSemistandardTableau([[2],[3,1],[4,1,1]]) + sage: t.multiply(t) + [[], [1, 1, 1, 1], [2, 2, 2, 1, 1]] + """ left = list(self) @@ -209,10 +216,10 @@ def multiply(self,other): right = [a+[0]*(m-len(a)) for a in right] p = max(len(left),len(right)) - left = left + left[-1]*(p-len(left)) - right = right + right[-1]*(p-len(right)) + left = left + [left[-1]]*(p-len(left)) + right = right + [right[-1]]*(p-len(right)) - result = [Partition([a+n for a in y]+x) for x,y in zip(left,right)] + result = [Partition([a+n for a in y]+list(x)) for x,y in zip(left,right)] return DualSemistandardTableau(result).rectify() @@ -243,6 +250,7 @@ def check_rectify(self): EXAMPLE:: + """ lhs = self.rectify().to_tableau() From 7cb9d1f8156c0d8cf11fee5a28948d12b256e80b Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Thu, 14 Jun 2018 10:49:18 +0100 Subject: [PATCH 026/300] More doctests --- src/sage/combinat/pathtableau/catalan.py | 3 +- src/sage/combinat/pathtableau/pathtableaux.py | 2 +- src/sage/combinat/pathtableau/semistandard.py | 48 ++++++++++++++++--- 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/sage/combinat/pathtableau/catalan.py b/src/sage/combinat/pathtableau/catalan.py index e1763b49ecd..7a8965c0b9d 100644 --- a/src/sage/combinat/pathtableau/catalan.py +++ b/src/sage/combinat/pathtableau/catalan.py @@ -1,5 +1,4 @@ - -""" +r""" This is an implementation of the Category PathTableaux. This is the simplest implementation of PathTableaux and is included to provide a convenient test case and for pedagogical purposes. diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index 3d539368aeb..0e62862f62d 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -1,4 +1,4 @@ -""" +r""" This is an abstract base class for using local rules to construct rectification and the action of the cactus group. This is an effective version of the Henriques-Kamnitzer construction of the action of the cactus diff --git a/src/sage/combinat/pathtableau/semistandard.py b/src/sage/combinat/pathtableau/semistandard.py index 1ae2829c25d..51d0036cb34 100644 --- a/src/sage/combinat/pathtableau/semistandard.py +++ b/src/sage/combinat/pathtableau/semistandard.py @@ -1,6 +1,4 @@ -""" -This is an impementation of the Category PathTableaux. - +r""" In this implementation we have sequences of partitions. These are in bijection with dual semistandard tableaux. This gives an effective version of operations on tableaux constructed using jeu-de-taquin. @@ -37,6 +35,20 @@ from sage.combinat.partition import Partition """ +This implementation is on dual semistandard tableaux. This is the standard +context for jeu-de-taquin operations. Here we show that the constructions +here agree with the jeu-de-taquin constructions. Even in this standard context +our operations extend the standard definitions in the sense that the +constructions here are naturally defined for skew semistandard tableaux. +The only caveat is that the two constructions of promotion agree on rectangular +tableaux but are, in general, different. + +-promotion +-evacuation +-rectify +-multiply +-Bender-Knuth + EXAMPLES:: sage: T = DualSemistandardTableau([[],[1],[2],[2,1]]) @@ -230,8 +242,8 @@ def check_bender_knuth(self,i): EXAMPLE:: - sage: ST = SemistandardTableaux([5,3,3,2,1],[2,1,4,2,2,2,1]) - sage: s = DualSemistandardTableau(ST.an_element()) + sage: t = SemistandardTableaux(8).random_element() + sage: s = DualSemistandardTableau(t) sage: s.check_bender_knuth(5) True sage: s.check_bender_knuth(4) @@ -250,6 +262,10 @@ def check_rectify(self): EXAMPLE:: + sage: t = SkewTableau([[None,None,1,3,3],[None,1,2,4],[2,2]]) + sage: s = DualSemistandardTableau(t) + sage: s.check_rectify() + True """ @@ -264,8 +280,8 @@ def check_evacuation(self): EXAMPLE:: - sage: ST = SemistandardTableaux([5,3,3,2,1],[2,1,4,2,2,2,1]) - sage: s = DualSemistandardTableau(ST.an_element()) + sage: t = SemistandardTableaux(6).random_element() + sage: s = DualSemistandardTableau(t) sage: s.check_evacuation() True @@ -274,6 +290,24 @@ def check_evacuation(self): rhs = self.to_tableau().evacuation() return lhs == rhs + def check_promotion(self): + """ + Check that jdt-promotion on the conjugate tableaux + is the promotion defined here. + + EXAMPLE:: + + sage: t = SemistandardTableaux(shape=[4,4,4],eval=[1]*12).an_element() + sage: s = DualSemistandardTableau(t) + sage: s.check_promotion() + True + + """ + lhs = self.promotion().to_tableau() + rhs = self.to_tableau().promotion_inverse(11) + return lhs == rhs + + def plot(self): """ This provides a plot of the dual semistandard tableau. From 8b2162836c311c4e5a6e7894607ca5a6d547f909 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Thu, 14 Jun 2018 10:55:10 +0100 Subject: [PATCH 027/300] rule changed to avoid use of vector --- src/sage/combinat/pathtableau/pathtableaux.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index 0e62862f62d..843dcd3270e 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -33,7 +33,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.combinat.partition import Partition -from sage.modules.free_module_element import vector +#from sage.modules.free_module_element import vector @add_metaclass(InheritComparisonClasscallMetaclass) @@ -344,8 +344,8 @@ class PathTableau_partitions(PathTableau): def _rule(x): y = map(list,x) m = max([ len(u) for u in y ]) - z = map( lambda u: vector(u + [0]*(m-len(u)) ), y ) - result = list(z[0]-z[1]+z[2]) + z = map( lambda u: u + [0]*(m-len(u)), y ) + result = [ abs(a-b+c) for a,b,c in zip(z[0],z[1],z[2]) ] result.sort(reverse=True) return Partition(result) From c751cc0b28748d8992dcbabf6f6ee5d4c6961d9b Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Wed, 25 Jul 2018 22:33:13 +0100 Subject: [PATCH 028/300] Moved tests. Use _test_ and other minor changes on tests. --- src/sage/combinat/pathtableau/catalan.py | 106 ++---- src/sage/combinat/pathtableau/pathtableaux.py | 344 +++++++----------- src/sage/combinat/pathtableau/semistandard.py | 179 ++++++++- 3 files changed, 331 insertions(+), 298 deletions(-) diff --git a/src/sage/combinat/pathtableau/catalan.py b/src/sage/combinat/pathtableau/catalan.py index 7a8965c0b9d..de4a8b24337 100644 --- a/src/sage/combinat/pathtableau/catalan.py +++ b/src/sage/combinat/pathtableau/catalan.py @@ -1,5 +1,5 @@ r""" -This is an implementation of the Category PathTableaux. +This is an implementation of the abstract base class PathTableaux. This is the simplest implementation of PathTableaux and is included to provide a convenient test case and for pedagogical purposes. @@ -26,16 +26,11 @@ from six import add_metaclass from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass -from sage.misc.abstract_method import abstract_method -from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.parent import Parent -from sage.categories.sets_cat import Sets - from sage.combinat.pathtableau.pathtableaux import PathTableau, PathTableaux from sage.combinat.dyck_word import DyckWord from sage.combinat.perfect_matching import PerfectMatching from sage.combinat.skew_tableau import SkewTableau -from sage.combinat.tableau import Tableau, Tableaux +from sage.combinat.tableau import Tableau from sage.rings.integer import Integer ############################################################################### @@ -44,7 +39,7 @@ Here we illustrate the slogan that promotion = rotation. -EXAMPLE:: +EXAMPLES:: sage: t = CatalanTableau([0,1,2,3,2,1,0]) sage: t.to_perfect_matching() @@ -62,7 +57,7 @@ sage: t.to_perfect_matching() [(0, 5), (1, 4), (2, 3)] -EXAMPLE:: +EXAMPLES:: sage: t = CatalanTableau([0,1,2,3,2,1,0]) sage: SkewTableau(t.cylindrical_diagram()).pp() @@ -74,48 +69,7 @@ . . . . . 0 1 0 1 2 1 0 . . . . . . 0 1 2 3 2 1 0 - - sage: t = CatalanTableau([0,1,2,3,2,1,0]) - sage: t.evacuation() - [0, 1, 2, 3, 2, 1, 0] - - sage: t.cactus(1,5) - [0, 1, 0, 1, 2, 1, 0] - - sage: t.cactus(1,6) - [0, 1, 2, 1, 0, 1, 0] - - sage: t.cactus(1,7) == t.evacuation() - True - - sage: t.cactus(1,7).cactus(1,6) == t.promotion() - True - - sage: t.check_involution_rule() - True - - sage: t.check_involution_cactus() - True - - sage: t.check_promotion() - True - - sage: t.check_involution_cactus() - True - - sage: t.check_commutation() - True - - sage: t.check_coboundary() - True - - sage: t.orbit() - {[0, 1, 0, 1, 0, 1, 0], - [0, 1, 0, 1, 2, 1, 0], - [0, 1, 2, 1, 0, 1, 0], - [0, 1, 2, 1, 2, 1, 0], - [0, 1, 2, 3, 2, 1, 0]} - + sage: TestSuite(t).run() """ @add_metaclass(InheritComparisonClasscallMetaclass) @@ -124,10 +78,11 @@ class CatalanTableau(PathTableau): An instance is the sequence of nonnegative integers given by the heights of a Dyck word. The acceptable inputs are: - - a sequence of nonnegative integers - - a two row standard skew tableau - - a Dyck word - - a noncrossing perfect matching + + - a sequence of nonnegative integers + - a two row standard skew tableau + - a Dyck word + - a noncrossing perfect matching EXAMPLES:: @@ -154,37 +109,37 @@ def __classcall_private__(cls, ot): w = None - if isinstance(ot,DyckWord): + if isinstance(ot, DyckWord): w = ot.heights() - if isinstance(ot,PerfectMatching): + if isinstance(ot, PerfectMatching): if ot.is_noncrossing(): w = [1]*ot.size() for a in ot.arcs(): w[a[1]-1] = 0 else: - raise ValueError("The perfect matching must be non crossing.") + raise ValueError("the perfect matching must be non crossing") - if isinstance(ot,Tableau): + if isinstance(ot, Tableau): if len(ot) == 2: if ot.is_standard(): - u = [1]*ot.size() + u = [1] * ot.size() for i in ot[1]: u[i-1] = 0 w = DyckWord(u).heights() else: - raise ValueError("The tableau must be standard.") + raise ValueError("the tableau must be standard") else: - raise ValueError("The tableau must have two rows.") + raise ValueError("the tableau must have two rows") - if isinstance(ot,(list,tuple)): + if isinstance(ot, (list,tuple)): try: - w = tuple([ Integer(a) for a in ot ]) + w = tuple([Integer(a) for a in ot]) except TypeError: - raise ValueError("%s is not a sequence of integers." % str(ot) ) + raise ValueError("%s is not a sequence of integers" % ot) - if w == None: - raise NotImplementedError( "Sorry; I don't know what to do with %s." % str(ot) ) + if w is None: + raise ValueError("invalid input %s" % ot) return CatalanTableaux()(w) @@ -203,23 +158,23 @@ def check(self): sage: CatalanTableau([0,1,0,-1,0]) Traceback (most recent call last): ... - ValueError: [0, 1, 0, -1, 0] has a negative entry. + ValueError: [0, 1, 0, -1, 0] has a negative entry sage: CatalanTableau([0,1,3,3,2,3]) Traceback (most recent call last): ... - ValueError: [0, 1, 3, 3, 2, 3] is not a Dyck path. + ValueError: [0, 1, 3, 3, 2, 3] is not a Dyck path """ n = len(self) if any(a < 0 for a in self): - raise ValueError( "%s has a negative entry." % (str(self)) ) + raise ValueError( "%s has a negative entry" % (str(self)) ) for i in range(n-1): if abs(self[i+1]-self[i]) != 1: - raise ValueError( "%s is not a Dyck path." % (str(self)) ) + raise ValueError( "%s is not a Dyck path" % (str(self)) ) @staticmethod - def _rule(x): + def _rule_(x): """ This overwrites the abstract method. """ @@ -244,7 +199,7 @@ def descents(self): """ Returns the descent set. - EXAMPLE:: + EXAMPLES:: sage: CatalanTableau([0,1,2,1,2,1,0,1,0]).descents() {3, 6} @@ -262,7 +217,7 @@ def to_word(self): """ Converts to a word in the alphabet 0,1 - EXAMPLE:: + EXAMPLES:: sage: CatalanTableau([1,0,1,2,1]).to_word() [0, 1, 1, 0] @@ -274,11 +229,10 @@ def to_perfect_matching(self): """ This converts to a perfect matching. - EXAMPLE:: + EXAMPLES:: sage: CatalanTableau([0,1,2,1,2,1,0,1,0]).to_perfect_matching() [(0, 5), (1, 2), (3, 4), (6, 7)] - """ w = self.to_word() y = DyckWord(w) diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index 843dcd3270e..a14a3e0c797 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -32,33 +32,12 @@ from sage.structure.list_clone import ClonableList from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent -from sage.combinat.partition import Partition -#from sage.modules.free_module_element import vector - +from sage.combinat.partition import Partition, _Partitions @add_metaclass(InheritComparisonClasscallMetaclass) class PathTableau(ClonableList): - - @staticmethod - def __classcall_private__(cls, t): - - if isinstance(t, cls): - return t - - raise NotImplementedError("This needs to be overwritten.") - - @abstract_method(optional=False) - def check(self): - """ - This is an abstract method. It must be overwritten - Typically an instance of - an Element class is a sequence of partitions with conditions - on adjacent partitions in the sequence. This function checks - that these conditions are met. - """ - @abstract_method(optional=False) - def _rule(self,p): + def _rule_(self,p): """ This is an abstract method. It must be overwritten. This rule provides the functionality. It is called in local_rule. @@ -99,10 +78,10 @@ def local_rule(self,i): the $i$-th object by the object returned by the rule. """ if not (i > 0 and i < len(self) ): - raise ValueError("%d is not a valid integer." % i) + raise ValueError("%d is not a valid integer" % i) result = list(self) - result[i] = self._rule(self[i-1:i+2]) + result[i] = self._rule_(self[i-1:i+2]) return self.parent()(result) @@ -112,12 +91,26 @@ def promotion(self): """ result = list(self) for i in range(1,len(result)-1): - result[i] = self._rule(result[i-1:i+2]) + result[i] = self._rule_(result[i-1:i+2]) return self.parent()(result) def evacuation(self): """ The evacuation operator. This is given by a triangular diagram. + + INPUT: A pathtableau + + OUTPUT: A pathtableau + + The output will have the same length, initial shape, and final shape as the input. + + EXAMPLES:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t.evacuation() + [0, 1, 2, 3, 2, 1, 0] + + """ if self.size() < 3: return self @@ -134,7 +127,7 @@ def evacuation(self): def path_rule(self,other,display=False): """ - This constructs the commutor of a pair of tableau. + This constructs the commutor of a pair of tableaux. This is given by a rectangular diagram. If display=True then the function will print @@ -143,14 +136,14 @@ def path_rule(self,other,display=False): n = len(self) m = len(other) if n == 0 or m == 0: - raise ValueError("This requires nonempty lists.") + raise ValueError("this requires nonempty lists") if n == 1 or m == 1: return (other,self) row = list(other) col = list(self) if col[-1] != row[0]: - raise ValueError("%s,%s is not a composable pair." % (self,other)) + raise ValueError("%s,%s is not a composable pair" % (self,other)) path = self.parent()(col + row[1:]) @@ -170,9 +163,31 @@ def cactus(self,i,j): This constructs the action of the generators of the cactus group. These generators are involutions and are usually denoted by $s_{i,\,j$}$. + + INPUT: A pathtableau, i >0, j >i + + OUTPUT: A pathtableau + + The output will have the same length, initial shape, and final shape as the input. + + EXAMPLES:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t.cactus(1,5) + [0, 1, 0, 1, 2, 1, 0] + + sage: t.cactus(1,6) + [0, 1, 2, 1, 0, 1, 0] + + sage: t.cactus(1,7) == t.evacuation() + True + + sage: t.cactus(1,7).cactus(1,6) == t.promotion() + True + """ if not 0 < i < j <= self.size(): - raise ValueError("Integers out of bounds.") + raise ValueError("integers out of bounds") if i == j: return self @@ -196,6 +211,18 @@ def cylindrical_diagram(self): are the powers of the promotion operator (which form the rows) and the cactus group operators $s_{1,\,j$}$ (which form the first half of the columns). + + EXAMPLES:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: SkewTableau(t.cylindrical_diagram()).pp() + 0 1 2 3 2 1 0 + . 0 1 2 1 0 1 0 + . . 0 1 0 1 2 1 0 + . . . 0 1 2 3 2 1 0 + . . . . 0 1 2 1 0 1 0 + . . . . . 0 1 0 1 2 1 0 + . . . . . . 0 1 2 3 2 1 0 """ n = len(self) result = [[None]*(2*n-1)]*n @@ -206,37 +233,57 @@ def cylindrical_diagram(self): return result - def check_involution_rule(self): + def _test_involution_rule(self, **options): """ This is to check that the local rule gives an involution. This is crucial. + + TESTS:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t._test_involution_rule() + """ - for i in range(self.size()-2): - if self.local_rule(i+1).local_rule(i+1) != self: - return False - return True + tester = self._tester(**options) + tester.assertTrue(all( self.local_rule(i+1).local_rule(i+1) == self + for i in range(self.size()-2) )) - def check_involution_cactus(self): + def _test_involution_cactus(self, **options): """ This is to check that the cactus group generators are - involutions.. + involutions. + + TESTS:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t._test_involution_cactus() """ - return all([ self.cactus(1,i).cactus(1,i) == self for i in range(2,self.size()+1 ) ]) + tester = self._tester(**options) + tester.assertTrue(all( self.cactus(1,i).cactus(1,i) == self + for i in range(2,self.size()+1) )) - def check_promotion(self): + def _test_promotion(self, **options): """ Promotion can be expressed in terms of the cactus generators. Here we check this relation. + + TESTS:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t._test_promotion() + """ + tester = self._tester(**options) n = self.size()-1 - return self == self.cactus(1,n-1).cactus(1,n).promotion() + tester.assertTrue( self.cactus(1,n-1).cactus(1,n).promotion() == self ) - def check_commutation(self): + def _test_commutation(self, **options): """ This is to check the commutation relations in the presentation of the cactus group. """ from itertools import combinations + tester = self._tester(**options) n = self.size() if n < 5: @@ -248,12 +295,17 @@ def check_commutation(self): return False return True - def check_coboundary(self): + def _test_coboundary(self, **options): """ This is to check the coboundary relations in the presentation of the cactus group. + + EXAMPLES:: + + t = """ from itertools import combinations + tester = self._tester(**options) n = self.size() if n < 4: @@ -268,6 +320,16 @@ def check_coboundary(self): def orbit(self): """ Constructs the orbit under the action of the cactus group. + + EXAMPLES:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t.orbit() + {[0, 1, 0, 1, 0, 1, 0], + [0, 1, 0, 1, 2, 1, 0], + [0, 1, 2, 1, 0, 1, 0], + [0, 1, 2, 1, 2, 1, 0], + [0, 1, 2, 3, 2, 1, 0]} """ n = self.size() orb = set([]) @@ -283,7 +345,7 @@ def orbit(self): rec = new.copy() new = set([]) - return orb + return orbit def dual_equivalence_graph(self): """ @@ -295,13 +357,25 @@ def dual_equivalence_graph(self): are given by replacing the label $i,i+2$ by $i$ and removing edges with other labels. - PLOT:: - - sage: t = SkewTableau([[None,1,1],[2,2]]) - sage: s = DualSemistandardTableau(t) - sage: s.dual_equivalence_graph().show() - Launched png viewer for Graphics object consisting of 4 graphics primitives - + EXAMPLES:: + + sage: s = CatalanTableau([0,1,2,3,2,3,2,1,0]) + sage: s.dual_equivalence_graph().adjacency_matrix() + [0 1 1 1 0 1 0 1 1 0 0 0 0 0] + [1 0 1 1 1 1 1 0 1 0 0 1 1 0] + [1 1 0 1 1 1 0 1 0 1 1 1 0 0] + [1 1 1 0 1 0 1 1 1 1 0 1 1 0] + [0 1 1 1 0 0 1 0 0 1 1 0 1 1] + [1 1 1 0 0 0 1 1 1 1 1 0 1 0] + [0 1 0 1 1 1 0 1 0 1 1 1 0 1] + [1 0 1 1 0 1 1 0 1 1 1 1 1 0] + [1 1 0 1 0 1 0 1 0 1 0 1 1 0] + [0 0 1 1 1 1 1 1 1 0 0 1 1 1] + [0 0 1 0 1 1 1 1 0 0 0 1 1 1] + [0 1 1 1 0 0 1 1 1 1 1 0 1 1] + [0 1 0 1 1 1 0 1 1 1 1 1 0 1] + [0 0 0 0 1 0 1 0 0 1 1 1 1 0] + """ from sage.graphs.graph import Graph from itertools import combinations @@ -316,173 +390,3 @@ def dual_equivalence_graph(self): G.add_edge(a,b,"%d,%d" % (i,j)) return G - def csp(self): - import sage.combinat.cyclic_sieving_phenomenon - -#### These functions don't belong here but I don't have a home for them. #### - - - -class PathTableaux(UniqueRepresentation,Parent): -# -# def __init__(self): -# Parent.__init__(self, category = Sets()) -# - def _element_constructor_(self, *args, **keywords): - return self.element_class(self, *args, **keywords) -# -# Element = PathTableau - -class PathTableau_partitions(PathTableau): - """ - This is an abstract base class. This class assumes that we have - a sequence of partitions. The main examples are the minuscule - representations of classical groups. - """ - - @staticmethod - def _rule(x): - y = map(list,x) - m = max([ len(u) for u in y ]) - z = map( lambda u: u + [0]*(m-len(u)), y ) - result = [ abs(a-b+c) for a,b,c in zip(z[0],z[1],z[2]) ] - result.sort(reverse=True) - return Partition(result) - - def _plotL(self): - """ - This draws a plot of the sequence of partitions. - This plot assumes we do not have a chain of partitions - and plots the partitions in a line. - - PLOT:: - - sage: t = SkewTableau([[None,1,1],[2,2]]) - sage: s = DualSemistandardTableau(t) - sage: s._plotL() - Launched png viewer for Graphics object consisting of 11 graphics primitives - - """ - from sage.plot.graphics import Graphics - from sage.plot.line import line - from copy import copy - - global gap - gap = 1 - - def draw_partition(p,origin): - - global gap - - if p == Partition([]): - return point(origin,axes=False,size=60) - - r = origin[0] - s = origin[1] - - u = p.to_dyck_word() - u = u[u.index(0):] - u.reverse() - u = u[u.index(1):] - u.reverse() - x = u.count(0) - y = u.count(1) - - gap = max(x,gap) - n = len(u) - - edge = [] - edge.append([r,-y+s]) - for i in range(n): - v = copy(edge[i]) - if u[i] == 1: - v[1] += 1 - else: - v[0] += 1 - edge.append(v) - - G = Graphics() - G += line([(r,-y+s),(r,s),(r+x,s)],axes=False,thickness=2) - G += line(edge,color='red',axes=False,thickness=3) - - for i, a in enumerate(p[1:]): - G += line([(r,s-i-1),(r+a,s-i-1)],color='green') - - for i, a in enumerate(p.conjugate()[1:]): - G += line([(r+i+1,s),(r+i+1,s-a)],color='green') - - return G - - G = Graphics() - - for i, x in enumerate(self): - G += draw_partition(x, (i*gap+1.5*i,0)) - - G.set_aspect_ratio(1) - - return G - - def _plotC(self): - """ - This draws a plot of the sequence of partitions. - This plot assumes the sequence is not a chain and so - plots the sequence. - - PLOT:: - - sage: t = SkewTableau([[None,1,1],[2,2]]) - sage: s = DualSemistandardTableau(t) - sage: s._plotC() - Launched png viewer for Graphics object consisting of 10 graphics primitives - - """ - from sage.plot.graphics import Graphics - from sage.plot.line import line - from copy import copy - - def draw_partition(p): - - if p == Partition([]): - return point((0,0),axes=False,size=60) - - u = p.to_dyck_word() - u = u[u.index(0):] - u.reverse() - u = u[u.index(1):] - u.reverse() - x = u.count(0) - y = u.count(1) - - n = len(u) - - edge = [] - edge.append([0,-y]) - for i in range(n): - v = copy(edge[i]) - if u[i] == 1: - v[1] += 1 - else: - v[0] += 1 - edge.append(v) - - return line(edge,color='red',axes=False,thickness=3) - - p = self.final_shape() - - G = line([(0,-len(p)),(0,0),(p[0],0)],axes=False) - - for i, a in enumerate(p[1:]): - G += line([(0,-i-1),(a,-i-1)],color='green') - - for i, a in enumerate(p.conjugate()[1:]): - G += line([(i+1,0),(i+1,-a)],color='green') - - for i, x in enumerate(self): - G += draw_partition(x) - - for p in self: - G += draw_partition(p) - - G.set_aspect_ratio(1) - - return G \ No newline at end of file diff --git a/src/sage/combinat/pathtableau/semistandard.py b/src/sage/combinat/pathtableau/semistandard.py index 51d0036cb34..f24c7afea68 100644 --- a/src/sage/combinat/pathtableau/semistandard.py +++ b/src/sage/combinat/pathtableau/semistandard.py @@ -36,7 +36,7 @@ """ This implementation is on dual semistandard tableaux. This is the standard -context for jeu-de-taquin operations. Here we show that the constructions +context for jeu-de-taquin operations. Here we show that the constructions here agree with the jeu-de-taquin constructions. Even in this standard context our operations extend the standard definitions in the sense that the constructions here are naturally defined for skew semistandard tableaux. @@ -322,4 +322,179 @@ def plot(self): class DualSemistandardTableaux(PathTableaux): - Element = DualSemistandardTableau \ No newline at end of file + Element = DualSemistandardTableau + +#### These functions don't belong here but I don't have a home for them. #### + +############################################################################# + + + +class PathTableaux(UniqueRepresentation,Parent): +# +# def __init__(self): +# Parent.__init__(self, category = Sets()) +# + def _element_constructor_(self, *args, **keywords): + return self.element_class(self, *args, **keywords) +# +# Element = PathTableau + +class PathTableau_partitions(PathTableau): + """ + This is an abstract base class. This class assumes that we have + a sequence of partitions. The main examples are the minuscule + representations of classical groups. + + TESTS:: + + sage: F = Foo() + sage: TestSuite(F).run() + """ + + @staticmethod + def _rule_(x): + y = map(list, x) + m = max(len(u) for u in y) # FIXME?: This will fail if y is empty + z = [u + [0]*(m-len(u)) for u in y] + result = [ abs(a-b+c) for a,b,c in zip(z[0],z[1],z[2]) ] + result.sort(reverse=True) + return _Partitions(result) + + def _plotL(self): + """ + This draws a plot of the sequence of partitions. + This plot assumes we do not have a chain of partitions + and plots the partitions in a line. + + PLOT:: + + sage: t = SkewTableau([[None,1,1],[2,2]]) + sage: s = DualSemistandardTableau(t) + sage: s._plotL() + Launched png viewer for Graphics object consisting of 11 graphics primitives + + """ + from sage.plot.graphics import Graphics + from sage.plot.line import line + from copy import copy + + global gap + gap = 1 + + def draw_partition(p,origin): + + global gap + + if p == _Partitions([]): + return point(origin,axes=False,size=60) + + r = origin[0] + s = origin[1] + + u = p.to_dyck_word() + u = u[u.index(0):] + u.reverse() + u = u[u.index(1):] + u.reverse() + x = u.count(0) + y = u.count(1) + + gap = max(x,gap) + n = len(u) + + edge = [] + edge.append([r,-y+s]) + for i in range(n): + v = copy(edge[i]) + if u[i] == 1: + v[1] += 1 + else: + v[0] += 1 + edge.append(v) + + G = Graphics() + G += line([(r,-y+s),(r,s),(r+x,s)],axes=False,thickness=2) + G += line(edge,color='red',axes=False,thickness=3) + + for i, a in enumerate(p[1:]): + G += line([(r,s-i-1),(r+a,s-i-1)],color='green') + + for i, a in enumerate(p.conjugate()[1:]): + G += line([(r+i+1,s),(r+i+1,s-a)],color='green') + + return G + + G = Graphics() + + for i, x in enumerate(self): + G += draw_partition(x, (i*gap+1.5*i,0)) + + G.set_aspect_ratio(1) + + return G + + def _plotC_(self): + """ + This draws a plot of the sequence of partitions. + This plot assumes the sequence is not a chain and so + plots the sequence. + + PLOT:: + + sage: t = SkewTableau([[None,1,1],[2,2]]) + sage: s = DualSemistandardTableau(t) + sage: s._plotC_() + Launched png viewer for Graphics object consisting of 10 graphics primitives + + """ + from sage.plot.graphics import Graphics + from sage.plot.line import line + from copy import copy + + def draw_partition(p): + + if p == _Partitions([]): + return point((0,0),axes=False,size=60) + + u = p.to_dyck_word() + u = u[u.index(0):] + u.reverse() + u = u[u.index(1):] + u.reverse() + x = u.count(0) + y = u.count(1) + + n = len(u) + + edge = [] + edge.append([0,-y]) + for i in range(n): + v = copy(edge[i]) + if u[i] == 1: + v[1] += 1 + else: + v[0] += 1 + edge.append(v) + + return line(edge,color='red',axes=False,thickness=3) + + p = self.final_shape() + + G = line([(0,-len(p)),(0,0),(p[0],0)],axes=False) + + for i, a in enumerate(p[1:]): + G += line([(0,-i-1),(a,-i-1)],color='green') + + for i, a in enumerate(p.conjugate()[1:]): + G += line([(i+1,0),(i+1,-a)],color='green') + + for i, x in enumerate(self): + G += draw_partition(x) + + for p in self: + G += draw_partition(p) + + G.set_aspect_ratio(1) + + return G \ No newline at end of file From bb2caa0adf1603a795995845a757584c1a8dcb81 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Wed, 25 Jul 2018 22:48:09 +0100 Subject: [PATCH 029/300] Moved PathTableaux class back --- src/sage/combinat/pathtableau/pathtableaux.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index a14a3e0c797..5c85b7f21a4 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -390,3 +390,12 @@ def dual_equivalence_graph(self): G.add_edge(a,b,"%d,%d" % (i,j)) return G +class PathTableaux(UniqueRepresentation,Parent): +# +# def __init__(self): +# Parent.__init__(self, category = Sets()) +# + def _element_constructor_(self, *args, **keywords): + return self.element_class(self, *args, **keywords) +# +# Element = PathTableau \ No newline at end of file From 8715ae9bc8344eac675dcb6dc950b6bb0c5df021 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Thu, 26 Jul 2018 13:34:45 +0100 Subject: [PATCH 030/300] All doctests pass --- src/sage/combinat/pathtableau/pathtableaux.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index 5c85b7f21a4..8689360d569 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -32,7 +32,7 @@ from sage.structure.list_clone import ClonableList from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent -from sage.combinat.partition import Partition, _Partitions +#from sage.combinat.partition import Partition, _Partitions @add_metaclass(InheritComparisonClasscallMetaclass) class PathTableau(ClonableList): @@ -291,9 +291,7 @@ def _test_commutation(self, **options): for i,j,r,s in combinations(range(1,n+1),4): lhs = self.cactus(i,j).cactus(r,s) rhs = self.cactus(r,s).cactus(i,j) - if lhs != rhs: - return False - return True + tester.assertTrue(lhs == rhs) def _test_coboundary(self, **options): """ @@ -313,9 +311,7 @@ def _test_coboundary(self, **options): for i,j,r,s in combinations(range(1,n+3),4): lhs = self.cactus(i,s-2).cactus(j-1,r-1) rhs = self.cactus(i+s-r-1,i+s-j-1).cactus(i,s-2) - if lhs != rhs: - return False - return True + tester.assertTrue(lhs == rhs) def orbit(self): """ @@ -331,7 +327,7 @@ def orbit(self): [0, 1, 2, 1, 2, 1, 0], [0, 1, 2, 3, 2, 1, 0]} """ - n = self.size() + orb = set([]) rec = set([self]) new = set([]) @@ -345,7 +341,7 @@ def orbit(self): rec = new.copy() new = set([]) - return orbit + return orb def dual_equivalence_graph(self): """ @@ -375,7 +371,7 @@ def dual_equivalence_graph(self): [0 1 1 1 0 0 1 1 1 1 1 0 1 1] [0 1 0 1 1 1 0 1 1 1 1 1 0 1] [0 0 0 0 1 0 1 0 0 1 1 1 1 0] - + """ from sage.graphs.graph import Graph from itertools import combinations From 800560cff5fcb0136736c25a3cb474c013da47c8 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Thu, 26 Jul 2018 19:11:15 +0100 Subject: [PATCH 031/300] Modified all.py --- src/sage/combinat/all.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 816a9ec2cef..9d20391da08 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -89,7 +89,7 @@ from .core import Core, Cores #Tableaux -lazy_import('sage.combinat.tableau',["Tableau", "SemistandardTableau", "StandardTableau", "RowStandardTableau", +lazy_import('sage.combinat.tableau',["Tableau", "SemistandardTableau", "StandardTableau", "RowStandardTableau", "Tableaux","SemistandardTableaux","StandardTableaux","RowStandardTableaux"]) from .skew_tableau import SkewTableau, SkewTableaux, StandardSkewTableaux, SemistandardSkewTableaux from .ribbon_shaped_tableau import RibbonShapedTableau, RibbonShapedTableaux, StandardRibbonShapedTableaux From 6229e0d6554077c74a5b8c47723fe56bce626a2f Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 27 Jul 2018 15:06:47 +0100 Subject: [PATCH 032/300] Semistandard removed --- src/sage/combinat/all.py | 6 +- src/sage/combinat/pathtableau/semistandard.py | 500 ------------------ 2 files changed, 3 insertions(+), 503 deletions(-) delete mode 100644 src/sage/combinat/pathtableau/semistandard.py diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 9d20391da08..6d1fb93f79e 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -220,6 +220,6 @@ 'GrowthDiagramYoungFibonacci', 'GrowthDiagramSylvester']) # Path tableaux -lazy_import('sage.combinat.pathtableau.pathtableaux',['PathTableau','PathTableaux']) -lazy_import('sage.combinat.pathtableau.catalan',['CatalanTableau','CatalanTableaux']) -lazy_import('sage.combinat.pathtableau.semistandard',['DualSemistandardTableau','DualSemistandardTableaux']) +lazy_import('sage.combinat.pathtableau.pathtableaux',['PathTableau', 'PathTableaux']) +lazy_import('sage.combinat.pathtableau.catalan',['CatalanTableau', 'CatalanTableaux']) + diff --git a/src/sage/combinat/pathtableau/semistandard.py b/src/sage/combinat/pathtableau/semistandard.py deleted file mode 100644 index f24c7afea68..00000000000 --- a/src/sage/combinat/pathtableau/semistandard.py +++ /dev/null @@ -1,500 +0,0 @@ -r""" -In this implementation we have sequences of partitions. These are in -bijection with dual semistandard tableaux. This gives an effective -version of operations on tableaux constructed using jeu-de-taquin. -In the standard constructions of these operations one usually assumes -the tableau is standard. - -For rectification and evacuation the operations here -agree with the standard construction. For promotion the construction -here agrees with the standard construction on rectangular standard -tableaux, but, in general, they are different. - -The operations here also give the Bender-Knuth involutions and -dual equivalence graphs. - -AUTHORS: - -- Bruce Westbury (2018): initial version -""" -#***************************************************************************** -# Copyright (C) 2018 Bruce Westbury , -# -# 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/ -#***************************************************************************** - -from six import add_metaclass -from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass -from sage.combinat.pathtableau.pathtableaux import PathTableau_partitions, PathTableaux -from sage.combinat.skew_tableau import SkewTableau -from sage.combinat.tableau import SemistandardTableau -from sage.combinat.partition import Partition - -""" -This implementation is on dual semistandard tableaux. This is the standard -context for jeu-de-taquin operations. Here we show that the constructions -here agree with the jeu-de-taquin constructions. Even in this standard context -our operations extend the standard definitions in the sense that the -constructions here are naturally defined for skew semistandard tableaux. -The only caveat is that the two constructions of promotion agree on rectangular -tableaux but are, in general, different. - --promotion --evacuation --rectify --multiply --Bender-Knuth - -EXAMPLES:: - - sage: T = DualSemistandardTableau([[],[1],[2],[2,1]]) - sage: T.evacuation() - [[], [1], [1, 1], [2, 1]] - - sage: Tableau([[1,2],[3]]).evacuation() - [[1, 3], [2]] - - sage: ST = SemistandardTableaux([5,3,3,2,1],[2,1,4,2,2,2,1]) - sage: ST.cardinality() - 84 - - sage: t = ST.an_element() - sage: s = DualSemistandardTableau(t.conjugate().to_chain()) - sage: v = Tableau(list(SkewTableau(chain=s.evacuation()))) - sage: v.conjugate() == t.evacuation() - True - - sage: ST = SemistandardTableaux([5,3,3,2,1],[2,1,4,2,2,2,1]) - sage: s = DualSemistandardTableau(ST.an_element()) - sage: s.check_involution_cactus() - True - - sage: s.check_commutation() - True - - sage: s.check_coboundary() - True - - sage: ST = StandardTableaux([3,3,3]) - sage: ST.cardinality() - 42 - - sage: t = ST.an_element() - sage: t.promotion() - [[1, 2, 5], [3, 6, 8], [4, 7, 9]] - - sage: ST = StandardTableaux([3,3,3]) - sage: t = ST.an_element() - sage: s = DualSemistandardTableau(t.to_chain()) - sage: u = StandardTableau(list(SkewTableau(chain=s.promotion()))) - sage: u.promotion() == t - True - - sage: ST.cardinality() - 42 - sage: t = ST.an_element() - sage: s = DualSemistandardTableau(t.to_chain()) - sage: len(s.orbit()) - 42 - -""" - -@add_metaclass(InheritComparisonClasscallMetaclass) -class DualSemistandardTableau(PathTableau_partitions): - """ - An instance is the sequence of partitions correspond to the - chain of partitions of a dual semistandard skew tableau. - - The acceptable inputs are: - - a sequence such that each term defines a partition - - a semistandard skew tableau - - EXAMPLES:: - - sage: DualSemistandardTableau([[],[1],[2],[2,1]]) - [[], [1], [2], [2, 1]] - - sage: t = SkewTableau([[None,None,None,4,4,5,6,7],[None,2,4,6,7,7,7],[None,4,5,8,8,9],[None,6,7,10],[None,8,8,11],[None],[4]]) - sage: DualSemistandardTableau(t) - [[6, 1, 1], [6, 1, 1], [6, 2, 1], [6, 2, 1], [7, 3, 2, 1, 1], [7, 3, 3, 1, 1, 1], [7, 4, 3, 2, 1, 1, 1], [7, 4, 4, 2, 2, 2, 2, 1], [7, 5, 5, 3, 3, 2, 2, 1], [7, 5, 5, 3, 3, 3, 2, 1], [7, 5, 5, 4, 3, 3, 2, 1], [7, 5, 5, 5, 3, 3, 2, 1]] - - """ - @staticmethod - def __classcall_private__(self, ot): - - w = None - - if isinstance(ot,(SkewTableau,SemistandardTableau)): - w = ot.conjugate().to_chain() - - if isinstance(ot,(list,tuple)): - try: - w = tuple([ Partition(a) for a in ot ]) - except TypeError: - raise ValueError("%s is not a sequence of partitions." % str(ot) ) - - if w == None: - raise ValueError( "Sorry, not sorry; I don't know what to do with %s." % str(ot) ) - - return DualSemistandardTableaux()(w) - - def _hash_(self): - return hash(tuple(map(tuple, self))) - - def check(self): - n = len(self) - for i in range(n-1): - h = self[i] - t = self[i+1] - if not t.contains(h): - raise ValueError( "%s must contain %s" % (str(t),str(h)) ) - for r, s in zip(h,t): - if s > r+1: - raise ValueError( "%s / %s is not a vertical strip" % (str(t),str(h)) ) - for a in t[len(h):]: - if a > 1: - raise ValueError( "%s / %s is not a vertical strip" % (str(t),str(h)) ) - - def evaluation(self): - z = [ p.size() for p in self ] - return [ z[i+1] - z[i] for i in range(len(self)-1) ] - - def to_tableau(self): - """ - Returns the conjugate skew tableau. This will be semistandard. - """ - ch = [ p.conjugate() for p in self] - s = SkewTableau(chain=ch) - if self.is_skew(): - return s - else: - return SemistandardTableau(list(s)) - - def is_skew(self): - """ - Returns True if Tableau is skew and False if not. - - EXAMPLE:: - sage: t = DualSemistandardTableau([[],[1],[2],[2,1]]) - sage: t.is_skew() - False - """ - return self[0] != Partition([]) - - def rectify(self,display=False): - """ - This is the same function as skew_tableau.rectify - - EXAMPLE:: - - sage: t = SkewTableau([[None,None,2,4],[1,3,5]]) - sage: s = DualSemistandardTableau(t.to_chain()) - sage: s.rectify(display=True) - [[2], [2, 1], [3, 1], [3, 2], [4, 2], [4, 3]] - [[1], [1, 1], [2, 1], [2, 2], [3, 2], [3, 3]] - [[], [1], [2], [2, 1], [3, 1], [3, 2]] - [[], [1], [2], [2, 1], [3, 1], [3, 2]] - - """ - p = self[0].conjugate() - path = [[]] - for i in range(len(p)): - path += [Partition(p[:i+1]).conjugate()] - - return DualSemistandardTableau(path).path_rule(self,display=display)[0] - - def multiply(self,other): - """ - This is the same function as tableau.slide_multiply and tableau.bump_multiply. - - EXAMPLE:: - - sage: t = DualSemistandardTableau([[2],[3,1],[4,1,1]]) - sage: t.multiply(t) - [[], [1, 1, 1, 1], [2, 2, 2, 1, 1]] - - """ - - left = list(self) - right = list(other) - - m = max([len(a) for a in right]) - n = max([ a[0] for a in left]) - - right = [a+[0]*(m-len(a)) for a in right] - - p = max(len(left),len(right)) - left = left + [left[-1]]*(p-len(left)) - right = right + [right[-1]]*(p-len(right)) - - result = [Partition([a+n for a in y]+list(x)) for x,y in zip(left,right)] - - return DualSemistandardTableau(result).rectify() - - def check_bender_knuth(self,i): - """ - Check that the i-th Bender-Knuth move on the conjugate - tableau is the i-th local rule. - - EXAMPLE:: - - sage: t = SemistandardTableaux(8).random_element() - sage: s = DualSemistandardTableau(t) - sage: s.check_bender_knuth(5) - True - sage: s.check_bender_knuth(4) - True - - """ - - lhs = self.local_rule(i).to_tableau() - rhs = self.to_tableau().bender_knuth_involution(i) - return lhs == rhs - - def check_rectify(self): - """ - Check that jdt-rectification on the conjugate tableaux - is the rectification defined here. - - EXAMPLE:: - - sage: t = SkewTableau([[None,None,1,3,3],[None,1,2,4],[2,2]]) - sage: s = DualSemistandardTableau(t) - sage: s.check_rectify() - True - - """ - - lhs = self.rectify().to_tableau() - rhs = self.to_tableau().rectify() - return lhs == rhs - - def check_evacuation(self): - """ - Check that jdt-evacuation on the conjugate tableaux - is the evacuation defined here. - - EXAMPLE:: - - sage: t = SemistandardTableaux(6).random_element() - sage: s = DualSemistandardTableau(t) - sage: s.check_evacuation() - True - - """ - lhs = self.evacuation().to_tableau() - rhs = self.to_tableau().evacuation() - return lhs == rhs - - def check_promotion(self): - """ - Check that jdt-promotion on the conjugate tableaux - is the promotion defined here. - - EXAMPLE:: - - sage: t = SemistandardTableaux(shape=[4,4,4],eval=[1]*12).an_element() - sage: s = DualSemistandardTableau(t) - sage: s.check_promotion() - True - - """ - lhs = self.promotion().to_tableau() - rhs = self.to_tableau().promotion_inverse(11) - return lhs == rhs - - - def plot(self): - """ - This provides a plot of the dual semistandard tableau. - PLOT:: - - sage: t = SkewTableau([[None,None,2,2],[3,4,4],[4]]) - sage: DualSemistandardTableau(t).plot() - Graphics object consisting of 16 graphics primitives - - """ - return self._plotC() - -class DualSemistandardTableaux(PathTableaux): - - Element = DualSemistandardTableau - -#### These functions don't belong here but I don't have a home for them. #### - -############################################################################# - - - -class PathTableaux(UniqueRepresentation,Parent): -# -# def __init__(self): -# Parent.__init__(self, category = Sets()) -# - def _element_constructor_(self, *args, **keywords): - return self.element_class(self, *args, **keywords) -# -# Element = PathTableau - -class PathTableau_partitions(PathTableau): - """ - This is an abstract base class. This class assumes that we have - a sequence of partitions. The main examples are the minuscule - representations of classical groups. - - TESTS:: - - sage: F = Foo() - sage: TestSuite(F).run() - """ - - @staticmethod - def _rule_(x): - y = map(list, x) - m = max(len(u) for u in y) # FIXME?: This will fail if y is empty - z = [u + [0]*(m-len(u)) for u in y] - result = [ abs(a-b+c) for a,b,c in zip(z[0],z[1],z[2]) ] - result.sort(reverse=True) - return _Partitions(result) - - def _plotL(self): - """ - This draws a plot of the sequence of partitions. - This plot assumes we do not have a chain of partitions - and plots the partitions in a line. - - PLOT:: - - sage: t = SkewTableau([[None,1,1],[2,2]]) - sage: s = DualSemistandardTableau(t) - sage: s._plotL() - Launched png viewer for Graphics object consisting of 11 graphics primitives - - """ - from sage.plot.graphics import Graphics - from sage.plot.line import line - from copy import copy - - global gap - gap = 1 - - def draw_partition(p,origin): - - global gap - - if p == _Partitions([]): - return point(origin,axes=False,size=60) - - r = origin[0] - s = origin[1] - - u = p.to_dyck_word() - u = u[u.index(0):] - u.reverse() - u = u[u.index(1):] - u.reverse() - x = u.count(0) - y = u.count(1) - - gap = max(x,gap) - n = len(u) - - edge = [] - edge.append([r,-y+s]) - for i in range(n): - v = copy(edge[i]) - if u[i] == 1: - v[1] += 1 - else: - v[0] += 1 - edge.append(v) - - G = Graphics() - G += line([(r,-y+s),(r,s),(r+x,s)],axes=False,thickness=2) - G += line(edge,color='red',axes=False,thickness=3) - - for i, a in enumerate(p[1:]): - G += line([(r,s-i-1),(r+a,s-i-1)],color='green') - - for i, a in enumerate(p.conjugate()[1:]): - G += line([(r+i+1,s),(r+i+1,s-a)],color='green') - - return G - - G = Graphics() - - for i, x in enumerate(self): - G += draw_partition(x, (i*gap+1.5*i,0)) - - G.set_aspect_ratio(1) - - return G - - def _plotC_(self): - """ - This draws a plot of the sequence of partitions. - This plot assumes the sequence is not a chain and so - plots the sequence. - - PLOT:: - - sage: t = SkewTableau([[None,1,1],[2,2]]) - sage: s = DualSemistandardTableau(t) - sage: s._plotC_() - Launched png viewer for Graphics object consisting of 10 graphics primitives - - """ - from sage.plot.graphics import Graphics - from sage.plot.line import line - from copy import copy - - def draw_partition(p): - - if p == _Partitions([]): - return point((0,0),axes=False,size=60) - - u = p.to_dyck_word() - u = u[u.index(0):] - u.reverse() - u = u[u.index(1):] - u.reverse() - x = u.count(0) - y = u.count(1) - - n = len(u) - - edge = [] - edge.append([0,-y]) - for i in range(n): - v = copy(edge[i]) - if u[i] == 1: - v[1] += 1 - else: - v[0] += 1 - edge.append(v) - - return line(edge,color='red',axes=False,thickness=3) - - p = self.final_shape() - - G = line([(0,-len(p)),(0,0),(p[0],0)],axes=False) - - for i, a in enumerate(p[1:]): - G += line([(0,-i-1),(a,-i-1)],color='green') - - for i, a in enumerate(p.conjugate()[1:]): - G += line([(i+1,0),(i+1,-a)],color='green') - - for i, x in enumerate(self): - G += draw_partition(x) - - for p in self: - G += draw_partition(p) - - G.set_aspect_ratio(1) - - return G \ No newline at end of file From efdd91d74bd3b437a4e0114dfefba8fb695a0c2a Mon Sep 17 00:00:00 2001 From: Ben Salisbury Date: Fri, 27 Jul 2018 12:47:23 -0400 Subject: [PATCH 033/300] Documentation updates --- src/doc/en/reference/combinat/module_list.rst | 2 + src/sage/combinat/all.py | 3 +- src/sage/combinat/pathtableau/catalan.py | 38 +++++---- src/sage/combinat/pathtableau/pathtableaux.py | 85 +++++++++++-------- 4 files changed, 72 insertions(+), 56 deletions(-) diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst index 64ee0fbd844..baa1586a70c 100644 --- a/src/doc/en/reference/combinat/module_list.rst +++ b/src/doc/en/reference/combinat/module_list.rst @@ -171,6 +171,8 @@ Comprehensive Module list sage/combinat/ordered_tree sage/combinat/output sage/combinat/parking_functions + sage/combinat/pathtableau/catalan + sage/combinat/pathtableau/pathtableaux sage/combinat/plane_partition sage/combinat/partition sage/combinat/partition_algebra diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 6d1fb93f79e..b772ea48dae 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -220,6 +220,5 @@ 'GrowthDiagramYoungFibonacci', 'GrowthDiagramSylvester']) # Path tableaux -lazy_import('sage.combinat.pathtableau.pathtableaux',['PathTableau', 'PathTableaux']) -lazy_import('sage.combinat.pathtableau.catalan',['CatalanTableau', 'CatalanTableaux']) +from sage.combinat.pathtableau.all import * diff --git a/src/sage/combinat/pathtableau/catalan.py b/src/sage/combinat/pathtableau/catalan.py index de4a8b24337..b6c0851f9ee 100644 --- a/src/sage/combinat/pathtableau/catalan.py +++ b/src/sage/combinat/pathtableau/catalan.py @@ -1,5 +1,8 @@ r""" -This is an implementation of the abstract base class PathTableaux. +Catalan Tableaux + +This is an implementation of the abstract base class +:class:`sage.combinat.pathtableau.pathtableaux`. This is the simplest implementation of PathTableaux and is included to provide a convenient test case and for pedagogical purposes. @@ -76,13 +79,14 @@ class CatalanTableau(PathTableau): """ An instance is the sequence of nonnegative - integers given by the heights of a Dyck word. The acceptable inputs - are: + integers given by the heights of a Dyck word. + + INPUT: - - a sequence of nonnegative integers - - a two row standard skew tableau - - a Dyck word - - a noncrossing perfect matching + - a sequence of nonnegative integers + - a two row standard skew tableau + - a Dyck word + - a noncrossing perfect matching EXAMPLES:: @@ -145,10 +149,10 @@ def __classcall_private__(cls, ot): def check(self): """ - This overwrites the abstract method. + Overwrites the abstract method. This checks that heights are nonnegative and that succesive heights - differ by +1 or -1. + differ by `+1` or `-1`. EXAMPLES:: @@ -176,13 +180,13 @@ def check(self): @staticmethod def _rule_(x): """ - This overwrites the abstract method. + Overwrites the abstract method. """ return abs(x[0]-x[1]+x[2]) def is_skew(self): """ - Returns True if Tableau is skew and False if not. + Return ``True`` if ``self`` is skew and ``False`` if not. EXAMPLES:: @@ -197,7 +201,7 @@ def is_skew(self): def descents(self): """ - Returns the descent set. + Return the descent set of ``self``. EXAMPLES:: @@ -215,7 +219,7 @@ def descents(self): def to_word(self): """ - Converts to a word in the alphabet 0,1 + Return the word in the alphabet `\{0,1\}` associated to ``self``. EXAMPLES:: @@ -227,7 +231,7 @@ def to_word(self): def to_perfect_matching(self): """ - This converts to a perfect matching. + Return the perfect matching associated to ``self``. EXAMPLES:: @@ -245,7 +249,7 @@ def to_perfect_matching(self): def to_tableau(self): """ - Converts to a skew tableau. + Return the skew tableau associated to ``self``. """ w = self.to_word() top = [ i for i, a in enumerate(w) if a == 1 ] @@ -254,7 +258,7 @@ def to_tableau(self): def draw(self): """ - This draws the Dyck path. + Return the Dyck path associated to ``self``. """ return line([ (i,a) for i, a in enumerate(self)]) @@ -270,4 +274,4 @@ def draw(self): class CatalanTableaux(PathTableaux): - Element = CatalanTableau \ No newline at end of file + Element = CatalanTableau diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index 8689360d569..8a0ffa1ab3b 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -1,4 +1,6 @@ r""" +Path Tableaux + This is an abstract base class for using local rules to construct rectification and the action of the cactus group. This is an effective version of the Henriques-Kamnitzer construction of the action of the cactus @@ -51,19 +53,19 @@ def _rule_(self,p): def size(self): """ - Returns the size or length. + Return the size or length. """ return len(self) def initial_shape(self): """ - Returns the initial shape. + Return the initial shape. """ return self[0] def final_shape(self): """ - Returns the final shape. + Return the final shape. """ return self[-1] @@ -73,9 +75,9 @@ def local_rule(self,i): """ This is the local that is used for the remaining constructions. This has input a list of objects. This method first takes - the list of objects of length three consisting of the $(i-1)$-st, - $i$-th and $(i+1)$-term and applies the rule. It then replaces - the $i$-th object by the object returned by the rule. + the list of objects of length three consisting of the `(i-1)`-st, + `i`-th and `(i+1)`-term and applies the rule. It then replaces + the `i`-th object by the object returned by the rule. """ if not (i > 0 and i < len(self) ): raise ValueError("%d is not a valid integer" % i) @@ -87,7 +89,9 @@ def local_rule(self,i): def promotion(self): """ - The promotion operator. This is given by a two row diagram. + Return the promotion operator applied to ``self``. + + This is given by a two row diagram. """ result = list(self) for i in range(1,len(result)-1): @@ -96,11 +100,17 @@ def promotion(self): def evacuation(self): """ - The evacuation operator. This is given by a triangular diagram. + Return the evacuation operator applied to ``self``. + + This is given by a triangular diagram. - INPUT: A pathtableau + INPUT: - OUTPUT: A pathtableau + - A pathtableau + + OUTPUT: + + - A pathtableau The output will have the same length, initial shape, and final shape as the input. @@ -127,10 +137,10 @@ def evacuation(self): def path_rule(self,other,display=False): """ - This constructs the commutor of a pair of tableaux. - This is given by a rectangular diagram. + Return the commutor of ``self`` with ``other`` - If display=True then the function will print + This is given by a rectangular diagram. + If ``display=True`` then the function will print the rectangle. """ n = len(self) @@ -160,15 +170,20 @@ def path_rule(self,other,display=False): def cactus(self,i,j): """ - This constructs the action of the generators of the cactus group. + Return the action of the generators of the cactus group on ``self``. These generators are involutions and are usually denoted by - $s_{i,\,j$}$. + `s_{i,j}`. - INPUT: A pathtableau, i >0, j >i + INPUT: - OUTPUT: A pathtableau + - A pathtableau, with `i >0` and `j >i` - The output will have the same length, initial shape, and final shape as the input. + OUTPUT: + + - A pathtableau + + The output will have the same length, initial shape, and final shape + as the input. EXAMPLES:: @@ -205,11 +220,12 @@ def cactus(self,i,j): def cylindrical_diagram(self): """ - This constructs the cylindrical growth diagram. This provides - a visual summary of several operations simultaneously. The - operations which can be read off directly from this diagram + Return the cylindrical growth diagram associated to ``self``. + + This provides a visual summary of several operations simultaneously. + The operations which can be read off directly from this diagram are the powers of the promotion operator (which form the rows) - and the cactus group operators $s_{1,\,j$}$ (which form the + and the cactus group operators `s_{1,j}` (which form the first half of the columns). EXAMPLES:: @@ -235,8 +251,7 @@ def cylindrical_diagram(self): def _test_involution_rule(self, **options): """ - This is to check that the local rule gives an involution. - This is crucial. + Check that the local rule gives an involution. TESTS:: @@ -250,8 +265,7 @@ def _test_involution_rule(self, **options): def _test_involution_cactus(self, **options): """ - This is to check that the cactus group generators are - involutions. + Check that the cactus group generators are involutions. TESTS:: @@ -264,8 +278,7 @@ def _test_involution_cactus(self, **options): def _test_promotion(self, **options): """ - Promotion can be expressed in terms of the cactus generators. - Here we check this relation. + Check that promotion can be expressed in terms of the cactus generators. TESTS:: @@ -279,8 +292,7 @@ def _test_promotion(self, **options): def _test_commutation(self, **options): """ - This is to check the commutation relations in the presentation - of the cactus group. + Check the commutation relations in the presentation of the cactus group. """ from itertools import combinations tester = self._tester(**options) @@ -295,8 +307,7 @@ def _test_commutation(self, **options): def _test_coboundary(self, **options): """ - This is to check the coboundary relations in the presentation - of the cactus group. + Check the coboundary relations in the presentation of the cactus group. EXAMPLES:: @@ -315,7 +326,7 @@ def _test_coboundary(self, **options): def orbit(self): """ - Constructs the orbit under the action of the cactus group. + Return the orbit under the action of the cactus group. EXAMPLES:: @@ -345,12 +356,12 @@ def orbit(self): def dual_equivalence_graph(self): """ - This constructs the graph with vertices the orbit of self + Return the graph with vertices the orbit of ``self`` and edges given by the action of the cactus group generators. - In most implementations the generators $s_{i,\,i+1}$ will act + In most implementations the generators `s_{i,i+1}` will act as the identity operators. The usual dual equivalence graphs - are given by replacing the label $i,i+2$ by $i$ and removing + are given by replacing the label `i,i+2` by `i` and removing edges with other labels. EXAMPLES:: @@ -394,4 +405,4 @@ class PathTableaux(UniqueRepresentation,Parent): def _element_constructor_(self, *args, **keywords): return self.element_class(self, *args, **keywords) # -# Element = PathTableau \ No newline at end of file +# Element = PathTableau From a3a6472ce2f82f2017e087ea9d55d5e02f317f13 Mon Sep 17 00:00:00 2001 From: Ben Salisbury Date: Fri, 27 Jul 2018 15:40:19 -0400 Subject: [PATCH 034/300] Doctests added --- src/sage/combinat/pathtableau/catalan.py | 29 ++++-- src/sage/combinat/pathtableau/pathtableaux.py | 99 ++++++++++++------- 2 files changed, 88 insertions(+), 40 deletions(-) diff --git a/src/sage/combinat/pathtableau/catalan.py b/src/sage/combinat/pathtableau/catalan.py index b6c0851f9ee..eed93348814 100644 --- a/src/sage/combinat/pathtableau/catalan.py +++ b/src/sage/combinat/pathtableau/catalan.py @@ -99,7 +99,6 @@ class CatalanTableau(PathTableau): sage: p = PerfectMatching([(1,2),(3,4)]) sage: CatalanTableau(p) - ... [1, 0, 1, 0] sage: t = Tableau([[1,2],[3,4]]) @@ -181,6 +180,14 @@ def check(self): def _rule_(x): """ Overwrites the abstract method. + + EXAMPLES:: + + sage: T = CatalanTableau([0,1,2,3,2,3]) + sage: T._rule_([1,2,1]) + 0 + sage: T._rule_([0,1,0]) + 1 """ return abs(x[0]-x[1]+x[2]) @@ -195,7 +202,6 @@ def is_skew(self): sage: CatalanTableau([1,0,1,2,1]).is_skew() True - """ return self[0] != 0 @@ -207,7 +213,6 @@ def descents(self): sage: CatalanTableau([0,1,2,1,2,1,0,1,0]).descents() {3, 6} - """ result = set() @@ -225,7 +230,6 @@ def to_word(self): sage: CatalanTableau([1,0,1,2,1]).to_word() [0, 1, 1, 0] - """ return [ (self[i+1]-self[i]+1)/2 for i in range(self.size()-1) ] @@ -250,16 +254,29 @@ def to_perfect_matching(self): def to_tableau(self): """ Return the skew tableau associated to ``self``. + + EXAMPLES:: + + sage: T = CatalanTableau([0,1,2,3,2,3]) + sage: T.to_tableau() + [[0, 1, 2, 4], [3]] """ w = self.to_word() top = [ i for i, a in enumerate(w) if a == 1 ] bot = [ i for i, a in enumerate(w) if a == 0 ] return SkewTableau([[None]*self[0]+top,bot]) - def draw(self): + def show(self): """ - Return the Dyck path associated to ``self``. + Return the plot of the Dyck path associated to ``self``. + + EXAMPLES:: + + sage: T = CatalanTableau([0,1,2,3,2,3]) + sage: T.show() + Graphics object consisting of 1 graphics primitive """ + from sage.plot.line import line return line([ (i,a) for i, a in enumerate(self)]) #class PathTableaux(UniqueRepresentation,Parent): diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index 8a0ffa1ab3b..79b1a7aa503 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -42,7 +42,8 @@ class PathTableau(ClonableList): def _rule_(self,p): """ This is an abstract method. It must be overwritten. - This rule provides the functionality. It is called in local_rule. + This rule provides the functionality. It is called in + :method:`_local_rule`. The key property is that the following operation on lists of length three is an involution: apply the rule to a list @@ -53,31 +54,55 @@ def _rule_(self,p): def size(self): """ - Return the size or length. + Return the size or length of ``self``. + + EXAMPLES:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t.size() + 7 """ return len(self) def initial_shape(self): """ - Return the initial shape. + Return the initial shape of ``self``. + + EXAMPLES:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t.initial_shape() + 0 """ return self[0] def final_shape(self): """ - Return the final shape. + Return the final shape of ``self``. + + EXAMPLES:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t.final_shape() + 0 """ return self[-1] ############################# Jeu de taquin ################################### - def local_rule(self,i): + def _local_rule(self,i): """ This is the local that is used for the remaining constructions. This has input a list of objects. This method first takes the list of objects of length three consisting of the `(i-1)`-st, `i`-th and `(i+1)`-term and applies the rule. It then replaces the `i`-th object by the object returned by the rule. + + EXAMPLES:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t._local_rule(3) + [0, 1, 2, 1, 2, 1, 0] """ if not (i > 0 and i < len(self) ): raise ValueError("%d is not a valid integer" % i) @@ -91,7 +116,11 @@ def promotion(self): """ Return the promotion operator applied to ``self``. - This is given by a two row diagram. + EXAMPLES:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t.promotion() + [0, 1, 2, 1, 0, 1, 0] """ result = list(self) for i in range(1,len(result)-1): @@ -102,25 +131,11 @@ def evacuation(self): """ Return the evacuation operator applied to ``self``. - This is given by a triangular diagram. - - INPUT: - - - A pathtableau - - OUTPUT: - - - A pathtableau - - The output will have the same length, initial shape, and final shape as the input. - EXAMPLES:: sage: t = CatalanTableau([0,1,2,3,2,1,0]) sage: t.evacuation() [0, 1, 2, 3, 2, 1, 0] - - """ if self.size() < 3: return self @@ -135,13 +150,28 @@ def evacuation(self): result.reverse() return self.parent()(result) - def path_rule(self,other,display=False): + def commutor(self,other,display=False): """ Return the commutor of ``self`` with ``other`` - This is given by a rectangular diagram. If ``display=True`` then the function will print the rectangle. + + EXAMPLES:: + + sage: t1 = CatalanTableau([0,1,2,3,2,1,0]) + sage: t2 = CatalanTableau([0,1,2,1,0]) + sage: t1.commutor(t2) + ([0, 1, 2, 1, 0], [0, 1, 2, 3, 2, 1, 0]) + sage: t1.commutor(t2,display=True) + [0, 1, 2, 1, 0] + [1, 2, 3, 2, 1] + [2, 3, 4, 3, 2] + [3, 4, 5, 4, 3] + [2, 3, 4, 3, 2] + [1, 2, 3, 2, 1] + [0, 1, 2, 1, 0] + ([0, 1, 2, 1, 0], [0, 1, 2, 3, 2, 1, 0]) """ n = len(self) m = len(other) @@ -161,7 +191,7 @@ def path_rule(self,other,display=False): if display: print path[n-i:n+m-i] for j in range(m-1): - path = path.local_rule(n+j-i) + path = path._local_rule(n+j-i) if display: print path[:m] @@ -176,14 +206,10 @@ def cactus(self,i,j): INPUT: - - A pathtableau, with `i >0` and `j >i` - - OUTPUT: + - ``i`` -- a positive integer - - A pathtableau + - ``j`` -- a positive integer strictly greater than ``i`` - The output will have the same length, initial shape, and final shape - as the input. EXAMPLES:: @@ -260,7 +286,7 @@ def _test_involution_rule(self, **options): """ tester = self._tester(**options) - tester.assertTrue(all( self.local_rule(i+1).local_rule(i+1) == self + tester.assertTrue(all( self._local_rule(i+1)._local_rule(i+1) == self for i in range(self.size()-2) )) def _test_involution_cactus(self, **options): @@ -284,7 +310,6 @@ def _test_promotion(self, **options): sage: t = CatalanTableau([0,1,2,3,2,1,0]) sage: t._test_promotion() - """ tester = self._tester(**options) n = self.size()-1 @@ -293,6 +318,11 @@ def _test_promotion(self, **options): def _test_commutation(self, **options): """ Check the commutation relations in the presentation of the cactus group. + + TESTS:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t._test_commutation() """ from itertools import combinations tester = self._tester(**options) @@ -309,9 +339,10 @@ def _test_coboundary(self, **options): """ Check the coboundary relations in the presentation of the cactus group. - EXAMPLES:: + TESTS:: - t = + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t._test_coboundary() """ from itertools import combinations tester = self._tester(**options) @@ -326,7 +357,7 @@ def _test_coboundary(self, **options): def orbit(self): """ - Return the orbit under the action of the cactus group. + Return the orbit of ``self`` under the action of the cactus group. EXAMPLES:: From f4b5642cbbfc2eb13c1d10299560c5af84437b18 Mon Sep 17 00:00:00 2001 From: Ben Salisbury Date: Fri, 27 Jul 2018 15:50:14 -0400 Subject: [PATCH 035/300] updated all.py --- src/sage/combinat/all.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index b772ea48dae..23c7d2722b8 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -220,5 +220,5 @@ 'GrowthDiagramYoungFibonacci', 'GrowthDiagramSylvester']) # Path tableaux -from sage.combinat.pathtableau.all import * +from .pathtableau.all import * From 3d2f309cbe680bf1004fa83f363e06aca68be00b Mon Sep 17 00:00:00 2001 From: Ben Salisbury Date: Fri, 27 Jul 2018 15:55:49 -0400 Subject: [PATCH 036/300] git added all.py and __init__.py --- src/sage/combinat/pathtableau/__init__.py | 7 +++++++ src/sage/combinat/pathtableau/all.py | 4 ++++ 2 files changed, 11 insertions(+) create mode 100644 src/sage/combinat/pathtableau/__init__.py create mode 100644 src/sage/combinat/pathtableau/all.py diff --git a/src/sage/combinat/pathtableau/__init__.py b/src/sage/combinat/pathtableau/__init__.py new file mode 100644 index 00000000000..efc26debc3b --- /dev/null +++ b/src/sage/combinat/pathtableau/__init__.py @@ -0,0 +1,7 @@ +r""" +Path Tableaux +============= + +- :ref:`sage.combinat.pathtableau.pathtableaux` +- :ref:`sage.combinat.pathtableau.catalan` +""" diff --git a/src/sage/combinat/pathtableau/all.py b/src/sage/combinat/pathtableau/all.py new file mode 100644 index 00000000000..924d2e938eb --- /dev/null +++ b/src/sage/combinat/pathtableau/all.py @@ -0,0 +1,4 @@ +from __future__ import absolute_import + +from .pathtableaux import PathTableau, PathTableaux +from .catalan import CatalanTableau, CatalanTableaux From 29b940175c2859133b308ef36aa091b81049b391 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 31 Aug 2018 12:12:24 +0100 Subject: [PATCH 037/300] Make print compatible with python3 and change _rule_ to _rule --- src/sage/combinat/pathtableau/catalan.py | 6 +++--- src/sage/combinat/pathtableau/pathtableaux.py | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/combinat/pathtableau/catalan.py b/src/sage/combinat/pathtableau/catalan.py index eed93348814..d9cdd4d9fc9 100644 --- a/src/sage/combinat/pathtableau/catalan.py +++ b/src/sage/combinat/pathtableau/catalan.py @@ -177,16 +177,16 @@ def check(self): raise ValueError( "%s is not a Dyck path" % (str(self)) ) @staticmethod - def _rule_(x): + def _rule(x): """ Overwrites the abstract method. EXAMPLES:: sage: T = CatalanTableau([0,1,2,3,2,3]) - sage: T._rule_([1,2,1]) + sage: T._rule([1,2,1]) 0 - sage: T._rule_([0,1,0]) + sage: T._rule([0,1,0]) 1 """ return abs(x[0]-x[1]+x[2]) diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index 79b1a7aa503..bf0f2f6ae75 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -39,7 +39,7 @@ @add_metaclass(InheritComparisonClasscallMetaclass) class PathTableau(ClonableList): @abstract_method(optional=False) - def _rule_(self,p): + def _rule(self,p): """ This is an abstract method. It must be overwritten. This rule provides the functionality. It is called in @@ -108,7 +108,7 @@ def _local_rule(self,i): raise ValueError("%d is not a valid integer" % i) result = list(self) - result[i] = self._rule_(self[i-1:i+2]) + result[i] = self._rule(self[i-1:i+2]) return self.parent()(result) @@ -124,7 +124,7 @@ def promotion(self): """ result = list(self) for i in range(1,len(result)-1): - result[i] = self._rule_(result[i-1:i+2]) + result[i] = self._rule(result[i-1:i+2]) return self.parent()(result) def evacuation(self): @@ -189,11 +189,11 @@ def commutor(self,other,display=False): for i in range(1,n): if display: - print path[n-i:n+m-i] + print(path[n-i:n+m-i]) for j in range(m-1): path = path._local_rule(n+j-i) if display: - print path[:m] + print(path[:m]) return (self.parent()(path[:m]),self.parent()(path[m-1:])) From 2a1af0b6e1dccaac68802b7f14574a4d797438da Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 31 Aug 2018 12:42:09 +0100 Subject: [PATCH 038/300] Typo and _rule made static --- src/sage/combinat/pathtableau/pathtableaux.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index bf0f2f6ae75..ba25310fd45 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -38,8 +38,9 @@ @add_metaclass(InheritComparisonClasscallMetaclass) class PathTableau(ClonableList): + @staticmethod @abstract_method(optional=False) - def _rule(self,p): + def _rule(p): """ This is an abstract method. It must be overwritten. This rule provides the functionality. It is called in @@ -92,7 +93,7 @@ def final_shape(self): def _local_rule(self,i): """ - This is the local that is used for the remaining constructions. + This is the local rule that is used for the remaining constructions. This has input a list of objects. This method first takes the list of objects of length three consisting of the `(i-1)`-st, `i`-th and `(i+1)`-term and applies the rule. It then replaces From baae1df5d51fb047f87093ee39bbe074bf042a96 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 31 Aug 2018 14:06:05 +0100 Subject: [PATCH 039/300] Reference added --- src/sage/combinat/pathtableau/pathtableaux.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index ba25310fd45..b236926c9e5 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -13,6 +13,10 @@ by jeu-de-taquin as does evacuation. Promotion agrees with promotion by jeu-de-taquin on rectangular tableaux but in general they are different. +REFERENCES: + +- Coboundary categories and local rules :arxiv:'1705.07141 + AUTHORS: - Bruce Westbury (2018): initial version From a716ba8f82573f5625ef133bf733fe0ee64d5a73 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 31 Aug 2018 14:20:04 +0100 Subject: [PATCH 040/300] Reference changed --- src/sage/combinat/pathtableau/pathtableaux.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index b236926c9e5..bcda7af5fb8 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -15,9 +15,11 @@ REFERENCES: -- Coboundary categories and local rules :arxiv:'1705.07141 + .. [Wes2017] Bruce Westbury. + *Coboundary categories and local rules*, + :arxiv:'1705.07141 -AUTHORS: +AUTHORS: - Bruce Westbury (2018): initial version """ From e36c89bfe892823b118467c0445ec2e69b914031 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 31 Aug 2018 14:23:19 +0100 Subject: [PATCH 041/300] Fixed reference --- src/sage/combinat/pathtableau/pathtableaux.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index bcda7af5fb8..cf3f81bea69 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -17,7 +17,7 @@ .. [Wes2017] Bruce Westbury. *Coboundary categories and local rules*, - :arxiv:'1705.07141 + :arxiv:'1705.07141' AUTHORS: From 52b8488f90bf6cd5175c4999f63477079e91d1b8 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 31 Aug 2018 14:26:41 +0100 Subject: [PATCH 042/300] Ref --- src/sage/combinat/pathtableau/pathtableaux.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index cf3f81bea69..95a8004aa01 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -14,12 +14,12 @@ by jeu-de-taquin on rectangular tableaux but in general they are different. REFERENCES: - + .. [Wes2017] Bruce Westbury. *Coboundary categories and local rules*, :arxiv:'1705.07141' -AUTHORS: +AUTHORS: - Bruce Westbury (2018): initial version """ From f03e4766fa8b6ad78f7f054e32f6be65f3a518c1 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 31 Aug 2018 14:28:43 +0100 Subject: [PATCH 043/300] Ref --- src/sage/combinat/pathtableau/pathtableaux.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index 95a8004aa01..f89d5eb9884 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -15,9 +15,9 @@ REFERENCES: - .. [Wes2017] Bruce Westbury. - *Coboundary categories and local rules*, - :arxiv:'1705.07141' +.. [Wes2017] Bruce Westbury. +*Coboundary categories and local rules*, +:arxiv:'1705.07141' AUTHORS: From 295aeebb0a9eeb04aa3e0d5b37f957775e8cfe76 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 31 Aug 2018 14:31:33 +0100 Subject: [PATCH 044/300] Ref --- src/sage/combinat/pathtableau/pathtableaux.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index f89d5eb9884..a5f0df8e06c 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -16,8 +16,8 @@ REFERENCES: .. [Wes2017] Bruce Westbury. -*Coboundary categories and local rules*, -:arxiv:'1705.07141' + *Coboundary categories and local rules*, + :arxiv:'1705.07141' AUTHORS: From 269ded8f14063d4227ba05ec6b4a95975721bd2b Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 31 Aug 2018 14:56:38 +0100 Subject: [PATCH 045/300] Ref --- src/sage/combinat/pathtableau/pathtableaux.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index a5f0df8e06c..ef75e754624 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -2,7 +2,9 @@ Path Tableaux This is an abstract base class for using local rules to construct rectification -and the action of the cactus group. This is an effective version +and the action of the cactus group, [Wes2017]_ + +This is an effective version of the Henriques-Kamnitzer construction of the action of the cactus group on tensor powers of a crystal. This is a generalisation of the Fomin growth rules which are an effective version of the operations From 340117e2904c628dd1f75c8366b6ec7fa7919468 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 31 Aug 2018 15:02:24 +0100 Subject: [PATCH 046/300] Ref --- src/sage/combinat/pathtableau/pathtableaux.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index ef75e754624..ee1147e4302 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -19,7 +19,7 @@ .. [Wes2017] Bruce Westbury. *Coboundary categories and local rules*, - :arxiv:'1705.07141' + :arxiv:`1705.07141` AUTHORS: From c3cde2ee190b1f37454d940b5268a5fdf966f2c7 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sat, 1 Sep 2018 11:35:44 +0100 Subject: [PATCH 047/300] Used clone --- src/sage/combinat/pathtableau/pathtableaux.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index ee1147e4302..1c4dd0adbaa 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -116,10 +116,10 @@ def _local_rule(self,i): if not (i > 0 and i < len(self) ): raise ValueError("%d is not a valid integer" % i) - result = list(self) - result[i] = self._rule(self[i-1:i+2]) + with self.clone() as result: + result[i] = self._rule(self[i-1:i+2]) - return self.parent()(result) + return result def promotion(self): """ From 5dcc3364869ff867afb6def5616fcc43432d1002 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sat, 1 Sep 2018 11:40:10 +0100 Subject: [PATCH 048/300] Another clone --- src/sage/combinat/pathtableau/pathtableaux.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index 1c4dd0adbaa..ce165ff9189 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -131,10 +131,11 @@ def promotion(self): sage: t.promotion() [0, 1, 2, 1, 0, 1, 0] """ - result = list(self) - for i in range(1,len(result)-1): - result[i] = self._rule(result[i-1:i+2]) - return self.parent()(result) + with self.clone() as result: + for i in range(1,len(result)-1): + result[i] = self._rule(result[i-1:i+2]) + + return result def evacuation(self): """ From d346b00f0dbf9db66d8b449ad4753d1ea921c966 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sat, 1 Sep 2018 12:54:55 +0100 Subject: [PATCH 049/300] Element added --- src/sage/combinat/pathtableau/pathtableaux.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index ce165ff9189..36ff1b1687e 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -42,10 +42,9 @@ from sage.structure.list_clone import ClonableList from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent -#from sage.combinat.partition import Partition, _Partitions @add_metaclass(InheritComparisonClasscallMetaclass) -class PathTableau(ClonableList): +class PathTableau(ClonableList,Element): @staticmethod @abstract_method(optional=False) def _rule(p): @@ -439,11 +438,11 @@ def dual_equivalence_graph(self): return G class PathTableaux(UniqueRepresentation,Parent): -# -# def __init__(self): -# Parent.__init__(self, category = Sets()) -# + + def __init__(self): + Parent.__init__(self, category = Sets()) + def _element_constructor_(self, *args, **keywords): return self.element_class(self, *args, **keywords) -# -# Element = PathTableau + + Element = PathTableau From 88862d605b30c1321ab627e2e260159f31b2167a Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sat, 1 Sep 2018 12:56:25 +0100 Subject: [PATCH 050/300] Element imported --- src/sage/combinat/pathtableau/pathtableaux.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index 36ff1b1687e..5889c6acc1f 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -42,6 +42,7 @@ from sage.structure.list_clone import ClonableList from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent +from sage.structure.element import Element @add_metaclass(InheritComparisonClasscallMetaclass) class PathTableau(ClonableList,Element): From 124c505519c3e6b734b3c2ea6d62036b953e0244 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sat, 1 Sep 2018 13:02:56 +0100 Subject: [PATCH 051/300] Sets --- src/sage/combinat/pathtableau/pathtableaux.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index 5889c6acc1f..d3c0415df5b 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -40,6 +40,7 @@ from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.misc.abstract_method import abstract_method from sage.structure.list_clone import ClonableList +from sage.categories.sets_cat import Sets from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.structure.element import Element From 954048ed9f852c03e681f253982f9a1b1297428b Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sat, 1 Sep 2018 13:34:11 +0100 Subject: [PATCH 052/300] Element removed --- src/sage/combinat/pathtableau/pathtableaux.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableau/pathtableaux.py index d3c0415df5b..27900bb3353 100644 --- a/src/sage/combinat/pathtableau/pathtableaux.py +++ b/src/sage/combinat/pathtableau/pathtableaux.py @@ -43,10 +43,9 @@ from sage.categories.sets_cat import Sets from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent -from sage.structure.element import Element @add_metaclass(InheritComparisonClasscallMetaclass) -class PathTableau(ClonableList,Element): +class PathTableau(ClonableList): @staticmethod @abstract_method(optional=False) def _rule(p): From 57c76e2b1de40439a4d1f3ff30babe4109784645 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sat, 1 Sep 2018 13:44:26 +0100 Subject: [PATCH 053/300] Directory and filename changed --- src/sage/combinat/pathtableau/__init__.py | 7 ------- src/sage/combinat/{pathtableau => pathtableaux}/all.py | 0 src/sage/combinat/{pathtableau => pathtableaux}/catalan.py | 0 .../pathtableaux.py => pathtableaux/pathtableau.py} | 0 4 files changed, 7 deletions(-) delete mode 100644 src/sage/combinat/pathtableau/__init__.py rename src/sage/combinat/{pathtableau => pathtableaux}/all.py (100%) rename src/sage/combinat/{pathtableau => pathtableaux}/catalan.py (100%) rename src/sage/combinat/{pathtableau/pathtableaux.py => pathtableaux/pathtableau.py} (100%) diff --git a/src/sage/combinat/pathtableau/__init__.py b/src/sage/combinat/pathtableau/__init__.py deleted file mode 100644 index efc26debc3b..00000000000 --- a/src/sage/combinat/pathtableau/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -r""" -Path Tableaux -============= - -- :ref:`sage.combinat.pathtableau.pathtableaux` -- :ref:`sage.combinat.pathtableau.catalan` -""" diff --git a/src/sage/combinat/pathtableau/all.py b/src/sage/combinat/pathtableaux/all.py similarity index 100% rename from src/sage/combinat/pathtableau/all.py rename to src/sage/combinat/pathtableaux/all.py diff --git a/src/sage/combinat/pathtableau/catalan.py b/src/sage/combinat/pathtableaux/catalan.py similarity index 100% rename from src/sage/combinat/pathtableau/catalan.py rename to src/sage/combinat/pathtableaux/catalan.py diff --git a/src/sage/combinat/pathtableau/pathtableaux.py b/src/sage/combinat/pathtableaux/pathtableau.py similarity index 100% rename from src/sage/combinat/pathtableau/pathtableaux.py rename to src/sage/combinat/pathtableaux/pathtableau.py From 8df41aca572414969078dcc5d083bee05cf1d1d1 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sat, 1 Sep 2018 13:47:12 +0100 Subject: [PATCH 054/300] Edit to all.py --- src/sage/combinat/all.py | 2 +- src/sage/combinat/pathtableaux/all.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 23c7d2722b8..4ecbf9524be 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -220,5 +220,5 @@ 'GrowthDiagramYoungFibonacci', 'GrowthDiagramSylvester']) # Path tableaux -from .pathtableau.all import * +from .pathtableaux.all import * diff --git a/src/sage/combinat/pathtableaux/all.py b/src/sage/combinat/pathtableaux/all.py index 924d2e938eb..122a2cb221c 100644 --- a/src/sage/combinat/pathtableaux/all.py +++ b/src/sage/combinat/pathtableaux/all.py @@ -1,4 +1,4 @@ from __future__ import absolute_import -from .pathtableaux import PathTableau, PathTableaux +from .pathtableau import PathTableau, PathTableaux from .catalan import CatalanTableau, CatalanTableaux From 212d2adf2c13487bdec028424e3941f5a0139b46 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sat, 1 Sep 2018 13:49:13 +0100 Subject: [PATCH 055/300] Corrected names --- src/sage/combinat/pathtableaux/catalan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/pathtableaux/catalan.py b/src/sage/combinat/pathtableaux/catalan.py index d9cdd4d9fc9..8d983e60ad9 100644 --- a/src/sage/combinat/pathtableaux/catalan.py +++ b/src/sage/combinat/pathtableaux/catalan.py @@ -29,7 +29,7 @@ from six import add_metaclass from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass -from sage.combinat.pathtableau.pathtableaux import PathTableau, PathTableaux +from sage.combinat.pathtableaux.pathtableau import PathTableau, PathTableaux from sage.combinat.dyck_word import DyckWord from sage.combinat.perfect_matching import PerfectMatching from sage.combinat.skew_tableau import SkewTableau From e2c3b1403612eeb8d1d46b20fb8e10ab5da7e774 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sun, 16 Sep 2018 15:11:54 +0100 Subject: [PATCH 056/300] Added __getattr__ and several Parents --- src/sage/combinat/pathtableaux/catalan.py | 68 ++----- src/sage/combinat/pathtableaux/pathtableau.py | 170 +++++++++++++++++- 2 files changed, 179 insertions(+), 59 deletions(-) diff --git a/src/sage/combinat/pathtableaux/catalan.py b/src/sage/combinat/pathtableaux/catalan.py index 8d983e60ad9..c9638f5ece6 100644 --- a/src/sage/combinat/pathtableaux/catalan.py +++ b/src/sage/combinat/pathtableaux/catalan.py @@ -174,9 +174,8 @@ def check(self): raise ValueError( "%s has a negative entry" % (str(self)) ) for i in range(n-1): if abs(self[i+1]-self[i]) != 1: - raise ValueError( "%s is not a Dyck path" % (str(self)) ) + raise ValueError( "%s is not a Dyck path" % str(self) ) - @staticmethod def _rule(x): """ Overwrites the abstract method. @@ -191,6 +190,15 @@ def _rule(x): """ return abs(x[0]-x[1]+x[2]) + _conversions = [ "to_DyckWord", + "to_standard_tableau", + "to_tableau", + "to_noncrossing_partition", + "to_binary_tree", + "to_ordered_tree", + "to_to_non_decreasing_parking_function", + "to_alternating_sign_matrix" ] + def is_skew(self): """ Return ``True`` if ``self`` is skew and ``False`` if not. @@ -205,6 +213,9 @@ def is_skew(self): """ return self[0] != 0 + def to_DyckWord(self): + return DyckWord(heights_sequence = list(self)) + def descents(self): """ Return the descent set of ``self``. @@ -222,62 +233,9 @@ def descents(self): return result - def to_word(self): - """ - Return the word in the alphabet `\{0,1\}` associated to ``self``. - - EXAMPLES:: - - sage: CatalanTableau([1,0,1,2,1]).to_word() - [0, 1, 1, 0] - """ - return [ (self[i+1]-self[i]+1)/2 for i in range(self.size()-1) ] - def to_perfect_matching(self): - """ - Return the perfect matching associated to ``self``. - EXAMPLES:: - sage: CatalanTableau([0,1,2,1,2,1,0,1,0]).to_perfect_matching() - [(0, 5), (1, 2), (3, 4), (6, 7)] - """ - w = self.to_word() - y = DyckWord(w) - pairs = set() - for i, a in enumerate(y): - c = y.associated_parenthesis(i) - if i < c: - pairs.add((i,c)) - return PerfectMatching(pairs) - - def to_tableau(self): - """ - Return the skew tableau associated to ``self``. - - EXAMPLES:: - - sage: T = CatalanTableau([0,1,2,3,2,3]) - sage: T.to_tableau() - [[0, 1, 2, 4], [3]] - """ - w = self.to_word() - top = [ i for i, a in enumerate(w) if a == 1 ] - bot = [ i for i, a in enumerate(w) if a == 0 ] - return SkewTableau([[None]*self[0]+top,bot]) - - def show(self): - """ - Return the plot of the Dyck path associated to ``self``. - - EXAMPLES:: - - sage: T = CatalanTableau([0,1,2,3,2,3]) - sage: T.show() - Graphics object consisting of 1 graphics primitive - """ - from sage.plot.line import line - return line([ (i,a) for i, a in enumerate(self)]) #class PathTableaux(UniqueRepresentation,Parent): # diff --git a/src/sage/combinat/pathtableaux/pathtableau.py b/src/sage/combinat/pathtableaux/pathtableau.py index 27900bb3353..d24452c1816 100644 --- a/src/sage/combinat/pathtableaux/pathtableau.py +++ b/src/sage/combinat/pathtableaux/pathtableau.py @@ -440,10 +440,172 @@ def dual_equivalence_graph(self): class PathTableaux(UniqueRepresentation,Parent): - def __init__(self): - Parent.__init__(self, category = Sets()) + @staticmethod + def __classcall_private__(cls, n=None, straight=True): + """ + Choose the correct parent based upon input. + + EXAMPLES:: + + sage: DW1 = DyckWords(3,3) + sage: DW2 = DyckWords(3) + sage: DW1 is DW2 + True + """ + if not n is None: + straight=True - def _element_constructor_(self, *args, **keywords): - return self.element_class(self, *args, **keywords) + if not straight: + return PathTableaux_all() + + if n is None: + return PathTableaux_straight() + + n = ZZ(n) + if n < 0: + raise ValueError("n (= %s) must be nonnegative" % n) + + return PathTableaux_size(n) Element = PathTableau + +######################################################################## + +class PathTableaux_all(PathTableaux): + + pass + +######################################################################## + +class PathTableaux_straight(PathTableaux): + """ + Paths starting with the empty path. + """ + def __init__(self): + r""" + TESTS: + + sage: TestSuite(DyckWords(4,2)).run() + """ + + PathTableaux.__init__(self, category=InfiniteEnumeratedSets()) + + def __contains__(self, x): + r""" + EXAMPLES:: + + """ + return not x.is_skew() + + def _repr_(self): + r""" + TESTS:: + + sage: PathTableaux_straight() + Paths starting with the empty path. + """ + return "Paths starting with the empty path." + + @cached_method + def elements(self): + r""" + Returns the elements of ``self`` + + Those are constructed as the elements below the maximal + elements of ``self`` in Bruhat order. + + OUTPUT: a :class:`RecursivelyEnumeratedSet_generic` object + + EXAMPLES:: + + sage: PF = WeylGroup(['A',3]).pieri_factors() + sage: [w.reduced_word() for w in PF.elements()] + [[3, 2, 1], [2, 1], [3, 1], [3, 2], [2], [1], [3], []] + + .. SEEALSO:: :meth:`maximal_elements` + + .. TODO:: + + Possibly remove this method and instead have this class + inherit from :class:`RecursivelyEnumeratedSet_generic`. + """ + return RecursivelyEnumeratedSet(PathTableau([]), + _successors, structure='graded', + enumeration='naive') + + def __iter__(self): + r""" + Returns an iterator over the elements of ``self`` + + EXAMPLES:: + + """ + return iter(self.elements()) + + + +######################################################################## + +class PathTableau_size(PathTableau_straight): + """ + Paths of length n starting with the empty path. + """ + def __init__(self, n): + r""" + TESTS:: + + sage: TestSuite(DyckWords(4,2)).run() + """ + self.n = ZZ(n) + + PathTableaux.__init__(self, category=FiniteEnumeratedSets()) + + def _repr_(self): + r""" + TESTS:: + + sage: PathTableaux(4) + Paths of length 4 starting with the empty path. + """ + return "Paths of length %s starting with the empty path." % self.n + + def __contains__(self, x): + r""" + EXAMPLES:: + + """ + return not x.is_skew() and x.size() == n + + def __iter__(self): + r""" + Return an iterator for Dyck words with ``k1`` opening and ``k2`` + closing parentheses. + + EXAMPLES:: + + sage: list(DyckWords(0)) + [[]] + sage: list(DyckWords(1)) + [[1, 0]] + sage: list(DyckWords(2)) + [[1, 0, 1, 0], [1, 1, 0, 0]] + 111111 sage: len(DyckWords(5)) + 42 + sage: list(DyckWords(3,2)) + [[1, 0, 1, 0, 1], + [1, 0, 1, 1, 0], + [1, 1, 0, 0, 1], + [1, 1, 0, 1, 0], + [1, 1, 1, 0, 0]] + """ + if self.k1 == 0: + yield self.element_class(self, []) + elif self.k2 == 0: + yield self.element_class(self, [open_symbol]*self.k1) + else: + for w in DyckWordBacktracker(self.k1, self.k2): + yield self.element_class(self, w) + +class PathTableaux_size(PathTableaux_straight): + + Element = PathTableau_size From 830636de53976c9867870e186eb47874e6346cbe Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Tue, 18 Sep 2018 17:42:58 +0100 Subject: [PATCH 057/300] Added __getatrr__ and other minor changes --- src/sage/combinat/all.py | 4 +- src/sage/combinat/pathtableaux/catalan.py | 38 +-- src/sage/combinat/pathtableaux/pathtableau.py | 268 +++++++----------- 3 files changed, 116 insertions(+), 194 deletions(-) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 4ecbf9524be..026fe1153d9 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -220,5 +220,5 @@ 'GrowthDiagramYoungFibonacci', 'GrowthDiagramSylvester']) # Path tableaux -from .pathtableaux.all import * - +lazy_import('sage.combinat.pathtableaux.pathtableau', ['PathTableau', 'PathTableaux']) +lazy_import('sage.combinat.pathtableaux.catalan', ['CatalanTableau', 'CatalanTableaux']) diff --git a/src/sage/combinat/pathtableaux/catalan.py b/src/sage/combinat/pathtableaux/catalan.py index c9638f5ece6..118e3df1b43 100644 --- a/src/sage/combinat/pathtableaux/catalan.py +++ b/src/sage/combinat/pathtableaux/catalan.py @@ -30,6 +30,7 @@ from six import add_metaclass from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.combinat.pathtableaux.pathtableau import PathTableau, PathTableaux +from sage.combinat.combinatorial_map import combinatorial_map from sage.combinat.dyck_word import DyckWord from sage.combinat.perfect_matching import PerfectMatching from sage.combinat.skew_tableau import SkewTableau @@ -176,6 +177,7 @@ def check(self): if abs(self[i+1]-self[i]) != 1: raise ValueError( "%s is not a Dyck path" % str(self) ) + @staticmethod def _rule(x): """ Overwrites the abstract method. @@ -190,15 +192,6 @@ def _rule(x): """ return abs(x[0]-x[1]+x[2]) - _conversions = [ "to_DyckWord", - "to_standard_tableau", - "to_tableau", - "to_noncrossing_partition", - "to_binary_tree", - "to_ordered_tree", - "to_to_non_decreasing_parking_function", - "to_alternating_sign_matrix" ] - def is_skew(self): """ Return ``True`` if ``self`` is skew and ``False`` if not. @@ -213,7 +206,17 @@ def is_skew(self): """ return self[0] != 0 + @combinatorial_map(name='to Dyck word') def to_DyckWord(self): + """ + Converts ``self`` to a Dyck word. + + EXAMPLES:: + + sage: c = CatalanTableau([0,1,2,1,0]) + sage: c.to_DyckWord() + [1, 1, 0, 0] + """ return DyckWord(heights_sequence = list(self)) def descents(self): @@ -233,20 +236,7 @@ def descents(self): return result - - - - -#class PathTableaux(UniqueRepresentation,Parent): -# -# def __init__(self): -# Parent.__init__(self, category = Sets()) -# -# def _element_constructor_(self, *args, **keywords): -# return self.element_class(self, *args, **keywords) -# -# Element = PathTableau - -class CatalanTableaux(PathTableaux): +class CatalanTableaux(PathTableaux) Element = CatalanTableau + diff --git a/src/sage/combinat/pathtableaux/pathtableau.py b/src/sage/combinat/pathtableaux/pathtableau.py index d24452c1816..c2ba068a83b 100644 --- a/src/sage/combinat/pathtableaux/pathtableau.py +++ b/src/sage/combinat/pathtableaux/pathtableau.py @@ -39,10 +39,15 @@ from six import add_metaclass from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.misc.abstract_method import abstract_method +from sage.misc.cachefunc import cached_method from sage.structure.list_clone import ClonableList from sage.categories.sets_cat import Sets from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent +from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_graded +from sage.rings.integer import Integer +from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets +from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets @add_metaclass(InheritComparisonClasscallMetaclass) class PathTableau(ClonableList): @@ -59,6 +64,90 @@ def _rule(p): and replace the middle term with the output. """ + def __getattr__(self,name): + """ + A magic method. If the method meth:`name' is not defined then + this converts ``self`` and tries to apply the method on the result. + + TESTS:: + + sage: c = CatalanTableau([0,1,2,1,0]) + sage: c.plot() + Graphics object consisting of 1 graphics primitive + sage: c._latex_() + '\\vcenter{\\hbox{$\\begin{tikzpicture}[scale=1]\n \\draw[dotted] (0, 0) grid (4, 2);\n \\draw[rounded corners=1, color=black, line width=2] (0, 0) -- (1, 1) -- (2, 2) -- (3, 1) -- (4, 0);\n\\end{tikzpicture}$}}' + sage: c.major_index() + 0 + sage: c.associated_parenthesis(2) + 1 + sage: c.nonsense() + ... + AttributeError: unable to find method nonsense + + """ + for x in self.parent()._conversions: + try: + return getattr(getattr(self,x)(),name) + except: + pass + + raise AttributeError("unable to find method "+name) + + def _test_conversions(self): + """ + Test that the conversions work. + + TESTS:: + + sage: c = CatalanTableau([0,1,2,1,0]) + sage: c._test_conversions() + to_DyckWord + (()) + + to_standard_tableau + [[1, 2], [3, 4]] + + to_binary_tree + [[., .], .] + + to_noncrossing_partition + [[1, 2]] + + to_ordered_tree + [[[]]] + + to_non_decreasing_parking_function + [1, 1] + + to_alternating_sign_matrix + [0 1] + [1 0] + + """ + for x in self.parent()._conversions: + print x, "\n", getattr(self,x)(), "\n" + + def _test_getattr(self): + """ + sage: c = CatalanTableau([0,1,0]) + sage: c._test_getattr() + to_DyckWord + ... + transpose + + """ + + for x in self.parent()._conversions: + print x + c = getattr(self,x)() + v = [ a for a in dir(c) if not a in dir(self) ] + for a in v: + try: + getattr(self,a)() + print(" "+a) + except: + pass + ################################# Book Keeping ################################ def size(self): @@ -423,6 +512,17 @@ def dual_equivalence_graph(self): [0 1 1 1 0 0 1 1 1 1 1 0 1 1] [0 1 0 1 1 1 0 1 1 1 1 1 0 1] [0 0 0 0 1 0 1 0 0 1 1 1 1 0] + sage: s = CatalanTableau([0,1,2,3,2,1,0]) + sage: sorted(s.dual_equivalence_graph().edges()) + [([0, 1, 0, 1, 0, 1, 0], [0, 1, 0, 1, 2, 1, 0], '4,7'), + ([0, 1, 0, 1, 0, 1, 0], [0, 1, 2, 1, 0, 1, 0], '2,5'), + ([0, 1, 0, 1, 0, 1, 0], [0, 1, 2, 1, 2, 1, 0], '2,7'), + ([0, 1, 0, 1, 2, 1, 0], [0, 1, 2, 1, 0, 1, 0], '2,6'), + ([0, 1, 0, 1, 2, 1, 0], [0, 1, 2, 1, 2, 1, 0], '1,4'), + ([0, 1, 0, 1, 2, 1, 0], [0, 1, 2, 3, 2, 1, 0], '2,7'), + ([0, 1, 2, 1, 0, 1, 0], [0, 1, 2, 1, 2, 1, 0], '4,7'), + ([0, 1, 2, 1, 0, 1, 0], [0, 1, 2, 3, 2, 1, 0], '3,7'), + ([0, 1, 2, 1, 2, 1, 0], [0, 1, 2, 3, 2, 1, 0], '3,6')] """ from sage.graphs.graph import Graph @@ -440,172 +540,4 @@ def dual_equivalence_graph(self): class PathTableaux(UniqueRepresentation,Parent): - @staticmethod - def __classcall_private__(cls, n=None, straight=True): - """ - Choose the correct parent based upon input. - - EXAMPLES:: - - sage: DW1 = DyckWords(3,3) - sage: DW2 = DyckWords(3) - sage: DW1 is DW2 - True - """ - if not n is None: - straight=True - - if not straight: - return PathTableaux_all() - - if n is None: - return PathTableaux_straight() - - n = ZZ(n) - if n < 0: - raise ValueError("n (= %s) must be nonnegative" % n) - - return PathTableaux_size(n) - Element = PathTableau - -######################################################################## - -class PathTableaux_all(PathTableaux): - - pass - -######################################################################## - -class PathTableaux_straight(PathTableaux): - """ - Paths starting with the empty path. - """ - def __init__(self): - r""" - TESTS: - - sage: TestSuite(DyckWords(4,2)).run() - """ - - PathTableaux.__init__(self, category=InfiniteEnumeratedSets()) - - def __contains__(self, x): - r""" - EXAMPLES:: - - """ - return not x.is_skew() - - def _repr_(self): - r""" - TESTS:: - - sage: PathTableaux_straight() - Paths starting with the empty path. - """ - return "Paths starting with the empty path." - - @cached_method - def elements(self): - r""" - Returns the elements of ``self`` - - Those are constructed as the elements below the maximal - elements of ``self`` in Bruhat order. - - OUTPUT: a :class:`RecursivelyEnumeratedSet_generic` object - - EXAMPLES:: - - sage: PF = WeylGroup(['A',3]).pieri_factors() - sage: [w.reduced_word() for w in PF.elements()] - [[3, 2, 1], [2, 1], [3, 1], [3, 2], [2], [1], [3], []] - - .. SEEALSO:: :meth:`maximal_elements` - - .. TODO:: - - Possibly remove this method and instead have this class - inherit from :class:`RecursivelyEnumeratedSet_generic`. - """ - return RecursivelyEnumeratedSet(PathTableau([]), - _successors, structure='graded', - enumeration='naive') - - def __iter__(self): - r""" - Returns an iterator over the elements of ``self`` - - EXAMPLES:: - - """ - return iter(self.elements()) - - - -######################################################################## - -class PathTableau_size(PathTableau_straight): - """ - Paths of length n starting with the empty path. - """ - def __init__(self, n): - r""" - TESTS:: - - sage: TestSuite(DyckWords(4,2)).run() - """ - self.n = ZZ(n) - - PathTableaux.__init__(self, category=FiniteEnumeratedSets()) - - def _repr_(self): - r""" - TESTS:: - - sage: PathTableaux(4) - Paths of length 4 starting with the empty path. - """ - return "Paths of length %s starting with the empty path." % self.n - - def __contains__(self, x): - r""" - EXAMPLES:: - - """ - return not x.is_skew() and x.size() == n - - def __iter__(self): - r""" - Return an iterator for Dyck words with ``k1`` opening and ``k2`` - closing parentheses. - - EXAMPLES:: - - sage: list(DyckWords(0)) - [[]] - sage: list(DyckWords(1)) - [[1, 0]] - sage: list(DyckWords(2)) - [[1, 0, 1, 0], [1, 1, 0, 0]] - 111111 sage: len(DyckWords(5)) - 42 - sage: list(DyckWords(3,2)) - [[1, 0, 1, 0, 1], - [1, 0, 1, 1, 0], - [1, 1, 0, 0, 1], - [1, 1, 0, 1, 0], - [1, 1, 1, 0, 0]] - """ - if self.k1 == 0: - yield self.element_class(self, []) - elif self.k2 == 0: - yield self.element_class(self, [open_symbol]*self.k1) - else: - for w in DyckWordBacktracker(self.k1, self.k2): - yield self.element_class(self, w) - -class PathTableaux_size(PathTableaux_straight): - - Element = PathTableau_size From d60ce49b2b5fb03dc1a827e579ad6d9dd12f21ab Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Wed, 19 Sep 2018 08:59:29 +0100 Subject: [PATCH 058/300] More work --- src/sage/combinat/pathtableaux/catalan.py | 55 ++++++++++++++++++- src/sage/combinat/pathtableaux/pathtableau.py | 2 + 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/pathtableaux/catalan.py b/src/sage/combinat/pathtableaux/catalan.py index 118e3df1b43..e3b9dc9c85f 100644 --- a/src/sage/combinat/pathtableaux/catalan.py +++ b/src/sage/combinat/pathtableaux/catalan.py @@ -236,7 +236,60 @@ def descents(self): return result -class CatalanTableaux(PathTableaux) + def to_word(self): + """ + Return the word in the alphabet `\{0,1\}` associated to ``self``. + + EXAMPLES:: + + sage: CatalanTableau([1,0,1,2,1]).to_word() + [0, 1, 1, 0] + """ + return [ (self[i+1]-self[i]+1)/2 for i in range(self.size()-1) ] + + def to_perfect_matching(self): + """ + Return the perfect matching associated to ``self``. + + EXAMPLES:: + + sage: CatalanTableau([0,1,2,1,2,1,0,1,0]).to_perfect_matching() + [(0, 5), (1, 2), (3, 4), (6, 7)] + """ + w = self.to_word() + y = DyckWord(w) + pairs = set() + for i, a in enumerate(y): + c = y.associated_parenthesis(i) + if i < c: + pairs.add((i,c)) + return PerfectMatching(pairs) + + def to_tableau(self): + """ + Return the skew tableau associated to ``self``. + + EXAMPLES:: + + sage: T = CatalanTableau([0,1,2,3,2,3]) + sage: T.to_tableau() + [[0, 1, 2, 4], [3]] + """ + w = self.to_word() + top = [ i for i, a in enumerate(w) if a == 1 ] + bot = [ i for i, a in enumerate(w) if a == 0 ] + return SkewTableau([[None]*self[0]+top,bot]) + +class CatalanTableaux(PathTableaux): + + _conversions = [ "to_DyckWord", + "to_standard_tableau", + "to_tableau", + "to_noncrossing_partition", + "to_binary_tree", + "to_ordered_tree", + "to_to_non_decreasing_parking_function", + "to_alternating_sign_matrix" ] Element = CatalanTableau diff --git a/src/sage/combinat/pathtableaux/pathtableau.py b/src/sage/combinat/pathtableaux/pathtableau.py index c2ba068a83b..3762b703782 100644 --- a/src/sage/combinat/pathtableaux/pathtableau.py +++ b/src/sage/combinat/pathtableaux/pathtableau.py @@ -540,4 +540,6 @@ def dual_equivalence_graph(self): class PathTableaux(UniqueRepresentation,Parent): + _conversions = [] + Element = PathTableau From 236ae8bc003a23b1b404ec4059b029f240e8ee3d Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Wed, 19 Sep 2018 15:07:21 +0100 Subject: [PATCH 059/300] Added construction from skew tableau --- src/sage/combinat/pathtableaux/catalan.py | 49 +++++++------------ src/sage/combinat/pathtableaux/pathtableau.py | 23 +++++---- 2 files changed, 33 insertions(+), 39 deletions(-) diff --git a/src/sage/combinat/pathtableaux/catalan.py b/src/sage/combinat/pathtableaux/catalan.py index e3b9dc9c85f..a8c5e971fee 100644 --- a/src/sage/combinat/pathtableaux/catalan.py +++ b/src/sage/combinat/pathtableaux/catalan.py @@ -40,7 +40,6 @@ ############################################################################### """ - Here we illustrate the slogan that promotion = rotation. EXAMPLES:: @@ -72,10 +71,10 @@ . . . . 0 1 2 1 0 1 0 . . . . . 0 1 0 1 2 1 0 . . . . . . 0 1 2 3 2 1 0 - sage: TestSuite(t).run() """ + @add_metaclass(InheritComparisonClasscallMetaclass) class CatalanTableau(PathTableau): """ @@ -99,7 +98,7 @@ class CatalanTableau(PathTableau): [0, 1, 2, 1, 0] sage: p = PerfectMatching([(1,2),(3,4)]) - sage: CatalanTableau(p) + sage: #CatalanTableau(p) [1, 0, 1, 0] sage: t = Tableau([[1,2],[3,4]]) @@ -125,7 +124,7 @@ def __classcall_private__(cls, ot): raise ValueError("the perfect matching must be non crossing") if isinstance(ot, Tableau): - if len(ot) == 2: + if len(ot) <= 2: if ot.is_standard(): u = [1] * ot.size() for i in ot[1]: @@ -134,7 +133,18 @@ def __classcall_private__(cls, ot): else: raise ValueError("the tableau must be standard") else: - raise ValueError("the tableau must have two rows") + raise ValueError("the tableau must have at most two rows") + + if isinstance(ot, SkewTableau): + if len(ot) <= 2: + # The check that ot is standard is not implemented + u = [1] * ot.size() + for i in ot[1]: + if i is not None: + u[i-1] = 0 + w = DyckWord(u).heights() + else: + raise ValueError("the skew tableau must have at most two rows") if isinstance(ot, (list,tuple)): try: @@ -148,28 +158,7 @@ def __classcall_private__(cls, ot): return CatalanTableaux()(w) def check(self): - """ - Overwrites the abstract method. - This checks that heights are nonnegative and that succesive heights - differ by `+1` or `-1`. - - EXAMPLES:: - - sage: CatalanTableau([0,1,2,3,2,3]) - [0, 1, 2, 3, 2, 3] - - sage: CatalanTableau([0,1,0,-1,0]) - Traceback (most recent call last): - ... - ValueError: [0, 1, 0, -1, 0] has a negative entry - - sage: CatalanTableau([0,1,3,3,2,3]) - Traceback (most recent call last): - ... - ValueError: [0, 1, 3, 3, 2, 3] is not a Dyck path - - """ n = len(self) if any(a < 0 for a in self): raise ValueError( "%s has a negative entry" % (str(self)) ) @@ -273,11 +262,11 @@ def to_tableau(self): sage: T = CatalanTableau([0,1,2,3,2,3]) sage: T.to_tableau() - [[0, 1, 2, 4], [3]] + [[1, 2, 3, 5], [4]] """ w = self.to_word() - top = [ i for i, a in enumerate(w) if a == 1 ] - bot = [ i for i, a in enumerate(w) if a == 0 ] + top = [ i+1 for i, a in enumerate(w) if a == 1 ] + bot = [ i+1 for i, a in enumerate(w) if a == 0 ] return SkewTableau([[None]*self[0]+top,bot]) class CatalanTableaux(PathTableaux): @@ -288,7 +277,7 @@ class CatalanTableaux(PathTableaux): "to_noncrossing_partition", "to_binary_tree", "to_ordered_tree", - "to_to_non_decreasing_parking_function", + "to_non_decreasing_parking_function", "to_alternating_sign_matrix" ] Element = CatalanTableau diff --git a/src/sage/combinat/pathtableaux/pathtableau.py b/src/sage/combinat/pathtableaux/pathtableau.py index 3762b703782..5577bd7d673 100644 --- a/src/sage/combinat/pathtableaux/pathtableau.py +++ b/src/sage/combinat/pathtableaux/pathtableau.py @@ -81,6 +81,7 @@ def __getattr__(self,name): sage: c.associated_parenthesis(2) 1 sage: c.nonsense() + Traceback (most recent call last): ... AttributeError: unable to find method nonsense @@ -93,26 +94,29 @@ def __getattr__(self,name): raise AttributeError("unable to find method "+name) - def _test_conversions(self): + def _check_conversions(self): """ Test that the conversions work. - TESTS:: + TESTS: sage: c = CatalanTableau([0,1,2,1,0]) - sage: c._test_conversions() + sage: c._check_conversions() to_DyckWord (()) to_standard_tableau [[1, 2], [3, 4]] - to_binary_tree - [[., .], .] + to_tableau + [[1, 2], [3, 4]] to_noncrossing_partition [[1, 2]] + to_binary_tree + [[., .], .] + to_ordered_tree [[[]]] @@ -122,15 +126,15 @@ def _test_conversions(self): to_alternating_sign_matrix [0 1] [1 0] - + """ for x in self.parent()._conversions: print x, "\n", getattr(self,x)(), "\n" - def _test_getattr(self): + def _check_getattr(self): """ sage: c = CatalanTableau([0,1,0]) - sage: c._test_getattr() + sage: c._check_getattr() to_DyckWord ... transpose @@ -542,4 +546,5 @@ class PathTableaux(UniqueRepresentation,Parent): _conversions = [] - Element = PathTableau + def _element_constructor_(self, *args, **keywords): + return self.element_class(self, *args, **keywords) From 11c5eb6f1c2c9be963985c1c8499ad971d7728c8 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 21 Sep 2018 11:20:41 +0100 Subject: [PATCH 060/300] File names changed in __init__.py --- src/sage/combinat/pathtableaux/__init__.py | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/sage/combinat/pathtableaux/__init__.py diff --git a/src/sage/combinat/pathtableaux/__init__.py b/src/sage/combinat/pathtableaux/__init__.py new file mode 100644 index 00000000000..9a5af620dd1 --- /dev/null +++ b/src/sage/combinat/pathtableaux/__init__.py @@ -0,0 +1,7 @@ +r""" +Path Tableaux +============= + +- :ref:`sage.combinat.pathtableaux.pathtableau` +- :ref:`sage.combinat.pathtableaux.catalan` +""" From 0818203a2062f8bb130ba842b2ad683652b48338 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Thu, 27 Sep 2018 19:15:25 +0100 Subject: [PATCH 061/300] Made _rule a helper function. --- src/sage/combinat/pathtableaux/catalan.py | 31 +++++++++++----- src/sage/combinat/pathtableaux/pathtableau.py | 36 +++---------------- 2 files changed, 26 insertions(+), 41 deletions(-) diff --git a/src/sage/combinat/pathtableaux/catalan.py b/src/sage/combinat/pathtableaux/catalan.py index a8c5e971fee..ce3b017e894 100644 --- a/src/sage/combinat/pathtableaux/catalan.py +++ b/src/sage/combinat/pathtableaux/catalan.py @@ -166,21 +166,34 @@ def check(self): if abs(self[i+1]-self[i]) != 1: raise ValueError( "%s is not a Dyck path" % str(self) ) - @staticmethod - def _rule(x): + def _local_rule(self,i): """ - Overwrites the abstract method. + This is the local rule that is used for the remaining constructions. + This has input a list of objects. This method first takes + the list of objects of length three consisting of the `(i-1)`-st, + `i`-th and `(i+1)`-term and applies the rule. It then replaces + the `i`-th object by the object returned by the rule. EXAMPLES:: - sage: T = CatalanTableau([0,1,2,3,2,3]) - sage: T._rule([1,2,1]) - 0 - sage: T._rule([0,1,0]) - 1 + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t._local_rule(3) + [0, 1, 2, 1, 2, 1, 0] """ - return abs(x[0]-x[1]+x[2]) + def _rule(x): + """ + This is the rule on a sequence of three letters. + """ + return abs(x[0]-x[1]+x[2]) + + if not (i > 0 and i < len(self) ): + raise ValueError("%d is not a valid integer" % i) + + with self.clone() as result: + result[i] = self._rule(self[i-1:i+2]) + + return result def is_skew(self): """ Return ``True`` if ``self`` is skew and ``False`` if not. diff --git a/src/sage/combinat/pathtableaux/pathtableau.py b/src/sage/combinat/pathtableaux/pathtableau.py index 5577bd7d673..5c4a84e347e 100644 --- a/src/sage/combinat/pathtableaux/pathtableau.py +++ b/src/sage/combinat/pathtableaux/pathtableau.py @@ -51,17 +51,11 @@ @add_metaclass(InheritComparisonClasscallMetaclass) class PathTableau(ClonableList): - @staticmethod - @abstract_method(optional=False) - def _rule(p): - """ - This is an abstract method. It must be overwritten. - This rule provides the functionality. It is called in - :method:`_local_rule`. - The key property is that the following operation on lists - of length three is an involution: apply the rule to a list - and replace the middle term with the output. + @abstractmethod(optional=False): + def _local_rule(self,i): + """ + This is the abstract local rule defined in any coboundary category. """ def __getattr__(self,name): @@ -192,28 +186,6 @@ def final_shape(self): ############################# Jeu de taquin ################################### - def _local_rule(self,i): - """ - This is the local rule that is used for the remaining constructions. - This has input a list of objects. This method first takes - the list of objects of length three consisting of the `(i-1)`-st, - `i`-th and `(i+1)`-term and applies the rule. It then replaces - the `i`-th object by the object returned by the rule. - - EXAMPLES:: - - sage: t = CatalanTableau([0,1,2,3,2,1,0]) - sage: t._local_rule(3) - [0, 1, 2, 1, 2, 1, 0] - """ - if not (i > 0 and i < len(self) ): - raise ValueError("%d is not a valid integer" % i) - - with self.clone() as result: - result[i] = self._rule(self[i-1:i+2]) - - return result - def promotion(self): """ Return the promotion operator applied to ``self``. From ee430d5342bb324616c71d9c43e08ad7b03b752b Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Thu, 27 Sep 2018 19:40:07 +0100 Subject: [PATCH 062/300] Made _rule a helper function --- src/sage/combinat/pathtableaux/catalan.py | 3 ++- src/sage/combinat/pathtableaux/pathtableau.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/pathtableaux/catalan.py b/src/sage/combinat/pathtableaux/catalan.py index ce3b017e894..6f330051767 100644 --- a/src/sage/combinat/pathtableaux/catalan.py +++ b/src/sage/combinat/pathtableaux/catalan.py @@ -191,9 +191,10 @@ def _rule(x): raise ValueError("%d is not a valid integer" % i) with self.clone() as result: - result[i] = self._rule(self[i-1:i+2]) + result[i] = _rule(self[i-1:i+2]) return result + def is_skew(self): """ Return ``True`` if ``self`` is skew and ``False`` if not. diff --git a/src/sage/combinat/pathtableaux/pathtableau.py b/src/sage/combinat/pathtableaux/pathtableau.py index 5c4a84e347e..654cf8b870c 100644 --- a/src/sage/combinat/pathtableaux/pathtableau.py +++ b/src/sage/combinat/pathtableaux/pathtableau.py @@ -52,7 +52,7 @@ @add_metaclass(InheritComparisonClasscallMetaclass) class PathTableau(ClonableList): - @abstractmethod(optional=False): + @abstract_method(optional=False) def _local_rule(self,i): """ This is the abstract local rule defined in any coboundary category. @@ -198,7 +198,7 @@ def promotion(self): """ with self.clone() as result: for i in range(1,len(result)-1): - result[i] = self._rule(result[i-1:i+2]) + result = result._local_rule(i) return result From bcd1acd7a8935fa7be061aa616f964b334817d84 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 28 Sep 2018 12:17:47 +0100 Subject: [PATCH 063/300] Tidy up --- src/sage/combinat/pathtableaux/catalan.py | 31 ++++++++++--------- src/sage/combinat/pathtableaux/pathtableau.py | 14 ++++++--- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/sage/combinat/pathtableaux/catalan.py b/src/sage/combinat/pathtableaux/catalan.py index 6f330051767..8f083b8cde4 100644 --- a/src/sage/combinat/pathtableaux/catalan.py +++ b/src/sage/combinat/pathtableaux/catalan.py @@ -98,8 +98,8 @@ class CatalanTableau(PathTableau): [0, 1, 2, 1, 0] sage: p = PerfectMatching([(1,2),(3,4)]) - sage: #CatalanTableau(p) - [1, 0, 1, 0] + sage: CatalanTableau(p) + [0, 1, 0, 1, 0] sage: t = Tableau([[1,2],[3,4]]) sage: CatalanTableau(t) @@ -107,6 +107,16 @@ class CatalanTableau(PathTableau): """ + _conversions = [ "to_DyckWord", + "to_perfect_matching", + "to_standard_tableau", + "to_tableau", + "to_noncrossing_partition", + "to_binary_tree", + "to_ordered_tree", + "to_non_decreasing_parking_function", + "to_alternating_sign_matrix" ] + @staticmethod def __classcall_private__(cls, ot): @@ -117,9 +127,10 @@ def __classcall_private__(cls, ot): if isinstance(ot, PerfectMatching): if ot.is_noncrossing(): - w = [1]*ot.size() + u = [1]*ot.size() for a in ot.arcs(): - w[a[1]-1] = 0 + u[a[1]-1] = 0 + w = DyckWord(u).heights() else: raise ValueError("the perfect matching must be non crossing") @@ -168,7 +179,6 @@ def check(self): def _local_rule(self,i): """ - This is the local rule that is used for the remaining constructions. This has input a list of objects. This method first takes the list of objects of length three consisting of the `(i-1)`-st, `i`-th and `(i+1)`-term and applies the rule. It then replaces @@ -194,7 +204,7 @@ def _rule(x): result[i] = _rule(self[i-1:i+2]) return result - + def is_skew(self): """ Return ``True`` if ``self`` is skew and ``False`` if not. @@ -285,14 +295,5 @@ def to_tableau(self): class CatalanTableaux(PathTableaux): - _conversions = [ "to_DyckWord", - "to_standard_tableau", - "to_tableau", - "to_noncrossing_partition", - "to_binary_tree", - "to_ordered_tree", - "to_non_decreasing_parking_function", - "to_alternating_sign_matrix" ] - Element = CatalanTableau diff --git a/src/sage/combinat/pathtableaux/pathtableau.py b/src/sage/combinat/pathtableaux/pathtableau.py index 654cf8b870c..a839cd84edd 100644 --- a/src/sage/combinat/pathtableaux/pathtableau.py +++ b/src/sage/combinat/pathtableaux/pathtableau.py @@ -52,6 +52,8 @@ @add_metaclass(InheritComparisonClasscallMetaclass) class PathTableau(ClonableList): + _conversions = [] + @abstract_method(optional=False) def _local_rule(self,i): """ @@ -80,7 +82,7 @@ def __getattr__(self,name): AttributeError: unable to find method nonsense """ - for x in self.parent()._conversions: + for x in self._conversions: try: return getattr(getattr(self,x)(),name) except: @@ -99,6 +101,9 @@ def _check_conversions(self): to_DyckWord (()) + to_perfect_matching + [(0, 3), (1, 2)] + to_standard_tableau [[1, 2], [3, 4]] @@ -122,7 +127,7 @@ def _check_conversions(self): [1 0] """ - for x in self.parent()._conversions: + for x in self._conversions: print x, "\n", getattr(self,x)(), "\n" def _check_getattr(self): @@ -135,7 +140,7 @@ def _check_getattr(self): """ - for x in self.parent()._conversions: + for x in self._conversions: print x c = getattr(self,x)() v = [ a for a in dir(c) if not a in dir(self) ] @@ -516,7 +521,8 @@ def dual_equivalence_graph(self): class PathTableaux(UniqueRepresentation,Parent): - _conversions = [] + def __init(self): + Parent.__init__(self, category=Sets()) def _element_constructor_(self, *args, **keywords): return self.element_class(self, *args, **keywords) From 6518f2149d1ab638727bc27cffc4061df56f50ea Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sat, 1 Dec 2018 09:12:49 -0600 Subject: [PATCH 064/300] Dealt with Travis' objection to my __getattr__ hack and most of his other comments. --- src/sage/combinat/pathtableaux/pathtableau.py | 122 +++--------------- 1 file changed, 20 insertions(+), 102 deletions(-) diff --git a/src/sage/combinat/pathtableaux/pathtableau.py b/src/sage/combinat/pathtableaux/pathtableau.py index a839cd84edd..67807124e15 100644 --- a/src/sage/combinat/pathtableaux/pathtableau.py +++ b/src/sage/combinat/pathtableaux/pathtableau.py @@ -40,117 +40,35 @@ from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method -from sage.structure.list_clone import ClonableList +from sage.structure.list_clone import ClonableArray from sage.categories.sets_cat import Sets from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent -from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_graded +#from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_graded from sage.rings.integer import Integer -from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets -from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets +#from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets +#from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets @add_metaclass(InheritComparisonClasscallMetaclass) -class PathTableau(ClonableList): - - _conversions = [] +class PathTableau(ClonableArray): @abstract_method(optional=False) def _local_rule(self,i): """ This is the abstract local rule defined in any coboundary category. - """ - def __getattr__(self,name): - """ - A magic method. If the method meth:`name' is not defined then - this converts ``self`` and tries to apply the method on the result. - - TESTS:: + This has input a list of objects. This method first takes + the list of objects of length three consisting of the `(i-1)`-st, + `i`-th and `(i+1)`-term and applies the rule. It then replaces + the `i`-th object by the object returned by the rule. - sage: c = CatalanTableau([0,1,2,1,0]) - sage: c.plot() - Graphics object consisting of 1 graphics primitive - sage: c._latex_() - '\\vcenter{\\hbox{$\\begin{tikzpicture}[scale=1]\n \\draw[dotted] (0, 0) grid (4, 2);\n \\draw[rounded corners=1, color=black, line width=2] (0, 0) -- (1, 1) -- (2, 2) -- (3, 1) -- (4, 0);\n\\end{tikzpicture}$}}' - sage: c.major_index() - 0 - sage: c.associated_parenthesis(2) - 1 - sage: c.nonsense() - Traceback (most recent call last): - ... - AttributeError: unable to find method nonsense - - """ - for x in self._conversions: - try: - return getattr(getattr(self,x)(),name) - except: - pass - - raise AttributeError("unable to find method "+name) - - def _check_conversions(self): - """ - Test that the conversions work. - - TESTS: - - sage: c = CatalanTableau([0,1,2,1,0]) - sage: c._check_conversions() - to_DyckWord - (()) - - to_perfect_matching - [(0, 3), (1, 2)] - - to_standard_tableau - [[1, 2], [3, 4]] - - to_tableau - [[1, 2], [3, 4]] - - to_noncrossing_partition - [[1, 2]] - - to_binary_tree - [[., .], .] - - to_ordered_tree - [[[]]] - - to_non_decreasing_parking_function - [1, 1] - - to_alternating_sign_matrix - [0 1] - [1 0] - - """ - for x in self._conversions: - print x, "\n", getattr(self,x)(), "\n" - - def _check_getattr(self): - """ - sage: c = CatalanTableau([0,1,0]) - sage: c._check_getattr() - to_DyckWord - ... - transpose - - """ - - for x in self._conversions: - print x - c = getattr(self,x)() - v = [ a for a in dir(c) if not a in dir(self) ] - for a in v: - try: - getattr(self,a)() - print(" "+a) - except: - pass + EXAMPLES:: + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t._local_rule(3) + [0, 1, 2, 1, 2, 1, 0] + """ + ################################# Book Keeping ################################ def size(self): @@ -230,11 +148,11 @@ def evacuation(self): result.reverse() return self.parent()(result) - def commutor(self,other,display=False): + def commutor(self,other,verbose=False): """ Return the commutor of ``self`` with ``other`` - If ``display=True`` then the function will print + If ``verbose=True`` then the function will print the rectangle. EXAMPLES:: @@ -243,7 +161,7 @@ def commutor(self,other,display=False): sage: t2 = CatalanTableau([0,1,2,1,0]) sage: t1.commutor(t2) ([0, 1, 2, 1, 0], [0, 1, 2, 3, 2, 1, 0]) - sage: t1.commutor(t2,display=True) + sage: t1.commutor(t2,verbose=True) [0, 1, 2, 1, 0] [1, 2, 3, 2, 1] [2, 3, 4, 3, 2] @@ -268,11 +186,11 @@ def commutor(self,other,display=False): path = self.parent()(col + row[1:]) for i in range(1,n): - if display: + if verbose: print(path[n-i:n+m-i]) for j in range(m-1): path = path._local_rule(n+j-i) - if display: + if verbose: print(path[:m]) From ec639273360dfd10575c3980230cc7fa82bc2014 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sat, 1 Dec 2018 09:14:32 -0600 Subject: [PATCH 065/300] Made minor changes to catalan.py --- src/sage/combinat/pathtableaux/catalan.py | 55 ++++++++++------------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/src/sage/combinat/pathtableaux/catalan.py b/src/sage/combinat/pathtableaux/catalan.py index 8f083b8cde4..6580ca51f89 100644 --- a/src/sage/combinat/pathtableaux/catalan.py +++ b/src/sage/combinat/pathtableaux/catalan.py @@ -80,46 +80,37 @@ class CatalanTableau(PathTableau): """ An instance is the sequence of nonnegative integers given by the heights of a Dyck word. + """ - INPUT: - - - a sequence of nonnegative integers - - a two row standard skew tableau - - a Dyck word - - a noncrossing perfect matching - - EXAMPLES:: - - sage: CatalanTableau([0,1,2,1,0]) - [0, 1, 2, 1, 0] + @staticmethod + def __classcall_private__(cls, ot): + """This is the preprocessing for creating paths. - sage: w = DyckWord([1,1,0,0]) - sage: CatalanTableau(w) - [0, 1, 2, 1, 0] + INPUT: - sage: p = PerfectMatching([(1,2),(3,4)]) - sage: CatalanTableau(p) - [0, 1, 0, 1, 0] + - a sequence of nonnegative integers + - a two row standard skew tableau + - a Dyck word + - a noncrossing perfect matching - sage: t = Tableau([[1,2],[3,4]]) - sage: CatalanTableau(t) - [0, 1, 2, 1, 0] + EXAMPLES:: - """ + sage: CatalanTableau([0,1,2,1,0]) + [0, 1, 2, 1, 0] - _conversions = [ "to_DyckWord", - "to_perfect_matching", - "to_standard_tableau", - "to_tableau", - "to_noncrossing_partition", - "to_binary_tree", - "to_ordered_tree", - "to_non_decreasing_parking_function", - "to_alternating_sign_matrix" ] + sage: w = DyckWord([1,1,0,0]) + sage: CatalanTableau(w) + [0, 1, 2, 1, 0] - @staticmethod - def __classcall_private__(cls, ot): + sage: p = PerfectMatching([(1,2),(3,4)]) + sage: CatalanTableau(p) + [0, 1, 0, 1, 0] + sage: t = Tableau([[1,2],[3,4]]) + sage: CatalanTableau(t) + [0, 1, 2, 1, 0] + + """ w = None if isinstance(ot, DyckWord): From 12b27c4a362a796e04f5f9fdd9df7d01c9def0a7 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sat, 1 Dec 2018 09:26:34 -0600 Subject: [PATCH 066/300] Changed directory name --- src/sage/combinat/all.py | 4 ++-- src/sage/combinat/path_tableaux/__init__.py | 7 +++++++ src/sage/combinat/{pathtableaux => path_tableaux}/all.py | 2 +- .../combinat/{pathtableaux => path_tableaux}/catalan.py | 0 .../pathtableau.py => path_tableaux/path_tableau.py} | 0 src/sage/combinat/pathtableaux/__init__.py | 7 ------- 6 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 src/sage/combinat/path_tableaux/__init__.py rename src/sage/combinat/{pathtableaux => path_tableaux}/all.py (64%) rename src/sage/combinat/{pathtableaux => path_tableaux}/catalan.py (100%) rename src/sage/combinat/{pathtableaux/pathtableau.py => path_tableaux/path_tableau.py} (100%) delete mode 100644 src/sage/combinat/pathtableaux/__init__.py diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 77cc23c2bf1..9df103eaa00 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -222,5 +222,5 @@ 'GrowthDiagramYoungFibonacci', 'GrowthDiagramSylvester']) # Path tableaux -lazy_import('sage.combinat.pathtableaux.pathtableau', ['PathTableau', 'PathTableaux']) -lazy_import('sage.combinat.pathtableaux.catalan', ['CatalanTableau', 'CatalanTableaux']) +lazy_import('sage.combinat.path_tableaux.path_tableau', ['PathTableau', 'PathTableaux']) +lazy_import('sage.combinat.path_tableaux.catalan', ['CatalanTableau', 'CatalanTableaux']) diff --git a/src/sage/combinat/path_tableaux/__init__.py b/src/sage/combinat/path_tableaux/__init__.py new file mode 100644 index 00000000000..977ae3aea9b --- /dev/null +++ b/src/sage/combinat/path_tableaux/__init__.py @@ -0,0 +1,7 @@ +r""" +Path Tableaux +============= + +- :ref:`sage.combinat.path_tableaux.path_tableau` +- :ref:`sage.combinat.path_tableaux.catalan` +""" diff --git a/src/sage/combinat/pathtableaux/all.py b/src/sage/combinat/path_tableaux/all.py similarity index 64% rename from src/sage/combinat/pathtableaux/all.py rename to src/sage/combinat/path_tableaux/all.py index 122a2cb221c..63ee69c26fb 100644 --- a/src/sage/combinat/pathtableaux/all.py +++ b/src/sage/combinat/path_tableaux/all.py @@ -1,4 +1,4 @@ from __future__ import absolute_import -from .pathtableau import PathTableau, PathTableaux +from .path_tableau import PathTableau, PathTableaux from .catalan import CatalanTableau, CatalanTableaux diff --git a/src/sage/combinat/pathtableaux/catalan.py b/src/sage/combinat/path_tableaux/catalan.py similarity index 100% rename from src/sage/combinat/pathtableaux/catalan.py rename to src/sage/combinat/path_tableaux/catalan.py diff --git a/src/sage/combinat/pathtableaux/pathtableau.py b/src/sage/combinat/path_tableaux/path_tableau.py similarity index 100% rename from src/sage/combinat/pathtableaux/pathtableau.py rename to src/sage/combinat/path_tableaux/path_tableau.py diff --git a/src/sage/combinat/pathtableaux/__init__.py b/src/sage/combinat/pathtableaux/__init__.py deleted file mode 100644 index 9a5af620dd1..00000000000 --- a/src/sage/combinat/pathtableaux/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -r""" -Path Tableaux -============= - -- :ref:`sage.combinat.pathtableaux.pathtableau` -- :ref:`sage.combinat.pathtableaux.catalan` -""" From 653f8a5630af1fe8241da52c9690418848941d5b Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sat, 1 Dec 2018 09:30:45 -0600 Subject: [PATCH 067/300] Changed import to new file names --- src/sage/combinat/path_tableaux/catalan.py | 38 +++++++++++----------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/sage/combinat/path_tableaux/catalan.py b/src/sage/combinat/path_tableaux/catalan.py index 6580ca51f89..adce2efa147 100644 --- a/src/sage/combinat/path_tableaux/catalan.py +++ b/src/sage/combinat/path_tableaux/catalan.py @@ -29,7 +29,7 @@ from six import add_metaclass from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass -from sage.combinat.pathtableaux.pathtableau import PathTableau, PathTableaux +from sage.combinat.path_tableaux.path_tableau import PathTableau, PathTableaux from sage.combinat.combinatorial_map import combinatorial_map from sage.combinat.dyck_word import DyckWord from sage.combinat.perfect_matching import PerfectMatching @@ -86,30 +86,30 @@ class CatalanTableau(PathTableau): def __classcall_private__(cls, ot): """This is the preprocessing for creating paths. - INPUT: + INPUT: - - a sequence of nonnegative integers - - a two row standard skew tableau - - a Dyck word - - a noncrossing perfect matching + - a sequence of nonnegative integers + - a two row standard skew tableau + - a Dyck word + - a noncrossing perfect matching - EXAMPLES:: + EXAMPLES:: + + sage: CatalanTableau([0,1,2,1,0]) + [0, 1, 2, 1, 0] - sage: CatalanTableau([0,1,2,1,0]) - [0, 1, 2, 1, 0] + sage: w = DyckWord([1,1,0,0]) + sage: CatalanTableau(w) + [0, 1, 2, 1, 0] - sage: w = DyckWord([1,1,0,0]) - sage: CatalanTableau(w) - [0, 1, 2, 1, 0] + sage: p = PerfectMatching([(1,2),(3,4)]) + sage: CatalanTableau(p) + [0, 1, 0, 1, 0] - sage: p = PerfectMatching([(1,2),(3,4)]) - sage: CatalanTableau(p) - [0, 1, 0, 1, 0] + sage: t = Tableau([[1,2],[3,4]]) + sage: CatalanTableau(t) + [0, 1, 2, 1, 0] - sage: t = Tableau([[1,2],[3,4]]) - sage: CatalanTableau(t) - [0, 1, 2, 1, 0] - """ w = None From 03152b8c8fd9e293083b3a344786f09ed0016fa6 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sun, 23 Dec 2018 18:25:26 -0600 Subject: [PATCH 068/300] Moved ClonableArray from ABC class to implementation --- src/sage/combinat/path_tableaux/catalan.py | 3 ++- src/sage/combinat/path_tableaux/path_tableau.py | 5 ++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/path_tableaux/catalan.py b/src/sage/combinat/path_tableaux/catalan.py index adce2efa147..acf656b278d 100644 --- a/src/sage/combinat/path_tableaux/catalan.py +++ b/src/sage/combinat/path_tableaux/catalan.py @@ -29,6 +29,7 @@ from six import add_metaclass from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass +from sage.structure.list_clone import ClonableArray from sage.combinat.path_tableaux.path_tableau import PathTableau, PathTableaux from sage.combinat.combinatorial_map import combinatorial_map from sage.combinat.dyck_word import DyckWord @@ -76,7 +77,7 @@ @add_metaclass(InheritComparisonClasscallMetaclass) -class CatalanTableau(PathTableau): +class CatalanTableau(ClonableArray,PathTableau): """ An instance is the sequence of nonnegative integers given by the heights of a Dyck word. diff --git a/src/sage/combinat/path_tableaux/path_tableau.py b/src/sage/combinat/path_tableaux/path_tableau.py index 67807124e15..b011ff77cc1 100644 --- a/src/sage/combinat/path_tableaux/path_tableau.py +++ b/src/sage/combinat/path_tableaux/path_tableau.py @@ -38,9 +38,8 @@ from six import add_metaclass from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass -from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method -from sage.structure.list_clone import ClonableArray +from sage.misc.abstract_method import abstract_method from sage.categories.sets_cat import Sets from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent @@ -50,7 +49,7 @@ #from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets @add_metaclass(InheritComparisonClasscallMetaclass) -class PathTableau(ClonableArray): +class PathTableau(): @abstract_method(optional=False) def _local_rule(self,i): From 6296795f10a50f58f42a956775ed0708d29064c0 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Wed, 13 Feb 2019 11:17:48 +0100 Subject: [PATCH 069/300] Added underscores to module list --- src/doc/en/reference/combinat/module_list.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst index dece071f843..4a6f6874650 100644 --- a/src/doc/en/reference/combinat/module_list.rst +++ b/src/doc/en/reference/combinat/module_list.rst @@ -172,8 +172,8 @@ Comprehensive Module list sage/combinat/output sage/combinat/parallelogram_polyomino sage/combinat/parking_functions - sage/combinat/pathtableau/catalan - sage/combinat/pathtableau/pathtableaux + sage/combinat/path_tableau/catalan + sage/combinat/path_tableau/path_tableaux sage/combinat/plane_partition sage/combinat/partition sage/combinat/partition_algebra From 415e70444f2535292ff8dae47a2352be3b34ce49 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Wed, 13 Feb 2019 14:28:59 -0600 Subject: [PATCH 070/300] I can't spell in French --- src/doc/en/reference/combinat/module_list.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst index 4a6f6874650..b229c14fd37 100644 --- a/src/doc/en/reference/combinat/module_list.rst +++ b/src/doc/en/reference/combinat/module_list.rst @@ -172,8 +172,8 @@ Comprehensive Module list sage/combinat/output sage/combinat/parallelogram_polyomino sage/combinat/parking_functions - sage/combinat/path_tableau/catalan - sage/combinat/path_tableau/path_tableaux + sage/combinat/path_tableaux/catalan + sage/combinat/path_tableaux/path_tableau sage/combinat/plane_partition sage/combinat/partition sage/combinat/partition_algebra From 4f519074a7c9730062e5ada048caff0a398f67b0 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Mon, 25 Feb 2019 16:06:34 -0500 Subject: [PATCH 071/300] Moved doc from classcall, added check in to_perfect_matching for skewness --- src/sage/combinat/path_tableaux/catalan.py | 46 ++++++++++++---------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/src/sage/combinat/path_tableaux/catalan.py b/src/sage/combinat/path_tableaux/catalan.py index acf656b278d..076f41ee024 100644 --- a/src/sage/combinat/path_tableaux/catalan.py +++ b/src/sage/combinat/path_tableaux/catalan.py @@ -81,35 +81,37 @@ class CatalanTableau(ClonableArray,PathTableau): """ An instance is the sequence of nonnegative integers given by the heights of a Dyck word. - """ - @staticmethod - def __classcall_private__(cls, ot): - """This is the preprocessing for creating paths. - INPUT: - - a sequence of nonnegative integers - - a two row standard skew tableau - - a Dyck word - - a noncrossing perfect matching + INPUT: - EXAMPLES:: + - a sequence of nonnegative integers + - a two row standard skew tableau + - a Dyck word + - a noncrossing perfect matching + + EXAMPLES:: - sage: CatalanTableau([0,1,2,1,0]) - [0, 1, 2, 1, 0] + sage: CatalanTableau([0,1,2,1,0]) + [0, 1, 2, 1, 0] - sage: w = DyckWord([1,1,0,0]) - sage: CatalanTableau(w) - [0, 1, 2, 1, 0] + sage: w = DyckWord([1,1,0,0]) + sage: CatalanTableau(w) + [0, 1, 2, 1, 0] - sage: p = PerfectMatching([(1,2),(3,4)]) - sage: CatalanTableau(p) - [0, 1, 0, 1, 0] + sage: p = PerfectMatching([(1,2),(3,4)]) + sage: CatalanTableau(p) + [0, 1, 0, 1, 0] - sage: t = Tableau([[1,2],[3,4]]) - sage: CatalanTableau(t) - [0, 1, 2, 1, 0] + sage: t = Tableau([[1,2],[3,4]]) + sage: CatalanTableau(t) + [0, 1, 2, 1, 0] + """ + + @staticmethod + def __classcall_private__(cls, ot): + """This is the preprocessing for creating paths. """ w = None @@ -261,6 +263,8 @@ def to_perfect_matching(self): sage: CatalanTableau([0,1,2,1,2,1,0,1,0]).to_perfect_matching() [(0, 5), (1, 2), (3, 4), (6, 7)] """ + if self.is_skew(): + raise ValueError( "%s does not start at 0" % (str(self)) ) w = self.to_word() y = DyckWord(w) pairs = set() From cd325b4f3f47d295ea9c5dc03a9e5150994ccdf2 Mon Sep 17 00:00:00 2001 From: Kevin Dilks Date: Mon, 25 Feb 2019 16:27:59 -0500 Subject: [PATCH 072/300] modified to_tableau method --- src/sage/combinat/path_tableaux/catalan.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/path_tableaux/catalan.py b/src/sage/combinat/path_tableaux/catalan.py index 076f41ee024..ec9552d482c 100644 --- a/src/sage/combinat/path_tableaux/catalan.py +++ b/src/sage/combinat/path_tableaux/catalan.py @@ -35,7 +35,7 @@ from sage.combinat.dyck_word import DyckWord from sage.combinat.perfect_matching import PerfectMatching from sage.combinat.skew_tableau import SkewTableau -from sage.combinat.tableau import Tableau +from sage.combinat.tableau import Tableau, StandardTableau from sage.rings.integer import Integer ############################################################################### @@ -280,14 +280,21 @@ def to_tableau(self): EXAMPLES:: - sage: T = CatalanTableau([0,1,2,3,2,3]) - sage: T.to_tableau() - [[1, 2, 3, 5], [4]] + sage: T = CatalanTableau([0,1,2,3,2,3]) + sage: T.to_tableau() + [[1, 2, 3, 5], [4]] + + sage: U = CatalanTableau([2,3,2,3]) + sage: U.to_tableau() + [[None, None, 1, 3], [2]] """ w = self.to_word() top = [ i+1 for i, a in enumerate(w) if a == 1 ] bot = [ i+1 for i, a in enumerate(w) if a == 0 ] - return SkewTableau([[None]*self[0]+top,bot]) + if self.is_skew(): + return SkewTableau([[None]*self[0]+top,bot]) + else: + return StandardTableau([[None]*self[0]+top,bot]) class CatalanTableaux(PathTableaux): From 4906a6a262625c5f9cc7bb37c2040c175df26660 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Tue, 9 Jul 2019 10:37:45 +0200 Subject: [PATCH 073/300] Minor changes --- src/sage/combinat/path_tableaux/catalan.py | 2 +- src/sage/combinat/path_tableaux/path_tableau.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/path_tableaux/catalan.py b/src/sage/combinat/path_tableaux/catalan.py index ec9552d482c..734cc159ff6 100644 --- a/src/sage/combinat/path_tableaux/catalan.py +++ b/src/sage/combinat/path_tableaux/catalan.py @@ -294,7 +294,7 @@ def to_tableau(self): if self.is_skew(): return SkewTableau([[None]*self[0]+top,bot]) else: - return StandardTableau([[None]*self[0]+top,bot]) + return StandardTableau([top,bot]) class CatalanTableaux(PathTableaux): diff --git a/src/sage/combinat/path_tableaux/path_tableau.py b/src/sage/combinat/path_tableaux/path_tableau.py index b011ff77cc1..09529ac9443 100644 --- a/src/sage/combinat/path_tableaux/path_tableau.py +++ b/src/sage/combinat/path_tableaux/path_tableau.py @@ -50,7 +50,8 @@ @add_metaclass(InheritComparisonClasscallMetaclass) class PathTableau(): - + r"""This is the abstract base class for path tableaux. + """ @abstract_method(optional=False) def _local_rule(self,i): """ From 1b7e13494daaa8e90a684e74dab69f99837c8866 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Thu, 11 Jul 2019 15:53:30 +0200 Subject: [PATCH 074/300] Edited doc strings. Added class CylindricalDiagram --- src/sage/combinat/all.py | 2 +- src/sage/combinat/path_tableaux/all.py | 2 +- src/sage/combinat/path_tableaux/catalan.py | 63 ++++---- .../combinat/path_tableaux/path_tableau.py | 134 +++++++++++++----- 4 files changed, 130 insertions(+), 71 deletions(-) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 60360bbd8cb..b77bdf4fd92 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -225,5 +225,5 @@ 'GrowthDiagramYoungFibonacci', 'GrowthDiagramSylvester']) # Path tableaux -lazy_import('sage.combinat.path_tableaux.path_tableau', ['PathTableau', 'PathTableaux']) +lazy_import('sage.combinat.path_tableaux.path_tableau', ['PathTableau', 'PathTableaux', 'CylindricalDiagram']) lazy_import('sage.combinat.path_tableaux.catalan', ['CatalanTableau', 'CatalanTableaux']) diff --git a/src/sage/combinat/path_tableaux/all.py b/src/sage/combinat/path_tableaux/all.py index 63ee69c26fb..36e8f5eafdf 100644 --- a/src/sage/combinat/path_tableaux/all.py +++ b/src/sage/combinat/path_tableaux/all.py @@ -1,4 +1,4 @@ from __future__ import absolute_import -from .path_tableau import PathTableau, PathTableaux +from .path_tableau import PathTableau, PathTableaux, CylindricalDiagram from .catalan import CatalanTableau, CatalanTableaux diff --git a/src/sage/combinat/path_tableaux/catalan.py b/src/sage/combinat/path_tableaux/catalan.py index 734cc159ff6..3b7d63e317f 100644 --- a/src/sage/combinat/path_tableaux/catalan.py +++ b/src/sage/combinat/path_tableaux/catalan.py @@ -1,21 +1,4 @@ -r""" -Catalan Tableaux - -This is an implementation of the abstract base class -:class:`sage.combinat.pathtableau.pathtableaux`. -This is the simplest implementation of PathTableaux and is included to -provide a convenient test case and for pedagogical purposes. - -In this implementation we have sequences of nonnegative integers. These -are required to be the heights Dyck words (except that we do not require -the sequence to start or end at height zero). These are in bijection -with skew standard tableaux with at most two rows. Sequences which start -and end at height zero are in bijection with noncrossing perfect matchings. - -AUTHORS: -- Bruce Westbury (2018): initial version -""" #***************************************************************************** # Copyright (C) 2018 Bruce Westbury , # @@ -26,11 +9,8 @@ # http://www.gnu.org/licenses/ #***************************************************************************** - -from six import add_metaclass -from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.structure.list_clone import ClonableArray -from sage.combinat.path_tableaux.path_tableau import PathTableau, PathTableaux +from sage.combinat.path_tableaux.path_tableau import PathTableau, PathTableaux, CylindricalDiagram from sage.combinat.combinatorial_map import combinatorial_map from sage.combinat.dyck_word import DyckWord from sage.combinat.perfect_matching import PerfectMatching @@ -39,8 +19,24 @@ from sage.rings.integer import Integer ############################################################################### +r""" +Catalan Tableaux + +This is an implementation of the abstract base class +:class:`sage.combinat.pathtableau.pathtableaux`. +This is the simplest implementation of PathTableaux and is included to +provide a convenient test case and for pedagogical purposes. + +In this implementation we have sequences of nonnegative integers. These +are required to be the heights Dyck words (except that we do not require +the sequence to start or end at height zero). These are in bijection +with skew standard tableaux with at most two rows. Sequences which start +and end at height zero are in bijection with noncrossing perfect matchings. + +AUTHORS: + +- Bruce Westbury (2018): initial version -""" Here we illustrate the slogan that promotion = rotation. EXAMPLES:: @@ -64,19 +60,18 @@ EXAMPLES:: sage: t = CatalanTableau([0,1,2,3,2,1,0]) - sage: SkewTableau(t.cylindrical_diagram()).pp() - 0 1 2 3 2 1 0 - . 0 1 2 1 0 1 0 - . . 0 1 0 1 2 1 0 - . . . 0 1 2 3 2 1 0 - . . . . 0 1 2 1 0 1 0 - . . . . . 0 1 0 1 2 1 0 - . . . . . . 0 1 2 3 2 1 0 + sage: print(CylindricalDiagram(t)) + The cylindrical growth diagram: + [0, 1, 2, 3, 2, 1, 0] + ['', 0, 1, 2, 1, 0, 1, 0] + ['', '', 0, 1, 0, 1, 2, 1, 0] + ['', '', '', 0, 1, 2, 3, 2, 1, 0] + ['', '', '', '', 0, 1, 2, 1, 0, 1, 0] + ['', '', '', '', '', 0, 1, 0, 1, 2, 1, 0] + ['', '', '', '', '', '', 0, 1, 2, 3, 2, 1, 0] sage: TestSuite(t).run() """ - -@add_metaclass(InheritComparisonClasscallMetaclass) class CatalanTableau(ClonableArray,PathTableau): """ An instance is the sequence of nonnegative @@ -297,6 +292,8 @@ def to_tableau(self): return StandardTableau([top,bot]) class CatalanTableaux(PathTableaux): - + """ + The parent class for CatalanTableau + """ Element = CatalanTableau diff --git a/src/sage/combinat/path_tableaux/path_tableau.py b/src/sage/combinat/path_tableaux/path_tableau.py index 09529ac9443..050768f8bc4 100644 --- a/src/sage/combinat/path_tableaux/path_tableau.py +++ b/src/sage/combinat/path_tableaux/path_tableau.py @@ -38,13 +38,13 @@ from six import add_metaclass from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass -from sage.misc.cachefunc import cached_method from sage.misc.abstract_method import abstract_method from sage.categories.sets_cat import Sets from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent #from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_graded -from sage.rings.integer import Integer +from sage.structure.sage_object import SageObject +from sage.misc.latex import latex #from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets #from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets @@ -68,7 +68,7 @@ def _local_rule(self,i): sage: t._local_rule(3) [0, 1, 2, 1, 2, 1, 0] """ - + ################################# Book Keeping ################################ def size(self): @@ -242,37 +242,6 @@ def cactus(self,i,j): ########################### Visualisation and checking ######################## - def cylindrical_diagram(self): - """ - Return the cylindrical growth diagram associated to ``self``. - - This provides a visual summary of several operations simultaneously. - The operations which can be read off directly from this diagram - are the powers of the promotion operator (which form the rows) - and the cactus group operators `s_{1,j}` (which form the - first half of the columns). - - EXAMPLES:: - - sage: t = CatalanTableau([0,1,2,3,2,1,0]) - sage: SkewTableau(t.cylindrical_diagram()).pp() - 0 1 2 3 2 1 0 - . 0 1 2 1 0 1 0 - . . 0 1 0 1 2 1 0 - . . . 0 1 2 3 2 1 0 - . . . . 0 1 2 1 0 1 0 - . . . . . 0 1 0 1 2 1 0 - . . . . . . 0 1 2 3 2 1 0 - """ - n = len(self) - result = [[None]*(2*n-1)]*n - T = self - for i in range(n): - result[i] = [None]*i + list(T) - T = T.promotion() - - return result - def _test_involution_rule(self, **options): """ Check that the local rule gives an involution. @@ -442,5 +411,98 @@ class PathTableaux(UniqueRepresentation,Parent): def __init(self): Parent.__init__(self, category=Sets()) - def _element_constructor_(self, *args, **keywords): - return self.element_class(self, *args, **keywords) + def _element_constructor_(self, *args, **kwds): + return self.element_class(self, *args, **kwds) + + + +class CylindricalDiagram(SageObject): + """ + A class for cylindrical growth diagrams. + + EXAMPLE:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: CylindricalDiagram(t) + A cylindrical growth diagram. + """ + + def __init__(self,T): + n = len(T) + result = [[None]*(2*n-1)]*n + for i in range(n): + result[i] = [""]*i + list(T) + T = T.promotion() + + self.diagram = result + + def __repr__(self): + return "A cylindrical growth diagram." + + def __str__(self): + """ + Returns a string representation of ``self`` + + EXAMPLE:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: print(CylindricalDiagram(t)) + The cylindrical growth diagram: + [0, 1, 2, 3, 2, 1, 0] + ['', 0, 1, 2, 1, 0, 1, 0] + ['', '', 0, 1, 0, 1, 2, 1, 0] + ['', '', '', 0, 1, 2, 3, 2, 1, 0] + ['', '', '', '', 0, 1, 2, 1, 0, 1, 0] + ['', '', '', '', '', 0, 1, 0, 1, 2, 1, 0] + ['', '', '', '', '', '', 0, 1, 2, 3, 2, 1, 0] + """ + + return "The cylindrical growth diagram:\n" + "\n".join( str(a) for a in self.diagram ) + + def _latex_(self): + """ + Returns a `\LaTeX` representation of ``self`` + + EXAMPLE:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: latex(CylindricalDiagram(t)) + \begin{array}{ccccccccccccc} + 0 & 1 & 2 & 3 & 2 & 1 & 0\\ + & 0 & 1 & 2 & 1 & 0 & 1 & 0\\ + & & 0 & 1 & 0 & 1 & 2 & 1 & 0\\ + & & & 0 & 1 & 2 & 3 & 2 & 1 & 0\\ + & & & & 0 & 1 & 2 & 1 & 0 & 1 & 0\\ + & & & & & 0 & 1 & 0 & 1 & 2 & 1 & 0\\ + & & & & & & 0 & 1 & 2 & 3 & 2 & 1 & 0 + \end{array} + + """ + + D = self.diagram + m = len(D[-1]) + result = "\\begin{array}{"+"c"*m + "}\n" + result += "\\\\ \n".join( " & ".join(latex(a) for a in x) for x in D ) + result += "\n \\end{array}\n" + return result + + + def pp(self): + """ + A pretty print utility method. + + EXAMPLES:: + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: c = CylindricalDiagram(t) + sage: c.pp() + 0 1 2 3 2 1 0 + 0 1 2 1 0 1 0 + 0 1 0 1 2 1 0 + 0 1 2 3 2 1 0 + 0 1 2 1 0 1 0 + 0 1 0 1 2 1 0 + 0 1 2 3 2 1 0 + + """ + m = max( max( len(str(a)) for a in x ) for x in self.diagram) + print "\n".join(" ".join("{:<{}}".format(a, m) for a in x) for x in self.diagram ) From 716b7cebd7a63844c1a6c4949be92421e22fef7a Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Thu, 11 Jul 2019 17:49:24 +0200 Subject: [PATCH 075/300] Added __init__ in CatalanTableau --- src/sage/combinat/path_tableaux/catalan.py | 65 ++++++++++--------- .../combinat/path_tableaux/path_tableau.py | 6 +- 2 files changed, 38 insertions(+), 33 deletions(-) diff --git a/src/sage/combinat/path_tableaux/catalan.py b/src/sage/combinat/path_tableaux/catalan.py index 3b7d63e317f..536df457152 100644 --- a/src/sage/combinat/path_tableaux/catalan.py +++ b/src/sage/combinat/path_tableaux/catalan.py @@ -1,24 +1,3 @@ - -#***************************************************************************** -# Copyright (C) 2018 Bruce Westbury , -# -# 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/ -#***************************************************************************** - -from sage.structure.list_clone import ClonableArray -from sage.combinat.path_tableaux.path_tableau import PathTableau, PathTableaux, CylindricalDiagram -from sage.combinat.combinatorial_map import combinatorial_map -from sage.combinat.dyck_word import DyckWord -from sage.combinat.perfect_matching import PerfectMatching -from sage.combinat.skew_tableau import SkewTableau -from sage.combinat.tableau import Tableau, StandardTableau -from sage.rings.integer import Integer - -############################################################################### r""" Catalan Tableaux @@ -72,7 +51,28 @@ sage: TestSuite(t).run() """ -class CatalanTableau(ClonableArray,PathTableau): +#***************************************************************************** +# Copyright (C) 2018 Bruce Westbury , +# +# 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/ +#***************************************************************************** + +from sage.structure.list_clone import ClonableArray +from sage.combinat.path_tableaux.path_tableau import PathTableau, PathTableaux +from sage.combinat.combinatorial_map import combinatorial_map +from sage.combinat.dyck_word import DyckWord +from sage.combinat.perfect_matching import PerfectMatching +from sage.combinat.skew_tableau import SkewTableau +from sage.combinat.tableau import Tableau, StandardTableau +from sage.rings.integer import Integer + +############################################################################### + +class CatalanTableau(PathTableau): """ An instance is the sequence of nonnegative integers given by the heights of a Dyck word. @@ -106,15 +106,18 @@ class CatalanTableau(ClonableArray,PathTableau): @staticmethod def __classcall_private__(cls, ot): - """This is the preprocessing for creating paths. - """ + This is the preprocessing for creating paths. + """ + return CatalanTableaux()(ot) + + def __init__(self, parent, ot, check=True): w = None if isinstance(ot, DyckWord): w = ot.heights() - if isinstance(ot, PerfectMatching): + elif isinstance(ot, PerfectMatching): if ot.is_noncrossing(): u = [1]*ot.size() for a in ot.arcs(): @@ -123,7 +126,7 @@ def __classcall_private__(cls, ot): else: raise ValueError("the perfect matching must be non crossing") - if isinstance(ot, Tableau): + elif isinstance(ot, Tableau): if len(ot) <= 2: if ot.is_standard(): u = [1] * ot.size() @@ -135,7 +138,7 @@ def __classcall_private__(cls, ot): else: raise ValueError("the tableau must have at most two rows") - if isinstance(ot, SkewTableau): + elif isinstance(ot, SkewTableau): if len(ot) <= 2: # The check that ot is standard is not implemented u = [1] * ot.size() @@ -146,7 +149,7 @@ def __classcall_private__(cls, ot): else: raise ValueError("the skew tableau must have at most two rows") - if isinstance(ot, (list,tuple)): + elif isinstance(ot, (list,tuple)): try: w = tuple([Integer(a) for a in ot]) except TypeError: @@ -154,9 +157,9 @@ def __classcall_private__(cls, ot): if w is None: raise ValueError("invalid input %s" % ot) - - return CatalanTableaux()(w) - + + ClonableArray.__init__(self, parent, w, check=check) + def check(self): n = len(self) diff --git a/src/sage/combinat/path_tableaux/path_tableau.py b/src/sage/combinat/path_tableaux/path_tableau.py index 050768f8bc4..7b9f6615278 100644 --- a/src/sage/combinat/path_tableaux/path_tableau.py +++ b/src/sage/combinat/path_tableaux/path_tableau.py @@ -44,13 +44,15 @@ from sage.structure.parent import Parent #from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_graded from sage.structure.sage_object import SageObject +from sage.structure.list_clone import ClonableArray from sage.misc.latex import latex #from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets #from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets @add_metaclass(InheritComparisonClasscallMetaclass) -class PathTableau(): - r"""This is the abstract base class for path tableaux. +class PathTableau(ClonableArray): + r""" + This is the abstract base class for path tableaux. """ @abstract_method(optional=False) def _local_rule(self,i): From 6f9d50418a680f8faee723696090fe3b73f097fb Mon Sep 17 00:00:00 2001 From: jmatherne Date: Tue, 23 Jul 2019 17:30:26 -0500 Subject: [PATCH 076/300] Added alpha-spectrum method to posets class --- src/sage/combinat/posets/posets.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 648f5c23ccb..1256aec9346 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -1618,6 +1618,20 @@ def linear_extensions(self, facade=False): from .linear_extensions import LinearExtensionsOfPoset return LinearExtensionsOfPoset(self, facade = facade) + def spectrum(P,a): + ''' + Input a pair (poset, element). + Outputs the a-spectrum in P. + ''' + aspec=[] + for i in range(len(P)): + aspec.append(0) + + for L in P.linear_extensions(): + # Warning! If facade=False in the definition of your poset, this won't work!! + aspec[L.index(a)] = aspec[L.index(a)]+1 + return aspec + def is_linear_extension(self, l): """ Returns whether ``l`` is a linear extension of ``self`` From 544eb660c2bd50076c4622b5e2c7d4c7c7f1e0ab Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Thu, 25 Jul 2019 14:32:05 +0100 Subject: [PATCH 077/300] Made corrections requested by Travis. --- src/sage/combinat/path_tableaux/catalan.py | 15 +++--- .../combinat/path_tableaux/path_tableau.py | 54 ++++++++----------- 2 files changed, 29 insertions(+), 40 deletions(-) diff --git a/src/sage/combinat/path_tableaux/catalan.py b/src/sage/combinat/path_tableaux/catalan.py index 536df457152..0e406313d64 100644 --- a/src/sage/combinat/path_tableaux/catalan.py +++ b/src/sage/combinat/path_tableaux/catalan.py @@ -77,14 +77,12 @@ class CatalanTableau(PathTableau): An instance is the sequence of nonnegative integers given by the heights of a Dyck word. - - INPUT: - - a sequence of nonnegative integers - - a two row standard skew tableau - - a Dyck word - - a noncrossing perfect matching + - a sequence of nonnegative integers + - a two row standard skew tableau + - a Dyck word + - a noncrossing perfect matching EXAMPLES:: @@ -107,11 +105,14 @@ class CatalanTableau(PathTableau): @staticmethod def __classcall_private__(cls, ot): """ - This is the preprocessing for creating paths. + This is the constructor for paths. """ return CatalanTableaux()(ot) def __init__(self, parent, ot, check=True): + """ + This is the preprocessing for creating paths. + """ w = None if isinstance(ot, DyckWord): diff --git a/src/sage/combinat/path_tableaux/path_tableau.py b/src/sage/combinat/path_tableaux/path_tableau.py index 7b9f6615278..f1a364ee625 100644 --- a/src/sage/combinat/path_tableaux/path_tableau.py +++ b/src/sage/combinat/path_tableaux/path_tableau.py @@ -71,7 +71,7 @@ def _local_rule(self,i): [0, 1, 2, 1, 2, 1, 0] """ -################################# Book Keeping ################################ + ################################# Book Keeping ############################ def size(self): """ @@ -109,7 +109,7 @@ def final_shape(self): """ return self[-1] -############################# Jeu de taquin ################################### + ############################# Jeu de taquin ############################### def promotion(self): """ @@ -242,7 +242,7 @@ def cactus(self,i,j): return self.cactus(1,j).cactus(1,j-i+1).cactus(1,j) -########################### Visualisation and checking ######################## + ########################### Visualisation and checking #################### def _test_involution_rule(self, **options): """ @@ -255,8 +255,9 @@ def _test_involution_rule(self, **options): """ tester = self._tester(**options) - tester.assertTrue(all( self._local_rule(i+1)._local_rule(i+1) == self - for i in range(self.size()-2) )) + for i in range(self.size()-2): + tester.assertTrue(self._local_rule(i+1)._local_rule(i+1) == self) + def _test_involution_cactus(self, **options): """ @@ -268,9 +269,9 @@ def _test_involution_cactus(self, **options): sage: t._test_involution_cactus() """ tester = self._tester(**options) - tester.assertTrue(all( self.cactus(1,i).cactus(1,i) == self - for i in range(2,self.size()+1) )) - + for i in range(2,self.size()+1): + tester.assertTrue(self.cactus(1,i).cactus(1,i) == self) + def _test_promotion(self, **options): """ Check that promotion can be expressed in terms of the cactus generators. @@ -282,7 +283,7 @@ def _test_promotion(self, **options): """ tester = self._tester(**options) n = self.size()-1 - tester.assertTrue( self.cactus(1,n-1).cactus(1,n).promotion() == self ) + tester.assertTrue(self.cactus(1,n-1).cactus(1,n).promotion() == self) def _test_commutation(self, **options): """ @@ -422,7 +423,7 @@ class CylindricalDiagram(SageObject): """ A class for cylindrical growth diagrams. - EXAMPLE:: + EXAMPLES:: sage: t = CatalanTableau([0,1,2,3,2,1,0]) sage: CylindricalDiagram(t) @@ -438,34 +439,14 @@ def __init__(self,T): self.diagram = result - def __repr__(self): + def _repr_(self): return "A cylindrical growth diagram." - def __str__(self): - """ - Returns a string representation of ``self`` - - EXAMPLE:: - - sage: t = CatalanTableau([0,1,2,3,2,1,0]) - sage: print(CylindricalDiagram(t)) - The cylindrical growth diagram: - [0, 1, 2, 3, 2, 1, 0] - ['', 0, 1, 2, 1, 0, 1, 0] - ['', '', 0, 1, 0, 1, 2, 1, 0] - ['', '', '', 0, 1, 2, 3, 2, 1, 0] - ['', '', '', '', 0, 1, 2, 1, 0, 1, 0] - ['', '', '', '', '', 0, 1, 0, 1, 2, 1, 0] - ['', '', '', '', '', '', 0, 1, 2, 3, 2, 1, 0] - """ - - return "The cylindrical growth diagram:\n" + "\n".join( str(a) for a in self.diagram ) - def _latex_(self): - """ + r""" Returns a `\LaTeX` representation of ``self`` - EXAMPLE:: + EXAMPLES:: sage: t = CatalanTableau([0,1,2,3,2,1,0]) sage: latex(CylindricalDiagram(t)) @@ -488,7 +469,14 @@ def _latex_(self): result += "\n \\end{array}\n" return result + def _ascii_art_(self): + r""" + """ + def _unicode_art_(self): + r""" + """ + def pp(self): """ A pretty print utility method. From 1005509be5429618f5af4dcc9653f233e4c8cf60 Mon Sep 17 00:00:00 2001 From: jmatherne Date: Thu, 25 Jul 2019 19:12:06 -0500 Subject: [PATCH 078/300] Added atkinson method to posets.py to use Atkinson's algorithm for computing linear extensions of posets whose underlying undirected graph is a forest --- src/sage/combinat/posets/posets.py | 209 ++++++++++++++++++++++++++++- 1 file changed, 206 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 1256aec9346..40cf1cd76d3 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -281,6 +281,7 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.misc.misc_c import prod from sage.functions.other import floor +from sage.functions.other import binomial from sage.categories.category import Category from sage.categories.sets_cat import Sets from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets @@ -1618,20 +1619,222 @@ def linear_extensions(self, facade=False): from .linear_extensions import LinearExtensionsOfPoset return LinearExtensionsOfPoset(self, facade = facade) - def spectrum(P,a): + def spectrum(self,a): ''' Input a pair (poset, element). Outputs the a-spectrum in P. ''' aspec=[] - for i in range(len(P)): + for i in range(len(self)): aspec.append(0) - for L in P.linear_extensions(): + for L in self.linear_extensions(): # Warning! If facade=False in the definition of your poset, this won't work!! aspec[L.index(a)] = aspec[L.index(a)]+1 return aspec + @staticmethod + def _glue_together(aspec, bspec, orientation): + r""" + Input the a-spectrum and b-spectrum of posets P and Q, respectively, + together with an orientation: a < b or b < a. + Return the a-spectrum (or b-spectrum, depending on orientation) of + the poset which is a disjoint union of P and Q, together with a new + covering relation a < b. + + INPUT: + + - ``aspec`` -- list; the a-spectrum of a poset P. + + - ``bspec`` -- list; the b-spectrum of a poset Q. + + - ``orientation`` -- boolean; True if a < b, False otherwise. + + OUTPUT: The a-spectrum (or b-spectrum, depending on orientation), returned + as a list, of the poset which is a disjoint union of P and Q, + together with the additional covering relation a < b. + + EXAMPLES: + + sage: Pdata = (0, 1, 2, 0) + sage: Qdata = (1, 1, 0) + sage: _glue_together(Pdata, Qdata, True) + [0, 20, 28, 18, 0, 0, 0] + + sage: Pdata = (0, 0, 2) + sage: Qdata = (0, 1) + sage: _glue_together(Pdata, Qdata, False) + [0, 0, 0, 0, 8] + + """ + newaspec = [] + + if orientation is False: + aspec, bspec = bspec, aspec + + p = len(aspec) + q = len(bspec) + + for r in range(1, p+q+1): + newaspec.append(0) + for i in range(max(1, r-q), min(p, r) + 1): + kval = binomial(r-1, i-1) * binomial(p+q-r, p-i) + if orientation: + inner_sum = sum(bspec[j-1] for j in range(r-i + 1, len(bspec) + 1)) + else: + inner_sum = sum(bspec[j-1] for j in range(1, r-i + 1)) + newaspec[-1] = newaspec[-1] + (aspec[i-1] * kval * inner_sum) + return newaspec + + + def _split(self, a, b): + r""" + Deletes the edge a < b from a poset. Returns the two resulting connected + components. + + INPUT: + + - ``self`` -- a poset. + + - ``a`` -- an element of the poset P. + + - ``b`` -- an element of the poset P. + + OUTPUT: A list [P', Q'] containing two posets P' and Q', which are the + connected components of the poset P after deleting the covering + relation a < b. + + EXAMPLES: + + sage: uc = [[1, 2], [], []] + sage: P = FinitePoset(DiGraph(dict([[i, uc[i]] for i in range(len(uc))])), facade = True) + sage: P._split(0, 1) + [Finite poset containing 2 elements, Finite poset containing 1 elements] + + sage: uc = [[1, 2], [], []] + sage: P = FinitePoset(DiGraph(dict([[i, uc[i]] for i in range(len(uc))])), facade = True) + sage: P._split(0, 2) + [Finite poset containing 2 elements, Finite poset containing 1 elements] + + """ + covers = self.cover_relations() + covers.remove([a, b]) + bothPPandQ = Poset((P.list(), covers), cover_relations = True) + com = bothPPandQ.connected_components() + if not len(com) == 2: + raise ValueError, "Wrong number of connected components after the covering relation is deleted!" + if a in com[0]: + return com + else: + return [com[1], com[0]] + + def _spectrum(self, a): + r""" + Computes the a spectrum of a poset whose underlying graph is a tree. + + INPUT: + + - ``self`` -- a poset for which the underlying undirected graph is a tree. + + - ``a`` -- an element of the poset. + + OUTPUT: The a-spectrum, returned as a list, of the poset self. + + EXAMPLES: + + sage: uc = [[2], [2], [3, 4], [], []] + sage: P = FinitePoset(DiGraph(dict([[i, uc[i]] for i in range(len(uc))])), facade = True) + sage: P._spectrum(0) + [2, 2, 0, 0, 0] + + sage: uc = [[2], [2], [3, 4], [], []] + sage: P = FinitePoset(DiGraph(dict([[i, uc[i]] for i in range(len(uc))])), facade = True) + sage: P._spectrum(2) + [0, 0, 4, 0, 0] + + sage: uc = [[2], [2], [3, 4], [], []] + sage: P = FinitePoset(DiGraph(dict([[i, uc[i]] for i in range(len(uc))])), facade = True) + sage: P._spectrum(3) + [0, 0, 0, 2, 2] + + """ + UC = self.upper_covers(a) + LC = self.lower_covers(a) + if not UC and not LC: + return [1] + if UC: + b = UC[0] + orientation = True + else: + (a, b) = (self.lower_covers(a)[0], a) + orientation = False + PP, Q = _split(self, a, b) + aspec = PP._spectrum(a) + bspec = Q._spectrum(b) + return _glue_together(aspec, bspec, orientation) + + + def atkinson(self, a): + r""" + Compute the a-spectrum of a poset whose underlying graph is a forest. + + INPUT: + + - ``self`` -- a poset for which the underlying undirected graph is a forest. + + - ``a`` -- an element of the poset. + + OUTPUT: The a-spectrum, as a list, of the poset. + + EXAMPLES: + + sage: uc = [[2], [2], [3, 4], [], []] + sage: P = FinitePoset(DiGraph(dict([[i, uc[i]] for i in range(len(uc))])), facade = True) + sage: _spectrum(P, 0) + [2, 2, 0, 0, 0] + + sage:uc = [[1], [2,3], [], [], [5,6], [], []] + sage: P = FinitePoset(DiGraph(dict([[i, uc[i]] for i in range(len(uc))])), facade = True) + sage: atkinson(P, 5) + [0, 10, 18, 24, 28, 30, 30] + + sage: P=posets.AntichainPoset(10) + sage: atkinson(P, 0) + [362880,362880,362880,362880,362880,362880,362880,362880,362880,362880] + + """ + if a not in self: + raise ValueError, "Input element is not in poset!" + + n = self.cardinality() + com = self.connected_components() + remainderposet = Poset() + + for X in com: + if a in X: + main = X + else: + remainderposet = remainderposet.disjoint_union(X) + + k = main.cardinality() + aspec = main._spectrum(a) + + if remainderposet.cardinality() == 0: + return aspec + + b = remainderposet.an_element() + bspec = remainderposet.atkinson(b) + nlinexts = sum(bspec) + + newaspec = [] + + for r in range(1, n+1): + newaspec.append(0) + for i in range(max(1, r-n+k), min(r,k) + 1): + kval = binomial(r-1, i-1) * binomial(n - r, k - i) + newaspec[-1] += kval * aspec[i-1] * nlinexts + return newaspec + def is_linear_extension(self, l): """ Returns whether ``l`` is a linear extension of ``self`` From fd63ff1f5e32c68a8cedca4a6fdcd81b02f353ce Mon Sep 17 00:00:00 2001 From: jmatherne Date: Fri, 26 Jul 2019 11:39:48 -0500 Subject: [PATCH 079/300] Fixed documentation. Code is ready to review. --- src/doc/en/reference/references/index.rst | 5 +- src/sage/combinat/posets/posets.py | 157 ++++++++++++++-------- 2 files changed, 104 insertions(+), 58 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 478171842e8..14b4232d6e9 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -243,6 +243,9 @@ REFERENCES: Math., Combinatorics (T. S. Motzkin, ed.), vol. 19, AMS, Providence 1971 +.. [At1990] \M. D. Atkinson. *On computing the number of linear extensions of a + tree.* Order 7 (1990) 20-25. + .. [At1992] \M. D. Atkinson. *Solomon's descent algebra revisited.* Bull. London Math. Soc. 24 (1992) 545-551. http://www.cs.otago.ac.nz/staffpriv/mike/Papers/Descent/DescAlgRevisited.pdf @@ -2555,7 +2558,7 @@ REFERENCES: Compositio Mathematica, **149** (2013), no. 10. :arxiv:`1111.3660`. -.. [Kly1990] Klyachko, Aleksandr Anatolevich. +.. [Kly1990] Klyachko, Aleksandr Anatolevich. Equivariant Bundles on Toral Varieties, Math USSR Izv. 35 (1990), 337-375. http://iopscience.iop.org/0025-5726/35/2/A04/pdf/0025-5726_35_2_A04.pdf diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 40cf1cd76d3..c2ce4dd0caf 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -1620,27 +1620,56 @@ def linear_extensions(self, facade=False): return LinearExtensionsOfPoset(self, facade = facade) def spectrum(self,a): - ''' - Input a pair (poset, element). - Outputs the a-spectrum in P. - ''' - aspec=[] + r""" + Returns the a-spectrum of this poset. + + The `a`-spectrum in this poset is the list of integers whose + i-th position contains the number of linear extensions of this poset + that have `a` in the i-th location. + + INPUT: + + - ``a`` -- an element of this poset. + + OUTPUT: The a-spectrum, returned as a list, of this poset. + + EXAMPLES: + + sage: P = posets.ChainPoset(5) + sage: P.spectrum(2) + [0, 0, 1, 0, 0] + + sage: P = posets.BooleanLattice(3) + sage: P.spectrum(5) + [0, 0, 0, 4, 12, 16, 16, 0] + + sage: P = posets.AntichainPoset(4) + sage: P.spectrum(3) + [6, 6, 6, 6] + + """ + if a not in self: + raise ValueError, "Input element is not in poset!" + + aspec = [] for i in range(len(self)): aspec.append(0) for L in self.linear_extensions(): - # Warning! If facade=False in the definition of your poset, this won't work!! - aspec[L.index(a)] = aspec[L.index(a)]+1 + aspec[L.index(a)] = aspec[L.index(a)] + 1 return aspec @staticmethod - def _glue_together(aspec, bspec, orientation): + def _glue_spectra(aspec, bspec, orientation): r""" - Input the a-spectrum and b-spectrum of posets P and Q, respectively, - together with an orientation: a < b or b < a. - Return the a-spectrum (or b-spectrum, depending on orientation) of - the poset which is a disjoint union of P and Q, together with a new - covering relation a < b. + Returns the a-spectrum of a poset by merging `aspec` and `bspec`. + + `aspec` and `bspec` are the a-spectrum and b-spectrum of two different + posets (see :meth:`atkinson` for the definition of a-spectrum). + + The orientation determines whether a < b or b < a in the combined poset. + + This is a helper method for :meth:`atkinson`. INPUT: @@ -1650,20 +1679,22 @@ def _glue_together(aspec, bspec, orientation): - ``orientation`` -- boolean; True if a < b, False otherwise. - OUTPUT: The a-spectrum (or b-spectrum, depending on orientation), returned - as a list, of the poset which is a disjoint union of P and Q, - together with the additional covering relation a < b. + OUTPUT: The a-spectrum (or b-spectrum, depending on orientation), + returned as a list, of the poset which is a disjoint union + of P and Q, together with the additional + covering relation a < b. EXAMPLES: - sage: Pdata = (0, 1, 2, 0) - sage: Qdata = (1, 1, 0) - sage: _glue_together(Pdata, Qdata, True) + sage: from sage.combinat.posets.posets import FinitePoset + sage: Pdata = [0, 1, 2, 0] + sage: Qdata = [1, 1, 0] + sage: FinitePoset._glue_spectra(Pdata, Qdata, True) [0, 20, 28, 18, 0, 0, 0] - sage: Pdata = (0, 0, 2) - sage: Qdata = (0, 1) - sage: _glue_together(Pdata, Qdata, False) + sage: Pdata = [0, 0, 2] + sage: Qdata = [0, 1] + sage: FinitePoset._glue_spectra(Pdata, Qdata, False) [0, 0, 0, 0, 8] """ @@ -1686,12 +1717,13 @@ def _glue_together(aspec, bspec, orientation): newaspec[-1] = newaspec[-1] + (aspec[i-1] * kval * inner_sum) return newaspec - def _split(self, a, b): r""" Deletes the edge a < b from a poset. Returns the two resulting connected components. + This is a helper method for :meth:`atkinson`. + INPUT: - ``self`` -- a poset. @@ -1706,20 +1738,18 @@ def _split(self, a, b): EXAMPLES: - sage: uc = [[1, 2], [], []] - sage: P = FinitePoset(DiGraph(dict([[i, uc[i]] for i in range(len(uc))])), facade = True) + sage: P = Poset({0: [1,2], 1: [], 2: []}) sage: P._split(0, 1) [Finite poset containing 2 elements, Finite poset containing 1 elements] - sage: uc = [[1, 2], [], []] - sage: P = FinitePoset(DiGraph(dict([[i, uc[i]] for i in range(len(uc))])), facade = True) - sage: P._split(0, 2) - [Finite poset containing 2 elements, Finite poset containing 1 elements] + sage: P = posets.ChainPoset(5) + sage: P._split(1, 2) + [Finite poset containing 2 elements, Finite poset containing 3 elements] """ covers = self.cover_relations() covers.remove([a, b]) - bothPPandQ = Poset((P.list(), covers), cover_relations = True) + bothPPandQ = Poset((self.list(), covers), cover_relations = True) com = bothPPandQ.connected_components() if not len(com) == 2: raise ValueError, "Wrong number of connected components after the covering relation is deleted!" @@ -1728,9 +1758,11 @@ def _split(self, a, b): else: return [com[1], com[0]] - def _spectrum(self, a): + def _spectrum_of_tree(self, a): r""" - Computes the a spectrum of a poset whose underlying graph is a tree. + Computes the a-spectrum of a poset whose underlying graph is a tree. + + This is a helper method for :meth:`atkinson`. INPUT: @@ -1742,19 +1774,16 @@ def _spectrum(self, a): EXAMPLES: - sage: uc = [[2], [2], [3, 4], [], []] - sage: P = FinitePoset(DiGraph(dict([[i, uc[i]] for i in range(len(uc))])), facade = True) - sage: P._spectrum(0) + sage: P = Poset({0: [2], 1: [2], 2: [3, 4], 3: [], 4: []}) + sage: P._spectrum_of_tree(0) [2, 2, 0, 0, 0] - sage: uc = [[2], [2], [3, 4], [], []] - sage: P = FinitePoset(DiGraph(dict([[i, uc[i]] for i in range(len(uc))])), facade = True) - sage: P._spectrum(2) + sage: P = Poset({0: [2], 1: [2], 2: [3, 4], 3: [], 4: []}) + sage: P._spectrum_of_tree(2) [0, 0, 4, 0, 0] - sage: uc = [[2], [2], [3, 4], [], []] - sage: P = FinitePoset(DiGraph(dict([[i, uc[i]] for i in range(len(uc))])), facade = True) - sage: P._spectrum(3) + sage: P = Poset({0: [2], 1: [2], 2: [3, 4], 3: [], 4: []}) + sage: P._spectrum_of_tree(3) [0, 0, 0, 2, 2] """ @@ -1768,15 +1797,21 @@ def _spectrum(self, a): else: (a, b) = (self.lower_covers(a)[0], a) orientation = False - PP, Q = _split(self, a, b) - aspec = PP._spectrum(a) - bspec = Q._spectrum(b) - return _glue_together(aspec, bspec, orientation) + PP, Q = self._split(a, b) + aspec = PP._spectrum_of_tree(a) + bspec = Q._spectrum_of_tree(b) + return FinitePoset._glue_spectra(aspec, bspec, orientation) def atkinson(self, a): r""" - Compute the a-spectrum of a poset whose underlying graph is a forest. + Compute the a-spectrum of this poset, whose underlying undirected graph + is a forest. + + This poset is expected to have its underlying undirected graph be a + forest. Given an element `a` in a poset `P`, the `a`-spectrum is + the list of integers whose i-th position contains the number of linear + extensions of `P` that have `a` in the i-th location. INPUT: @@ -1788,25 +1823,32 @@ def atkinson(self, a): EXAMPLES: - sage: uc = [[2], [2], [3, 4], [], []] - sage: P = FinitePoset(DiGraph(dict([[i, uc[i]] for i in range(len(uc))])), facade = True) - sage: _spectrum(P, 0) + sage: P = Poset({0: [2], 1: [2], 2: [3, 4], 3: [], 4: []}) + sage: P.atkinson(0) [2, 2, 0, 0, 0] - sage:uc = [[1], [2,3], [], [], [5,6], [], []] - sage: P = FinitePoset(DiGraph(dict([[i, uc[i]] for i in range(len(uc))])), facade = True) - sage: atkinson(P, 5) + sage: P = Poset({0: [1], 1: [2, 3], 2: [], 3: [], 4: [5, 6], 5: [], 6: []}) + sage: P.atkinson(5) [0, 10, 18, 24, 28, 30, 30] - sage: P=posets.AntichainPoset(10) - sage: atkinson(P, 0) - [362880,362880,362880,362880,362880,362880,362880,362880,362880,362880] + sage: P = posets.AntichainPoset(10) + sage: P.atkinson(0) + [362880, 362880, 362880, 362880, 362880, 362880, 362880, 362880, 362880, 362880] + + .. NOTE:: + + This function is the implementation of the algorithm from [At1990]_. """ if a not in self: raise ValueError, "Input element is not in poset!" + if not self.hasse_diagram().to_undirected().is_forest(): + raise ValueError, "This poset is not a forest." + n = self.cardinality() + + # Compute the component of this poset containing `a` and its complement com = self.connected_components() remainderposet = Poset() @@ -1816,8 +1858,7 @@ def atkinson(self, a): else: remainderposet = remainderposet.disjoint_union(X) - k = main.cardinality() - aspec = main._spectrum(a) + aspec = main._spectrum_of_tree(a) if remainderposet.cardinality() == 0: return aspec @@ -1827,7 +1868,9 @@ def atkinson(self, a): nlinexts = sum(bspec) newaspec = [] + k = main.cardinality() + # Compute number of shuffles of linear extensions of the two posets for r in range(1, n+1): newaspec.append(0) for i in range(max(1, r-n+k), min(r,k) + 1): From 7df574c18db780a316b61c5196e18055d414a58b Mon Sep 17 00:00:00 2001 From: jmatherne Date: Fri, 26 Jul 2019 14:11:59 -0500 Subject: [PATCH 080/300] Updated to adhere to the Python/Sage style guide --- src/sage/combinat/posets/posets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index c2ce4dd0caf..6d481c00084 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -1650,7 +1650,7 @@ def spectrum(self,a): """ if a not in self: raise ValueError, "Input element is not in poset!" - + aspec = [] for i in range(len(self)): aspec.append(0) @@ -1738,7 +1738,7 @@ def _split(self, a, b): EXAMPLES: - sage: P = Poset({0: [1,2], 1: [], 2: []}) + sage: P = Poset({0: [1, 2], 1: [], 2: []}) sage: P._split(0, 1) [Finite poset containing 2 elements, Finite poset containing 1 elements] From 002ae1523d5144769aba55a1a158ea04e999dc6a Mon Sep 17 00:00:00 2001 From: Bryan Gillespie Date: Sat, 4 Apr 2020 12:13:16 -0600 Subject: [PATCH 081/300] Implement small revisions for rebase to 9.1.beta9 This makes a few syntax changes for Python 3 compatibility, and fixes some formatting in the relevant docstrings. --- src/sage/combinat/posets/posets.py | 89 ++++++++++++++---------------- 1 file changed, 41 insertions(+), 48 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 8f24693dc76..8d15891b05a 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -1557,7 +1557,7 @@ def linear_extension(self, linear_extension=None, check=True): @cached_method def linear_extensions(self, facade=False): """ - Returns the enumerated set of all the linear extensions of this poset + Return the enumerated set of all the linear extensions of this poset INPUT: @@ -1631,21 +1631,21 @@ def linear_extensions(self, facade=False): from .linear_extensions import LinearExtensionsOfPoset return LinearExtensionsOfPoset(self, facade = facade) - def spectrum(self,a): + def spectrum(self, a): r""" - Returns the a-spectrum of this poset. + Return the `a`-spectrum of this poset. The `a`-spectrum in this poset is the list of integers whose - i-th position contains the number of linear extensions of this poset - that have `a` in the i-th location. + `i`-th position contains the number of linear extensions of this poset + that have `a` in the `i`-th location. INPUT: - ``a`` -- an element of this poset. - OUTPUT: The a-spectrum, returned as a list, of this poset. + OUTPUT: The `a`-spectrum of this poset, returned as a list. - EXAMPLES: + EXAMPLES:: sage: P = posets.ChainPoset(5) sage: P.spectrum(2) @@ -1658,10 +1658,9 @@ def spectrum(self,a): sage: P = posets.AntichainPoset(4) sage: P.spectrum(3) [6, 6, 6, 6] - """ if a not in self: - raise ValueError, "Input element is not in poset!" + raise ValueError("Input element is not in poset!") aspec = [] for i in range(len(self)): @@ -1674,29 +1673,29 @@ def spectrum(self,a): @staticmethod def _glue_spectra(aspec, bspec, orientation): r""" - Returns the a-spectrum of a poset by merging `aspec` and `bspec`. + Return the `a`-spectrum of a poset by merging ``aspec`` and ``bspec``. - `aspec` and `bspec` are the a-spectrum and b-spectrum of two different - posets (see :meth:`atkinson` for the definition of a-spectrum). + ``aspec`` and ``bspec`` are the `a`-spectrum and `b`-spectrum of two different + posets (see :meth:`atkinson` for the definition of `a`-spectrum). - The orientation determines whether a < b or b < a in the combined poset. + The orientation determines whether `a < b` or `b < a` in the combined poset. This is a helper method for :meth:`atkinson`. INPUT: - - ``aspec`` -- list; the a-spectrum of a poset P. + - ``aspec`` -- list; the `a`-spectrum of a poset `P`. - - ``bspec`` -- list; the b-spectrum of a poset Q. + - ``bspec`` -- list; the `b`-spectrum of a poset `Q`. - - ``orientation`` -- boolean; True if a < b, False otherwise. + - ``orientation`` -- boolean; ``True`` if `a < b`, ``False`` otherwise. - OUTPUT: The a-spectrum (or b-spectrum, depending on orientation), + OUTPUT: The `a`-spectrum (or `b`-spectrum, depending on orientation), returned as a list, of the poset which is a disjoint union - of P and Q, together with the additional - covering relation a < b. + of `P` and `Q`, together with the additional + covering relation `a < b`. - EXAMPLES: + EXAMPLES:: sage: from sage.combinat.posets.posets import FinitePoset sage: Pdata = [0, 1, 2, 0] @@ -1708,7 +1707,6 @@ def _glue_spectra(aspec, bspec, orientation): sage: Qdata = [0, 1] sage: FinitePoset._glue_spectra(Pdata, Qdata, False) [0, 0, 0, 0, 8] - """ newaspec = [] @@ -1731,8 +1729,8 @@ def _glue_spectra(aspec, bspec, orientation): def _split(self, a, b): r""" - Deletes the edge a < b from a poset. Returns the two resulting connected - components. + Return the two connected components obtained by deleting the covering relation + `a < b` from a poset whose Hasse daigram is a tree. This is a helper method for :meth:`atkinson`. @@ -1740,15 +1738,14 @@ def _split(self, a, b): - ``self`` -- a poset. - - ``a`` -- an element of the poset P. + - ``a`` -- an element of the poset. - - ``b`` -- an element of the poset P. + - ``b`` -- an element of the poset which covers ``a``. - OUTPUT: A list [P', Q'] containing two posets P' and Q', which are the - connected components of the poset P after deleting the covering - relation a < b. + OUTPUT: A list containing two posets which are the connected components + of this poset after deleting the covering relation `a < b`. - EXAMPLES: + EXAMPLES:: sage: P = Poset({0: [1, 2], 1: [], 2: []}) sage: P._split(0, 1) @@ -1757,14 +1754,13 @@ def _split(self, a, b): sage: P = posets.ChainPoset(5) sage: P._split(1, 2) [Finite poset containing 2 elements, Finite poset containing 3 elements] - """ covers = self.cover_relations() covers.remove([a, b]) - bothPPandQ = Poset((self.list(), covers), cover_relations = True) + bothPPandQ = Poset((self.list(), covers), cover_relations=True) com = bothPPandQ.connected_components() if not len(com) == 2: - raise ValueError, "Wrong number of connected components after the covering relation is deleted!" + raise ValueError("Wrong number of connected components after the covering relation is deleted!") if a in com[0]: return com else: @@ -1772,7 +1768,7 @@ def _split(self, a, b): def _spectrum_of_tree(self, a): r""" - Computes the a-spectrum of a poset whose underlying graph is a tree. + Return the `a`-spectrum of a poset whose underlying graph is a tree. This is a helper method for :meth:`atkinson`. @@ -1782,9 +1778,9 @@ def _spectrum_of_tree(self, a): - ``a`` -- an element of the poset. - OUTPUT: The a-spectrum, returned as a list, of the poset self. + OUTPUT: The `a`-spectrum of this poset, returned as a list. - EXAMPLES: + EXAMPLES:: sage: P = Poset({0: [2], 1: [2], 2: [3, 4], 3: [], 4: []}) sage: P._spectrum_of_tree(0) @@ -1797,7 +1793,6 @@ def _spectrum_of_tree(self, a): sage: P = Poset({0: [2], 1: [2], 2: [3, 4], 3: [], 4: []}) sage: P._spectrum_of_tree(3) [0, 0, 0, 2, 2] - """ UC = self.upper_covers(a) LC = self.lower_covers(a) @@ -1817,13 +1812,12 @@ def _spectrum_of_tree(self, a): def atkinson(self, a): r""" - Compute the a-spectrum of this poset, whose underlying undirected graph - is a forest. + Return the `a`-spectrum of a poset whose Hasse diagram is cycle-free as + an undirected graph. - This poset is expected to have its underlying undirected graph be a - forest. Given an element `a` in a poset `P`, the `a`-spectrum is - the list of integers whose i-th position contains the number of linear - extensions of `P` that have `a` in the i-th location. + Given an element `a` in a poset `P`, the `a`-spectrum is the list of + integers whose `i`-th term contains the number of linear extensions of + `P` with element `a` located in the i-th position. INPUT: @@ -1831,9 +1825,9 @@ def atkinson(self, a): - ``a`` -- an element of the poset. - OUTPUT: The a-spectrum, as a list, of the poset. + OUTPUT: The `a`-spectrum of this poset, returned as a list. - EXAMPLES: + EXAMPLES:: sage: P = Poset({0: [2], 1: [2], 2: [3, 4], 3: [], 4: []}) sage: P.atkinson(0) @@ -1850,13 +1844,12 @@ def atkinson(self, a): .. NOTE:: This function is the implementation of the algorithm from [At1990]_. - """ if a not in self: - raise ValueError, "Input element is not in poset!" + raise ValueError("Input element is not in poset!") if not self.hasse_diagram().to_undirected().is_forest(): - raise ValueError, "This poset is not a forest." + raise ValueError("This poset is not a forest.") n = self.cardinality() @@ -1892,7 +1885,7 @@ def atkinson(self, a): def is_linear_extension(self, l): """ - Returns whether ``l`` is a linear extension of ``self`` + Return whether ``l`` is a linear extension of ``self`` INPUT: From d30bd348b4031f51735e27c3b630b470b31e17fa Mon Sep 17 00:00:00 2001 From: Bryan Gillespie Date: Sat, 4 Apr 2020 14:18:31 -0600 Subject: [PATCH 082/300] Small style changes to code --- src/sage/combinat/posets/posets.py | 107 +++++++++++++++-------------- 1 file changed, 55 insertions(+), 52 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 8d15891b05a..682380d2e5c 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -1662,20 +1662,19 @@ def spectrum(self, a): if a not in self: raise ValueError("Input element is not in poset!") - aspec = [] - for i in range(len(self)): - aspec.append(0) - + a_spec = [0] * len(self) for L in self.linear_extensions(): - aspec[L.index(a)] = aspec[L.index(a)] + 1 - return aspec + idx = L.index(a) + a_spec[idx] += 1 + + return a_spec @staticmethod - def _glue_spectra(aspec, bspec, orientation): + def _glue_spectra(a_spec, b_spec, orientation): r""" - Return the `a`-spectrum of a poset by merging ``aspec`` and ``bspec``. + Return the `a`-spectrum of a poset by merging ``a_spec`` and ``b_spec``. - ``aspec`` and ``bspec`` are the `a`-spectrum and `b`-spectrum of two different + ``a_spec`` and ``b_spec`` are the `a`-spectrum and `b`-spectrum of two different posets (see :meth:`atkinson` for the definition of `a`-spectrum). The orientation determines whether `a < b` or `b < a` in the combined poset. @@ -1684,9 +1683,9 @@ def _glue_spectra(aspec, bspec, orientation): INPUT: - - ``aspec`` -- list; the `a`-spectrum of a poset `P`. + - ``a_spec`` -- list; the `a`-spectrum of a poset `P`. - - ``bspec`` -- list; the `b`-spectrum of a poset `Q`. + - ``b_spec`` -- list; the `b`-spectrum of a poset `Q`. - ``orientation`` -- boolean; ``True`` if `a < b`, ``False`` otherwise. @@ -1708,24 +1707,25 @@ def _glue_spectra(aspec, bspec, orientation): sage: FinitePoset._glue_spectra(Pdata, Qdata, False) [0, 0, 0, 0, 8] """ - newaspec = [] + new_a_spec = [] if orientation is False: - aspec, bspec = bspec, aspec + a_spec, b_spec = b_spec, a_spec - p = len(aspec) - q = len(bspec) + p = len(a_spec) + q = len(b_spec) for r in range(1, p+q+1): - newaspec.append(0) + new_a_spec.append(0) for i in range(max(1, r-q), min(p, r) + 1): - kval = binomial(r-1, i-1) * binomial(p+q-r, p-i) + k_val = binomial(r-1, i-1) * binomial(p+q-r, p-i) if orientation: - inner_sum = sum(bspec[j-1] for j in range(r-i + 1, len(bspec) + 1)) + inner_sum = sum(b_spec[j-1] for j in range(r-i + 1, len(b_spec) + 1)) else: - inner_sum = sum(bspec[j-1] for j in range(1, r-i + 1)) - newaspec[-1] = newaspec[-1] + (aspec[i-1] * kval * inner_sum) - return newaspec + inner_sum = sum(b_spec[j-1] for j in range(1, r-i + 1)) + new_a_spec[-1] = new_a_spec[-1] + (a_spec[i-1] * k_val * inner_sum) + + return new_a_spec def _split(self, a, b): r""" @@ -1757,14 +1757,17 @@ def _split(self, a, b): """ covers = self.cover_relations() covers.remove([a, b]) - bothPPandQ = Poset((self.list(), covers), cover_relations=True) - com = bothPPandQ.connected_components() - if not len(com) == 2: + split_poset = Poset((self.list(), covers), cover_relations=True) + components = split_poset.connected_components() + + if not len(components) == 2: raise ValueError("Wrong number of connected components after the covering relation is deleted!") - if a in com[0]: - return com - else: - return [com[1], com[0]] + + c1, c2 = components + if a in c2: + c1, c2 = c2, c1 + + return [c1, c2] def _spectrum_of_tree(self, a): r""" @@ -1794,20 +1797,20 @@ def _spectrum_of_tree(self, a): sage: P._spectrum_of_tree(3) [0, 0, 0, 2, 2] """ - UC = self.upper_covers(a) - LC = self.lower_covers(a) - if not UC and not LC: + upper_covers = self.upper_covers(a) + lower_covers = self.lower_covers(a) + if not upper_covers and not lower_covers: return [1] - if UC: - b = UC[0] + if upper_covers: + b = upper_covers[0] orientation = True else: (a, b) = (self.lower_covers(a)[0], a) orientation = False - PP, Q = self._split(a, b) - aspec = PP._spectrum_of_tree(a) - bspec = Q._spectrum_of_tree(b) - return FinitePoset._glue_spectra(aspec, bspec, orientation) + P, Q = self._split(a, b) + a_spec = P._spectrum_of_tree(a) + b_spec = Q._spectrum_of_tree(b) + return FinitePoset._glue_spectra(a_spec, b_spec, orientation) def atkinson(self, a): @@ -1854,34 +1857,34 @@ def atkinson(self, a): n = self.cardinality() # Compute the component of this poset containing `a` and its complement - com = self.connected_components() - remainderposet = Poset() + components = self.connected_components() + remainder_poset = Poset() - for X in com: + for X in components: if a in X: main = X else: - remainderposet = remainderposet.disjoint_union(X) + remainder_poset = remainder_poset.disjoint_union(X) - aspec = main._spectrum_of_tree(a) + a_spec = main._spectrum_of_tree(a) - if remainderposet.cardinality() == 0: - return aspec + if remainder_poset.cardinality() == 0: + return a_spec - b = remainderposet.an_element() - bspec = remainderposet.atkinson(b) - nlinexts = sum(bspec) + b = remainder_poset.an_element() + b_spec = remainder_poset.atkinson(b) + n_lin_exts = sum(b_spec) - newaspec = [] + new_a_spec = [] k = main.cardinality() # Compute number of shuffles of linear extensions of the two posets for r in range(1, n+1): - newaspec.append(0) + new_a_spec.append(0) for i in range(max(1, r-n+k), min(r,k) + 1): - kval = binomial(r-1, i-1) * binomial(n - r, k - i) - newaspec[-1] += kval * aspec[i-1] * nlinexts - return newaspec + k_val = binomial(r-1, i-1) * binomial(n - r, k - i) + new_a_spec[-1] += k_val * a_spec[i-1] * n_lin_exts + return new_a_spec def is_linear_extension(self, l): """ From a62bbbfef419ff421fbf20ffbcb2367650f09122 Mon Sep 17 00:00:00 2001 From: Bryan Gillespie Date: Sun, 5 Apr 2020 11:35:13 -0600 Subject: [PATCH 083/300] Add tests for error conditions --- src/sage/combinat/posets/posets.py | 36 ++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 682380d2e5c..50f8b2c0eea 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -1658,6 +1658,14 @@ def spectrum(self, a): sage: P = posets.AntichainPoset(4) sage: P.spectrum(3) [6, 6, 6, 6] + + TESTS:: + + sage: P = posets.ChainPoset(5) + sage: P.spectrum(6) + Traceback (most recent call last): + ... + ValueError: Input element is not in poset! """ if a not in self: raise ValueError("Input element is not in poset!") @@ -1754,6 +1762,20 @@ def _split(self, a, b): sage: P = posets.ChainPoset(5) sage: P._split(1, 2) [Finite poset containing 2 elements, Finite poset containing 3 elements] + + TESTS:: + + sage: P = posets.BooleanLattice(3) + sage: P._split(0, 1) + Traceback (most recent call last): + ... + ValueError: Wrong number of connected components after the covering relation is deleted! + + sage: P = Poset({0: [1], 1: [], 2: []}) + sage: P._split(0, 1) + Traceback (most recent call last): + ... + ValueError: Wrong number of connected components after the covering relation is deleted! """ covers = self.cover_relations() covers.remove([a, b]) @@ -1844,6 +1866,20 @@ def atkinson(self, a): sage: P.atkinson(0) [362880, 362880, 362880, 362880, 362880, 362880, 362880, 362880, 362880, 362880] + TESTS:: + + sage: P = posets.ChainPoset(5) + sage: P.atkinson(6) + Traceback (most recent call last): + ... + ValueError: Input element is not in poset! + + sage: P = posets.BooleanLattice(2) + sage: P.atkinson(1) + Traceback (most recent call last): + ... + ValueError: This poset is not a forest. + .. NOTE:: This function is the implementation of the algorithm from [At1990]_. From ca4ee7d644ff3ee45b2c6e6c9ae8b5a08c54abda Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Mon, 6 Apr 2020 18:08:31 +0200 Subject: [PATCH 084/300] modify doctests such that they work with various pari verions --- src/sage/lfunctions/dokchitser.py | 10 +- src/sage/lfunctions/pari.py | 2 +- src/sage/rings/number_field/number_field.py | 112 +++++++++++++----- .../number_field/number_field_element.pyx | 16 ++- .../rings/number_field/number_field_ideal.py | 23 +++- src/sage/rings/number_field/unit_group.py | 7 +- .../polynomial/polynomial_quotient_ring.py | 43 ++++++- .../elliptic_curves/ell_number_field.py | 24 +++- 8 files changed, 189 insertions(+), 48 deletions(-) diff --git a/src/sage/lfunctions/dokchitser.py b/src/sage/lfunctions/dokchitser.py index 680ac17dfd4..d4798b084f7 100644 --- a/src/sage/lfunctions/dokchitser.py +++ b/src/sage/lfunctions/dokchitser.py @@ -109,9 +109,8 @@ class Dokchitser(SageObject): 48 sage: L.taylor_series(1,4) 0.000000000000000 + 0.305999773834052*z + 0.186547797268162*z^2 - 0.136791463097188*z^3 + O(z^4) - sage: L.check_functional_equation() - 6.11218974700000e-18 # 32-bit - 6.04442711160669e-18 # 64-bit + sage: L.check_functional_equation() # abs tol 1e-19 + 6.04442711160669e-18 RANK 2 ELLIPTIC CURVE: @@ -668,9 +667,8 @@ def check_functional_equation(self, T=1.2): EXAMPLES:: sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1') - sage: L.check_functional_equation() - -1.35525271600000e-20 # 32-bit - -2.71050543121376e-20 # 64-bit + sage: L.check_functional_equation() # abs tol 1e-19 + -2.71050543121376e-20 If we choose the sign in functional equation for the `\zeta` function incorrectly, the functional equation diff --git a/src/sage/lfunctions/pari.py b/src/sage/lfunctions/pari.py index c60f944ed4e..361d1db2d77 100644 --- a/src/sage/lfunctions/pari.py +++ b/src/sage/lfunctions/pari.py @@ -422,7 +422,7 @@ class LFunction(SageObject): 50 sage: L.taylor_series(1,4) 0.000000000000000 + 0.305999773834052*z + 0.186547797268162*z^2 - 0.136791463097188*z^3 + O(z^4) - sage: L.check_functional_equation() + sage: L.check_functional_equation() # abs tol 4e-19 1.08420217248550e-19 .. RUBRIC:: Rank 2 elliptic curve diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 2732f22a093..e4dbf212afc 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -3425,7 +3425,7 @@ def ideals_of_bdd_norm(self, bound): sage: d = K.ideals_of_bdd_norm(10) sage: for n in d: ....: print(n) - ....: for I in d[n]: + ....: for I in sorted(d[n]): ....: print(I) 1 Fractional ideal (1) @@ -3436,25 +3436,25 @@ def ideals_of_bdd_norm(self, bound): Fractional ideal (3, 1/2*a - 1/2) Fractional ideal (3, 1/2*a + 1/2) 4 - Fractional ideal (4, 1/2*a + 3/2) Fractional ideal (2) + Fractional ideal (4, 1/2*a + 3/2) Fractional ideal (4, 1/2*a + 5/2) 5 6 Fractional ideal (1/2*a - 1/2) + Fractional ideal (1/2*a + 1/2) Fractional ideal (6, 1/2*a + 5/2) Fractional ideal (6, 1/2*a + 7/2) - Fractional ideal (1/2*a + 1/2) 7 8 - Fractional ideal (1/2*a + 3/2) Fractional ideal (4, a - 1) Fractional ideal (4, a + 1) + Fractional ideal (1/2*a + 3/2) Fractional ideal (1/2*a - 3/2) 9 - Fractional ideal (9, 1/2*a + 11/2) Fractional ideal (3) Fractional ideal (9, 1/2*a + 7/2) + Fractional ideal (9, 1/2*a + 11/2) 10 """ hnf_ideals = self.pari_nf().ideallist(bound) @@ -4541,17 +4541,25 @@ def _S_class_group_and_units(self, S, proof=True): sage: K._S_class_group_and_units( (K.ideal(5),) ) ([5, -1], []) - TESTS:: + TESTS: + + Note for the following test that the representation of + the units depends on the PARI version:: sage: K. = NumberField(x^3 - 381 * x + 127) - sage: K._S_class_group_and_units(tuple(K.primes_above(13))) - ([2/13*a^2 + 1/13*a - 677/13, - 1/13*a^2 + 7/13*a - 332/13, - -1/13*a^2 + 6/13*a + 345/13, - -1, - 2/13*a^2 + 1/13*a - 755/13, - 1/13*a^2 - 19/13*a - 7/13], - [(Fractional ideal (11, a - 2), 2), (Fractional ideal (19, a + 7), 2)]) + sage: units, clpg_gens = K._S_class_group_and_units(tuple(K.primes_above(13))) + sage: clpg_gens + [(Fractional ideal (11, a - 2), 2), (Fractional ideal (19, a + 7), 2)] + sage: units[:5] + [2/13*a^2 + 1/13*a - 677/13, + 1/13*a^2 + 7/13*a - 332/13, + -1/13*a^2 + 6/13*a + 345/13, + -1, + 2/13*a^2 + 1/13*a - 755/13] + sage: units[5] in (1/13*a^2 - 19/13*a - 7/13, 1/13*a^2 + 20/13*a - 7/13) + True + sage: len(units) == 6 + True Number fields defined by non-monic and non-integral polynomials are supported (:trac:`252`):: @@ -4699,18 +4707,25 @@ def selmer_group(self, S, m, proof=True, orders=False): sage: S in ([2, a + 1, a], [2, a + 1, -a], [2, -a - 1, a], [2, -a - 1, -a]) or S True - Verify that :trac:`14489` is fixed:: + Verify that :trac:`14489` is fixed; + the representation depends on the PARI version:: sage: K. = NumberField(x^3 - 381 * x + 127) - sage: K.selmer_group(K.primes_above(13), 2) + sage: gens = K.selmer_group(K.primes_above(13), 2) + sage: len(gens) == 8 + True + sage: gens[:5] [2/13*a^2 + 1/13*a - 677/13, 1/13*a^2 + 7/13*a - 332/13, -1/13*a^2 + 6/13*a + 345/13, -1, - 2/13*a^2 + 1/13*a - 755/13, - 1/13*a^2 - 19/13*a - 7/13, - -1/13*a^2 + 45/13*a - 97/13, - 2/13*a^2 + 40/13*a - 27/13] + 2/13*a^2 + 1/13*a - 755/13] + sage: gens[5] in (1/13*a^2 - 19/13*a - 7/13, 1/13*a^2 + 20/13*a - 7/13) + True + sage: gens[6] in (-1/13*a^2 + 45/13*a - 97/13, 1/13*a^2 - 45/13*a + 97/13) + True + sage: gens[7] in (2/13*a^2 + 40/13*a - 27/13, -2/13*a^2 - 40/13*a + 27/13) + True Verify that :trac:`16708` is fixed:: @@ -5351,11 +5366,13 @@ def elements_of_norm(self, n, proof=None): TESTS: Number fields defined by non-monic and non-integral - polynomials are supported (:trac:`252`):: + polynomials are supported (:trac:`252`); + the representation depends on the PARI version:: sage: K. = NumberField(7/9*x^3 + 7/3*x^2 - 56*x + 123) - sage: K.elements_of_norm(7) - [7/225*a^2 - 7/75*a - 42/25] + sage: [x] = K.elements_of_norm(7) + sage: x in (7/225*a^2 - 7/75*a - 42/25, 28/225*a^2 + 77/75*a - 133/25) + True """ proof = proof_flag(proof) B = self.pari_bnf(proof).bnfisintnorm(n) @@ -5457,7 +5474,8 @@ def factor(self, n): sage: pari('setrand(2)') sage: L. = K.extension(x^2 - 7) - sage: f = L.factor(a + 1); f + sage: f = L.factor(a + 1) + sage: f # representation varies, not tested (Fractional ideal (1/2*a*b - a + 1/2)) * (Fractional ideal (-1/2*a*b - a + 1/2)) sage: f.value() == a+1 True @@ -5472,6 +5490,18 @@ def factor(self, n): AUTHORS: - Alex Clemesha (2006-05-20), Francis Clarke (2009-04-21): examples + + TESTS: + + We test the above doctest. The representation depends on the PARI version:: + + sage: (fi, fj) = f[::] + sage: (fi[1], fj[1]) + (1, 1) + sage: fi[0] == L.fractional_ideal(1/2*a*b - a + 1/2) + True + sage: fj[0] == L.fractional_ideal(-1/2*a*b - a + 1/2) + True """ return self.ideal(n).factor() @@ -6151,7 +6181,7 @@ def zeta_function(self, prec=53, """ if algorithm is None: algorithm = 'pari' - + if algorithm == 'gp': from sage.lfunctions.all import Dokchitser r1, r2 = self.signature() @@ -6534,7 +6564,7 @@ def uniformizer(self, P, others="positive"): [t - 1] sage: [K.uniformizer(P) for P,e in factor(K.ideal(5))] [t^2 - t + 1, t + 2, t - 2] - sage: [K.uniformizer(P) for P,e in factor(K.ideal(7))] + sage: [K.uniformizer(P) for P,e in factor(K.ideal(7))] # representation varies, not tested [t^2 + 3*t + 1] sage: [K.uniformizer(P) for P,e in factor(K.ideal(67))] [t + 23, t + 26, t - 32, t - 18] @@ -6545,6 +6575,14 @@ def uniformizer(self, P, others="positive"): :pari:`idealprimedec` in the "positive" case. Use :pari:`idealappr` with exponent of -1 and invert the result in the "negative" case. + + TESTS: + + We test the above doctest. The representation depends on the PARI version:: + + sage: [x] = [K.uniformizer(P) for P,e in factor(K.ideal(7))] + sage: x in (t^2 + 3*t +1, t^2 - 4*t +1) + True """ if not is_NumberFieldIdeal(P): P = self.ideal(P) @@ -7800,7 +7838,7 @@ def optimized_representation(self, name=None, both_maps=True): polynomials are supported (:trac:`252`):: sage: K. = NumberField(7/9*x^3 + 7/3*x^2 - 56*x + 123) - sage: K.optimized_representation() + sage: K.optimized_representation() # representation varies, not tested (Number Field in a1 with defining polynomial x^3 - 7*x - 7, Ring morphism: From: Number Field in a1 with defining polynomial x^3 - 7*x - 7 @@ -7810,6 +7848,26 @@ def optimized_representation(self, name=None, both_maps=True): From: Number Field in a with defining polynomial 7/9*x^3 + 7/3*x^2 - 56*x + 123 To: Number Field in a1 with defining polynomial x^3 - 7*x - 7 Defn: a |--> -15/7*a1^2 + 9) + + TESTS: + + We test the above doctest. The representation depends on the PARI version:: + + sage: N, M1, M2 = K.optimized_representation(); N, M1, M2 + (Number Field in a1 with defining polynomial x^3 - 7*x - 7, + Ring morphism: + From: Number Field in a1 with defining polynomial x^3 - 7*x - 7 + To: Number Field in a with defining polynomial 7/9*x^3 + 7/3*x^2 - 56*x + 123 + Defn: a1 |--> ..., + Ring morphism: + From: Number Field in a with defining polynomial 7/9*x^3 + 7/3*x^2 - 56*x + 123 + To: Number Field in a1 with defining polynomial x^3 - 7*x - 7 + Defn: a |--> ...) + sage: a1 = M1.domain().gens()[0] + sage: M2(a) in (-15/7*a1^2 + 9, -60/7*a1^2 + 15*a1 + 39) + True + sage: M1(M2(a)) == a + True """ if name is None: name = self.variable_names() diff --git a/src/sage/rings/number_field/number_field_element.pyx b/src/sage/rings/number_field/number_field_element.pyx index 59bab07db08..e4a3e9448be 100644 --- a/src/sage/rings/number_field/number_field_element.pyx +++ b/src/sage/rings/number_field/number_field_element.pyx @@ -1732,7 +1732,7 @@ cdef class NumberFieldElement(FieldElement): sage: K. = NumberField(x^3 + x^2 - 2*x - 1, 'a') sage: P. = K[] sage: L = NumberField(X^2 + a^2 + 2*a + 1, 'b') - sage: K(17)._rnfisnorm(L) + sage: K(17)._rnfisnorm(L) # representation depends, not tested ((a^2 - 2)*b - 4, 1) sage: K. = NumberField(x^3 + x + 1) @@ -1768,6 +1768,20 @@ cdef class NumberFieldElement(FieldElement): sage: a._rnfisnorm(L) (a*b + a + 1/2, 1) + We test the above doctest, which was not tested. + The representation depends on the PARI version:: + + sage: K. = NumberField(x^3 + x^2 - 2*x - 1, 'a') + sage: P. = K[] + sage: L. = NumberField(X^2 + a^2 + 2*a + 1, 'b') + sage: (xbar, q) = K(17)._rnfisnorm(L) + sage: q == 1 + 1 + sage: xbar.norm() + 4913 + sage: xbar in ((a^2 - 2)*b - 4, (a^2 - 2)*b + 4) + True + AUTHORS: - Craig Citro (2008-04-05) diff --git a/src/sage/rings/number_field/number_field_ideal.py b/src/sage/rings/number_field/number_field_ideal.py index b4eabe8fb75..2f82137db12 100644 --- a/src/sage/rings/number_field/number_field_ideal.py +++ b/src/sage/rings/number_field/number_field_ideal.py @@ -1823,11 +1823,17 @@ def factor(self): TESTS: Number fields defined by non-monic and non-integral - polynomials are supported (:trac:`252`):: + polynomials are supported (:trac:`252`); + the representation depends on the PARI version:: sage: F. = NumberField(2*x^3 + x + 1) - sage: fact = F.factor(2); fact - (Fractional ideal (2*a^2 + 1))^2 * (Fractional ideal (-2*a^2)) + sage: fact = F.factor(2) + sage: (fact[0][1], fact[1][1]) + (2, 1) + sage: fact[0][0] == F.ideal(2*a^2 + 1) + True + sage: fact[1][0] == F.ideal(-2*a^2) + True sage: [p[0].norm() for p in fact] [2, 2] """ @@ -2417,12 +2423,21 @@ def idealcoprime(self, J): sage: B = k.ideal(3) sage: A.is_coprime(B) False - sage: lam = A.idealcoprime(B); lam + sage: lam = A.idealcoprime(B) + sage: lam # representation depends, not tested -1/6*a + 1/6 sage: (lam*A).is_coprime(B) True ALGORITHM: Uses Pari function :pari:`idealcoprime`. + + TESTS: + + Check the above doctests, where the representation + depends on the PARI version:: + + sage: lam in (-1/6*a + 1/6, 1/6*a - 1/6) + True """ if not (self.is_integral() and J.is_integral()): raise ValueError("Both ideals must be integral.") diff --git a/src/sage/rings/number_field/unit_group.py b/src/sage/rings/number_field/unit_group.py index 6ed0aea16b8..5c94f7407dd 100644 --- a/src/sage/rings/number_field/unit_group.py +++ b/src/sage/rings/number_field/unit_group.py @@ -273,13 +273,16 @@ def __init__(self, number_field, proof=True, S=None): TESTS: Number fields defined by non-monic and non-integral - polynomials are supported (:trac:`252`):: + polynomials are supported (:trac:`252`); + the representation depends on the PARI version:: sage: K. = NumberField(7/9*x^3 + 7/3*x^2 - 56*x + 123) sage: K.unit_group() Unit group with structure C2 x Z x Z of Number Field in a with defining polynomial 7/9*x^3 + 7/3*x^2 - 56*x + 123 sage: UnitGroup(K, S=tuple(K.primes_above(7))) - S-unit group with structure C2 x Z x Z x Z of Number Field in a with defining polynomial 7/9*x^3 + 7/3*x^2 - 56*x + 123 with S = (Fractional ideal (7/225*a^2 - 7/75*a - 42/25),) + S-unit group with structure C2 x Z x Z x Z of Number Field in a with defining polynomial 7/9*x^3 + 7/3*x^2 - 56*x + 123 with S = (Fractional ideal (...),) + sage: K.primes_above(7)[0] in (7/225*a^2 - 7/75*a - 42/25, 28/225*a^2 + 77/75*a - 133/25) + True Conversion from unit group to a number field and back gives the right results (:trac:`25874`):: diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring.py b/src/sage/rings/polynomial/polynomial_quotient_ring.py index 1e2052c1ece..72d7eba646d 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring.py @@ -1281,7 +1281,7 @@ def S_class_group(self, S, proof=True): sage: K. = QuadraticField(-5) sage: R. = K[] sage: S. = R.quotient((x^2 + 23)*(x^2 + 31)) - sage: S.S_class_group([]) + sage: S.S_class_group([]) # representation varies, not tested [((1/4*xbar^2 + 31/4, (-1/8*a + 1/8)*xbar^2 - 31/8*a + 31/8, 1/16*xbar^3 + 1/16*xbar^2 + 31/16*xbar + 31/16, @@ -1313,6 +1313,41 @@ def S_class_group(self, S, proof=True): sage: type(CG[0][1]) + TESTS: + + We verify the above test, where the representation depends on the PARI version:: + + sage: K. = QuadraticField(-5) + sage: R. = K[] + sage: S. = R.quotient((x^2 + 23)*(x^2 + 31)) + sage: C = S.S_class_group([]) + sage: C[:2] + [((1/4*xbar^2 + 31/4, + (-1/8*a + 1/8)*xbar^2 - 31/8*a + 31/8, + 1/16*xbar^3 + 1/16*xbar^2 + 31/16*xbar + 31/16, + -1/16*a*xbar^3 + (1/16*a + 1/8)*xbar^2 - 31/16*a*xbar + 31/16*a + 31/8), + 6), + ((-1/4*xbar^2 - 23/4, + (1/8*a - 1/8)*xbar^2 + 23/8*a - 23/8, + -1/16*xbar^3 - 1/16*xbar^2 - 23/16*xbar - 23/16, + 1/16*a*xbar^3 + (-1/16*a - 1/8)*xbar^2 + 23/16*a*xbar - 23/16*a - 23/8), + 6)] + sage: C[2][1] + 2 + sage: gens = C[2][0] + sage: expected_gens = ( + ....: -5/4*xbar^2 - 115/4, + ....: 1/4*a*xbar^2 + 23/4*a, + ....: -1/16*xbar^3 - 7/16*xbar^2 - 23/16*xbar - 161/16, + ....: 1/16*a*xbar^3 - 1/16*a*xbar^2 + 23/16*a*xbar - 23/16*a) + sage: gens[0] == expected_gens[0] + True + sage: gens[1] in (expected_gens[1], expected_gens[1]/2 + expected_gens[0]/2) + True + sage: gens[2] in (expected_gens[2], expected_gens[2] + expected_gens[0]/2) + True + sage: gens[3] in (expected_gens[3], expected_gens[3] + expected_gens[0]/2) + True """ fields, isos, iso_classes = self._S_decomposition(tuple(S)) n = len(fields) @@ -1413,7 +1448,7 @@ def class_group(self, proof=True): sage: K. = QuadraticField(-5) sage: R. = K[] sage: S. = R.quotient((x^2 + 23)*(x^2 + 31)) - sage: S.class_group() + sage: S.class_group() # representation varies, not tested [((1/4*xbar^2 + 31/4, (-1/8*a + 1/8)*xbar^2 - 31/8*a + 31/8, 1/16*xbar^3 + 1/16*xbar^2 + 31/16*xbar + 31/16, @@ -1785,7 +1820,7 @@ def _isomorphic_ring(self): # recursively try to rewrite the isomorphic_quotient isomorphic_ring_to_isomorphic_quotient, isomorphic_quotient_to_isomorphic_ring, isomorphic_ring = isomorphic_quotient._isomorphic_ring() - + # the process has likely refined the category of # isomorphic_quotient (to Fields e.g.) so we use the same category # for self @@ -1857,7 +1892,7 @@ def _isomorphic_ring(self): x = A.solve_left(A.column_space().basis()[1]) primitive_element = sum(c*b for c,b in zip(x.list(), basis)) from_isomorphic_ring = isomorphic_ring.hom([primitive_element], check=False) - + return from_isomorphic_ring, to_isomorphic_ring, isomorphic_ring from sage.categories.all import NumberFields diff --git a/src/sage/schemes/elliptic_curves/ell_number_field.py b/src/sage/schemes/elliptic_curves/ell_number_field.py index 2967f085cae..9499b339b27 100644 --- a/src/sage/schemes/elliptic_curves/ell_number_field.py +++ b/src/sage/schemes/elliptic_curves/ell_number_field.py @@ -302,7 +302,7 @@ def simon_two_descent(self, verbose=0, lim1=2, lim3=4, limtriv=2, (3, 3, [(0 : 0 : 1), - (-1/2*zeta43_0^2 - 1/2*zeta43_0 + 7 : -3/2*zeta43_0^2 - 5/2*zeta43_0 + 18 : 1)]) + (-1/2*zeta43_0^2 - 1/2*zeta43_0 + 7 : -3/2*zeta43_0^2 - 5/2*zeta43_0 + 18 : 1)...) """ verbose = int(verbose) if known_points is None: @@ -809,7 +809,8 @@ def global_integral_model(self): sage: K. = NumberField(x^2 + 161*x - 150) sage: E = EllipticCurve([25105/216*v - 3839/36, 634768555/7776*v - 98002625/1296, 634768555/7776*v - 98002625/1296, 0, 0]) - sage: E.global_integral_model() + sage: M = E.global_integral_model() + sage: M # choice varies, not tested Elliptic Curve defined by y^2 + (2094779518028859*v-1940492905300351)*x*y + (477997268472544193101178234454165304071127500*v-442791377441346852919930773849502871958097500)*y = x^3 + (26519784690047674853185542622500*v-24566525306469707225840460652500)*x^2 over Number Field in v with defining polynomial x^2 + 161*x - 150 :trac:`14476`:: @@ -820,6 +821,21 @@ def global_integral_model(self): sage: E.global_integral_model() Elliptic Curve defined by y^2 + (15*g^3-48*g-42)*x*y + (-111510*g^3-162162*g^2-44145*g+37638)*y = x^3 + (-954*g^3-1134*g^2+81*g+576)*x^2 over Number Field in g with defining polynomial t^4 - t^3 - 3*t^2 - t + 1 + TESTS: + + Check the skipped test from above:: + + sage: b = M.ainvs() + sage: b[0] in (2094779518028859*v-1940492905300351, 33872485050625*v - 31078224284250) + True + sage: b[1] in (26519784690047674853185542622500*v - 24566525306469707225840460652500, + ....: 6933305282258321342920781250*v - 6422644400723486559914062500) + True + sage: b[2] in (442791377441346852919930773849502871958097500, + ....: 2020602604156076340058146664245468750000*v - 1871778534673615560803175189398437500000) + True + sage: b[3:] + (0, 0) """ K = self.base_field() ai = self.a_invariants() @@ -918,7 +934,9 @@ def _scale_by_units(self): EXAMPLES:: sage: K. = NumberField(x^2-10) - sage: u = K.units()[0] + sage: u = a + 3 + sage: u.is_unit() + True sage: E = EllipticCurve([0, 0, 0, 4536*a + 14148, -163728*a - 474336]) sage: E1 = E.scale_curve(u^5) sage: E1.ainvs() From 98bfefda186e4c7992f7120b5956b5b41bfdcbb3 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Mon, 6 Apr 2020 18:24:43 +0200 Subject: [PATCH 085/300] small fix --- src/sage/schemes/elliptic_curves/ell_number_field.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/schemes/elliptic_curves/ell_number_field.py b/src/sage/schemes/elliptic_curves/ell_number_field.py index 9499b339b27..99e5e20cfb4 100644 --- a/src/sage/schemes/elliptic_curves/ell_number_field.py +++ b/src/sage/schemes/elliptic_curves/ell_number_field.py @@ -831,7 +831,7 @@ def global_integral_model(self): sage: b[1] in (26519784690047674853185542622500*v - 24566525306469707225840460652500, ....: 6933305282258321342920781250*v - 6422644400723486559914062500) True - sage: b[2] in (442791377441346852919930773849502871958097500, + sage: b[2] in (477997268472544193101178234454165304071127500*v -442791377441346852919930773849502871958097500, ....: 2020602604156076340058146664245468750000*v - 1871778534673615560803175189398437500000) True sage: b[3:] From 4e14bfc30ad2ed87330483a2c3bf0514759e444c Mon Sep 17 00:00:00 2001 From: Bryan Gillespie Date: Tue, 7 Apr 2020 08:45:03 -0600 Subject: [PATCH 086/300] Fix typo in docstring of FinitePoset._split --- src/sage/combinat/posets/posets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 50f8b2c0eea..fcd57782869 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -1738,7 +1738,7 @@ def _glue_spectra(a_spec, b_spec, orientation): def _split(self, a, b): r""" Return the two connected components obtained by deleting the covering relation - `a < b` from a poset whose Hasse daigram is a tree. + `a < b` from a poset whose Hasse diagram is a tree. This is a helper method for :meth:`atkinson`. From 855098cb2f1c8d88592c2cb021bdb1bf099121fd Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Fri, 10 Apr 2020 15:30:53 +0200 Subject: [PATCH 087/300] create the context for the tests locally --- src/sage/rings/number_field/number_field.py | 8 ++++++-- src/sage/rings/number_field/number_field_ideal.py | 4 ++++ src/sage/schemes/elliptic_curves/ell_number_field.py | 6 ++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index e4dbf212afc..2f909743179 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -5474,8 +5474,7 @@ def factor(self, n): sage: pari('setrand(2)') sage: L. = K.extension(x^2 - 7) - sage: f = L.factor(a + 1) - sage: f # representation varies, not tested + sage: f = L.factor(a + 1); f # representation varies, not tested (Fractional ideal (1/2*a*b - a + 1/2)) * (Fractional ideal (-1/2*a*b - a + 1/2)) sage: f.value() == a+1 True @@ -5495,6 +5494,9 @@ def factor(self, n): We test the above doctest. The representation depends on the PARI version:: + sage: K. = NumberField(x^2 + 1) + sage: L. = K.extension(x^2 - 7) + sage: f = L.factor(a + 1) sage: (fi, fj) = f[::] sage: (fi[1], fj[1]) (1, 1) @@ -6580,6 +6582,7 @@ def uniformizer(self, P, others="positive"): We test the above doctest. The representation depends on the PARI version:: + sage: K. = NumberField(x^4 - x^3 - 3*x^2 - x + 1) sage: [x] = [K.uniformizer(P) for P,e in factor(K.ideal(7))] sage: x in (t^2 + 3*t +1, t^2 - 4*t +1) True @@ -7853,6 +7856,7 @@ def optimized_representation(self, name=None, both_maps=True): We test the above doctest. The representation depends on the PARI version:: + sage: K. = NumberField(7/9*x^3 + 7/3*x^2 - 56*x + 123) sage: N, M1, M2 = K.optimized_representation(); N, M1, M2 (Number Field in a1 with defining polynomial x^3 - 7*x - 7, Ring morphism: diff --git a/src/sage/rings/number_field/number_field_ideal.py b/src/sage/rings/number_field/number_field_ideal.py index 2f82137db12..563b5198ff9 100644 --- a/src/sage/rings/number_field/number_field_ideal.py +++ b/src/sage/rings/number_field/number_field_ideal.py @@ -2436,6 +2436,10 @@ def idealcoprime(self, J): Check the above doctests, where the representation depends on the PARI version:: + sage: k. = NumberField(x^2 + 23) + sage: A = k.ideal(a+1) + sage: B = k.ideal(3) + sage: lam = A.idealcoprime(B) sage: lam in (-1/6*a + 1/6, 1/6*a - 1/6) True """ diff --git a/src/sage/schemes/elliptic_curves/ell_number_field.py b/src/sage/schemes/elliptic_curves/ell_number_field.py index 99e5e20cfb4..0a8ac891361 100644 --- a/src/sage/schemes/elliptic_curves/ell_number_field.py +++ b/src/sage/schemes/elliptic_curves/ell_number_field.py @@ -809,8 +809,7 @@ def global_integral_model(self): sage: K. = NumberField(x^2 + 161*x - 150) sage: E = EllipticCurve([25105/216*v - 3839/36, 634768555/7776*v - 98002625/1296, 634768555/7776*v - 98002625/1296, 0, 0]) - sage: M = E.global_integral_model() - sage: M # choice varies, not tested + sage: M = E.global_integral_model(); M # choice varies, not tested Elliptic Curve defined by y^2 + (2094779518028859*v-1940492905300351)*x*y + (477997268472544193101178234454165304071127500*v-442791377441346852919930773849502871958097500)*y = x^3 + (26519784690047674853185542622500*v-24566525306469707225840460652500)*x^2 over Number Field in v with defining polynomial x^2 + 161*x - 150 :trac:`14476`:: @@ -825,6 +824,9 @@ def global_integral_model(self): Check the skipped test from above:: + sage: K. = NumberField(x^2 + 161*x - 150) + sage: E = EllipticCurve([25105/216*v - 3839/36, 634768555/7776*v - 98002625/1296, 634768555/7776*v - 98002625/1296, 0, 0]) + sage: M = E.global_integral_model() sage: b = M.ainvs() sage: b[0] in (2094779518028859*v-1940492905300351, 33872485050625*v - 31078224284250) True From 4f86bc37571a3c7912edb94d2976f857b93662b1 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Fri, 10 Apr 2020 17:48:40 +0200 Subject: [PATCH 088/300] fix failing doctest --- src/sage/rings/number_field/number_field.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 2f909743179..566e19b8264 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -5474,7 +5474,8 @@ def factor(self, n): sage: pari('setrand(2)') sage: L. = K.extension(x^2 - 7) - sage: f = L.factor(a + 1); f # representation varies, not tested + sage: f = L.factor(a + 1) + sage: f # representation varies, not tested (Fractional ideal (1/2*a*b - a + 1/2)) * (Fractional ideal (-1/2*a*b - a + 1/2)) sage: f.value() == a+1 True From e3f2b25145a6feb8f725a461be60e1ff6ff3dba4 Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Fri, 17 Apr 2020 10:59:53 +0200 Subject: [PATCH 089/300] rebase on top of ticket #21262 --- src/module_list.py | 3 + .../polynomial/skew_polynomial_element.pyx | 100 +- .../skew_polynomial_finite_field.pxd | 15 + .../skew_polynomial_finite_field.pyx | 1108 +++++++++++++++++ .../rings/polynomial/skew_polynomial_ring.py | 231 +++- 5 files changed, 1419 insertions(+), 38 deletions(-) create mode 100644 src/sage/rings/polynomial/skew_polynomial_finite_field.pxd create mode 100644 src/sage/rings/polynomial/skew_polynomial_finite_field.pyx diff --git a/src/module_list.py b/src/module_list.py index c74615f75db..310f0c6d71b 100644 --- a/src/module_list.py +++ b/src/module_list.py @@ -1531,6 +1531,9 @@ def uname_specific(name, value, alternative): Extension('sage.rings.polynomial.skew_polynomial_finite_order', sources = ['sage/rings/polynomial/skew_polynomial_finite_order.pyx']), + Extension('sage.rings.polynomial.skew_polynomial_finite_field', + sources = ['sage/rings/polynomial/skew_polynomial_finite_field.pyx']), + # Note that weil_polynomials includes distutils directives in order to support # conditional OpenMP compilation (by uncommenting lines) Extension('sage.rings.polynomial.weil.weil_polynomials', diff --git a/src/sage/rings/polynomial/skew_polynomial_element.pyx b/src/sage/rings/polynomial/skew_polynomial_element.pyx index f1f3385b57b..1edebe2d08a 100644 --- a/src/sage/rings/polynomial/skew_polynomial_element.pyx +++ b/src/sage/rings/polynomial/skew_polynomial_element.pyx @@ -1381,6 +1381,71 @@ cdef class SkewPolynomial(AlgebraElement): A = A.left_monic() return A + def _left_lcm_cofactor(self, other): + R = self._parent + U = R.one() + G = self + V1 = R.zero() + V3 = other + while not V3.is_zero(): + Q, R = G.right_quo_rem(V3) + T = U - Q*V1 + U = V1 + G = V3 + V1 = T + V3 = R + return V1 + + @coerce_binop + def left_xlcm(self, other, monic=True): + r""" + Return the left lcm of ``self`` and ``other`` together + with two skew polynomials `u` and `v` such that + `u \cdot \text{self} = v \cdot \text{other} = \text{llcm`` + """ + if self.base_ring() not in Fields: + raise TypeError("the base ring must be a field") + if self.is_zero() or other.is_zero(): + raise ZeroDivisionError("division by zero is not valid") + V1 = self._left_lcm_cofactor(other) + L = V1 * self + if monic: + s = ~(L.leading_coefficient()) + L = s * L + V1 = s * V1 + return L, V1, L // other + + def _right_lcm_cofactor(self, other): + R = self._parent + U = R.one() + G = self + V1 = R.zero() + V3 = other + while not V3.is_zero(): + Q, R = G.left_quo_rem(V3) + T = U - V1*Q + U = V1 + G = V3 + V1 = T + V3 = R + return V1 + + @coerce_binop + def right_xlcm(self, other, monic=True): + if self.base_ring() not in Fields: + raise TypeError("the base ring must be a field") + if self.is_zero() or other.is_zero(): + raise ZeroDivisionError("division by zero is not valid") + V1 = self._right_lcm_cofactor(other) + L = self * V1 + if monic: + s = self._parent.twist_map(-self.degree())(~(L.leading_coefficient())) + L = L * s + V1 = V1 * s + W1, _ = L.left_quo_rem(other) + return L, V1, W1 + + @coerce_binop def left_lcm(self, other, monic=True): r""" @@ -1444,21 +1509,10 @@ cdef class SkewPolynomial(AlgebraElement): raise TypeError("the base ring must be a field") if self.is_zero() or other.is_zero(): raise ZeroDivisionError("division by zero is not valid") - U = self._parent.one() - G = self - V1 = self._parent.zero() - V3 = other - while not V3.is_zero(): - Q, R = G.right_quo_rem(V3) - T = U - Q*V1 - U = V1 - G = V3 - V1 = T - V3 = R - V1 = V1 * self + L = self._left_lcm_cofactor(other) * self if monic: - V1 = V1.right_monic() - return V1 + L = L.right_monic() + return L @coerce_binop def right_lcm(self, other, monic=True): @@ -1539,22 +1593,10 @@ cdef class SkewPolynomial(AlgebraElement): raise TypeError("the base ring must be a field") if self.is_zero() or other.is_zero(): raise ZeroDivisionError("division by zero is not valid") - R = self.parent() - U = R.one() - G = self - V1 = R.zero() - V3 = other - while not V3.is_zero(): - Q, R = G.left_quo_rem(V3) - T = U - V1*Q - U = V1 - G = V3 - V1 = T - V3 = R - V1 = self * V1 + L = self * self._right_lcm_cofactor(other) if monic: - V1 = V1.left_monic() - return V1 + L = L.left_monic() + return L def _repr_(self, name=None): r""" diff --git a/src/sage/rings/polynomial/skew_polynomial_finite_field.pxd b/src/sage/rings/polynomial/skew_polynomial_finite_field.pxd new file mode 100644 index 00000000000..06a90f4f590 --- /dev/null +++ b/src/sage/rings/polynomial/skew_polynomial_finite_field.pxd @@ -0,0 +1,15 @@ +from sage.rings.polynomial.skew_polynomial_finite_order cimport SkewPolynomial_finite_order_dense +from sage.matrix.matrix_dense cimport Matrix_dense + +cdef class SkewPolynomial_finite_field_dense (SkewPolynomial_finite_order_dense): + cdef _norm_factor + cdef dict _rdivisors + cdef dict _types + cdef _factorization + + # Finding divisors + cdef SkewPolynomial_finite_field_dense _rdivisor_c(P, N) + + # Finding factorizations + cdef _factor_c(self) + cdef _factor_uniform_c(self) diff --git a/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx b/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx new file mode 100644 index 00000000000..65e28abd38c --- /dev/null +++ b/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx @@ -0,0 +1,1108 @@ +r""" +Univariate Dense Skew Polynomials over Finite Fields + +This module provides the :class:`~sage.rings.polynomial.skew_polynomial_finite_field.SkewPolynomial_finite_field_dense` +which constructs a single univariate skew polynomial over a finite field equipped with the Frobenius +Endomorphism. + +AUTHOR:: + +- Xavier Caruso (2012-06-29): initial version + +- Arpit Merchant (2016-08-04): improved docstrings, fixed doctests and refactored classes and methods + +""" + +############################################################################# +# Copyright (C) 2012 Xavier Caruso +# +# 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/ +#**************************************************************************** + +from cysignals.signals cimport sig_on, sig_off + +import copy +import cysignals +from sage.rings.ring cimport Ring +from sage.rings.all import ZZ + +from sage.structure.element cimport RingElement +from sage.rings.integer cimport Integer + +from sage.rings.polynomial.polynomial_element cimport Polynomial +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.polynomial.skew_polynomial_finite_order cimport SkewPolynomial_finite_order_dense + +from sage.combinat.permutation import Permutation, Permutations +from sage.combinat.partition import Partition +from sage.structure.factorization import Factorization +from sage.misc.mrange import xmrange_iter +from sage.arith.misc import factorial +from sage.combinat.q_analogues import q_jordan + + +cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): + def _reduced_norm_factored(self): + """ + Return the reduced norm of this polynomial factorized in the center + + EXAMPLES:: + + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x', Frob] + + sage: a = (x^2 + 1) * (x+3) + sage: a._reduced_norm_factored() + (z + 3) * (z + 2)^2 + """ + if self._norm_factor is None: + N = self._parent._working_center(self.reduced_norm(var=False)) + self._norm_factor = N.factor() + return self._norm_factor + + def is_irreducible(self): + """ + Return True if this skew polynomial is irreducible + + EXAMPLES:: + + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + + sage: a = x^2 + t*x + 1 + sage: a.is_irreducible() + False + sage: a.factor() + (x + 4*t^2 + 4*t + 1) * (x + 3*t + 2) + + sage: a = x^2 + t*x + t + 1 + sage: a.is_irreducible() + True + sage: a.factor() + x^2 + t*x + t + 1 + + Skew polynomials of degree `1` are of course irreducible:: + + sage: a = x + t + sage: a.is_irreducible() + True + + A random irreducible skew polynomial is irreducible:: + + sage: a = S.random_irreducible(degree=4,monic=True); a # random + x^4 + (t + 1)*x^3 + (3*t^2 + 2*t + 3)*x^2 + 3*t*x + 3*t + sage: a.is_irreducible() + True + + By convention, constant skew polynomials are not irreducible:: + + sage: S(1).is_irreducible() + False + sage: S(0).is_irreducible() + False + """ + if self._norm_factor is not None: + return len(self._norm_factor) == 1 and self._norm_factor[0][1] == 1 + N = self._parent._working_center(self.reduced_norm(var=False)) + return N.is_irreducible() + + + def type(self,N): + """ + Return the `N`-type of this skew polynomial (see definition below) + + INPUT: + + - ``N`` -- an irreducible polynomial in the + center of the underlying skew polynomial ring + + .. NOTE:: + + The result is cached. + + DEFINITION: + + The `N`-type of a skew polynomial `a` is the Partition + `(t_0, t_1, t_2, ...)` defined by + + .. MATH:: + + t_0 + \cdots + t_i = \frac{\deg gcd(a,N^i)}{\deg N} + + where `\deg N` is the degree of `N` considered as an + element in the center. + + This notion has an important mathematical interest because + it corresponds to the Jordan type of the `N`-typical part + of the associated Galois representation. + + EXAMPLES:: + + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: Z = S.center(); x3 = Z.gen() + + sage: a = x^4 + x^3 + (4*t^2 + 4)*x^2 + (t^2 + 2)*x + 4*t^2 + sage: N = x3^2 + x3 + 1 + sage: a.type(N) + [1] + sage: N = x3 + 1 + sage: a.type(N) + [2] + + sage: a = x^3 + (3*t^2 + 1)*x^2 + (3*t^2 + t + 1)*x + t + 1 + sage: N = x3 + 1 + sage: a.type(N) + [2, 1] + + If `N` does not divide the reduced map of `a`, the type + is empty:: + + sage: N = x3 + 2 + sage: a.type(N) + [] + + If `a = N`, the type is just `[r]` where `r` is the order + of the twist map ``Frob``:: + + sage: N = x3^2 + x3 + 1 + sage: S(N).type(N) + [3] + + `N` must be irreducible:: + + sage: N = (x3 + 1) * (x3 + 2) + sage: a.type(N) + Traceback (most recent call last): + ... + ValueError: N is not irreducible + """ + skew_ring = self._parent + if N.parent() is not skew_ring._working_center: + N = skew_ring._working_center(N) + try: + return self._types[N] + except (KeyError, TypeError): + if not N.is_irreducible(): + raise ValueError("N is not irreducible") + if self._norm_factor is None: + m = -1 + else: + i = [ n for n,_ in self._norm_factor ].index(N) + m = self._norm_factor[i][1] + NS = skew_ring(N) + type = [ ] + degN = N.degree() + while True: + d = self.right_gcd(NS) + deg = d.degree()/degN + if deg == 0: + break + if m >= 0: + if deg == 1: + type += m * [1] + break + m -= deg + self = self // d + type.append(deg) + # type = Partition(type) + if self._types is None: + self._types = { N: type } + else: + self._types[N] = type + return type + + + # Finding divisors + # ---------------- + + cdef SkewPolynomial_finite_field_dense _rdivisor_c(self, N): + """ + Return a right divisor of this skew polynomial whose + reduced norm is `N` + + .. WARNING:: + + `N` needs to be an irreducible factor of the + reduced norm. This function does not check + this (and his behaviour is not defined if the + require property doesn't hold). + """ + from sage.matrix.matrix_space import MatrixSpace + from sage.matrix.matrix2 import NotFullRankError + cdef skew_ring = self._parent + cdef SkewPolynomial_finite_field_dense NS = skew_ring(N) + cdef SkewPolynomial_finite_field_dense P = self.right_gcd(NS) + cdef Py_ssize_t d = N.degree() + cdef Py_ssize_t e = P.degree() // d + if e == 1: + return P.right_monic() + + cdef SkewPolynomial_finite_field_dense D + cdef SkewPolynomial_finite_field_dense Q = (NS // P) + cdef SkewPolynomial_finite_field_dense R, X + cdef Py_ssize_t i, j, t, r = skew_ring._order + cdef Polynomial dd, xx, yy, zz + cdef Integer exp + cdef list lM, lV + + center = N.parent() + E = center.quo(N) + PE = PolynomialRing(E, name='T') + if skew_ring.characteristic() != 2: + exp = Integer((E.cardinality()-1)/2) + while True: + R = skew_ring.random_element((e*r-1,e*r-1)) + R = Q*R + X = Q._new_c(Q._coeffs[:],Q._parent) + lM = [ ] + for j from 0 <= j < e: + for i from 0 <= i < e: + coeffs = [skew_ring._retraction(X[t*r+i]) for t in range(d)] + value = E(coeffs) + lM.append(value) + X = (R*X) % NS + M = MatrixSpace(E,e,e)(lM).transpose() + V = MatrixSpace(E,e,1)([ E([skew_ring._retraction(X[t*r+i]) for t in range(d)]) for i in range(e) ]) + try: + W = M._solve_right_nonsingular_square(V) + except NotFullRankError: + skew_ring._new_retraction_map() + continue + xx = PE(W.list() + [E(-1)]) + if skew_ring.characteristic() == 2: + yy = PE.gen() + zz = PE.gen() + for i from 1 <= i < d: + zz = (zz*zz) % xx + yy += zz + dd = xx.gcd(yy) + if dd.degree() != 1: continue + else: + yy = PE.gen().__pow__(exp,xx) - 1 + dd = xx.gcd(yy) + if dd.degree() != 1: + yy += 2 + dd = xx.gcd(yy) + if dd.degree() != 1: continue + D = P.right_gcd(R + skew_ring(center((dd[0]/dd[1]).list()))) + if D.degree() == 0: + continue + D = D.right_monic() + return D + + + def _reduced_norm_factor_uniform(self): + r""" + Return a factor of the reduced norm of this skew + polynomial, the probability of a given factor to + show up being proportional to the number of irreducible + divisors of ``self`` having this norm + + This method is an helper function; it is not supposed + to be called directly. + + EXAMPLES:: + + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x', Frob] + sage: Z. = S.center() + + In the two examples below, the reduced norms of `P` and `Q` + have a unique factor:: + + sage: P = x + a + sage: P.reduced_norm().factor() + z + 2 + sage: P._reduced_norm_factor_uniform() + z + 2 + + sage: Q = x^3 + 1 + sage: Q.reduced_norm().factor() + (z + 1)^3 + sage: Q._reduced_norm_factor_uniform() + z + 1 + + Now, we consider the product `R = P*Q`; it admits 32 irreducible + divisors but among them, only one has norm `z + 2`, the others + having norm `z + 1`. + Therefore this method outputs `z + 2` with probability 1/32 + and `z + 1` with probability 31/32. + + sage: R = P*Q + sage: counts = { z+1: 0, z+2: 0 } + sage: for _ in range(1000): + ....: N = R._reduced_norm_factor_uniform() + ....: counts[N] += 1 + sage: counts # random + {z + 1: 969, z + 2: 31} + """ + skew_ring = self._parent + F = self._reduced_norm_factored() + center = F[0][0].parent() + cardcenter = center.base_ring().cardinality() + gencenter = center.gen() + count = [ ] + total = 0 + for n, _ in F: + if n == gencenter: + total += 1 + else: + degn = n.degree() + P = self.right_gcd(skew_ring(n)) + m = P.degree() // degn + cardL = cardcenter**degn + total += (cardL**m - 1) / (cardL - 1) + count.append(total) + random = ZZ.random_element(total) + for i in range(len(F)): + if random < count[i]: + return F[i][0] + + + def _irreducible_divisors(self, right): + """ + Return an iterator over all irreducible monic + divisors of this skew polynomial + + Do not use this function. Use instead + :meth:`right_irreducible_divisors` and + :meth:`left_irreducible_divisors`. + + INPUT: + + - ``right`` -- a boolean; if ``True``, return right divisors, + otherwise, return left divisors + + TESTS:: + + sage: k. = GF(7^4) + sage: Frob = k.frobenius_endomorphism(2) + sage: S. = k['x', Frob] + + sage: P = S.random_element(degree=10) + sage: rightdiv = [ f for f in P.right_irreducible_divisors() ] # indirect doctest + sage: len(rightdiv) == P.count_irreducible_divisors() + True + sage: len(rightdiv) == Set(rightdiv).cardinality() # check no duplicates + True + sage: for D in rightdiv: + ....: assert P.is_right_divisible_by(D), "not right divisible" + ....: assert D.is_irreducible(), "not irreducible" + + sage: P = S.random_element(degree=10) + sage: leftdiv = [ f for f in P.left_irreducible_divisors() ] # indirect doctest + sage: len(leftdiv) == P.count_irreducible_divisors() + True + sage: len(leftdiv) == Set(leftdiv).cardinality() # check no duplicates + True + sage: for D in leftdiv: + ....: assert P.is_left_divisible_by(D), "not left divisible" + ....: assert D.is_irreducible(), "not irreducible" + """ + if self.is_zero(): + return + if right: + quo_rem = SkewPolynomial_finite_field_dense.right_quo_rem + quo_rem2 = SkewPolynomial_finite_field_dense.left_quo_rem + gcd = SkewPolynomial_finite_field_dense.right_gcd + gcd2 = SkewPolynomial_finite_field_dense.left_gcd + def mul(a,b): return a*b + else: + quo_rem = SkewPolynomial_finite_field_dense.left_quo_rem + quo_rem2 = SkewPolynomial_finite_field_dense.right_quo_rem + gcd = SkewPolynomial_finite_field_dense.left_gcd + gcd2 = SkewPolynomial_finite_field_dense.right_gcd + def mul(a,b): return b*a + skew_ring = self._parent + center = skew_ring._working_center + kfixed = center.base_ring() + F = self._reduced_norm_factored() + for N, _ in F: + if N == center.gen(): + yield skew_ring.gen() + continue + degN = N.degree() + NS = skew_ring(N) + P = gcd(self, NS) + m = P.degree()/degN + if m == 1: + yield P + continue + Q,_ = quo_rem(NS, P) + if right: + P1 = self._rdivisor_c(N) + else: + D = self._rdivisor_c(N) + degrandom = NS.degree() - 1 + while True: + P1 = P // P.right_gcd(NS // D) + if P1.degree() == degN: break + while True: + R = skew_ring.random_element((degrandom,degrandom)) + if NS.right_gcd(R) == 1: break + D = NS.right_gcd(D*R) + Q1,_ = quo_rem(P, P1) + degrandom = P.degree() - 1 + while True: + R = skew_ring.random_element((degrandom, degrandom)) + _, g = quo_rem2(mul(R,Q), P) + if gcd2(g,P) != 1: continue + L = Q1 + V = L + for i in range(1,m): + L = gcd2(mul(g,L), P) + V = gcd2(V,L) + if V == 1: break + rng = xmrange_iter([kfixed]*degN, center) + for i in range(m): + for pol in xmrange_iter([rng]*i): + f = skew_ring(1) + for j in range(i): + coeff = pol.pop() + _, f = quo_rem2(g*f + coeff, P) + d = gcd2(mul(f,Q1), P) + d, _ = quo_rem2(P, d) + yield d + + + def right_irreducible_divisor(self, uniform=False): + """ + Return a right irreducible divisor of this skew polynomial + + INPUT: + + - ``uniform`` -- a boolean (default: ``False``); whether the + output irreducible divisor should be uniformly distributed + among all possibilities + + EXAMPLES:: + + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: a = x^6 + 3*t*x^5 + (3*t + 1)*x^3 + (4*t^2 + 3*t + 4)*x^2 + (t^2 + 2)*x + 4*t^2 + 3*t + 3 + + sage: dr = a.right_irreducible_divisor(); dr # random + x^3 + (2*t^2 + t + 4)*x^2 + (4*t + 1)*x + 4*t^2 + t + 1 + sage: a.is_right_divisible_by(dr) + True + + Right divisors are cached. Hence, if we ask again for a + right divisor, we will get the same answer:: + + sage: a.right_irreducible_divisor() # random + x^3 + (2*t^2 + t + 4)*x^2 + (4*t + 1)*x + 4*t^2 + t + 1 + + However the algorithm is probabilistic. Hence, if we first + reinitialize `a`, we may get a different answer:: + + sage: a = x^6 + 3*t*x^5 + (3*t + 1)*x^3 + (4*t^2 + 3*t + 4)*x^2 + (t^2 + 2)*x + 4*t^2 + 3*t + 3 + sage: a.right_irreducible_divisor() # random + x^3 + (t^2 + 3*t + 4)*x^2 + (t + 2)*x + 4*t^2 + t + 1 + + We can also generate uniformly distributed irreducible monic + divisors as follows:: + + sage: a.right_irreducible_divisor(uniform=True) # random + x^3 + (4*t + 2)*x^2 + (2*t^2 + 2*t + 2)*x + 2*t^2 + 2 + sage: a.right_irreducible_divisor(uniform=True) # random + x^3 + (t^2 + 2)*x^2 + (3*t^2 + 1)*x + 4*t^2 + 2*t + sage: a.right_irreducible_divisor(uniform=True) # random + x^3 + x^2 + (4*t^2 + 2*t + 4)*x + t^2 + 3 + + By convention, the zero skew polynomial has no irreducible + divisor: + + sage: S(0).right_irreducible_divisor() + Traceback (most recent call last): + ... + ValueError: 0 has no irreducible divisor + """ + if self.is_zero(): + raise ValueError("0 has no irreducible divisor") + skew_ring = self._parent + if uniform: + N = self._reduced_norm_factor_uniform() + else: + N = self._reduced_norm_factored()[0][0] + NS = skew_ring(N) + degN = N.degree() + D = self._rdivisor_c(N) + if uniform: + P1 = self.right_gcd(NS) + if P1.degree() != degN: + Q1 = NS // P1 + deg = P1.degree() - 1 + while True: + R = Q1 * skew_ring.random_element((deg,deg)) + if P1.right_gcd(R) == 1: + break + D = P1.right_gcd(D*R) + return D + + def left_irreducible_divisor(self, uniform=False): + """ + Return a left irreducible divisor of this skew polynomial + + INPUT: + + - ``uniform`` -- a boolean (default: ``False``); whether the + output irreducible divisor should be uniformly distributed + among all possibilities + + EXAMPLES:: + + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: a = x^6 + 3*t*x^5 + (3*t + 1)*x^3 + (4*t^2 + 3*t + 4)*x^2 + (t^2 + 2)*x + 4*t^2 + 3*t + 3 + sage: dl = a.left_irreducible_divisor(); dl # random + x^3 + (t^2 + t + 2)*x^2 + (t + 2)*x + 3*t^2 + t + 4 + sage: a.is_left_divisible_by(dl) + True + + The algorithm is probabilistic. Hence, if we ask again for + a left irreducible divisor of `a`, we may get a different + answer:: + + sage: a.left_irreducible_divisor() # random + x^3 + (4*t + 3)*x^2 + (2*t^2 + 3*t + 4)*x + 4*t^2 + 2*t + + We can also generate uniformly distributed irreducible monic + divisors as follows:: + + sage: a.left_irreducible_divisor(uniform=True) + x^3 + (4*t^2 + 3*t + 4)*x^2 + (t^2 + t + 3)*x + 2*t^2 + 3 + sage: a.left_irreducible_divisor(uniform=True) + x^3 + (2*t^2 + t + 4)*x^2 + (2*t^2 + 4*t + 4)*x + 2*t + 3 + sage: a.left_irreducible_divisor(uniform=True) + x^3 + (t^2 + t + 2)*x^2 + (3*t^2 + t)*x + 2*t + 1 + + By convention, the zero skew polynomial has no irreducible + divisor: + + sage: S(0).left_irreducible_divisor() + Traceback (most recent call last): + ... + ValueError: 0 has no irreducible divisor + """ + if self.is_zero(): + raise ValueError("0 has no irreducible divisor") + if uniform: + N = self._reduced_norm_factor_uniform() + else: + N = self._reduced_norm_factored()[0][0] + skew_ring = self._parent + NS = skew_ring(N) + degN = N.degree() + D = self._rdivisor_c(N) + deg = NS.degree() - 1 + P1 = self.left_gcd(NS) + while True: + if uniform: + while True: + R = skew_ring.random_element((deg,deg)) + if NS.right_gcd(R) == 1: break + D = NS.right_gcd(D*R) + LD = P1 // P1.right_gcd(NS // D) + if LD.degree() == degN: + return LD + uniform = True + + + def right_irreducible_divisors(self): + """ + Return an iterator over all irreducible monic right divisors + of this skew polynomial + + EXAMPLES: + + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: a = x^4 + 2*t*x^3 + 3*t^2*x^2 + (t^2 + t + 1)*x + 4*t + 3 + sage: iter = a.right_irreducible_divisors(); iter + + sage: next(iter) # random + x + 2*t^2 + 4*t + 4 + sage: next(iter) # random + x + 3*t^2 + 4*t + 1 + + We can use this function to build the list of all monic + irreducible divisors of `a`:: + + sage: rightdiv = [ d for d in a.right_irreducible_divisors() ] + + Note that the algorithm is probabilistic. As a consequence, if we + build again the list of right monic irreducible divisors of `a`, we + may get a different ordering:: + + sage: rightdiv2 = [ d for d in a.right_irreducible_divisors() ] + sage: rightdiv == rightdiv2 + False + sage: Set(rightdiv) == Set(rightdiv2) + True + """ + return self._irreducible_divisors(True) + + def left_irreducible_divisors(self): + """ + Return an iterator over all irreducible monic left divisors + of this skew polynomial + + EXAMPLES: + + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: a = x^4 + 2*t*x^3 + 3*t^2*x^2 + (t^2 + t + 1)*x + 4*t + 3 + sage: iter = a.left_irreducible_divisors(); iter + + sage: next(iter) # random + x + 3*t + 3 + sage: next(iter) # random + x + 4*t + 2 + + We can use this function to build the list of all monic + irreducible divisors of `a`:: + + sage: leftdiv = [ d for d in a.left_irreducible_divisors() ] + + Note that the algorithm is probabilistic. As a consequence, if we + build again the list of left monic irreducible divisors of `a`, we + may get a different ordering:: + + sage: leftdiv2 = [ d for d in a.left_irreducible_divisors() ] + sage: leftdiv == leftdiv2 + False + sage: Set(leftdiv) == Set(leftdiv2) + True + """ + return self._irreducible_divisors(False) + + + def count_irreducible_divisors(self): + """ + Return the number of irreducible monic divisors of + this skew polynomial. + + .. NOTE:: + + One can prove that there are always as many left + irreducible monic divisors as right irreducible + monic divisors. + + EXAMPLES:: + + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + + We illustrate that a skew polynomial may have a number of irreducible + divisors greater than its degree. + + sage: a = x^4 + (4*t + 3)*x^3 + t^2*x^2 + (4*t^2 + 3*t)*x + 3*t + sage: a.count_irreducible_divisors() + 12 + + We illustrate that an irreducible polynomial in the center have + in general a lot of irreducible divisors in the skew polynomial + ring:: + + sage: Z. = S.center() + sage: N = x3^5 + 4*x3^4 + 4*x3^2 + 4*x3 + 3; N + x3^5 + 4*x3^4 + 4*x3^2 + 4*x3 + 3 + sage: N.is_irreducible() + True + sage: S(N).count_irreducible_divisors() + 9768751 + """ + if self.is_zero(): + return 0 + skew_ring = self.parent() + cardcenter = skew_ring._working_center.base_ring().cardinality() + gencenter = skew_ring._working_center.gen() + F = self._reduced_norm_factored() + val = self.valuation() + self >>= val + count = 0 + if val > 0: + count = 1 + for N,_ in F: + if N == gencenter: + continue + degN = N.degree() + P = self.right_gcd(skew_ring(N)) + m = P.degree() // degN + cardL = cardcenter**degN + count += (cardL**m - 1) // (cardL - 1) + return count + + + # Finding factorizations + # ---------------------- + + cdef _factor_c(self): + """ + Compute a factorization of ``self`` + + This is the low level implementation of :meth:`factor`. + """ + cdef skew_ring = self._parent + cdef SkewPolynomial_finite_field_dense poly = self.right_monic() + cdef list a = poly._coeffs + cdef Py_ssize_t val = 0 + if len(a) < 0: + return Factorization([], sort=False, unit=skew_ring.zero_element()) + while a[0].is_zero(): + del a[0] + val += 1 + + cdef Py_ssize_t degQ, degrandom, m, mP, i + cdef N + cdef list factors = [ (skew_ring.gen(), val) ] + cdef SkewPolynomial_finite_field_dense P, Q, P1, NS, g, right, Pn + cdef RingElement unit = self.leading_coefficient() + cdef Polynomial gencenter = skew_ring._working_center.gen() + cdef Py_ssize_t p = skew_ring.characteristic() + cdef F = self._reduced_norm_factored() + + for N, m in F: + if N == gencenter: + continue + degN = N.degree() + if poly.degree() == degN: + factors.append((poly, 1)) + break + NS = skew_ring(N) + P1 = None + while True: + P = poly.right_gcd(NS) + P = P.right_monic() + mP = P.degree() / degN + if mP == 0: break + if mP == 1: + factors.append((P,1)) + poly = poly // P + for i from 1 <= i < m: + if poly.degree() == degN: + factors.append((poly,1)) + break + P = poly.right_gcd(NS).right_monic() + factors.append((P, 1)) + poly = poly // P + break + if P1 is None: + P1 = P._rdivisor_c(N) + Q = NS._new_c(NS._coeffs[:], NS._parent) + Q = P1 * (Q // P) + factors.append((P1, 1)) + right = P1._new_c(P1._coeffs[:], P1._parent) + m -= (mP-1) + degrandom = P.degree() + while mP > 2: + while True: + g = skew_ring.random_element((degrandom, degrandom)) + g = (Q*g).right_gcd(P) + Pn = right._left_lcm_cofactor(g) + if Pn.degree() == degN: break + Pn = Pn.right_monic() + factors.append((Pn, 1)) + right = Pn * right + degrandom -= degN + mP -= 1 + poly = poly // right + P1, _ = P.right_quo_rem(right) + factors.reverse() + return Factorization(factors, sort=False, unit=unit) + + + cdef _factor_uniform_c(self): + """ + Compute a uniformly distrbuted factorization of ``self`` + + This is the low level implementation of :meth:`factor`. + """ + skew_ring = self._parent + cdef Integer cardE, cardcenter = skew_ring._working_center.base_ring().cardinality() + cdef gencenter = skew_ring._working_center.gen() + cdef SkewPolynomial_finite_field_dense gen = skew_ring.gen() + + cdef list factorsN = [ ] + cdef dict dict_divisor = { } + cdef dict dict_type = { } + cdef dict dict_right = { } + cdef Py_ssize_t m + cdef list type + + for N, m in self._reduced_norm_factored(): + factorsN += m * [N] + if N == gencenter: continue + type = list(self.type(N)) + dict_type[N] = type + if type[0] > 1: + dict_divisor[N] = self._rdivisor_c(N) + dict_right[N] = skew_ring(1) + cdef list indices = list(Permutations(len(factorsN)).random_element()) + + cdef RingElement unit = self.leading_coefficient() + cdef SkewPolynomial_finite_field_dense left = self._new_c(self._coeffs[:],skew_ring) + left = left.right_monic() + cdef SkewPolynomial_finite_field_dense right = skew_ring(1) + cdef SkewPolynomial_finite_field_dense L, R + cdef SkewPolynomial_finite_field_dense NS, P, Q, D, D1, D2, d + cdef list factors = [ ] + cdef list maxtype + cdef Py_ssize_t i, j, degN, deg + cdef count, maxcount + + for i in indices: + N = factorsN[i-1] + if N == gencenter: + D1 = gen + else: + type = dict_type[N] + NS = skew_ring(N) + P = left.right_gcd(NS) + if type[0] == 1: + D1 = P + else: + R = right._new_c(right._coeffs[:],skew_ring) + R = R // dict_right[N] + D = R._left_lcm_cofactor(dict_divisor[N]) + maxtype = list(type) + maxtype[-1] -= 1 + degN = N.degree() + cardE = cardcenter ** degN + maxcount = q_jordan(Partition(maxtype),cardE) + Q = NS // P + deg = P.degree()-1 + while 1: + while 1: + R = skew_ring.random_element((deg,deg)) + R = Q*R + if P.right_gcd(R).degree() == 0: + break + D1 = P.right_gcd(D*R).right_monic() + + L = left._new_c(list(left._coeffs),skew_ring) + L = L // D1 + degN = N.degree() + for j in range(len(type)): + if type[j] == 1: + newtype = type[:-1] + break + d = L.right_gcd(NS).right_monic() + deg = d.degree() / degN + if deg < type[j]: + newtype = type[:] + newtype[j] = deg + break + L = L // d + count = q_jordan(Partition(newtype),cardE) + if ZZ.random_element(maxcount) < count: + break + dict_type[N] = newtype + + D2 = D._new_c(list(D._coeffs),skew_ring) + D2 = D2.right_monic() + while D2 == D1: + while True: + R = skew_ring.random_element((deg,deg)) + R = Q*R + if P.right_gcd(R).degree() == 0: + break + D2 = P.right_gcd(D*R).right_monic() + dict_divisor[N] = D1.left_lcm(D2) + factors.append((D1,1)) + left = left // D1 + right = D1 * right + dict_right[N] = right._new_c(list(right._coeffs),skew_ring) + + factors.reverse() + return Factorization(factors, sort=False, unit=unit) + + + def factor(self, uniform=False): + """ + Return a factorization of this skew polynomial + + INPUT: + + - ``uniform`` -- a boolean (default: ``False``); whether the + output irreducible divisor should be uniformly distributed + among all possibilities + + EXAMPLES:: + + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: a = x^3 + (t^2 + 4*t + 2)*x^2 + (3*t + 3)*x + t^2 + 1 + sage: F = a.factor(); F # random + (x + t^2 + 4) * (x + t + 3) * (x + t) + sage: F.value() == a + True + + The result of the factorization is cached. Hence, if we try + again to factor `a`, we will get the same answer:: + + sage: a.factor() # random + (x + t^2 + 4) * (x + t + 3) * (x + t) + + However, the algorithm is probabilistic. Hence if we first + reinitialiaze `a`, we may get a different answer:: + + sage: a = x^3 + (t^2 + 4*t + 2)*x^2 + (3*t + 3)*x + t^2 + 1 + sage: F = a.factor(); F # random + (x + t^2 + t + 2) * (x + 2*t^2 + t + 4) * (x + t) + sage: F.value() == a + True + + There is a priori no guarantee on the distribution of the + factorizations we get. Passing in the keyword ``uniform=True`` + ensures the output is uniformly distributed among all + factorizations. + + sage: a.factor(uniform=True) # random + (x + t^2 + 4) * (x + t) * (x + t + 3) + sage: a.factor(uniform=True) # random + (x + 2*t^2) * (x + t^2 + t + 1) * (x + t^2 + t + 2) + sage: a.factor(uniform=True) # random + (x + 2*t^2 + 3*t) * (x + 4*t + 2) * (x + 2*t + 2) + + By convention, the zero skew polynomial has no factorization: + + sage: S(0).factor() + Traceback (most recent call last): + ... + ValueError: factorization of 0 not defined + """ + if self.is_zero(): + raise ValueError("factorization of 0 not defined") + sig_on() + if uniform: + F = self._factor_uniform_c() + if self._factorization is None: + self._factorization = F + else: + if self._factorization is None: + self._factorization = self._factor_c() + F = self._factorization + sig_off() + return F + + + def count_factorizations(self): + """ + Return the number of factorizations (as a product of a + unit and a product of irreducible monic factors) of this + skew polynomial. + + EXAMPLES:: + + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: a = x^4 + (4*t + 3)*x^3 + t^2*x^2 + (4*t^2 + 3*t)*x + 3*t + sage: a.count_factorizations() + 216 + + We illustrate that an irreducible polynomial in the center have + in general a lot of distinct factorizations in the skew polynomial + ring:: + + sage: Z. = S.center() + sage: N = x3^5 + 4*x3^4 + 4*x3^2 + 4*x3 + 3 + sage: N.is_irreducible() + True + sage: S(N).count_factorizations() + 30537115626 + """ + if self.is_zero(): + raise ValueError("factorization of 0 not defined") + cardcenter = self._parent._working_center.base_ring().cardinality() + gencenter = self._parent._working_center.gen() + F = self._reduced_norm_factored() + summ = 0 + count = 1 + for N, m in F: + summ += m + if m == 1: continue + if N != gencenter: + count *= q_jordan(self.type(N), cardcenter**N.degree()) + count /= factorial(m) + return count * factorial(summ) + + + # Not optimized: + # many calls to reduced_norm, reduced_norm_factor, _rdivisor_c, which are slow + def factorizations(self): + """ + Return an iterator over all factorizations (as a product + of a unit and a product of irreducible monic factors) of + this skew polynomial. + + EXAMPLES:: + + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: a = x^3 + (t^2 + 1)*x^2 + (2*t + 3)*x + t^2 + t + 2 + sage: iter = a.factorizations(); iter + + sage: next(iter) # random + (x + 3*t^2 + 4*t) * (x + 2*t^2) * (x + 4*t^2 + 4*t + 2) + sage: next(iter) # random + (x + 3*t^2 + 4*t) * (x + 3*t^2 + 2*t + 2) * (x + 4*t^2 + t + 2) + + We can use this function to build the list of factorizations + of `a`:: + + sage: factorizations = [ F for F in a.factorizations() ] + + We do some checks:: + + sage: len(factorizations) == a.count_factorizations() + True + sage: len(factorizations) == Set(factorizations).cardinality() # check no duplicates + True + sage: for F in factorizations: + ....: assert F.value() == a, "factorization has a different value" + ....: for d,_ in F: + ....: assert d.is_irreducible(), "a factor is not irreducible" + + Note that the algorithm used in this method is probabilistic. + As a consequence, if we call it two times with the same input, + we can get different orderings:: + + sage: factorizations2 = [ F for F in a.factorizations() ] + sage: factorizations == factorizations2 + False + sage: sorted(factorizations) == sorted(factorizations2) + True + """ + if self.is_zero(): + raise ValueError("factorization of 0 not defined") + def factorizations_rec(P): + if P.is_irreducible(): + yield [ (P,1) ] + else: + for div in P._irreducible_divisors(True): + Q = P // div + # Here, we should update Q._norm, Q._norm_factor, Q._rdivisors + for factors in factorizations_rec(Q): + factors.append((div,1)) + yield factors + unit = self.leading_coefficient() + for factors in factorizations_rec(~unit*self): + yield Factorization(factors, sort=False, unit=unit) diff --git a/src/sage/rings/polynomial/skew_polynomial_ring.py b/src/sage/rings/polynomial/skew_polynomial_ring.py index 1c30938bc73..289593a22e6 100644 --- a/src/sage/rings/polynomial/skew_polynomial_ring.py +++ b/src/sage/rings/polynomial/skew_polynomial_ring.py @@ -385,7 +385,7 @@ class SkewPolynomialRing(Algebra, UniqueRepresentation): - Multivariate Skew Polynomial Ring - Add derivations. """ - Element = sage.rings.polynomial.skew_polynomial_element.SkewPolynomial_generic_dense + Element = None @staticmethod def __classcall_private__(cls, base_ring, twist_map=None, names=None, sparse=False): @@ -409,14 +409,14 @@ def __classcall_private__(cls, base_ring, twist_map=None, names=None, sparse=Fal sage: S is T True - When the twisting morphism has finite order, a special class + When the twisting morphism is a Frobenius over a finite field, a special class is used:: sage: k. = GF(7^5) sage: Frob = k.frobenius_endomorphism(2) sage: S. = SkewPolynomialRing(k, Frob) sage: type(S) - + """ if base_ring not in CommutativeRings(): raise TypeError('base_ring must be a commutative ring') @@ -436,13 +436,21 @@ def __classcall_private__(cls, base_ring, twist_map=None, names=None, sparse=Fal except IndexError: raise NotImplementedError("multivariate skew polynomials rings not supported") - # We check if the twisting morphism has finite order + # We find the best constructor + constructor = None if base_ring in Fields(): try: order = twist_map.order() if order is not Infinity: - from sage.rings.polynomial.skew_polynomial_ring import SkewPolynomialRing_finite_order - return SkewPolynomialRing_finite_order(base_ring, twist_map, names, sparse) + if base_ring.is_finite(): + constructor = SkewPolynomialRing_finite_field + else: + constructor = SkewPolynomialRing_finite_order + except (AttributeError, NotImplementedError): + pass + if constructor is not None: + try: + return constructor(base_ring, twist_map, names, sparse) except (AttributeError, NotImplementedError): pass @@ -477,6 +485,8 @@ def __init__(self, base_ring, twist_map, name, sparse, category=None): 0 sage: TestSuite(S).run() """ + if self.Element is None: + self.Element = sage.rings.polynomial.skew_polynomial_element.SkewPolynomial_generic_dense self.__is_sparse = sparse self._map = twist_map self._maps = {0: IdentityMorphism(base_ring), 1: self._map} @@ -973,6 +983,56 @@ def random_element(self, degree=2, monic=False, *args, **kwds): else: return self([R.random_element(*args, **kwds) for _ in range(degree+1)]) + def random_irreducible(self, degree=2, monic=True, *args, **kwds): + r""" + Return a random irreducible skew polynomial. + + .. WARNING:: + + Elements of this skew polynomial ring need to have a method + is_irreducible(). Currently, this method is implemented only + when the base ring is a finite field. + + INPUT: + + - ``degree`` - Integer with degree (default: 2) + or a tuple of integers with minimum and maximum degrees + + - ``monic`` - if True, returns a monic skew polynomial + (default: True) + + - ``*args, **kwds`` - Passed on to the ``random_element`` method for + the base ring + + OUTPUT: + + - A random skew polynomial + + EXAMPLES:: + + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: A = S.random_irreducible(); A + x^2 + (4*t^2 + 3*t + 4)*x + 4*t^2 + t + sage: A.is_irreducible() + True + sage: B = S.random_irreducible(degree=3,monic=False); B # random + (4*t + 1)*x^3 + (t^2 + 3*t + 3)*x^2 + (3*t^2 + 2*t + 2)*x + 3*t^2 + 3*t + 1 + sage: B.is_irreducible() + True + """ + if isinstance(degree, (list, tuple)): + if len(degree) != 2: + raise ValueError("degree argument must be an integer or a tuple of 2 integers (min_degree, max_degree)") + if degree[0] > degree[1]: + raise ValueError("minimum degree must be less or equal than maximum degree") + degree = randint(*degree) + while True: + irred = self.random_element((degree,degree), monic=monic) + if irred.is_irreducible(): + return irred + def is_commutative(self): r""" Return ``True`` if this skew polynomial ring is commutative, i.e. if the @@ -1293,9 +1353,6 @@ class SkewPolynomialRing_finite_order(SkewPolynomialRing): :class:`sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialRing` :mod:`sage.rings.polynomial.skew_polynomial_finite_order` """ - import sage.rings.polynomial.skew_polynomial_finite_order - Element = sage.rings.polynomial.skew_polynomial_finite_order.SkewPolynomial_finite_order_dense - def __init__(self, base_ring, twist_map, name, sparse, category=None): r""" Initialize this skew polynomial @@ -1324,6 +1381,9 @@ def __init__(self, base_ring, twist_map, name, sparse, category=None): sage: S.center() is Z True """ + if self.Element is None: + import sage.rings.polynomial.skew_polynomial_finite_order + self.Element = sage.rings.polynomial.skew_polynomial_finite_order.SkewPolynomial_finite_order_dense SkewPolynomialRing.__init__(self, base_ring, twist_map, name, sparse, category) self._order = twist_map.order() (self._constants, self._embed_constants) = twist_map.fixed_field() @@ -1475,4 +1535,157 @@ def center(self, name=None, names=None, default=False): if default or (self._center_variable_name is None): self._center_variable_name = name return center + + +# Special class for skew polynomial over finite fields +###################################################### + +class SkewPolynomialRing_finite_field(SkewPolynomialRing_finite_order): + """ + A specialized class for skew polynomial rings over finite fields. + + .. SEEALSO:: + + :meth:`sage.rings.polynomial.skew_polynomial_ring_constructor.SkewPolynomialRing` + :class:`sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialRing_general` + :mod:`sage.rings.polynomial.skew_polynomial_finite_field` + + .. TODO:: + + Add methods related to center of skew polynomial ring, irreducibility, karatsuba + multiplication and factorization. + """ + def __init__(self, base_ring, twist_map, names, sparse, category=None): + """ + This method is a constructor for a general, dense univariate skew polynomial ring + over a finite field. + + INPUT: + + - ``base_ring`` -- a commutative ring + + - ``map`` -- an automorphism of the base ring + + - ``name`` -- string or list of strings representing the name of the variables of ring + + - ``sparse`` -- boolean (default: ``False``) + + - ``element_class`` -- class representing the type of element to be used in ring + + ..NOTE:: + + Multivariate and Sparse rings are not implemented. + + EXAMPLES:: + + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: T. = k['x', Frob]; T + Skew Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 + """ + if self.Element is None: + import sage.rings.polynomial.skew_polynomial_finite_field + self.Element = sage.rings.polynomial.skew_polynomial_finite_field.SkewPolynomial_finite_field_dense + SkewPolynomialRing_finite_order.__init__(self, base_ring, twist_map, names, sparse, category) + self._matrix_retraction = None + + def _new_retraction_map(self, seed=None): + """ + Create a retraction map from the ring of coefficient + of this skew polynomial ring to its fixed subfield under + the twisting morphism + + This is an internal function used in factorization. + + INPUT: + + - ``seed`` -- an element of the base ring or ``None`` + (default: ``None``); it ``None``, a random element + is picked + + TESTS:: + + sage: k. = GF(11^4) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x', Frob] + + sage: S._new_retraction_map() + sage: S._matrix_retraction # random + [ 9 4 10 4] + + We can specify a seed:: + + sage: S._new_retraction_map(seed=a) + sage: S._matrix_retraction + [ 0 6 3 10] + sage: S._new_retraction_map(seed=a) + sage: S._matrix_retraction + [ 0 6 3 10] + """ + k = self.base_ring() + base = k.base_ring() + (kfixed, embed) = self._maps[1].fixed_field() + section = embed.section() + if not kfixed.has_coerce_map_from(base): + raise NotImplementedError("No coercion map from %s to %s" % (base, kfixed)) + if seed is None: + seed = k.random_element() + self._seed_retraction = seed + trace = [ ] + elt = seed + for _ in range(k.degree()): + x = elt + tr = elt + for _ in range(1, self._order): + x = self._map(x) + tr += x + elt *= k.gen() + trace.append(section(tr)) + from sage.matrix.matrix_space import MatrixSpace + self._matrix_retraction = MatrixSpace(kfixed, 1, k.degree())(trace) + + def _retraction(self, x, newmap=False, seed=None): + """ + Return the image of `x` under the retraction map + (see also :meth:`_new_retraction_map`) + + This is an internal function used in factorization. + INPUT: + + - ``newmap`` -- a boolean (default: ``False``); whether we + first create and use a new retraction map + + - ``seed`` -- an element of the base ring or ``None`` (default: + ``None``); if given, first create a new random retraction map + with given seed + + TESTS:: + + sage: k. = GF(11^4) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x', Frob] + + sage: S._retraction(a) # random + 6 + + Note that a retraction map has been automatically created:: + + sage: S._matrix_retraction # random + [ 0 6 3 10] + + If we call again the method :meth:`_retraction`, + the same retraction map is used:: + + sage: S._retraction(a) # random + 6 + + We can specify a seed:: + + sage: S._retraction(a^2, seed=a) + 10 + """ + # Better to return the retraction map but more difficult + if newmap or seed is not None or self._matrix_retraction is None: + self._new_retraction_map() + return (self._matrix_retraction*self.base_ring()(x)._vector_())[0] From 96dab844189554f6568dd757e9bc5780b7b2114f Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Fri, 17 Apr 2020 15:41:44 +0200 Subject: [PATCH 090/300] add missing doctest in skew_polynomial_element --- .../polynomial/skew_polynomial_element.pyx | 98 ++++++++++++++++++- 1 file changed, 94 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/polynomial/skew_polynomial_element.pyx b/src/sage/rings/polynomial/skew_polynomial_element.pyx index 1edebe2d08a..3e5fb850035 100644 --- a/src/sage/rings/polynomial/skew_polynomial_element.pyx +++ b/src/sage/rings/polynomial/skew_polynomial_element.pyx @@ -1382,6 +1382,26 @@ cdef class SkewPolynomial(AlgebraElement): return A def _left_lcm_cofactor(self, other): + r""" + Return a skew polynomial `U` such that `U P = c L` + where `P` is this skew polynomial (``self``), `L` + is the left lcm of `P` and ``other`` and `c` is a + constant + + TESTS:: + + sage: k. = GF(7^5) + sage: Frob = k.frobenius_endomorphism(3) + sage: S. = k['x', Frob] + + sage: D = S.random_element() + sage: P = S.random_element() * D + sage: Q = S.random_element() * D + sage: L = P.left_lcm(Q) + sage: U = P._left_lcm_cofactor(Q) + sage: (U*P).right_monic() == L + True + """ R = self._parent U = R.one() G = self @@ -1399,9 +1419,28 @@ cdef class SkewPolynomial(AlgebraElement): @coerce_binop def left_xlcm(self, other, monic=True): r""" - Return the left lcm of ``self`` and ``other`` together - with two skew polynomials `u` and `v` such that - `u \cdot \text{self} = v \cdot \text{other} = \text{llcm`` + Return the left lcm `L` of ``self`` and ``other`` together + with two skew polynomials `U` and `V` such that + + .. MATH:: + + `U \cdot \text{self} = V \cdot \text{other} = L` + + EXAMPLES:: + + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: P = (x + t^2) * (x + t) + sage: Q = 2 * (x^2 + t + 1) * (x * t) + sage: L, U, V = P.left_xlcm(Q) + sage: L + x^5 + (2*t^2 + t + 4)*x^4 + (3*t^2 + 4)*x^3 + (3*t^2 + 3*t + 2)*x^2 + (t^2 + t + 2)*x + + sage: U*P == L + True + sage: V*Q == L + True """ if self.base_ring() not in Fields: raise TypeError("the base ring must be a field") @@ -1416,6 +1455,26 @@ cdef class SkewPolynomial(AlgebraElement): return L, V1, L // other def _right_lcm_cofactor(self, other): + r""" + Return a skew polynomial `U` such that `P U = L c` + where `P` is this skew polynomial (``self``), `L` + is the right lcm of `P` and ``other`` and `c` is a + constant + + EXAMPLES:: + + sage: k. = GF(7^5) + sage: Frob = k.frobenius_endomorphism(3) + sage: S. = k['x', Frob] + + sage: D = S.random_element() + sage: P = D * S.random_element() + sage: Q = D * S.random_element() + sage: L = P.right_lcm(Q) + sage: U = P._right_lcm_cofactor(Q) + sage: (P*U).left_monic() == L + True + """ R = self._parent U = R.one() G = self @@ -1432,6 +1491,36 @@ cdef class SkewPolynomial(AlgebraElement): @coerce_binop def right_xlcm(self, other, monic=True): + r""" + Return the right lcm `L` of ``self`` and ``other`` together + with two skew polynomials `U` and `V` such that + + .. MATH:: + + `\text{self} \cdot U = \text{other} \cdot V = L` + + INPUT: + + - ``other`` -- a skew polynomial in the same ring as ``self`` + + - ``monic`` -- a boolean (default: ``True``); whether the right lcm + should be normalized to be monic + + EXAMPLES:: + + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: P = (x + t) * (x + t^2) + sage: Q = 2 * (x + t) * (x^2 + t + 1) + sage: L, U, V = P.right_xlcm(Q) + sage: L + x^4 + (2*t^2 + t + 2)*x^3 + (3*t^2 + 4*t + 1)*x^2 + (3*t^2 + 4*t + 1)*x + t^2 + 4 + sage: P*U == L + True + sage: Q*V == L + True + """ if self.base_ring() not in Fields: raise TypeError("the base ring must be a field") if self.is_zero() or other.is_zero(): @@ -1439,7 +1528,8 @@ cdef class SkewPolynomial(AlgebraElement): V1 = self._right_lcm_cofactor(other) L = self * V1 if monic: - s = self._parent.twist_map(-self.degree())(~(L.leading_coefficient())) + s = self.base_ring()(~L.leading_coefficient()) + s = self._parent.twist_map(-L.degree())(s) L = L * s V1 = V1 * s W1, _ = L.left_quo_rem(other) From e8e9139a8248126c0e6a742786b8628eb7a38836 Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Fri, 17 Apr 2020 17:37:20 +0200 Subject: [PATCH 091/300] add a reference to my paper with Le Borgne --- src/doc/en/reference/references/index.rst | 4 ++++ src/sage/rings/polynomial/skew_polynomial_finite_field.pyx | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 27bfdc2263f..e69def5b098 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1390,6 +1390,10 @@ REFERENCES: Ann. Combinatorics (6), 2002 pp. 125-145. :doi:`10.1007/PL00012580`. +.. [CL2017] Xavier Caruso and Jérémy Le Borgne, + *A new faster algorithm for factoring skew polynomials over finite fields* + J. Symbolic Comput. 79 (2017), 411-443. + .. [CL2013] Maria Chlouveraki and Sofia Lambropoulou. *The Yokonuma-Hecke algebras and the HOMFLYPT polynomial*. (2015) :arxiv:`1204.1871v4`. diff --git a/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx b/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx index 65e28abd38c..ba3b14dd58c 100644 --- a/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx +++ b/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx @@ -3,7 +3,7 @@ Univariate Dense Skew Polynomials over Finite Fields This module provides the :class:`~sage.rings.polynomial.skew_polynomial_finite_field.SkewPolynomial_finite_field_dense` which constructs a single univariate skew polynomial over a finite field equipped with the Frobenius -Endomorphism. +endomorphism. Among other things, it implements the fast factorization algorithm designed in [CL2017]_. AUTHOR:: From 5897dfc3410ed8f584de7ea7a83e9b8170e5390c Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Tue, 21 Apr 2020 18:16:40 +0200 Subject: [PATCH 092/300] address Travis' comments --- .../polynomial/skew_polynomial_element.pxd | 12 +- .../polynomial/skew_polynomial_element.pyx | 70 +++--- .../skew_polynomial_finite_field.pxd | 4 +- .../skew_polynomial_finite_field.pyx | 211 +++++++++--------- 4 files changed, 158 insertions(+), 139 deletions(-) diff --git a/src/sage/rings/polynomial/skew_polynomial_element.pxd b/src/sage/rings/polynomial/skew_polynomial_element.pxd index 6d73ec293e5..803a0009cba 100644 --- a/src/sage/rings/polynomial/skew_polynomial_element.pxd +++ b/src/sage/rings/polynomial/skew_polynomial_element.pxd @@ -8,23 +8,27 @@ cdef class SkewPolynomial(AlgebraElement): cdef _is_gen cdef long _hash_c(self) - cdef SkewPolynomial _new_c(self,list coeffs,Parent P,char check=*) - cpdef SkewPolynomial _new_constant_poly(self,RingElement a,Parent P,char check=*) + cdef SkewPolynomial _new_c(self, list coeffs, Parent P, char check=*) + cpdef SkewPolynomial _new_constant_poly(self, RingElement a, Parent P, char check=*) cpdef _neg_(self) cpdef _floordiv_(self, right) cpdef _mod_(self, right) cpdef bint is_zero(self) cpdef bint is_one(self) - + cpdef operator_eval(self, eval_pt) + cdef SkewPolynomial _left_lcm_cofactor(self, SkewPolynomial other) + cdef SkewPolynomial _right_lcm_cofactor(self, SkewPolynomial other) + # Abstract methods cdef void _inplace_rmul(self, SkewPolynomial_generic_dense right) cdef void _inplace_pow(self, Py_ssize_t n) cpdef int degree(self) cpdef list coefficients(self, sparse=*) + cdef class SkewPolynomial_generic_dense(SkewPolynomial): cdef list _coeffs @@ -38,7 +42,7 @@ cdef class SkewPolynomial_generic_dense(SkewPolynomial): cpdef right_power_mod(self, exp, modulus) cpdef left_power_mod(self, exp, modulus) + cdef class SkewPolynomialBaseringInjection(Morphism): cdef RingElement _an_element cdef object _new_constant_poly_ - diff --git a/src/sage/rings/polynomial/skew_polynomial_element.pyx b/src/sage/rings/polynomial/skew_polynomial_element.pyx index 3e5fb850035..2b6c56ae840 100644 --- a/src/sage/rings/polynomial/skew_polynomial_element.pyx +++ b/src/sage/rings/polynomial/skew_polynomial_element.pyx @@ -1381,7 +1381,7 @@ cdef class SkewPolynomial(AlgebraElement): A = A.left_monic() return A - def _left_lcm_cofactor(self, other): + cdef SkewPolynomial _left_lcm_cofactor(self, SkewPolynomial other): r""" Return a skew polynomial `U` such that `U P = c L` where `P` is this skew polynomial (``self``), `L` @@ -1390,6 +1390,12 @@ cdef class SkewPolynomial(AlgebraElement): TESTS:: + sage: cython(''' + ....: from sage.rings.polynomial.skew_polynomial_element cimport SkewPolynomial + ....: def left_lcm_cofactor(SkewPolynomial P, SkewPolynomial Q): + ....: return P._left_lcm_cofactor(Q) + ....: ''') + sage: k. = GF(7^5) sage: Frob = k.frobenius_endomorphism(3) sage: S. = k['x', Frob] @@ -1398,23 +1404,21 @@ cdef class SkewPolynomial(AlgebraElement): sage: P = S.random_element() * D sage: Q = S.random_element() * D sage: L = P.left_lcm(Q) - sage: U = P._left_lcm_cofactor(Q) + sage: U = left_lcm_cofactor(P, Q) sage: (U*P).right_monic() == L True """ - R = self._parent - U = R.one() - G = self - V1 = R.zero() - V3 = other - while not V3.is_zero(): - Q, R = G.right_quo_rem(V3) - T = U - Q*V1 - U = V1 - G = V3 - V1 = T - V3 = R - return V1 + cdef SkewPolynomial Q, R, T + cdef SkewPolynomial U = self._parent.one() + cdef SkewPolynomial V = self._parent.zero() + while other: + Q, R = self.right_quo_rem(other) + T = U - Q*V + U = V + V = T + self = other + other = R + return V @coerce_binop def left_xlcm(self, other, monic=True): @@ -1454,14 +1458,20 @@ cdef class SkewPolynomial(AlgebraElement): V1 = s * V1 return L, V1, L // other - def _right_lcm_cofactor(self, other): + cdef SkewPolynomial _right_lcm_cofactor(self, SkewPolynomial other): r""" Return a skew polynomial `U` such that `P U = L c` where `P` is this skew polynomial (``self``), `L` is the right lcm of `P` and ``other`` and `c` is a constant - EXAMPLES:: + TESTS:: + + sage: cython(''' + ....: from sage.rings.polynomial.skew_polynomial_element cimport SkewPolynomial + ....: def right_lcm_cofactor(SkewPolynomial P, SkewPolynomial Q): + ....: return P._right_lcm_cofactor(Q) + ....: ''') sage: k. = GF(7^5) sage: Frob = k.frobenius_endomorphism(3) @@ -1471,23 +1481,21 @@ cdef class SkewPolynomial(AlgebraElement): sage: P = D * S.random_element() sage: Q = D * S.random_element() sage: L = P.right_lcm(Q) - sage: U = P._right_lcm_cofactor(Q) + sage: U = right_lcm_cofactor(P, Q) sage: (P*U).left_monic() == L True """ - R = self._parent - U = R.one() - G = self - V1 = R.zero() - V3 = other - while not V3.is_zero(): - Q, R = G.left_quo_rem(V3) - T = U - V1*Q - U = V1 - G = V3 - V1 = T - V3 = R - return V1 + cdef SkewPolynomial Q, R, T + cdef SkewPolynomial U = self._parent.one() + cdef SkewPolynomial V = self._parent.zero() + while other: + Q, R = self.left_quo_rem(other) + T = U - V*Q + U = V + V = T + self = other + other = R + return V @coerce_binop def right_xlcm(self, other, monic=True): diff --git a/src/sage/rings/polynomial/skew_polynomial_finite_field.pxd b/src/sage/rings/polynomial/skew_polynomial_finite_field.pxd index 06a90f4f590..798aa1bd0d8 100644 --- a/src/sage/rings/polynomial/skew_polynomial_finite_field.pxd +++ b/src/sage/rings/polynomial/skew_polynomial_finite_field.pxd @@ -1,12 +1,12 @@ from sage.rings.polynomial.skew_polynomial_finite_order cimport SkewPolynomial_finite_order_dense -from sage.matrix.matrix_dense cimport Matrix_dense cdef class SkewPolynomial_finite_field_dense (SkewPolynomial_finite_order_dense): cdef _norm_factor - cdef dict _rdivisors cdef dict _types cdef _factorization + cdef inline _reduced_norm_factored(self) + # Finding divisors cdef SkewPolynomial_finite_field_dense _rdivisor_c(P, N) diff --git a/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx b/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx index ba3b14dd58c..1a64f02f51a 100644 --- a/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx +++ b/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx @@ -46,19 +46,9 @@ from sage.combinat.q_analogues import q_jordan cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): - def _reduced_norm_factored(self): + cdef inline _reduced_norm_factored(self): """ - Return the reduced norm of this polynomial factorized in the center - - EXAMPLES:: - - sage: k. = GF(5^3) - sage: Frob = k.frobenius_endomorphism() - sage: S. = k['x', Frob] - - sage: a = (x^2 + 1) * (x+3) - sage: a._reduced_norm_factored() - (z + 3) * (z + 2)^2 + Return the reduced norm of this polynomial factorized in the center. """ if self._norm_factor is None: N = self._parent._working_center(self.reduced_norm(var=False)) @@ -67,7 +57,7 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): def is_irreducible(self): """ - Return True if this skew polynomial is irreducible + Return True if this skew polynomial is irreducible. EXAMPLES:: @@ -113,9 +103,9 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): return N.is_irreducible() - def type(self,N): + def type(self, N): """ - Return the `N`-type of this skew polynomial (see definition below) + Return the `N`-type of this skew polynomial (see definition below). INPUT: @@ -184,40 +174,41 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): ... ValueError: N is not irreducible """ + cdef SkewPolynomial_finite_field_dense P, d, NS + cdef Py_ssize_t deg, degN, m + cdef list type skew_ring = self._parent if N.parent() is not skew_ring._working_center: N = skew_ring._working_center(N) - try: + if self._types is None: + self._types = dict() + elif N in self._types: return self._types[N] - except (KeyError, TypeError): - if not N.is_irreducible(): - raise ValueError("N is not irreducible") - if self._norm_factor is None: - m = -1 - else: - i = [ n for n,_ in self._norm_factor ].index(N) - m = self._norm_factor[i][1] - NS = skew_ring(N) - type = [ ] - degN = N.degree() - while True: - d = self.right_gcd(NS) - deg = d.degree()/degN - if deg == 0: + if not N.is_irreducible(): + raise ValueError("N is not irreducible") + if self._norm_factor is None: + m = -1 + else: + i = [ n for n,_ in self._norm_factor ].index(N) + m = self._norm_factor[i][1] + NS = skew_ring(N) + type = [ ] + degN = N.degree() + P = self + d = P.right_gcd(NS) + deg = d.degree() // degN + while deg > 0: + if m >= 0: + if deg == 1: + type += m * [1] break - if m >= 0: - if deg == 1: - type += m * [1] - break - m -= deg - self = self // d - type.append(deg) - # type = Partition(type) - if self._types is None: - self._types = { N: type } - else: - self._types[N] = type - return type + m -= deg + P = P // d + type.append(deg) + d = P.right_gcd(NS) + deg = d.degree() // degN + self._types[N] = type + return type # Finding divisors @@ -226,7 +217,7 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): cdef SkewPolynomial_finite_field_dense _rdivisor_c(self, N): """ Return a right divisor of this skew polynomial whose - reduced norm is `N` + reduced norm is `N`. .. WARNING:: @@ -252,19 +243,21 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): cdef Polynomial dd, xx, yy, zz cdef Integer exp cdef list lM, lV - + cdef bint char2 + center = N.parent() E = center.quo(N) PE = PolynomialRing(E, name='T') - if skew_ring.characteristic() != 2: - exp = Integer((E.cardinality()-1)/2) + char2 = skew_ring.characteristic() != 2 + if not char2: + exp = ((E.cardinality()-1) // 2) while True: R = skew_ring.random_element((e*r-1,e*r-1)) R = Q*R X = Q._new_c(Q._coeffs[:],Q._parent) lM = [ ] - for j from 0 <= j < e: - for i from 0 <= i < e: + for j in range(e): + for i in range(e): coeffs = [skew_ring._retraction(X[t*r+i]) for t in range(d)] value = E(coeffs) lM.append(value) @@ -277,21 +270,22 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): skew_ring._new_retraction_map() continue xx = PE(W.list() + [E(-1)]) - if skew_ring.characteristic() == 2: - yy = PE.gen() - zz = PE.gen() - for i from 1 <= i < d: + if char2: + zz = yy = PE.gen() + for i in range(1,d): zz = (zz*zz) % xx yy += zz dd = xx.gcd(yy) - if dd.degree() != 1: continue + if dd.degree() != 1: + continue else: yy = PE.gen().__pow__(exp,xx) - 1 dd = xx.gcd(yy) if dd.degree() != 1: yy += 2 dd = xx.gcd(yy) - if dd.degree() != 1: continue + if dd.degree() != 1: + continue D = P.right_gcd(R + skew_ring(center((dd[0]/dd[1]).list()))) if D.degree() == 0: continue @@ -304,7 +298,7 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): Return a factor of the reduced norm of this skew polynomial, the probability of a given factor to show up being proportional to the number of irreducible - divisors of ``self`` having this norm + divisors of ``self`` having this norm. This method is an helper function; it is not supposed to be called directly. @@ -368,10 +362,10 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): return F[i][0] - def _irreducible_divisors(self, right): + def _irreducible_divisors(self, bint right): """ Return an iterator over all irreducible monic - divisors of this skew polynomial + divisors of this skew polynomial. Do not use this function. Use instead :meth:`right_irreducible_divisors` and @@ -408,20 +402,22 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): ....: assert P.is_left_divisible_by(D), "not left divisible" ....: assert D.is_irreducible(), "not irreducible" """ - if self.is_zero(): + cdef SkewPolynomial_finite_field_dense NS, P, Q, R, P1, Q1, L, V, g, d + cdef Py_ssize_t i, m, degrandom + if not self: return if right: quo_rem = SkewPolynomial_finite_field_dense.right_quo_rem quo_rem2 = SkewPolynomial_finite_field_dense.left_quo_rem gcd = SkewPolynomial_finite_field_dense.right_gcd gcd2 = SkewPolynomial_finite_field_dense.left_gcd - def mul(a,b): return a*b + mul = lambda a,b: a*b else: quo_rem = SkewPolynomial_finite_field_dense.left_quo_rem quo_rem2 = SkewPolynomial_finite_field_dense.right_quo_rem gcd = SkewPolynomial_finite_field_dense.left_gcd gcd2 = SkewPolynomial_finite_field_dense.right_gcd - def mul(a,b): return b*a + mul = lambda a,b: b*a skew_ring = self._parent center = skew_ring._working_center kfixed = center.base_ring() @@ -445,23 +441,27 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): degrandom = NS.degree() - 1 while True: P1 = P // P.right_gcd(NS // D) - if P1.degree() == degN: break + if P1.degree() == degN: + break while True: R = skew_ring.random_element((degrandom,degrandom)) - if NS.right_gcd(R) == 1: break + if NS.right_gcd(R) == 1: + break D = NS.right_gcd(D*R) Q1,_ = quo_rem(P, P1) degrandom = P.degree() - 1 while True: R = skew_ring.random_element((degrandom, degrandom)) _, g = quo_rem2(mul(R,Q), P) - if gcd2(g,P) != 1: continue + if gcd2(g,P) != 1: + continue L = Q1 V = L for i in range(1,m): L = gcd2(mul(g,L), P) V = gcd2(V,L) - if V == 1: break + if V == 1: + break rng = xmrange_iter([kfixed]*degN, center) for i in range(m): for pol in xmrange_iter([rng]*i): @@ -476,7 +476,7 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): def right_irreducible_divisor(self, uniform=False): """ - Return a right irreducible divisor of this skew polynomial + Return a right irreducible divisor of this skew polynomial. INPUT: @@ -551,7 +551,7 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): def left_irreducible_divisor(self, uniform=False): """ - Return a left irreducible divisor of this skew polynomial + Return a left irreducible divisor of this skew polynomial. INPUT: @@ -580,11 +580,11 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): We can also generate uniformly distributed irreducible monic divisors as follows:: - sage: a.left_irreducible_divisor(uniform=True) + sage: a.left_irreducible_divisor(uniform=True) # random x^3 + (4*t^2 + 3*t + 4)*x^2 + (t^2 + t + 3)*x + 2*t^2 + 3 - sage: a.left_irreducible_divisor(uniform=True) + sage: a.left_irreducible_divisor(uniform=True) # random x^3 + (2*t^2 + t + 4)*x^2 + (2*t^2 + 4*t + 4)*x + 2*t + 3 - sage: a.left_irreducible_divisor(uniform=True) + sage: a.left_irreducible_divisor(uniform=True) # random x^3 + (t^2 + t + 2)*x^2 + (3*t^2 + t)*x + 2*t + 1 By convention, the zero skew polynomial has no irreducible @@ -607,22 +607,25 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): D = self._rdivisor_c(N) deg = NS.degree() - 1 P1 = self.left_gcd(NS) + if not uniform: + LD = P1 // P1.right_gcd(NS // D) + if LD.degree() == degN: + return LD while True: - if uniform: - while True: - R = skew_ring.random_element((deg,deg)) - if NS.right_gcd(R) == 1: break - D = NS.right_gcd(D*R) + while True: + R = skew_ring.random_element((deg,deg)) + if NS.right_gcd(R) == 1: + break + D = NS.right_gcd(D*R) LD = P1 // P1.right_gcd(NS // D) if LD.degree() == degN: return LD - uniform = True def right_irreducible_divisors(self): """ Return an iterator over all irreducible monic right divisors - of this skew polynomial + of this skew polynomial. EXAMPLES: @@ -657,7 +660,7 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): def left_irreducible_divisors(self): """ Return an iterator over all irreducible monic left divisors - of this skew polynomial + of this skew polynomial. EXAMPLES: @@ -753,7 +756,7 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): cdef _factor_c(self): """ - Compute a factorization of ``self`` + Compute a factorization of ``self``. This is the low level implementation of :meth:`factor`. """ @@ -791,9 +794,9 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): mP = P.degree() / degN if mP == 0: break if mP == 1: - factors.append((P,1)) + factors.append((P, 1)) poly = poly // P - for i from 1 <= i < m: + for i in range(1, m): if poly.degree() == degN: factors.append((poly,1)) break @@ -828,7 +831,7 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): cdef _factor_uniform_c(self): """ - Compute a uniformly distrbuted factorization of ``self`` + Compute a uniformly distrbuted factorization of ``self``. This is the low level implementation of :meth:`factor`. """ @@ -846,10 +849,11 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): for N, m in self._reduced_norm_factored(): factorsN += m * [N] - if N == gencenter: continue + if N == gencenter: + continue type = list(self.type(N)) dict_type[N] = type - if type[0] > 1: + if (type[0]) > 1: dict_divisor[N] = self._rdivisor_c(N) dict_right[N] = skew_ring(1) cdef list indices = list(Permutations(len(factorsN)).random_element()) @@ -873,7 +877,7 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): type = dict_type[N] NS = skew_ring(N) P = left.right_gcd(NS) - if type[0] == 1: + if (type[0]) == 1: D1 = P else: R = right._new_c(right._coeffs[:],skew_ring) @@ -886,10 +890,10 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): maxcount = q_jordan(Partition(maxtype),cardE) Q = NS // P deg = P.degree()-1 - while 1: - while 1: + while True: + while True: R = skew_ring.random_element((deg,deg)) - R = Q*R + R = Q * R if P.right_gcd(R).degree() == 0: break D1 = P.right_gcd(D*R).right_monic() @@ -898,27 +902,27 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): L = L // D1 degN = N.degree() for j in range(len(type)): - if type[j] == 1: + if (type[j]) == 1: newtype = type[:-1] break d = L.right_gcd(NS).right_monic() deg = d.degree() / degN - if deg < type[j]: + if deg < (type[j]): newtype = type[:] newtype[j] = deg break L = L // d - count = q_jordan(Partition(newtype),cardE) + count = q_jordan(newtype, cardE) if ZZ.random_element(maxcount) < count: break dict_type[N] = newtype - D2 = D._new_c(list(D._coeffs),skew_ring) + D2 = D._new_c(list(D._coeffs), skew_ring) D2 = D2.right_monic() while D2 == D1: while True: R = skew_ring.random_element((deg,deg)) - R = Q*R + R = Q * R if P.right_gcd(R).degree() == 0: break D2 = P.right_gcd(D*R).right_monic() @@ -926,7 +930,7 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): factors.append((D1,1)) left = left // D1 right = D1 * right - dict_right[N] = right._new_c(list(right._coeffs),skew_ring) + dict_right[N] = right._new_c(list(right._coeffs), skew_ring) factors.reverse() return Factorization(factors, sort=False, unit=unit) @@ -934,13 +938,13 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): def factor(self, uniform=False): """ - Return a factorization of this skew polynomial + Return a factorization of this skew polynomial. INPUT: - ``uniform`` -- a boolean (default: ``False``); whether the - output irreducible divisor should be uniformly distributed - among all possibilities + output irreducible divisor should be uniformly distributed + among all possibilities EXAMPLES:: @@ -989,16 +993,18 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): """ if self.is_zero(): raise ValueError("factorization of 0 not defined") - sig_on() if uniform: + sig_on() F = self._factor_uniform_c() + sig_off() if self._factorization is None: self._factorization = F else: if self._factorization is None: + sig_on() self._factorization = self._factor_c() + sig_off() F = self._factorization - sig_off() return F @@ -1037,7 +1043,8 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): count = 1 for N, m in F: summ += m - if m == 1: continue + if m == 1: + continue if N != gencenter: count *= q_jordan(self.type(N), cardcenter**N.degree()) count /= factorial(m) @@ -1099,7 +1106,7 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): else: for div in P._irreducible_divisors(True): Q = P // div - # Here, we should update Q._norm, Q._norm_factor, Q._rdivisors + # Here, we should update Q._norm, Q._norm_factor for factors in factorizations_rec(Q): factors.append((div,1)) yield factors From 05c6bdf8e1752ba678f93e4539948694c656b28e Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Thu, 23 Apr 2020 15:00:50 +0200 Subject: [PATCH 093/300] make left_quo_rem and right_quo_rem cdef functions --- .../polynomial/skew_polynomial_element.pxd | 2 + .../polynomial/skew_polynomial_element.pyx | 263 ++++++++++-------- .../skew_polynomial_finite_field.pxd | 3 + .../skew_polynomial_finite_field.pyx | 68 ++--- 4 files changed, 186 insertions(+), 150 deletions(-) diff --git a/src/sage/rings/polynomial/skew_polynomial_element.pxd b/src/sage/rings/polynomial/skew_polynomial_element.pxd index 803a0009cba..0964cd4ba1d 100644 --- a/src/sage/rings/polynomial/skew_polynomial_element.pxd +++ b/src/sage/rings/polynomial/skew_polynomial_element.pxd @@ -19,6 +19,8 @@ cdef class SkewPolynomial(AlgebraElement): cpdef operator_eval(self, eval_pt) + cdef _left_quo_rem(self, SkewPolynomial other) + cdef _right_quo_rem(self, SkewPolynomial other) cdef SkewPolynomial _left_lcm_cofactor(self, SkewPolynomial other) cdef SkewPolynomial _right_lcm_cofactor(self, SkewPolynomial other) diff --git a/src/sage/rings/polynomial/skew_polynomial_element.pyx b/src/sage/rings/polynomial/skew_polynomial_element.pyx index 2b6c56ae840..db64f3ce84f 100644 --- a/src/sage/rings/polynomial/skew_polynomial_element.pyx +++ b/src/sage/rings/polynomial/skew_polynomial_element.pyx @@ -60,7 +60,8 @@ AUTHORS: #**************************************************************************** import re -from copy import copy +from cysignals.signals cimport sig_check + from sage.rings.infinity import infinity from sage.structure.factorization import Factorization from sage.structure.element cimport Element, RingElement, AlgebraElement, ModuleElement @@ -1117,21 +1118,23 @@ cdef class SkewPolynomial(AlgebraElement): """ if self.base_ring() not in Fields: raise TypeError("the base ring must be a field") - G = self - U = self._parent.one() - if other.is_zero(): + cdef SkewPolynomial_generic_dense G = self + cdef SkewPolynomial_generic_dense U = self._parent.one() + cdef SkewPolynomial_generic_dense V, V1, V2, Q, R, T + if not other: V = self._parent.zero() else: V1 = self._parent.zero() V3 = other - while not V3.is_zero(): - Q,R = G.left_quo_rem(V3) + while V3: + Q,R = G._left_quo_rem(V3) T = U - V1*Q U = V1 G = V3 V1 = T V3 = R - V, _ = (G - self*U).left_quo_rem(other) + V = G - self*U + V, _ = V._left_quo_rem(other) if monic: lc = ~G.leading_coefficient() lc = self._parent.twist_map(-G.degree())(lc) @@ -1140,6 +1143,119 @@ cdef class SkewPolynomial(AlgebraElement): V = V * lc return G,U,V + cdef _left_quo_rem(self, SkewPolynomial other): + r""" + Return the quotient and remainder of the left euclidean + division of ``self`` by ``other`` (C implementation). + + Must be implemented in subclasses. + """ + raise NotImplementedError("left Euclidean division is not implemented") + + @coerce_binop + def left_quo_rem(self, other): + r""" + Return the quotient and remainder of the left euclidean + division of ``self`` by ``other``. + + INPUT: + + - ``other`` -- a skew polynomial in the same ring as ``self`` + + OUTPUT: + + - the quotient and the remainder of the left euclidean + division of this skew polynomial by ``other`` + + .. NOTE:: + + This will fail if the leading coefficient of ``other`` is not a unit + or if Sage can't invert the twist map. + + EXAMPLES:: + + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x',Frob] + sage: a = (3*t^2 + 3*t + 2)*x^3 + (2*t^2 + 3)*x^2 + (4*t^2 + t + 4)*x + 2*t^2 + 2 + sage: b = (3*t^2 + 4*t + 2)*x^2 + (2*t^2 + 4*t + 3)*x + 2*t^2 + t + 1 + sage: q,r = a.left_quo_rem(b) + sage: a == b*q + r + True + + In the following example, Sage does not know the inverse + of the twist map:: + + sage: R. = ZZ[] + sage: sigma = R.hom([t+1]) + sage: S. = R['x',sigma] + sage: a = (-2*t^2 - t + 1)*x^3 + (-t^2 + t)*x^2 + (-12*t - 2)*x - t^2 - 95*t + 1 + sage: b = x^2 + (5*t - 6)*x - 4*t^2 + 4*t - 1 + sage: a.left_quo_rem(b) + Traceback (most recent call last): + ... + NotImplementedError: inversion of the twist map Ring endomorphism of Univariate Polynomial Ring in t over Integer Ring + Defn: t |--> t + 1 + """ + if not other: + raise ZeroDivisionError("division by zero is not valid") + return self._left_quo_rem(other) + + cdef _right_quo_rem(self, SkewPolynomial other): + r""" + Return the quotient and remainder of the right euclidean + division of ``self`` by ``other`` (C implementation). + + Must be implemented in subclasses. + """ + raise NotImplementedError("right Euclidean division is not implemented") + + @coerce_binop + def right_quo_rem(self, other): + r""" + Return the quotient and remainder of the right euclidean + division of ``self`` by ``other``. + + INPUT: + + - ``other`` -- a skew polynomial in the same ring as ``self`` + + OUTPUT: + + - the quotient and the remainder of the left euclidean + division of this skew polynomial by ``other`` + + .. NOTE:: + + This will fail if the leading coefficient of the divisor + is not a unit. + + EXAMPLES:: + + sage: R. = ZZ[] + sage: sigma = R.hom([t+1]) + sage: S. = R['x',sigma] + sage: a = S.random_element(degree=4); a + (-t - 95)*x^4 + x^3 + (2*t - 1)*x + sage: b = S.random_element(monic=True); b + x^2 + (-12*t - 2)*x + sage: q,r = a.right_quo_rem(b) + sage: a == q*b + r + True + + The leading coefficient of the divisor need to be invertible:: + + sage: c = S.random_element(); c + (t - 1)*x^2 + t^2*x + sage: a.right_quo_rem(c) + Traceback (most recent call last): + ... + NotImplementedError: the leading coefficient of the divisor is not invertible + """ + if not other: + raise ZeroDivisionError("division by zero is not valid") + return self._right_quo_rem(other) + @coerce_binop def right_xgcd(self, other, monic=True): r""" @@ -1212,21 +1328,23 @@ cdef class SkewPolynomial(AlgebraElement): """ if self.base_ring() not in Fields: raise TypeError("the base ring must be a field") - G = self - U = self._parent.one() + cdef SkewPolynomial_generic_dense G = self + cdef SkewPolynomial_generic_dense U = self._parent.one() + cdef SkewPolynomial_generic_dense V, V1, V3, Q, R, T if other.is_zero(): V = self._parent.zero() else: V1 = self._parent.zero() V3 = other while not V3.is_zero(): - Q, R = G.right_quo_rem(V3) + Q, R = G._right_quo_rem(V3) T = U - Q*V1 U = V1 G = V3 V1 = T V3 = R - V,_ = (G - U*self).right_quo_rem(other) + V = G - U*self + V,_ = V._right_quo_rem(other) if monic: lc = ~G.leading_coefficient() G = lc * G @@ -1291,8 +1409,8 @@ cdef class SkewPolynomial(AlgebraElement): raise TypeError("the base ring must be a field") if other.is_zero(): return self - A = self - B = other + cdef SkewPolynomial_generic_dense A = self + cdef SkewPolynomial_generic_dense B = other while not B.is_zero(): A, B = B, A % B if monic: @@ -1371,12 +1489,12 @@ cdef class SkewPolynomial(AlgebraElement): raise TypeError("the base ring must be a field") if other.is_zero(): return self - A = self - B = other + cdef SkewPolynomial_generic_dense A_, A = self + cdef SkewPolynomial_generic_dense B = other while not B.is_zero(): A_ = A A = B - _, B = A_.left_quo_rem(B) + _, B = A_._left_quo_rem(B) if monic: A = A.left_monic() return A @@ -1412,7 +1530,7 @@ cdef class SkewPolynomial(AlgebraElement): cdef SkewPolynomial U = self._parent.one() cdef SkewPolynomial V = self._parent.zero() while other: - Q, R = self.right_quo_rem(other) + Q, R = self._right_quo_rem(other) T = U - Q*V U = V V = T @@ -1450,8 +1568,8 @@ cdef class SkewPolynomial(AlgebraElement): raise TypeError("the base ring must be a field") if self.is_zero() or other.is_zero(): raise ZeroDivisionError("division by zero is not valid") - V1 = self._left_lcm_cofactor(other) - L = V1 * self + cdef SkewPolynomial_generic_dense V1 = self._left_lcm_cofactor(other) + cdef SkewPolynomial_generic_dense L = V1 * self if monic: s = ~(L.leading_coefficient()) L = s * L @@ -1489,7 +1607,7 @@ cdef class SkewPolynomial(AlgebraElement): cdef SkewPolynomial U = self._parent.one() cdef SkewPolynomial V = self._parent.zero() while other: - Q, R = self.left_quo_rem(other) + Q, R = self._left_quo_rem(other) T = U - V*Q U = V V = T @@ -1533,14 +1651,14 @@ cdef class SkewPolynomial(AlgebraElement): raise TypeError("the base ring must be a field") if self.is_zero() or other.is_zero(): raise ZeroDivisionError("division by zero is not valid") - V1 = self._right_lcm_cofactor(other) - L = self * V1 + cdef SkewPolynomial_generic_dense V1 = self._right_lcm_cofactor(other) + cdef SkewPolynomial_generic_dense L = self * V1 if monic: s = self.base_ring()(~L.leading_coefficient()) s = self._parent.twist_map(-L.degree())(s) L = L * s V1 = V1 * s - W1, _ = L.left_quo_rem(other) + W1, _ = L._left_quo_rem(other) return L, V1, W1 @@ -2909,57 +3027,16 @@ cdef class SkewPolynomial_generic_dense(SkewPolynomial): """ return self._new_c(self._coeffs[:n], self._parent, 1) - @coerce_binop - def left_quo_rem(self, other): + cdef _left_quo_rem(self, SkewPolynomial other): r""" Return the quotient and remainder of the left euclidean - division of ``self`` by ``other``. - - INPUT: - - - ``other`` -- a skew polynomial in the same ring as ``self`` - - OUTPUT: - - - the quotient and the remainder of the left euclidean - division of this skew polynomial by ``other`` - - .. NOTE:: - - This will fail if the leading coefficient of ``other`` is not a unit - or if Sage can't invert the twist map. - - EXAMPLES:: - - sage: k. = GF(5^3) - sage: Frob = k.frobenius_endomorphism() - sage: S. = k['x',Frob] - sage: a = (3*t^2 + 3*t + 2)*x^3 + (2*t^2 + 3)*x^2 + (4*t^2 + t + 4)*x + 2*t^2 + 2 - sage: b = (3*t^2 + 4*t + 2)*x^2 + (2*t^2 + 4*t + 3)*x + 2*t^2 + t + 1 - sage: q,r = a.left_quo_rem(b) - sage: a == b*q + r - True - - In the following example, Sage does not know the inverse - of the twist map:: - - sage: R. = ZZ[] - sage: sigma = R.hom([t+1]) - sage: S. = R['x',sigma] - sage: a = (-2*t^2 - t + 1)*x^3 + (-t^2 + t)*x^2 + (-12*t - 2)*x - t^2 - 95*t + 1 - sage: b = x^2 + (5*t - 6)*x - 4*t^2 + 4*t - 1 - sage: a.left_quo_rem(b) - Traceback (most recent call last): - ... - NotImplementedError: inversion of the twist map Ring endomorphism of Univariate Polynomial Ring in t over Integer Ring - Defn: t |--> t + 1 + division of ``self`` by ``other`` (C implementation). """ + sig_check() cdef list a = list(self._coeffs) - cdef list b = (other)._coeffs + cdef list b = (other)._coeffs cdef Py_ssize_t i, j cdef Py_ssize_t da = self.degree(), db = other.degree() - if db < 0: - raise ZeroDivisionError("division by zero is not valid") if da < db: return (self._new_c([], self._parent), self) try: @@ -2979,55 +3056,17 @@ cdef class SkewPolynomial_generic_dense(SkewPolynomial): q.reverse() return (self._new_c(q, parent), self._new_c(a[:db], parent, 1)) - @coerce_binop - def right_quo_rem(self, other): + cdef _right_quo_rem(self, SkewPolynomial other): r""" Return the quotient and remainder of the right euclidean - division of ``self`` by ``other``. - - INPUT: - - - ``other`` -- a skew polynomial in the same ring as ``self`` - - OUTPUT: - - - the quotient and the remainder of the left euclidean - division of this skew polynomial by ``other`` - - .. NOTE:: - - This will fail if the leading coefficient of the divisor - is not a unit. - - EXAMPLES:: - - sage: R. = ZZ[] - sage: sigma = R.hom([t+1]) - sage: S. = R['x',sigma] - sage: a = S.random_element(degree=4); a - (-t - 95)*x^4 + x^3 + (2*t - 1)*x - sage: b = S.random_element(monic=True); b - x^2 + (-12*t - 2)*x - sage: q,r = a.right_quo_rem(b) - sage: a == q*b + r - True - - The leading coefficient of the divisor need to be invertible:: - - sage: c = S.random_element(); c - (t - 1)*x^2 + t^2*x - sage: a.right_quo_rem(c) - Traceback (most recent call last): - ... - NotImplementedError: the leading coefficient of the divisor is not invertible + division of ``self`` by ``other`` (C implementation). """ + sig_check() cdef list a = list(self._coeffs) - cdef list b = (other)._coeffs + cdef list b = (other)._coeffs cdef Py_ssize_t i, j cdef Py_ssize_t da = self.degree(), db = other.degree() parent = self._parent - if db < 0: - raise ZeroDivisionError("division by zero is not valid") if da < db: return (self._new_c([],parent), self) try: @@ -3104,7 +3143,7 @@ cdef class SkewPolynomial_generic_dense(SkewPolynomial): r._inplace_pow(exp) if modulus: - _, r = r.left_quo_rem(modulus) + _, r = r._left_quo_rem(modulus) return r cpdef right_power_mod(self, exp, modulus): @@ -3174,7 +3213,7 @@ cdef class SkewPolynomial_generic_dense(SkewPolynomial): r._inplace_pow(exp) if modulus: - _, r = r.right_quo_rem(modulus) + _, r = r._right_quo_rem(modulus) return r def __pow__(self, exp, modulus): diff --git a/src/sage/rings/polynomial/skew_polynomial_finite_field.pxd b/src/sage/rings/polynomial/skew_polynomial_finite_field.pxd index 798aa1bd0d8..f27cfdd6ff1 100644 --- a/src/sage/rings/polynomial/skew_polynomial_finite_field.pxd +++ b/src/sage/rings/polynomial/skew_polynomial_finite_field.pxd @@ -13,3 +13,6 @@ cdef class SkewPolynomial_finite_field_dense (SkewPolynomial_finite_order_dense) # Finding factorizations cdef _factor_c(self) cdef _factor_uniform_c(self) + +cdef inline SkewPolynomial_finite_field_dense mul_op(SkewPolynomial_finite_field_dense P, SkewPolynomial_finite_field_dense Q): + return Q * P diff --git a/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx b/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx index 1a64f02f51a..0f3d603b252 100644 --- a/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx +++ b/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx @@ -23,14 +23,11 @@ AUTHOR:: # http://www.gnu.org/licenses/ #**************************************************************************** -from cysignals.signals cimport sig_on, sig_off - import copy -import cysignals + +from sage.structure.element cimport parent from sage.rings.ring cimport Ring from sage.rings.all import ZZ - -from sage.structure.element cimport RingElement from sage.rings.integer cimport Integer from sage.rings.polynomial.polynomial_element cimport Polynomial @@ -41,6 +38,7 @@ from sage.combinat.permutation import Permutation, Permutations from sage.combinat.partition import Partition from sage.structure.factorization import Factorization from sage.misc.mrange import xmrange_iter +from sage.misc.prandom import sample from sage.arith.misc import factorial from sage.combinat.q_analogues import q_jordan @@ -178,7 +176,7 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): cdef Py_ssize_t deg, degN, m cdef list type skew_ring = self._parent - if N.parent() is not skew_ring._working_center: + if parent(N) is not skew_ring._working_center: N = skew_ring._working_center(N) if self._types is None: self._types = dict() @@ -189,8 +187,9 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): if self._norm_factor is None: m = -1 else: - i = [ n for n,_ in self._norm_factor ].index(N) - m = self._norm_factor[i][1] + for n, m in self._norm_factor: + if n == N: + break NS = skew_ring(N) type = [ ] degN = N.degree() @@ -245,31 +244,31 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): cdef list lM, lV cdef bint char2 - center = N.parent() + center = parent(N) E = center.quo(N) PE = PolynomialRing(E, name='T') char2 = skew_ring.characteristic() != 2 if not char2: exp = ((E.cardinality()-1) // 2) while True: - R = skew_ring.random_element((e*r-1,e*r-1)) + R = skew_ring.random_element((e*r-1, e*r-1)) R = Q*R - X = Q._new_c(Q._coeffs[:],Q._parent) - lM = [ ] + X = Q._new_c(list(Q._coeffs), Q._parent) + lM = [ None ] * (e**2) for j in range(e): for i in range(e): coeffs = [skew_ring._retraction(X[t*r+i]) for t in range(d)] value = E(coeffs) - lM.append(value) + lM[i*e+j] = value X = (R*X) % NS - M = MatrixSpace(E,e,e)(lM).transpose() + M = MatrixSpace(E,e,e)(lM) V = MatrixSpace(E,e,1)([ E([skew_ring._retraction(X[t*r+i]) for t in range(d)]) for i in range(e) ]) try: W = M._solve_right_nonsingular_square(V) except NotFullRankError: skew_ring._new_retraction_map() continue - xx = PE(W.list() + [E(-1)]) + xx = PE(W.list() + [E(-1)]) if char2: zz = yy = PE.gen() for i in range(1,d): @@ -289,7 +288,6 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): D = P.right_gcd(R + skew_ring(center((dd[0]/dd[1]).list()))) if D.degree() == 0: continue - D = D.right_monic() return D @@ -411,13 +409,13 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): quo_rem2 = SkewPolynomial_finite_field_dense.left_quo_rem gcd = SkewPolynomial_finite_field_dense.right_gcd gcd2 = SkewPolynomial_finite_field_dense.left_gcd - mul = lambda a,b: a*b + mul = SkewPolynomial_finite_field_dense.__mul__ # why _mul_ doesn't work? else: quo_rem = SkewPolynomial_finite_field_dense.left_quo_rem quo_rem2 = SkewPolynomial_finite_field_dense.right_quo_rem gcd = SkewPolynomial_finite_field_dense.left_gcd gcd2 = SkewPolynomial_finite_field_dense.right_gcd - mul = lambda a,b: b*a + mul = mul_op skew_ring = self._parent center = skew_ring._working_center kfixed = center.base_ring() @@ -465,7 +463,7 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): rng = xmrange_iter([kfixed]*degN, center) for i in range(m): for pol in xmrange_iter([rng]*i): - f = skew_ring(1) + f = skew_ring.one() for j in range(i): coeff = pol.pop() _, f = quo_rem2(g*f + coeff, P) @@ -764,9 +762,7 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): cdef SkewPolynomial_finite_field_dense poly = self.right_monic() cdef list a = poly._coeffs cdef Py_ssize_t val = 0 - if len(a) < 0: - return Factorization([], sort=False, unit=skew_ring.zero_element()) - while a[0].is_zero(): + while not a[0]: del a[0] val += 1 @@ -774,7 +770,7 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): cdef N cdef list factors = [ (skew_ring.gen(), val) ] cdef SkewPolynomial_finite_field_dense P, Q, P1, NS, g, right, Pn - cdef RingElement unit = self.leading_coefficient() + cdef unit = self.leading_coefficient() cdef Polynomial gencenter = skew_ring._working_center.gen() cdef Py_ssize_t p = skew_ring.characteristic() cdef F = self._reduced_norm_factored() @@ -790,7 +786,6 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): P1 = None while True: P = poly.right_gcd(NS) - P = P.right_monic() mP = P.degree() / degN if mP == 0: break if mP == 1: @@ -800,7 +795,7 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): if poly.degree() == degN: factors.append((poly,1)) break - P = poly.right_gcd(NS).right_monic() + P = poly.right_gcd(NS) factors.append((P, 1)) poly = poly // P break @@ -855,13 +850,14 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): dict_type[N] = type if (type[0]) > 1: dict_divisor[N] = self._rdivisor_c(N) - dict_right[N] = skew_ring(1) - cdef list indices = list(Permutations(len(factorsN)).random_element()) + dict_right[N] = skew_ring.one() + m = len(factorsN) + cdef list indices = sample(range(1, m+1), m) - cdef RingElement unit = self.leading_coefficient() + cdef unit = self.leading_coefficient() cdef SkewPolynomial_finite_field_dense left = self._new_c(self._coeffs[:],skew_ring) left = left.right_monic() - cdef SkewPolynomial_finite_field_dense right = skew_ring(1) + cdef SkewPolynomial_finite_field_dense right = skew_ring.one() cdef SkewPolynomial_finite_field_dense L, R cdef SkewPolynomial_finite_field_dense NS, P, Q, D, D1, D2, d cdef list factors = [ ] @@ -887,7 +883,7 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): maxtype[-1] -= 1 degN = N.degree() cardE = cardcenter ** degN - maxcount = q_jordan(Partition(maxtype),cardE) + maxcount = q_jordan(maxtype, cardE) Q = NS // P deg = P.degree()-1 while True: @@ -896,7 +892,7 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): R = Q * R if P.right_gcd(R).degree() == 0: break - D1 = P.right_gcd(D*R).right_monic() + D1 = P.right_gcd(D*R) L = left._new_c(list(left._coeffs),skew_ring) L = L // D1 @@ -905,10 +901,10 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): if (type[j]) == 1: newtype = type[:-1] break - d = L.right_gcd(NS).right_monic() + d = L.right_gcd(NS) deg = d.degree() / degN if deg < (type[j]): - newtype = type[:] + newtype = list(type) newtype[j] = deg break L = L // d @@ -925,7 +921,7 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): R = Q * R if P.right_gcd(R).degree() == 0: break - D2 = P.right_gcd(D*R).right_monic() + D2 = P.right_gcd(D*R) dict_divisor[N] = D1.left_lcm(D2) factors.append((D1,1)) left = left // D1 @@ -994,16 +990,12 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): if self.is_zero(): raise ValueError("factorization of 0 not defined") if uniform: - sig_on() F = self._factor_uniform_c() - sig_off() if self._factorization is None: self._factorization = F else: if self._factorization is None: - sig_on() self._factorization = self._factor_c() - sig_off() F = self._factorization return F From 2ed055d22430d7866fd6e4b6f046b90dc9907fc3 Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Sat, 25 Apr 2020 15:12:27 +0200 Subject: [PATCH 094/300] move imports --- src/sage/rings/polynomial/skew_polynomial_element.pxd | 1 + src/sage/rings/polynomial/skew_polynomial_finite_field.pyx | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/polynomial/skew_polynomial_element.pxd b/src/sage/rings/polynomial/skew_polynomial_element.pxd index 0964cd4ba1d..1591df63702 100644 --- a/src/sage/rings/polynomial/skew_polynomial_element.pxd +++ b/src/sage/rings/polynomial/skew_polynomial_element.pxd @@ -21,6 +21,7 @@ cdef class SkewPolynomial(AlgebraElement): cdef _left_quo_rem(self, SkewPolynomial other) cdef _right_quo_rem(self, SkewPolynomial other) + cdef SkewPolynomial _left_lcm_cofactor(self, SkewPolynomial other) cdef SkewPolynomial _right_lcm_cofactor(self, SkewPolynomial other) diff --git a/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx b/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx index 0f3d603b252..6f4f090cab9 100644 --- a/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx +++ b/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx @@ -23,15 +23,16 @@ AUTHOR:: # http://www.gnu.org/licenses/ #**************************************************************************** -import copy - from sage.structure.element cimport parent from sage.rings.ring cimport Ring from sage.rings.all import ZZ from sage.rings.integer cimport Integer +from sage.matrix.matrix_space import MatrixSpace +from sage.matrix.matrix2 import NotFullRankError from sage.rings.polynomial.polynomial_element cimport Polynomial from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.polynomial.skew_polynomial_element cimport SkewPolynomial from sage.rings.polynomial.skew_polynomial_finite_order cimport SkewPolynomial_finite_order_dense from sage.combinat.permutation import Permutation, Permutations @@ -225,8 +226,6 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): this (and his behaviour is not defined if the require property doesn't hold). """ - from sage.matrix.matrix_space import MatrixSpace - from sage.matrix.matrix2 import NotFullRankError cdef skew_ring = self._parent cdef SkewPolynomial_finite_field_dense NS = skew_ring(N) cdef SkewPolynomial_finite_field_dense P = self.right_gcd(NS) From 03ce5ddf54da213eecbf0ea96ab31b20ee07ebd4 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Wed, 29 Apr 2020 07:56:33 +0100 Subject: [PATCH 095/300] No idea --- .../combinat/path_tableaux/path_tableau.py | 46 ++++++++++++------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/src/sage/combinat/path_tableaux/path_tableau.py b/src/sage/combinat/path_tableaux/path_tableau.py index f1a364ee625..a4ab7e3e8ec 100644 --- a/src/sage/combinat/path_tableaux/path_tableau.py +++ b/src/sage/combinat/path_tableaux/path_tableau.py @@ -257,7 +257,7 @@ def _test_involution_rule(self, **options): tester = self._tester(**options) for i in range(self.size()-2): tester.assertTrue(self._local_rule(i+1)._local_rule(i+1) == self) - + def _test_involution_cactus(self, **options): """ @@ -271,7 +271,7 @@ def _test_involution_cactus(self, **options): tester = self._tester(**options) for i in range(2,self.size()+1): tester.assertTrue(self.cactus(1,i).cactus(1,i) == self) - + def _test_promotion(self, **options): """ Check that promotion can be expressed in terms of the cactus generators. @@ -445,21 +445,21 @@ def _repr_(self): def _latex_(self): r""" Returns a `\LaTeX` representation of ``self`` - + EXAMPLES:: - + sage: t = CatalanTableau([0,1,2,3,2,1,0]) sage: latex(CylindricalDiagram(t)) \begin{array}{ccccccccccccc} - 0 & 1 & 2 & 3 & 2 & 1 & 0\\ - & 0 & 1 & 2 & 1 & 0 & 1 & 0\\ - & & 0 & 1 & 0 & 1 & 2 & 1 & 0\\ - & & & 0 & 1 & 2 & 3 & 2 & 1 & 0\\ - & & & & 0 & 1 & 2 & 1 & 0 & 1 & 0\\ - & & & & & 0 & 1 & 0 & 1 & 2 & 1 & 0\\ + 0 & 1 & 2 & 3 & 2 & 1 & 0\\ + & 0 & 1 & 2 & 1 & 0 & 1 & 0\\ + & & 0 & 1 & 0 & 1 & 2 & 1 & 0\\ + & & & 0 & 1 & 2 & 3 & 2 & 1 & 0\\ + & & & & 0 & 1 & 2 & 1 & 0 & 1 & 0\\ + & & & & & 0 & 1 & 0 & 1 & 2 & 1 & 0\\ & & & & & & 0 & 1 & 2 & 3 & 2 & 1 & 0 \end{array} - + """ D = self.diagram @@ -469,22 +469,36 @@ def _latex_(self): result += "\n \\end{array}\n" return result + def __len__(self): + return len(self.diagram) + def _ascii_art_(self): - r""" """ + Returns an ascii art representation of ``self`` + TESTS:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: ascii_art(CylindricalDiagram(t)) + [ 1 3 1 2 ] + [ 2 , 3 ] + """ + from sage.typeset.ascii_art import AsciiArt + D = [ map(str,x) for x in self.diagram ] + S = [ ' '.join(x) for x in D ] + return AsciiArt(S) def _unicode_art_(self): r""" """ - + def pp(self): """ A pretty print utility method. - + EXAMPLES:: + sage: t = CatalanTableau([0,1,2,3,2,1,0]) - sage: c = CylindricalDiagram(t) - sage: c.pp() + sage: CylindricalDiagram(t).pp() 0 1 2 3 2 1 0 0 1 2 1 0 1 0 0 1 0 1 2 1 0 From 2473d5b0ce136f2ae586197ddbda350597f5be19 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Wed, 29 Apr 2020 18:36:04 +0100 Subject: [PATCH 096/300] Minor edits --- src/sage/combinat/path_tableaux/catalan.py | 2 +- src/sage/combinat/path_tableaux/path_tableau.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/path_tableaux/catalan.py b/src/sage/combinat/path_tableaux/catalan.py index 0e406313d64..90f24501865 100644 --- a/src/sage/combinat/path_tableaux/catalan.py +++ b/src/sage/combinat/path_tableaux/catalan.py @@ -162,7 +162,7 @@ def __init__(self, parent, ot, check=True): ClonableArray.__init__(self, parent, w, check=check) def check(self): - + """ Checks that ``self`` is a valid path.""" n = len(self) if any(a < 0 for a in self): raise ValueError( "%s has a negative entry" % (str(self)) ) diff --git a/src/sage/combinat/path_tableaux/path_tableau.py b/src/sage/combinat/path_tableaux/path_tableau.py index a4ab7e3e8ec..a1aa86bcc64 100644 --- a/src/sage/combinat/path_tableaux/path_tableau.py +++ b/src/sage/combinat/path_tableaux/path_tableau.py @@ -410,8 +410,8 @@ def dual_equivalence_graph(self): return G class PathTableaux(UniqueRepresentation,Parent): - - def __init(self): + """ The abstract parent class for PathTableau.""" + def __init__(self): Parent.__init__(self, category=Sets()) def _element_constructor_(self, *args, **kwds): @@ -470,6 +470,7 @@ def _latex_(self): return result def __len__(self): + """Returns the length of ``self``""" return len(self.diagram) def _ascii_art_(self): From f3dc239fb4cb8ea71f0426f4bce96db05e9bfeb1 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Thu, 30 Apr 2020 10:19:30 +0100 Subject: [PATCH 097/300] Worked on doc tests --- src/sage/combinat/path_tableaux/all.py | 3 ++ src/sage/combinat/path_tableaux/catalan.py | 21 ++++++----- .../combinat/path_tableaux/path_tableau.py | 37 ++++++++++++++----- 3 files changed, 41 insertions(+), 20 deletions(-) diff --git a/src/sage/combinat/path_tableaux/all.py b/src/sage/combinat/path_tableaux/all.py index 36e8f5eafdf..b7f6bf01a5a 100644 --- a/src/sage/combinat/path_tableaux/all.py +++ b/src/sage/combinat/path_tableaux/all.py @@ -1,3 +1,6 @@ +r""" +PathTableau features that are imported by default in the interpreter namespace +""" from __future__ import absolute_import from .path_tableau import PathTableau, PathTableaux, CylindricalDiagram diff --git a/src/sage/combinat/path_tableaux/catalan.py b/src/sage/combinat/path_tableaux/catalan.py index 90f24501865..1ca859b7a1d 100644 --- a/src/sage/combinat/path_tableaux/catalan.py +++ b/src/sage/combinat/path_tableaux/catalan.py @@ -40,14 +40,15 @@ sage: t = CatalanTableau([0,1,2,3,2,1,0]) sage: print(CylindricalDiagram(t)) - The cylindrical growth diagram: - [0, 1, 2, 3, 2, 1, 0] - ['', 0, 1, 2, 1, 0, 1, 0] - ['', '', 0, 1, 0, 1, 2, 1, 0] - ['', '', '', 0, 1, 2, 3, 2, 1, 0] - ['', '', '', '', 0, 1, 2, 1, 0, 1, 0] - ['', '', '', '', '', 0, 1, 0, 1, 2, 1, 0] - ['', '', '', '', '', '', 0, 1, 2, 3, 2, 1, 0] + + [0, 1, 2, 3, 2, 1, 0] + ['', 0, 1, 2, 1, 0, 1, 0] + ['', '', 0, 1, 0, 1, 2, 1, 0] + ['', '', '', 0, 1, 2, 3, 2, 1, 0] + ['', '', '', '', 0, 1, 2, 1, 0, 1, 0] + ['', '', '', '', '', 0, 1, 0, 1, 2, 1, 0] + ['', '', '', '', '', '', 0, 1, 2, 3, 2, 1, 0] + sage: TestSuite(t).run() """ @@ -158,9 +159,9 @@ def __init__(self, parent, ot, check=True): if w is None: raise ValueError("invalid input %s" % ot) - + ClonableArray.__init__(self, parent, w, check=check) - + def check(self): """ Checks that ``self`` is a valid path.""" n = len(self) diff --git a/src/sage/combinat/path_tableaux/path_tableau.py b/src/sage/combinat/path_tableaux/path_tableau.py index a1aa86bcc64..0fc42e1cbf9 100644 --- a/src/sage/combinat/path_tableaux/path_tableau.py +++ b/src/sage/combinat/path_tableaux/path_tableau.py @@ -199,10 +199,10 @@ def commutor(self,other,verbose=False): return (self.parent()(path[:m]),self.parent()(path[m-1:])) def cactus(self,i,j): - """ + r""" Return the action of the generators of the cactus group on ``self``. These generators are involutions and are usually denoted by - `s_{i,j}`. + $s_{i,j}$. INPUT: @@ -227,7 +227,7 @@ def cactus(self,i,j): True """ - if not 0 < i < j <= self.size(): + if not 0 < i <= j <= self.size(): raise ValueError("integers out of bounds") if i == j: @@ -427,7 +427,15 @@ class CylindricalDiagram(SageObject): sage: t = CatalanTableau([0,1,2,3,2,1,0]) sage: CylindricalDiagram(t) - A cylindrical growth diagram. + + [0, 1, 2, 3, 2, 1, 0] + ['', 0, 1, 2, 1, 0, 1, 0] + ['', '', 0, 1, 0, 1, 2, 1, 0] + ['', '', '', 0, 1, 2, 3, 2, 1, 0] + ['', '', '', '', 0, 1, 2, 1, 0, 1, 0] + ['', '', '', '', '', 0, 1, 0, 1, 2, 1, 0] + ['', '', '', '', '', '', 0, 1, 2, 3, 2, 1, 0] + """ def __init__(self,T): @@ -439,8 +447,11 @@ def __init__(self,T): self.diagram = result - def _repr_(self): - return "A cylindrical growth diagram." +# def __str__(self): +# return "A cylindrical growth diagram." + + def __repr__(self): + return ''.join('\n ' + str(x) for x in self.diagram) def _latex_(self): r""" @@ -480,8 +491,14 @@ def _ascii_art_(self): sage: t = CatalanTableau([0,1,2,3,2,1,0]) sage: ascii_art(CylindricalDiagram(t)) - [ 1 3 1 2 ] - [ 2 , 3 ] + 0 1 2 3 2 1 0 + 0 1 2 1 0 1 0 + 0 1 0 1 2 1 0 + 0 1 2 3 2 1 0 + 0 1 2 1 0 1 0 + 0 1 0 1 2 1 0 + 0 1 2 3 2 1 0 + """ from sage.typeset.ascii_art import AsciiArt D = [ map(str,x) for x in self.diagram ] @@ -509,5 +526,5 @@ def pp(self): 0 1 2 3 2 1 0 """ - m = max( max( len(str(a)) for a in x ) for x in self.diagram) - print "\n".join(" ".join("{:<{}}".format(a, m) for a in x) for x in self.diagram ) +# m = max( max( len(str(a)) for a in x ) for x in self.diagram) + print('\n'.join(' '.join('{:0}'.format(a) for a in x) for x in self.diagram )) From 3d82797086102fd665d62e0dfe40313efa2505a3 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Thu, 30 Apr 2020 11:29:33 +0100 Subject: [PATCH 098/300] All tests passed! --- .../combinat/path_tableaux/path_tableau.py | 53 +++++++++---------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/src/sage/combinat/path_tableaux/path_tableau.py b/src/sage/combinat/path_tableaux/path_tableau.py index 0fc42e1cbf9..795fdcd97ec 100644 --- a/src/sage/combinat/path_tableaux/path_tableau.py +++ b/src/sage/combinat/path_tableaux/path_tableau.py @@ -51,7 +51,7 @@ @add_metaclass(InheritComparisonClasscallMetaclass) class PathTableau(ClonableArray): - r""" + """ This is the abstract base class for path tableaux. """ @abstract_method(optional=False) @@ -206,9 +206,9 @@ def cactus(self,i,j): INPUT: - - ``i`` -- a positive integer + ``i`` -- a positive integer - - ``j`` -- a positive integer strictly greater than ``i`` + ``j`` -- a positive integer strictly greater than ``i`` EXAMPLES:: @@ -222,10 +222,8 @@ def cactus(self,i,j): sage: t.cactus(1,7) == t.evacuation() True - sage: t.cactus(1,7).cactus(1,6) == t.promotion() True - """ if not 0 < i <= j <= self.size(): raise ValueError("integers out of bounds") @@ -252,7 +250,6 @@ def _test_involution_rule(self, **options): sage: t = CatalanTableau([0,1,2,3,2,1,0]) sage: t._test_involution_rule() - """ tester = self._tester(**options) for i in range(self.size()-2): @@ -394,7 +391,6 @@ def dual_equivalence_graph(self): ([0, 1, 2, 1, 0, 1, 0], [0, 1, 2, 1, 2, 1, 0], '4,7'), ([0, 1, 2, 1, 0, 1, 0], [0, 1, 2, 3, 2, 1, 0], '3,7'), ([0, 1, 2, 1, 2, 1, 0], [0, 1, 2, 3, 2, 1, 0], '3,6')] - """ from sage.graphs.graph import Graph from itertools import combinations @@ -427,15 +423,13 @@ class CylindricalDiagram(SageObject): sage: t = CatalanTableau([0,1,2,3,2,1,0]) sage: CylindricalDiagram(t) - - [0, 1, 2, 3, 2, 1, 0] - ['', 0, 1, 2, 1, 0, 1, 0] - ['', '', 0, 1, 0, 1, 2, 1, 0] - ['', '', '', 0, 1, 2, 3, 2, 1, 0] - ['', '', '', '', 0, 1, 2, 1, 0, 1, 0] - ['', '', '', '', '', 0, 1, 0, 1, 2, 1, 0] - ['', '', '', '', '', '', 0, 1, 2, 3, 2, 1, 0] - + [0, 1, 2, 3, 2, 1, 0] + ['', 0, 1, 2, 1, 0, 1, 0] + ['', '', 0, 1, 0, 1, 2, 1, 0] + ['', '', '', 0, 1, 2, 3, 2, 1, 0] + ['', '', '', '', 0, 1, 2, 1, 0, 1, 0] + ['', '', '', '', '', 0, 1, 0, 1, 2, 1, 0] + ['', '', '', '', '', '', 0, 1, 2, 3, 2, 1, 0] """ def __init__(self,T): @@ -451,7 +445,8 @@ def __init__(self,T): # return "A cylindrical growth diagram." def __repr__(self): - return ''.join('\n ' + str(x) for x in self.diagram) + dg = self.diagram + return ' '+str(dg[0])+''.join('\n ' + str(x) for x in self.diagram[1:]) def _latex_(self): r""" @@ -481,16 +476,24 @@ def _latex_(self): return result def __len__(self): - """Returns the length of ``self``""" + """Returns the length of ``self`` + + TESTS:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: len(CylindricalDiagram(t)) + 7 + """ return len(self.diagram) - def _ascii_art_(self): + + def _unicode_art_(self): """ Returns an ascii art representation of ``self`` TESTS:: sage: t = CatalanTableau([0,1,2,3,2,1,0]) - sage: ascii_art(CylindricalDiagram(t)) + sage: unicode_art(CylindricalDiagram(t)) 0 1 2 3 2 1 0 0 1 2 1 0 1 0 0 1 0 1 2 1 0 @@ -500,14 +503,10 @@ def _ascii_art_(self): 0 1 2 3 2 1 0 """ - from sage.typeset.ascii_art import AsciiArt + from sage.typeset.unicode_art import UnicodeArt D = [ map(str,x) for x in self.diagram ] S = [ ' '.join(x) for x in D ] - return AsciiArt(S) - - def _unicode_art_(self): - r""" - """ + return UnicodeArt(S) def pp(self): """ @@ -527,4 +526,4 @@ def pp(self): """ # m = max( max( len(str(a)) for a in x ) for x in self.diagram) - print('\n'.join(' '.join('{:0}'.format(a) for a in x) for x in self.diagram )) + print('\n'.join(' '.join('{:0<}'.format(a) for a in x) for x in self.diagram )) From 009466d8f84063f194f3e110c23e7a63944a90fb Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Thu, 30 Apr 2020 12:27:38 +0100 Subject: [PATCH 099/300] Added doc tests --- src/sage/combinat/path_tableaux/catalan.py | 36 ++++++++- .../combinat/path_tableaux/path_tableau.py | 80 +++++++++++++------ 2 files changed, 89 insertions(+), 27 deletions(-) diff --git a/src/sage/combinat/path_tableaux/catalan.py b/src/sage/combinat/path_tableaux/catalan.py index 1ca859b7a1d..97d60b5e5df 100644 --- a/src/sage/combinat/path_tableaux/catalan.py +++ b/src/sage/combinat/path_tableaux/catalan.py @@ -105,14 +105,30 @@ class CatalanTableau(PathTableau): @staticmethod def __classcall_private__(cls, ot): - """ - This is the constructor for paths. + r""" + This ensures that a tableau is only ever constructed as an + ``element_class`` call of an appropriate parent. + + TESTS:: + + sage: t = CatalanTableau([0,1,2,1,0]) + + sage: t.parent() + + sage: t.category() + Category of elements of + sage: type(t) + """ return CatalanTableaux()(ot) def __init__(self, parent, ot, check=True): """ - This is the preprocessing for creating paths. + Initialize a Catalan tableau. + + TESTS:: + + sage: t = CatalanTableau([0,1,2,1,0]) """ w = None @@ -163,7 +179,19 @@ def __init__(self, parent, ot, check=True): ClonableArray.__init__(self, parent, w, check=check) def check(self): - """ Checks that ``self`` is a valid path.""" + """ Checks that ``self`` is a valid path. + + TESTS:: + sage: CatalanTableau([0,1,0,-1,0]) + Traceback (most recent call last): + ... + ValueError: [0, 1, 0, -1, 0] has a negative entry + + sage: CatalanTableau([0,1,3,1,0]) + Traceback (most recent call last): + ... + ValueError: [0, 1, 3, 1, 0] is not a Dyck path + """ n = len(self) if any(a < 0 for a in self): raise ValueError( "%s has a negative entry" % (str(self)) ) diff --git a/src/sage/combinat/path_tableaux/path_tableau.py b/src/sage/combinat/path_tableaux/path_tableau.py index 795fdcd97ec..f1e6a70c185 100644 --- a/src/sage/combinat/path_tableaux/path_tableau.py +++ b/src/sage/combinat/path_tableaux/path_tableau.py @@ -408,31 +408,45 @@ def dual_equivalence_graph(self): class PathTableaux(UniqueRepresentation,Parent): """ The abstract parent class for PathTableau.""" def __init__(self): + """ + Initializes the abstract class of all PathTableaux + + TESTS:: + + sage: t = CatalanTableau([0,1,2,1,0]) + sage: t.parent() + + """ Parent.__init__(self, category=Sets()) def _element_constructor_(self, *args, **kwds): + r""" + Constructs an object as an element of ``self``, if possible. + """ return self.element_class(self, *args, **kwds) - - class CylindricalDiagram(SageObject): """ A class for cylindrical growth diagrams. - - EXAMPLES:: - - sage: t = CatalanTableau([0,1,2,3,2,1,0]) - sage: CylindricalDiagram(t) - [0, 1, 2, 3, 2, 1, 0] - ['', 0, 1, 2, 1, 0, 1, 0] - ['', '', 0, 1, 0, 1, 2, 1, 0] - ['', '', '', 0, 1, 2, 3, 2, 1, 0] - ['', '', '', '', 0, 1, 2, 1, 0, 1, 0] - ['', '', '', '', '', 0, 1, 0, 1, 2, 1, 0] - ['', '', '', '', '', '', 0, 1, 2, 3, 2, 1, 0] """ - def __init__(self,T): + """ + Initializes an object of ``self`` from the PathTableau object T + + TESTS:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: CylindricalDiagram(t) + [0, 1, 2, 3, 2, 1, 0] + ['', 0, 1, 2, 1, 0, 1, 0] + ['', '', 0, 1, 0, 1, 2, 1, 0] + ['', '', '', 0, 1, 2, 3, 2, 1, 0] + ['', '', '', '', 0, 1, 2, 1, 0, 1, 0] + ['', '', '', '', '', 0, 1, 0, 1, 2, 1, 0] + ['', '', '', '', '', '', 0, 1, 2, 3, 2, 1, 0] + """ + if not isinstance(T,PathTableau): + raise ValueError('{0} must be a path tableau'.format(str(T))) n = len(T) result = [[None]*(2*n-1)]*n for i in range(n): @@ -441,10 +455,15 @@ def __init__(self,T): self.diagram = result -# def __str__(self): -# return "A cylindrical growth diagram." - def __repr__(self): + """ + Returns a string representation of ``self`` + + TESTS:: + + sage: print(CatalanTableau([0,1,2,1,2,1,0])) + [0, 1, 2, 1, 2, 1, 0] + """ dg = self.diagram return ' '+str(dg[0])+''.join('\n ' + str(x) for x in self.diagram[1:]) @@ -465,9 +484,7 @@ def _latex_(self): & & & & & 0 & 1 & 0 & 1 & 2 & 1 & 0\\ & & & & & & 0 & 1 & 2 & 3 & 2 & 1 & 0 \end{array} - """ - D = self.diagram m = len(D[-1]) result = "\\begin{array}{"+"c"*m + "}\n" @@ -486,10 +503,29 @@ def __len__(self): """ return len(self.diagram) + def _ascii_art_(self): + """ + Returns an ascii art representation of ``self`` + TESTS:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: ascii_art(CylindricalDiagram(t)) + 0 1 2 3 2 1 0 + 0 1 2 1 0 1 0 + 0 1 0 1 2 1 0 + 0 1 2 3 2 1 0 + 0 1 2 1 0 1 0 + 0 1 0 1 2 1 0 + 0 1 2 3 2 1 0 + """ + from sage.typeset.ascii_art import AsciiArt + D = [ map(str,x) for x in self.diagram ] + S = [ ' '.join(x) for x in D ] + return AsciiArt(S) def _unicode_art_(self): """ - Returns an ascii art representation of ``self`` + Returns a unicode art representation of ``self`` TESTS:: sage: t = CatalanTableau([0,1,2,3,2,1,0]) @@ -501,7 +537,6 @@ def _unicode_art_(self): 0 1 2 1 0 1 0 0 1 0 1 2 1 0 0 1 2 3 2 1 0 - """ from sage.typeset.unicode_art import UnicodeArt D = [ map(str,x) for x in self.diagram ] @@ -525,5 +560,4 @@ def pp(self): 0 1 2 3 2 1 0 """ -# m = max( max( len(str(a)) for a in x ) for x in self.diagram) print('\n'.join(' '.join('{:0<}'.format(a) for a in x) for x in self.diagram )) From 7884fc5ec26c2b7b2bcf530bca55f60d38cd6476 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Thu, 30 Apr 2020 13:52:26 +0100 Subject: [PATCH 100/300] More tests --- src/sage/combinat/path_tableaux/catalan.py | 39 ++++++++++++++++------ 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/src/sage/combinat/path_tableaux/catalan.py b/src/sage/combinat/path_tableaux/catalan.py index 97d60b5e5df..ead0ca4023e 100644 --- a/src/sage/combinat/path_tableaux/catalan.py +++ b/src/sage/combinat/path_tableaux/catalan.py @@ -123,12 +123,30 @@ def __classcall_private__(cls, ot): return CatalanTableaux()(ot) def __init__(self, parent, ot, check=True): - """ + r""" Initialize a Catalan tableau. + INPUT: + Can be any of: + + * word of nonnegative integers with successive differences $\pm 1$ + * a DyckWord + * a noncrossing perfect matching + * a two row standard tableau + * a two row standard skew tab;eau + TESTS:: - sage: t = CatalanTableau([0,1,2,1,0]) + sage: CatalanTableau([0,1,2,1,0]) + [0, 1, 2, 1, 0] + sage: CatalanTableau(DyckWord([1, 0, 1, 0])) + [0, 1, 0, 1, 0] + sage: CatalanTableau(PerfectMatching([(1, 4), (2, 3), (5, 6)])) + [0, 1, 2, 1, 0, 1, 0] + sage: CatalanTableau(Tableau([[1,2,4],[3,5,6]])) + [0, 1, 2, 1, 2, 1, 0] + sage: CatalanTableau(SkewTableau([[None, 1,4],[2,3]])) + [1, 2, 1, 0, 1] """ w = None @@ -157,15 +175,16 @@ def __init__(self, parent, ot, check=True): raise ValueError("the tableau must have at most two rows") elif isinstance(ot, SkewTableau): - if len(ot) <= 2: - # The check that ot is standard is not implemented - u = [1] * ot.size() - for i in ot[1]: - if i is not None: - u[i-1] = 0 - w = DyckWord(u).heights() - else: + if len(ot) > 2: raise ValueError("the skew tableau must have at most two rows") + # The check that ot is standard is not implemented + c = ot.to_chain() + w = [0]*len(c) + for i,a in enumerate(c): + if len(a) == 1: + w[i] = a[0] + else: + w[i] = a[0]-a[1] elif isinstance(ot, (list,tuple)): try: From c0c9e5c11a61276e5eb9519c76f2e6a19d668113 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 1 May 2020 09:14:10 +0100 Subject: [PATCH 101/300] Tidied documentation --- src/sage/combinat/path_tableaux/catalan.py | 13 ------------- src/sage/combinat/path_tableaux/path_tableau.py | 14 +++++++++----- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/sage/combinat/path_tableaux/catalan.py b/src/sage/combinat/path_tableaux/catalan.py index ead0ca4023e..f620225f2a1 100644 --- a/src/sage/combinat/path_tableaux/catalan.py +++ b/src/sage/combinat/path_tableaux/catalan.py @@ -36,19 +36,6 @@ sage: t.to_perfect_matching() [(0, 5), (1, 4), (2, 3)] -EXAMPLES:: - - sage: t = CatalanTableau([0,1,2,3,2,1,0]) - sage: print(CylindricalDiagram(t)) - - [0, 1, 2, 3, 2, 1, 0] - ['', 0, 1, 2, 1, 0, 1, 0] - ['', '', 0, 1, 0, 1, 2, 1, 0] - ['', '', '', 0, 1, 2, 3, 2, 1, 0] - ['', '', '', '', 0, 1, 2, 1, 0, 1, 0] - ['', '', '', '', '', 0, 1, 0, 1, 2, 1, 0] - ['', '', '', '', '', '', 0, 1, 2, 3, 2, 1, 0] - sage: TestSuite(t).run() """ diff --git a/src/sage/combinat/path_tableaux/path_tableau.py b/src/sage/combinat/path_tableaux/path_tableau.py index f1e6a70c185..7746f3524f9 100644 --- a/src/sage/combinat/path_tableaux/path_tableau.py +++ b/src/sage/combinat/path_tableaux/path_tableau.py @@ -422,12 +422,14 @@ def __init__(self): def _element_constructor_(self, *args, **kwds): r""" Constructs an object as an element of ``self``, if possible. + """ return self.element_class(self, *args, **kwds) class CylindricalDiagram(SageObject): """ A class for cylindrical growth diagrams. + """ def __init__(self,T): """ @@ -457,7 +459,7 @@ def __init__(self,T): def __repr__(self): """ - Returns a string representation of ``self`` + Return a string representation of ``self`` TESTS:: @@ -469,7 +471,7 @@ def __repr__(self): def _latex_(self): r""" - Returns a `\LaTeX` representation of ``self`` + Return a `\LaTeX` representation of ``self`` EXAMPLES:: @@ -493,7 +495,7 @@ def _latex_(self): return result def __len__(self): - """Returns the length of ``self`` + """Return the length of ``self`` TESTS:: @@ -505,7 +507,8 @@ def __len__(self): def _ascii_art_(self): """ - Returns an ascii art representation of ``self`` + Return an ascii art representation of ``self`` + TESTS:: sage: t = CatalanTableau([0,1,2,3,2,1,0]) @@ -525,7 +528,8 @@ def _ascii_art_(self): def _unicode_art_(self): """ - Returns a unicode art representation of ``self`` + Return a unicode art representation of ``self`` + TESTS:: sage: t = CatalanTableau([0,1,2,3,2,1,0]) From f5887d6bf505aba836b28351574229df6ee3c864 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 1 May 2020 09:20:46 +0100 Subject: [PATCH 102/300] Removed trailing spaces --- src/sage/combinat/path_tableaux/path_tableau.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/path_tableaux/path_tableau.py b/src/sage/combinat/path_tableaux/path_tableau.py index 7746f3524f9..64dd624c098 100644 --- a/src/sage/combinat/path_tableaux/path_tableau.py +++ b/src/sage/combinat/path_tableaux/path_tableau.py @@ -422,14 +422,14 @@ def __init__(self): def _element_constructor_(self, *args, **kwds): r""" Constructs an object as an element of ``self``, if possible. - + """ return self.element_class(self, *args, **kwds) class CylindricalDiagram(SageObject): """ A class for cylindrical growth diagrams. - + """ def __init__(self,T): """ From ddf1a4b11ec182744633903da256a639b29af1be Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 1 May 2020 19:57:10 +0100 Subject: [PATCH 103/300] Completed doctests --- src/sage/combinat/path_tableaux/catalan.py | 25 ++++++++++--------- .../combinat/path_tableaux/path_tableau.py | 8 ++++-- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/sage/combinat/path_tableaux/catalan.py b/src/sage/combinat/path_tableaux/catalan.py index f620225f2a1..ba57b7cc442 100644 --- a/src/sage/combinat/path_tableaux/catalan.py +++ b/src/sage/combinat/path_tableaux/catalan.py @@ -67,10 +67,10 @@ class CatalanTableau(PathTableau): INPUT: - - a sequence of nonnegative integers - - a two row standard skew tableau - - a Dyck word - - a noncrossing perfect matching + * a sequence of nonnegative integers + * a two row standard skew tableau + * a Dyck word + * a noncrossing perfect matching EXAMPLES:: @@ -114,13 +114,14 @@ def __init__(self, parent, ot, check=True): Initialize a Catalan tableau. INPUT: - Can be any of: - * word of nonnegative integers with successive differences $\pm 1$ - * a DyckWord - * a noncrossing perfect matching - * a two row standard tableau - * a two row standard skew tab;eau + Can be any of: + + * word of nonnegative integers with successive differences $\pm 1$ + * a DyckWord + * a noncrossing perfect matching + * a two row standard tableau + * a two row standard skew tab;eau TESTS:: @@ -188,12 +189,12 @@ def check(self): """ Checks that ``self`` is a valid path. TESTS:: - sage: CatalanTableau([0,1,0,-1,0]) + sage: CatalanTableau([0,1,0,-1,0]) # indirect doctest Traceback (most recent call last): ... ValueError: [0, 1, 0, -1, 0] has a negative entry - sage: CatalanTableau([0,1,3,1,0]) + sage: CatalanTableau([0,1,3,1,0]) # indirect doctest Traceback (most recent call last): ... ValueError: [0, 1, 3, 1, 0] is not a Dyck path diff --git a/src/sage/combinat/path_tableaux/path_tableau.py b/src/sage/combinat/path_tableaux/path_tableau.py index 64dd624c098..6585ea22bee 100644 --- a/src/sage/combinat/path_tableaux/path_tableau.py +++ b/src/sage/combinat/path_tableaux/path_tableau.py @@ -206,9 +206,9 @@ def cactus(self,i,j): INPUT: - ``i`` -- a positive integer + ``i`` -- a positive integer - ``j`` -- a positive integer strictly greater than ``i`` + ``j`` -- a positive integer weakly greater than ``i`` EXAMPLES:: @@ -423,6 +423,10 @@ def _element_constructor_(self, *args, **kwds): r""" Constructs an object as an element of ``self``, if possible. + TESTS:: + + sage: CatalanTableau([0,1,2,1,0]) # indirect doctest + [0, 1, 2, 1, 0] """ return self.element_class(self, *args, **kwds) From 51d3b738b8ee31fb5a707495edf53dd77c10f179 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 1 May 2020 20:28:30 +0100 Subject: [PATCH 104/300] Added tests of ValueError --- src/sage/combinat/path_tableaux/catalan.py | 43 +++++++++++++++++----- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/src/sage/combinat/path_tableaux/catalan.py b/src/sage/combinat/path_tableaux/catalan.py index ba57b7cc442..82212c78482 100644 --- a/src/sage/combinat/path_tableaux/catalan.py +++ b/src/sage/combinat/path_tableaux/catalan.py @@ -135,6 +135,30 @@ def __init__(self, parent, ot, check=True): [0, 1, 2, 1, 2, 1, 0] sage: CatalanTableau(SkewTableau([[None, 1,4],[2,3]])) [1, 2, 1, 0, 1] + sage: CatalanTableau(PerfectMatching([(1, 3), (2, 4), (5, 6)])) + Traceback (most recent call last): + ... + ValueError: the perfect matching must be non crossing + sage: CatalanTableau(Tableau([[1,2,5],[3,5,6]])) + Traceback (most recent call last): + ... + ValueError: the tableau must be standard + sage: CatalanTableau(Tableau([[1,2,4],[3,5,6],[7]])) + Traceback (most recent call last): + ... + ValueError: the tableau must have at most two rows + sage: CatalanTableau(SkewTableau([[None, 1,4],[2,3],[5]])) + Traceback (most recent call last): + ... + ValueError: the skew tableau must have at most two rows + sage: CatalanTableau([0,1,2.5,1,0]) + Traceback (most recent call last): + ... + ValueError: [0, 1, 2.50000000000000, 1, 0] is not a sequence of integers + sage: CatalanTableau(Partition([3,2,1])) + Traceback (most recent call last): + ... + ValueError: invalid input [3, 2, 1] """ w = None @@ -151,16 +175,16 @@ def __init__(self, parent, ot, check=True): raise ValueError("the perfect matching must be non crossing") elif isinstance(ot, Tableau): - if len(ot) <= 2: - if ot.is_standard(): - u = [1] * ot.size() - for i in ot[1]: - u[i-1] = 0 - w = DyckWord(u).heights() - else: - raise ValueError("the tableau must be standard") - else: + if len(ot) > 2: raise ValueError("the tableau must have at most two rows") + if ot.is_standard(): + u = [1] * ot.size() + for i in ot[1]: + u[i-1] = 0 + w = DyckWord(u).heights() + else: + raise ValueError("the tableau must be standard") + elif isinstance(ot, SkewTableau): if len(ot) > 2: @@ -189,6 +213,7 @@ def check(self): """ Checks that ``self`` is a valid path. TESTS:: + sage: CatalanTableau([0,1,0,-1,0]) # indirect doctest Traceback (most recent call last): ... From 7866ab4812259aba6fb241cde7b666302d461bec Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 1 May 2020 21:07:09 +0100 Subject: [PATCH 105/300] More tests --- src/sage/combinat/path_tableaux/catalan.py | 23 +++++++++- .../combinat/path_tableaux/path_tableau.py | 46 +++++++++++++++++-- 2 files changed, 64 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/path_tableaux/catalan.py b/src/sage/combinat/path_tableaux/catalan.py index 82212c78482..ea6f4d5cb5d 100644 --- a/src/sage/combinat/path_tableaux/catalan.py +++ b/src/sage/combinat/path_tableaux/catalan.py @@ -243,6 +243,20 @@ def _local_rule(self,i): sage: t = CatalanTableau([0,1,2,3,2,1,0]) sage: t._local_rule(3) [0, 1, 2, 1, 2, 1, 0] + + TESTS:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t._local_rule(0) + Traceback (most recent call last): + ... + ValueError: 0 is not a valid integer + sage: t._local_rule(5) + [0, 1, 2, 3, 2, 1, 0] + sage: t._local_rule(6) + Traceback (most recent call last): + ... + ValueError: 6 is not a valid integer """ def _rule(x): @@ -251,7 +265,7 @@ def _rule(x): """ return abs(x[0]-x[1]+x[2]) - if not (i > 0 and i < len(self) ): + if not (i > 0 and i < len(self)-1): raise ValueError("%d is not a valid integer" % i) with self.clone() as result: @@ -322,6 +336,13 @@ def to_perfect_matching(self): sage: CatalanTableau([0,1,2,1,2,1,0,1,0]).to_perfect_matching() [(0, 5), (1, 2), (3, 4), (6, 7)] + + TESTS:: + + sage: CatalanTableau([1,2,1,2,1,0,1]).to_perfect_matching() + Traceback (most recent call last): + ... + ValueError: [1, 2, 1, 2, 1, 0, 1] does not start at 0 """ if self.is_skew(): raise ValueError( "%s does not start at 0" % (str(self)) ) diff --git a/src/sage/combinat/path_tableaux/path_tableau.py b/src/sage/combinat/path_tableaux/path_tableau.py index 6585ea22bee..c0581f749a8 100644 --- a/src/sage/combinat/path_tableaux/path_tableau.py +++ b/src/sage/combinat/path_tableaux/path_tableau.py @@ -172,6 +172,27 @@ def commutor(self,other,verbose=False): [1, 2, 3, 2, 1] [0, 1, 2, 1, 0] ([0, 1, 2, 1, 0], [0, 1, 2, 3, 2, 1, 0]) + + TESTS:: + + sage: t1 = CatalanTableau([]) + sage: t2 = CatalanTableau([0,1,2,1,0]) + sage: t1.commutor(t2) + Traceback (most recent call last): + ... + ValueError: this requires nonempty lists + sage: t1 = CatalanTableau([0,1,2,3,2,1,0]) + sage: t2 = CatalanTableau([]) + sage: t1.commutor(t2) + Traceback (most recent call last): + ... + ValueError: this requires nonempty lists + sage: t1 = CatalanTableau([0,1,2,3,2,1]) + sage: t2 = CatalanTableau([0,1,2,1,0]) + sage: t1.commutor(t2) + Traceback (most recent call last): + ... + ValueError: [0, 1, 2, 3, 2, 1],[0, 1, 2, 1, 0] is not a composable pair """ n = len(self) m = len(other) @@ -224,6 +245,18 @@ def cactus(self,i,j): True sage: t.cactus(1,7).cactus(1,6) == t.promotion() True + + TESTS:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t.cactus(1,8) + Traceback (most recent call last): + ... + ValueError: integers out of bounds + sage: t.cactus(0,3) + Traceback (most recent call last): + ... + ValueError: integers out of bounds """ if not 0 < i <= j <= self.size(): raise ValueError("integers out of bounds") @@ -414,7 +447,7 @@ def __init__(self): TESTS:: sage: t = CatalanTableau([0,1,2,1,0]) - sage: t.parent() + sage: t.parent() # indirect test """ Parent.__init__(self, category=Sets()) @@ -437,7 +470,7 @@ class CylindricalDiagram(SageObject): """ def __init__(self,T): """ - Initializes an object of ``self`` from the PathTableau object T + Initialise an object of ``self`` from the PathTableau object T TESTS:: @@ -450,6 +483,11 @@ def __init__(self,T): ['', '', '', '', 0, 1, 2, 1, 0, 1, 0] ['', '', '', '', '', 0, 1, 0, 1, 2, 1, 0] ['', '', '', '', '', '', 0, 1, 2, 3, 2, 1, 0] + + sage: CylindricalDiagram(2) + Traceback (most recent call last): + ... + ValueError: 2 must be a path tableau """ if not isinstance(T,PathTableau): raise ValueError('{0} must be a path tableau'.format(str(T))) @@ -467,11 +505,11 @@ def __repr__(self): TESTS:: - sage: print(CatalanTableau([0,1,2,1,2,1,0])) + sage: print(CatalanTableau([0,1,2,1,2,1,0])) # indirect test [0, 1, 2, 1, 2, 1, 0] """ dg = self.diagram - return ' '+str(dg[0])+''.join('\n ' + str(x) for x in self.diagram[1:]) + return ' '+str(dg[0])+''.join('\n ' + str(x) for x in dg[1:]) def _latex_(self): r""" From f4c8064c0c14726d802076d1475c36e477eaa24a Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Sat, 2 May 2020 21:54:58 +0200 Subject: [PATCH 106/300] 29635: fix degneglex term order in libsingular --- src/sage/libs/singular/ring.pyx | 18 +++++++++++++++--- src/sage/rings/polynomial/term_order.py | 3 ++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/sage/libs/singular/ring.pyx b/src/sage/libs/singular/ring.pyx index f331ed549c1..63b63070cd2 100644 --- a/src/sage/libs/singular/ring.pyx +++ b/src/sage/libs/singular/ring.pyx @@ -116,6 +116,17 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL: sage: P. = Zmod(25213521351515232)[]; P Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 25213521351515232 + + TESTS: + + Check that ``degneglex`` and ``degrevlex`` are the same up to reversal of + variables (:trac:`29635`):: + + sage: R = PolynomialRing(QQ, 'x', 4, order='degrevlex') + sage: S = PolynomialRing(QQ, tuple(reversed(R.gens())), order='degneglex') + sage: L = [v for d in (0..4) for v in IntegerVectors(d, 4)] + sage: sorted([R.monomial(*e) for e in L]) == sorted([S.monomial(*e) for e in L]) + True """ cdef long cexponent cdef GFInfo* _param @@ -212,12 +223,13 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL: nlen = len(order[i]) _wvhdl[idx] = omAlloc0(len(order[i])*sizeof(int)) - for j in range(nlen): _wvhdl[idx][j] = 1 - _block0[idx] = offset + 1 # same like subsequent rp block + for j in range(nlen): + _wvhdl[idx][j] = 1 + _block0[idx] = offset + 1 # same like subsequent ls block _block1[idx] = offset + nlen idx += 1; # we need one more block here - _order[idx] = ringorder_rp + _order[idx] = ringorder_ls else: # ordinary orders _order[idx] = order_dict.get(s, ringorder_dp) diff --git a/src/sage/rings/polynomial/term_order.py b/src/sage/rings/polynomial/term_order.py index d1be2db8576..eb44e9d02be 100644 --- a/src/sage/rings/polynomial/term_order.py +++ b/src/sage/rings/polynomial/term_order.py @@ -225,7 +225,8 @@ `x^a < x^b` if and only if `\deg(x^a) < \deg(x^b)` or `\deg(x^a) = \deg(x^b)` and there exists `1 \le i \le n` such that `a_1 = b_1, \dots, a_{i-1} = b_{i-1}, a_i > b_i`. This term order is called 'dp_asc' in PolyBoRi. - Singular has the extra weight vector ordering '(r(1:n),rp)' for this purpose. + Singular has the extra weight vector ordering ``(a(1:n),ls)`` for this + purpose. EXAMPLES: From e63290f37a70f9535345cc106eb6aa3b1789bf42 Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Sun, 3 May 2020 01:21:09 +0200 Subject: [PATCH 107/300] 29635: fix conversion of degneglex order from Singular to Sage --- src/sage/rings/polynomial/term_order.py | 33 ++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/polynomial/term_order.py b/src/sage/rings/polynomial/term_order.py index eb44e9d02be..5928b92029c 100644 --- a/src/sage/rings/polynomial/term_order.py +++ b/src/sage/rings/polynomial/term_order.py @@ -2187,30 +2187,55 @@ def termorder_from_singular(S): Lexicographic term order of length 2) sage: T._singular_ringorder_column 1 + + TESTS: + + Check that ``degneglex`` term orders are converted correctly + (:trac:`29635`):: + + sage: _ = singular.ring(0, '(x,y,z,w)', '(a(1:4),ls(4))') + sage: termorder_from_singular(singular).singular_str() + '(a(1:4),ls(4))' + sage: _ = singular.ring(0, '(x,y,z,w)', '(a(1:2),ls(2),a(1:2),ls(2))') + sage: termorder_from_singular(singular).singular_str() + '(a(1:2),ls(2),a(1:2),ls(2))' + sage: _ = singular.ring(0, '(x,y,z,w)', '(a(1:2),ls(2),C,a(1:2),ls(2))') + sage: termorder_from_singular(singular).singular_str() + '(a(1:2),ls(2),C,a(1:2),ls(2))' + sage: PolynomialRing(QQ, 'x,y', order='degneglex')('x^2')._singular_().sage() + x^2 """ from sage.all import ZZ singular = S T = singular('ringlist(basering)[3]') order = [] ringorder_column = None - for block in T: + weights_one_block = False + for idx, block in enumerate(T): blocktype = singular.eval('%s[1]'%block.name()) if blocktype in ['a']: + weights = list(block[2].sage()) + weights_one_block = all(w == 1 for w in weights) continue elif blocktype == 'c': - ringorder_column = 2*len(order) + 1 + ringorder_column = 2*idx + 1 elif blocktype == 'C': - if len(order) < len(T) - 1: # skip Singular default - ringorder_column = 2*len(order) + if idx < len(T) - 1: # skip Singular default + ringorder_column = 2*idx elif blocktype == 'M': from sage.matrix.constructor import matrix coefs = list(block[2].sage()) n = ZZ(len(coefs)).sqrt() order.append(TermOrder(matrix(n,coefs))) + elif weights_one_block and blocktype == 'ls': + # 'degneglex' is encoded as '(a(1:n),ls(n))' + n = ZZ(singular.eval("size(%s[2])" % block.name())) + order.append(TermOrder('degneglex', n)) elif blocktype[0] in ['w','W']: order.append(TermOrder(inv_singular_name_mapping[blocktype], list(block[2].sage()))) else: order.append(TermOrder(inv_singular_name_mapping[blocktype], ZZ(singular.eval("size(%s[2])"%block.name())))) + weights_one_block = False if not order: raise ValueError("invalid term order in Singular") From edbb69d6f02364d6586e432bd165513d9122523a Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Sun, 3 May 2020 13:35:30 +0200 Subject: [PATCH 108/300] 29635: fix more issues in handling of degneglex sage: T = PolynomialRing(GF(101^5), 'u,v,w', order=TermOrder('degneglex')).term_order() sage: T.singular_str() # should be (a(1:3),ls(3)) '(a(1:%(ngens)i),ls(%(ngens)i))' sage: (T + T).singular_str() # should be (a(1:3),ls(3),a(1:3),ls(3)) '(a(1:6),ls(6),a(1:6),ls(6))' --- src/sage/rings/polynomial/term_order.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sage/rings/polynomial/term_order.py b/src/sage/rings/polynomial/term_order.py index 5928b92029c..6c411c2011e 100644 --- a/src/sage/rings/polynomial/term_order.py +++ b/src/sage/rings/polynomial/term_order.py @@ -680,12 +680,23 @@ def __init__(self, name='lex', n=0, force=False): // block 1 : ordering C // block 2 : ordering dp // : names x y z + + Check that :trac:`29635` is fixed:: + + sage: T = PolynomialRing(GF(101^5), 'u,v,w', order=TermOrder('degneglex')).term_order() + sage: T.singular_str() + '(a(1:3),ls(3))' + sage: (T + T).singular_str() + '(a(1:3),ls(3),a(1:3),ls(3))' """ if isinstance(name, TermOrder): self.__copy(name) if n: if not name.is_block_order() and not name.is_weighted_degree_order(): self._length = n + if self._length != 0: + self._singular_str = (self._singular_str + % dict(ngens=self._length)) elif self._length != n: raise ValueError("the length of the given term order ({}) differs from the number of variables ({})" .format(self._length, n)) From 66bf321e35062aeac0364aab969da7bd09471eee Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 May 2020 20:28:27 -0700 Subject: [PATCH 109/300] src/sage/algebras: Move Extension options from src/module_list.py to distutils directives --- src/module_list.py | 17 +---------------- .../quatalg/quaternion_algebra_cython.pyx | 2 ++ .../quatalg/quaternion_algebra_element.pyx | 2 ++ 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/module_list.py b/src/module_list.py index d7b5f459cf0..abdebba46d3 100644 --- a/src/module_list.py +++ b/src/module_list.py @@ -133,22 +133,7 @@ def uname_specific(name, value, alternative): ## ################################ - Extension('sage.algebras.quatalg.quaternion_algebra_element', - sources = ['sage/algebras/quatalg/quaternion_algebra_element.pyx'], - language='c++', - libraries = ["gmp", "m", "ntl"]), - - Extension('*', sources = ['sage/algebras/letterplace/*.pyx']), - - Extension('*', sources = ['sage/algebras/finite_dimensional_algebras/*.pyx']), - - Extension('sage.algebras.quatalg.quaternion_algebra_cython', - sources = ['sage/algebras/quatalg/quaternion_algebra_cython.pyx'], - language='c++', - libraries = ["gmp", "m", "ntl"]), - - Extension('sage.algebras.lie_algebras.lie_algebra_element', - sources = ["sage/algebras/lie_algebras/lie_algebra_element.pyx"]), + Extension('*', ['sage/algebras/**/*.pyx']), ################################ ## diff --git a/src/sage/algebras/quatalg/quaternion_algebra_cython.pyx b/src/sage/algebras/quatalg/quaternion_algebra_cython.pyx index 01fb64c1868..d0d291ccdd8 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra_cython.pyx +++ b/src/sage/algebras/quatalg/quaternion_algebra_cython.pyx @@ -1,3 +1,5 @@ +# distutils: language = c++ +# distutils: libraries = gmp m ntl """ Optimized Cython code needed by quaternion algebras diff --git a/src/sage/algebras/quatalg/quaternion_algebra_element.pyx b/src/sage/algebras/quatalg/quaternion_algebra_element.pyx index a578badf0df..929f3910242 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra_element.pyx +++ b/src/sage/algebras/quatalg/quaternion_algebra_element.pyx @@ -1,3 +1,5 @@ +# distutils: language = c++ +# distutils: libraries = gmp m ntl """ Elements of Quaternion Algebras From f31b6a09b38cd9b6e3b9070ab5e20cb605866812 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 May 2020 20:41:00 -0700 Subject: [PATCH 110/300] src/sage/geometry: Move Extension options from src/module_list.py to distutils directives --- src/module_list.py | 49 +------------------ .../combinatorial_face.pyx | 4 ++ .../face_iterator.pyx | 4 ++ .../list_of_faces.pyx | 4 ++ .../polyhedron_face_lattice.pyx | 4 ++ src/sage/geometry/triangulation/base.pyx | 4 ++ 6 files changed, 21 insertions(+), 48 deletions(-) diff --git a/src/module_list.py b/src/module_list.py index abdebba46d3..3147d3437f7 100644 --- a/src/module_list.py +++ b/src/module_list.py @@ -264,54 +264,7 @@ def uname_specific(name, value, alternative): ## ################################ - Extension('sage.geometry.point_collection', - sources = ['sage/geometry/point_collection.pyx']), - - Extension('sage.geometry.toric_lattice_element', - sources = ['sage/geometry/toric_lattice_element.pyx']), - - Extension('sage.geometry.integral_points', - sources = ['sage/geometry/integral_points.pyx']), - - Extension('sage.geometry.triangulation.base', - sources = ['sage/geometry/triangulation/base.pyx', - 'sage/geometry/triangulation/functions.cc', - 'sage/geometry/triangulation/data.cc', - 'sage/geometry/triangulation/triangulations.cc'], - depends = ['sage/geometry/triangulation/functions.h', - 'sage/geometry/triangulation/data.h', - 'sage/geometry/triangulation/triangulations.h'], - language="c++"), - - Extension('sage.geometry.polyhedron.combinatorial_polyhedron.base', - sources = ['sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx']), - - Extension('sage.geometry.polyhedron.combinatorial_polyhedron.list_of_faces', - sources = ['sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx'], - depends = ['sage/geometry/polyhedron/combinatorial_polyhedron/bit_vector_operations.cc'], - language="c++", - extra_compile_args=['-std=c++11']), - - Extension('sage.geometry.polyhedron.combinatorial_polyhedron.face_iterator', - sources = ['sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx'], - depends = ['sage/geometry/polyhedron/combinatorial_polyhedron/bit_vector_operations.cc'], - language="c++", - extra_compile_args=['-std=c++11']), - - Extension('sage.geometry.polyhedron.combinatorial_polyhedron.polyhedron_face_lattice', - sources = ['sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx'], - depends = ['sage/geometry/polyhedron/combinatorial_polyhedron/bit_vector_operations.cc'], - language="c++", - extra_compile_args=['-std=c++11']), - - Extension('sage.geometry.polyhedron.combinatorial_polyhedron.combinatorial_face', - sources = ['sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx'], - depends = ['sage/geometry/polyhedron/combinatorial_polyhedron/bit_vector_operations.cc'], - language="c++", - extra_compile_args=['-std=c++11']), - - Extension('sage.geometry.polyhedron.combinatorial_polyhedron.conversions', - sources = ['sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx']), + Extension('*', ['sage/geometry/**/*.pyx']), ################################ ## diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx index b7131b58e65..e28b4f035ba 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx @@ -1,3 +1,7 @@ +# distutils: depends = sage/geometry/polyhedron/combinatorial_polyhedron/bit_vector_operations.cc +# distutils: language = c++ +# distutils: extra_compile_args = -std=c++11 + r""" Combinatorial face of a polyhedron diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx index 4e56cb205f2..22f489dbfbe 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx @@ -1,3 +1,7 @@ +# distutils: depends = sage/geometry/polyhedron/combinatorial_polyhedron/bit_vector_operations.cc +# distutils: language = c++ +# distutils: extra_compile_args = -std=c++11 + r""" Face iterator for polyhedra diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx index 920f297a89a..0c5c03d9566 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx @@ -1,3 +1,7 @@ +# distutils: depends = sage/geometry/polyhedron/combinatorial_polyhedron/bit_vector_operations.cc +# distutils: language = c++ +# distutils: extra_compile_args = -std=c++11 + r""" List of faces diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx index f7af68746e5..76d7552db42 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx @@ -1,3 +1,7 @@ +# distutils: depends = sage/geometry/polyhedron/combinatorial_polyhedron/bit_vector_operations.cc +# distutils: language = c++ +# distutils: extra_compile_args = -std=c++11 + r""" PolyhedronFaceLattice diff --git a/src/sage/geometry/triangulation/base.pyx b/src/sage/geometry/triangulation/base.pyx index b575e5af4d1..df958418391 100644 --- a/src/sage/geometry/triangulation/base.pyx +++ b/src/sage/geometry/triangulation/base.pyx @@ -1,3 +1,7 @@ +# distutils: sources = sage/geometry/triangulation/base.pyx sage/geometry/triangulation/functions.cc sage/geometry/triangulation/data.cc sage/geometry/triangulation/triangulations.cc +# distutils: depends = sage/geometry/triangulation/functions.h sage/geometry/triangulation/data.h sage/geometry/triangulation/triangulations.h +# distutils: language = c++ + r""" Base classes for triangulations From 0c0ef436367253b44d7c7dce5c30b18c63b79a73 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 May 2020 21:33:31 -0700 Subject: [PATCH 111/300] src/sage/libs/ntl: Move Extension options from src/module_list.py to distutils directives --- src/module_list.py | 105 +------------------------ src/sage/libs/ntl/convert.pyx | 3 + src/sage/libs/ntl/error.pyx | 3 + src/sage/libs/ntl/ntl_GF2.pyx | 3 + src/sage/libs/ntl/ntl_GF2E.pyx | 3 + src/sage/libs/ntl/ntl_GF2EContext.pyx | 3 + src/sage/libs/ntl/ntl_GF2EX.pyx | 3 + src/sage/libs/ntl/ntl_GF2X.pyx | 3 + src/sage/libs/ntl/ntl_ZZ.pyx | 3 + src/sage/libs/ntl/ntl_ZZX.pyx | 3 + src/sage/libs/ntl/ntl_ZZ_p.pyx | 3 + src/sage/libs/ntl/ntl_ZZ_pContext.pyx | 3 + src/sage/libs/ntl/ntl_ZZ_pE.pyx | 3 + src/sage/libs/ntl/ntl_ZZ_pEContext.pyx | 3 + src/sage/libs/ntl/ntl_ZZ_pEX.pyx | 3 + src/sage/libs/ntl/ntl_ZZ_pX.pyx | 3 + src/sage/libs/ntl/ntl_lzz_p.pyx | 3 + src/sage/libs/ntl/ntl_lzz_pContext.pyx | 3 + src/sage/libs/ntl/ntl_lzz_pX.pyx | 3 + src/sage/libs/ntl/ntl_mat_GF2.pyx | 3 + src/sage/libs/ntl/ntl_mat_GF2E.pyx | 3 + src/sage/libs/ntl/ntl_mat_ZZ.pyx | 3 + 22 files changed, 64 insertions(+), 104 deletions(-) diff --git a/src/module_list.py b/src/module_list.py index 3147d3437f7..1125f73b3ec 100644 --- a/src/module_list.py +++ b/src/module_list.py @@ -595,110 +595,7 @@ def uname_specific(name, value, alternative): ## ################################### - Extension('sage.libs.ntl.convert', - sources = ["sage/libs/ntl/convert.pyx"], - libraries = ["ntl", "gmp"], - language='c++'), - - Extension('sage.libs.ntl.error', - sources = ["sage/libs/ntl/error.pyx"], - libraries = ["ntl", "gmp"], - language='c++'), - - Extension('sage.libs.ntl.ntl_GF2', - sources = ["sage/libs/ntl/ntl_GF2.pyx"], - libraries = ["ntl", "gmp"], - language='c++'), - - Extension('sage.libs.ntl.ntl_GF2E', - sources = ["sage/libs/ntl/ntl_GF2E.pyx"], - libraries = ["ntl", "gmp", "m"], - language='c++'), - - Extension('sage.libs.ntl.ntl_GF2EContext', - sources = ["sage/libs/ntl/ntl_GF2EContext.pyx"], - libraries = ["ntl", "gmp", "m"], - language='c++'), - - Extension('sage.libs.ntl.ntl_GF2EX', - sources = ["sage/libs/ntl/ntl_GF2EX.pyx"], - libraries = ["ntl", "gmp", "m"], - language='c++'), - - Extension('sage.libs.ntl.ntl_GF2X', - sources = ["sage/libs/ntl/ntl_GF2X.pyx"], - libraries = ["ntl", "gmp", "m"], - language='c++'), - - Extension('sage.libs.ntl.ntl_lzz_p', - sources = ["sage/libs/ntl/ntl_lzz_p.pyx"], - libraries = ["ntl", "gmp", "m"], - language='c++'), - - Extension('sage.libs.ntl.ntl_lzz_pContext', - sources = ["sage/libs/ntl/ntl_lzz_pContext.pyx"], - libraries = ["ntl", "gmp", "m"], - language='c++'), - - Extension('sage.libs.ntl.ntl_lzz_pX', - sources = ["sage/libs/ntl/ntl_lzz_pX.pyx"], - libraries = ["ntl", "gmp", "m"], - language='c++'), - - Extension('sage.libs.ntl.ntl_mat_GF2', - sources = ["sage/libs/ntl/ntl_mat_GF2.pyx"], - libraries = ["ntl", "gmp", "m"], - language='c++'), - - Extension('sage.libs.ntl.ntl_mat_GF2E', - sources = ["sage/libs/ntl/ntl_mat_GF2E.pyx"], - libraries = ["ntl", "gmp", "m"], - language='c++'), - - Extension('sage.libs.ntl.ntl_mat_ZZ', - sources = ["sage/libs/ntl/ntl_mat_ZZ.pyx"], - libraries = ["ntl", "gmp", "m"], - language='c++'), - - Extension('sage.libs.ntl.ntl_ZZ', - sources = ["sage/libs/ntl/ntl_ZZ.pyx"], - libraries = ["ntl", "gmp", "m"], - language='c++'), - - Extension('sage.libs.ntl.ntl_ZZX', - sources = ["sage/libs/ntl/ntl_ZZX.pyx"], - libraries = ["ntl", "gmp", "m"], - language='c++'), - - Extension('sage.libs.ntl.ntl_ZZ_p', - sources = ["sage/libs/ntl/ntl_ZZ_p.pyx"], - libraries = ["ntl", "gmp", "m"], - language='c++'), - - Extension('sage.libs.ntl.ntl_ZZ_pContext', - sources = ["sage/libs/ntl/ntl_ZZ_pContext.pyx"], - libraries = ["ntl", "gmp", "m"], - language='c++'), - - Extension('sage.libs.ntl.ntl_ZZ_pE', - sources = ["sage/libs/ntl/ntl_ZZ_pE.pyx"], - libraries = ["ntl", "gmp", "m"], - language='c++'), - - Extension('sage.libs.ntl.ntl_ZZ_pEContext', - sources = ["sage/libs/ntl/ntl_ZZ_pEContext.pyx"], - libraries = ["ntl", "gmp", "m"], - language='c++'), - - Extension('sage.libs.ntl.ntl_ZZ_pEX', - sources = ["sage/libs/ntl/ntl_ZZ_pEX.pyx"], - libraries = ["ntl", "gmp", "m"], - language='c++'), - - Extension('sage.libs.ntl.ntl_ZZ_pX', - sources = ["sage/libs/ntl/ntl_ZZ_pX.pyx"], - libraries = ["ntl", "gmp", "m"], - language='c++'), + Extension('*', ["sage/libs/ntl/*.pyx"]), ################################ ## diff --git a/src/sage/libs/ntl/convert.pyx b/src/sage/libs/ntl/convert.pyx index 1da7afd077c..19380ded8ea 100644 --- a/src/sage/libs/ntl/convert.pyx +++ b/src/sage/libs/ntl/convert.pyx @@ -1,4 +1,7 @@ # distutils: depends = NTL/ZZ.h +# distutils: libraries = ntl gmp +# distutils: language = c++ + """ Conversion between NTL's ``ZZ`` and various other types """ diff --git a/src/sage/libs/ntl/error.pyx b/src/sage/libs/ntl/error.pyx index 9052fe0a286..99d6ca92a0c 100644 --- a/src/sage/libs/ntl/error.pyx +++ b/src/sage/libs/ntl/error.pyx @@ -1,3 +1,6 @@ +# distutils: libraries = ntl gmp +# distutils: language = c++ + """ NTL error handler diff --git a/src/sage/libs/ntl/ntl_GF2.pyx b/src/sage/libs/ntl/ntl_GF2.pyx index 5aa701f451f..21f69956b7c 100644 --- a/src/sage/libs/ntl/ntl_GF2.pyx +++ b/src/sage/libs/ntl/ntl_GF2.pyx @@ -1,3 +1,6 @@ +# distutils: libraries = ntl gmp +# distutils: language = c++ + #***************************************************************************** # Copyright (C) 2007 Martin Albrecht # diff --git a/src/sage/libs/ntl/ntl_GF2E.pyx b/src/sage/libs/ntl/ntl_GF2E.pyx index ee6ab1c6adc..f45ad616a94 100644 --- a/src/sage/libs/ntl/ntl_GF2E.pyx +++ b/src/sage/libs/ntl/ntl_GF2E.pyx @@ -1,3 +1,6 @@ +# distutils: libraries = ntl gmp m +# distutils: language = c++ + #***************************************************************************** # Copyright (C) 2005 William Stein # Copyright (C) 2007 Martin Albrecht diff --git a/src/sage/libs/ntl/ntl_GF2EContext.pyx b/src/sage/libs/ntl/ntl_GF2EContext.pyx index ab0ea3b9d0e..b1b453ae781 100644 --- a/src/sage/libs/ntl/ntl_GF2EContext.pyx +++ b/src/sage/libs/ntl/ntl_GF2EContext.pyx @@ -1,3 +1,6 @@ +# distutils: libraries = ntl gmp m +# distutils: language = c++ + #***************************************************************************** # Copyright (C) 2005 William Stein # diff --git a/src/sage/libs/ntl/ntl_GF2EX.pyx b/src/sage/libs/ntl/ntl_GF2EX.pyx index 0067bb6175b..4a3ac4a3c0e 100644 --- a/src/sage/libs/ntl/ntl_GF2EX.pyx +++ b/src/sage/libs/ntl/ntl_GF2EX.pyx @@ -1,3 +1,6 @@ +# distutils: libraries = ntl gmp m +# distutils: language = c++ + #***************************************************************************** # Copyright (C) 2005 William Stein # diff --git a/src/sage/libs/ntl/ntl_GF2X.pyx b/src/sage/libs/ntl/ntl_GF2X.pyx index 19dee747696..f3817f9cac2 100644 --- a/src/sage/libs/ntl/ntl_GF2X.pyx +++ b/src/sage/libs/ntl/ntl_GF2X.pyx @@ -1,3 +1,6 @@ +# distutils: libraries = ntl gmp m +# distutils: language = c++ + # **************************************************************************** # Copyright (C) 2005 William Stein # Copyright (C) 2007 Martin Albrecht diff --git a/src/sage/libs/ntl/ntl_ZZ.pyx b/src/sage/libs/ntl/ntl_ZZ.pyx index 7e040cd9c76..a396e705e2f 100644 --- a/src/sage/libs/ntl/ntl_ZZ.pyx +++ b/src/sage/libs/ntl/ntl_ZZ.pyx @@ -1,3 +1,6 @@ +# distutils: libraries = ntl gmp m +# distutils: language = c++ + #***************************************************************************** # Copyright (C) 2005 William Stein # diff --git a/src/sage/libs/ntl/ntl_ZZX.pyx b/src/sage/libs/ntl/ntl_ZZX.pyx index 228da080442..22e945814ae 100644 --- a/src/sage/libs/ntl/ntl_ZZX.pyx +++ b/src/sage/libs/ntl/ntl_ZZX.pyx @@ -1,3 +1,6 @@ +# distutils: libraries = ntl gmp m +# distutils: language = c++ + #***************************************************************************** # Copyright (C) 2005 William Stein # diff --git a/src/sage/libs/ntl/ntl_ZZ_p.pyx b/src/sage/libs/ntl/ntl_ZZ_p.pyx index e03170bda00..da368d25572 100644 --- a/src/sage/libs/ntl/ntl_ZZ_p.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_p.pyx @@ -1,3 +1,6 @@ +# distutils: libraries = ntl gmp m +# distutils: language = c++ + #***************************************************************************** # Copyright (C) 2005 William Stein # diff --git a/src/sage/libs/ntl/ntl_ZZ_pContext.pyx b/src/sage/libs/ntl/ntl_ZZ_pContext.pyx index dab23a36171..81415974f4b 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pContext.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pContext.pyx @@ -1,3 +1,6 @@ +# distutils: libraries = ntl gmp m +# distutils: language = c++ + #***************************************************************************** # Copyright (C) 2005 William Stein # diff --git a/src/sage/libs/ntl/ntl_ZZ_pE.pyx b/src/sage/libs/ntl/ntl_ZZ_pE.pyx index 7be19458c2d..c0981c8e9da 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pE.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pE.pyx @@ -1,3 +1,6 @@ +# distutils: libraries = ntl gmp m +# distutils: language = c++ + #***************************************************************************** # Copyright (C) 2005 William Stein # diff --git a/src/sage/libs/ntl/ntl_ZZ_pEContext.pyx b/src/sage/libs/ntl/ntl_ZZ_pEContext.pyx index 3855eb1cd22..c5abe44a5f8 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pEContext.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pEContext.pyx @@ -1,3 +1,6 @@ +# distutils: libraries = ntl gmp m +# distutils: language = c++ + #***************************************************************************** # Copyright (C) 2005 William Stein # diff --git a/src/sage/libs/ntl/ntl_ZZ_pEX.pyx b/src/sage/libs/ntl/ntl_ZZ_pEX.pyx index 07efc9ea163..b8f07db7c74 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pEX.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pEX.pyx @@ -1,3 +1,6 @@ +# distutils: libraries = ntl gmp m +# distutils: language = c++ + """ Wrapper for NTL's polynomials over finite ring extensions of $\Z / p\Z.$ diff --git a/src/sage/libs/ntl/ntl_ZZ_pX.pyx b/src/sage/libs/ntl/ntl_ZZ_pX.pyx index b2336c1c9a1..a31f9a4c807 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pX.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pX.pyx @@ -1,3 +1,6 @@ +# distutils: libraries = ntl gmp m +# distutils: language = c++ + # **************************************************************************** # Copyright (C) 2005 William Stein # diff --git a/src/sage/libs/ntl/ntl_lzz_p.pyx b/src/sage/libs/ntl/ntl_lzz_p.pyx index 7809288152f..582e6f088f4 100644 --- a/src/sage/libs/ntl/ntl_lzz_p.pyx +++ b/src/sage/libs/ntl/ntl_lzz_p.pyx @@ -1,3 +1,6 @@ +# distutils: libraries = ntl gmp m +# distutils: language = c++ + """ ntl_lzz_p.pyx diff --git a/src/sage/libs/ntl/ntl_lzz_pContext.pyx b/src/sage/libs/ntl/ntl_lzz_pContext.pyx index 9836b7240ab..30667a452d2 100644 --- a/src/sage/libs/ntl/ntl_lzz_pContext.pyx +++ b/src/sage/libs/ntl/ntl_lzz_pContext.pyx @@ -1,3 +1,6 @@ +# distutils: libraries = ntl gmp m +# distutils: language = c++ + #***************************************************************************** # Copyright (C) 2005 William Stein # diff --git a/src/sage/libs/ntl/ntl_lzz_pX.pyx b/src/sage/libs/ntl/ntl_lzz_pX.pyx index c063e30548b..d953a55248f 100644 --- a/src/sage/libs/ntl/ntl_lzz_pX.pyx +++ b/src/sage/libs/ntl/ntl_lzz_pX.pyx @@ -1,3 +1,6 @@ +# distutils: libraries = ntl gmp m +# distutils: language = c++ + """ ntl_lzz_pX.pyx diff --git a/src/sage/libs/ntl/ntl_mat_GF2.pyx b/src/sage/libs/ntl/ntl_mat_GF2.pyx index 19641a869f8..5ac36f96285 100644 --- a/src/sage/libs/ntl/ntl_mat_GF2.pyx +++ b/src/sage/libs/ntl/ntl_mat_GF2.pyx @@ -1,3 +1,6 @@ +# distutils: libraries = ntl gmp m +# distutils: language = c++ + """ Matrices over the $\GF{2}$ via NTL diff --git a/src/sage/libs/ntl/ntl_mat_GF2E.pyx b/src/sage/libs/ntl/ntl_mat_GF2E.pyx index 123dc81e3c0..23c998a6e84 100644 --- a/src/sage/libs/ntl/ntl_mat_GF2E.pyx +++ b/src/sage/libs/ntl/ntl_mat_GF2E.pyx @@ -1,3 +1,6 @@ +# distutils: libraries = ntl gmp m +# distutils: language = c++ + #***************************************************************************** # Copyright (C) 2005 William Stein # diff --git a/src/sage/libs/ntl/ntl_mat_ZZ.pyx b/src/sage/libs/ntl/ntl_mat_ZZ.pyx index 2fa8e3e7487..faeb3a1a552 100644 --- a/src/sage/libs/ntl/ntl_mat_ZZ.pyx +++ b/src/sage/libs/ntl/ntl_mat_ZZ.pyx @@ -1,3 +1,6 @@ +# distutils: libraries = ntl gmp m +# distutils: language = c++ + #***************************************************************************** # Copyright (C) 2005 William Stein # From a4d04d34ebec904216fa846f25b03d8a15a996bd Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 May 2020 21:37:06 -0700 Subject: [PATCH 112/300] src/sage/modular: Move Extension options from src/module_list.py to distutils directives --- src/module_list.py | 40 +-------------------------- src/sage/modular/modsym/apply.pyx | 2 ++ src/sage/modular/modsym/heilbronn.pyx | 2 ++ src/sage/modular/modsym/p1list.pyx | 3 ++ 4 files changed, 8 insertions(+), 39 deletions(-) diff --git a/src/module_list.py b/src/module_list.py index 1125f73b3ec..3a80eb9a8a9 100644 --- a/src/module_list.py +++ b/src/module_list.py @@ -768,45 +768,7 @@ def uname_specific(name, value, alternative): ## ################################ - Extension('sage.modular.arithgroup.congroup', - sources = ['sage/modular/arithgroup/congroup.pyx']), - - Extension('sage.modular.arithgroup.farey_symbol', - sources = ['sage/modular/arithgroup/farey_symbol.pyx']), - - Extension('sage.modular.arithgroup.arithgroup_element', - sources = ['sage/modular/arithgroup/arithgroup_element.pyx']), - - Extension('sage.modular.hypergeometric_misc', - sources = ['sage/modular/hypergeometric_misc.pyx']), - - Extension('sage.modular.modform.eis_series_cython', - sources = ['sage/modular/modform/eis_series_cython.pyx']), - - Extension('sage.modular.modform.l_series_gross_zagier_coeffs', - sources = ['sage/modular/modform/l_series_gross_zagier_coeffs.pyx']), - - Extension('sage.modular.modsym.apply', - sources = ['sage/modular/modsym/apply.pyx'], - extra_compile_args=["-D_XPG6"]), - - Extension('sage.modular.modsym.manin_symbol', - sources = ['sage/modular/modsym/manin_symbol.pyx']), - - Extension('sage.modular.modsym.relation_matrix_pyx', - sources = ['sage/modular/modsym/relation_matrix_pyx.pyx']), - - Extension('sage.modular.modsym.heilbronn', - sources = ['sage/modular/modsym/heilbronn.pyx'], - extra_compile_args=["-D_XPG6"]), - - Extension('sage.modular.modsym.p1list', - sources = ['sage/modular/modsym/p1list.pyx']), - - Extension('sage.modular.pollack_stevens.dist', - sources = ['sage/modular/pollack_stevens/dist.pyx'], - libraries = ["gmp", "zn_poly"], - extra_compile_args = ["-D_XPG6"]), + Extension('*', ['sage/modular/**/*.pyx']), ################################ ## diff --git a/src/sage/modular/modsym/apply.pyx b/src/sage/modular/modsym/apply.pyx index a4a1bf6470b..ff22f208c00 100644 --- a/src/sage/modular/modsym/apply.pyx +++ b/src/sage/modular/modsym/apply.pyx @@ -1,3 +1,5 @@ +# distutils: extra_compile_args = -D_XPG6 + """ Monomial expansion of `(aX + bY)^i (cX + dY)^{j-i}` """ diff --git a/src/sage/modular/modsym/heilbronn.pyx b/src/sage/modular/modsym/heilbronn.pyx index 823458318e3..b5d04dab169 100644 --- a/src/sage/modular/modsym/heilbronn.pyx +++ b/src/sage/modular/modsym/heilbronn.pyx @@ -1,3 +1,5 @@ +# distutils: extra_compile_args = -D_XPG6 + """ Heilbronn matrix computation """ diff --git a/src/sage/modular/modsym/p1list.pyx b/src/sage/modular/modsym/p1list.pyx index 841b920f68e..3e0b6d25421 100644 --- a/src/sage/modular/modsym/p1list.pyx +++ b/src/sage/modular/modsym/p1list.pyx @@ -1,3 +1,6 @@ +# distutils: libraries = gmp zn_poly +# distutils: extra_compile_args = -D_XPG6 + r""" Lists of Manin symbols (elements of `\mathbb{P}^1(\ZZ/N\ZZ)`) over `\QQ` """ From 17ca1d722dde4293be7daca9043a2d4dce9a03fc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 May 2020 22:08:34 -0700 Subject: [PATCH 113/300] src/sage/env.py (cython_aliases): Add aliases for libraries use in module_list.py --- src/sage/env.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/sage/env.py b/src/sage/env.py index 18d86fe6c49..4c290c38931 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -413,10 +413,18 @@ def cython_aliases(): aliases = {} - for lib in ['fflas-ffpack', 'givaro', 'gsl', 'linbox', 'Singular']: + for lib in ['fflas-ffpack', 'givaro', 'gsl', 'linbox', 'Singular', + 'libpng', 'gdlib', 'm4ri', 'zlib', 'cblas', 'lapack']: var = lib.upper().replace("-", "") + "_" aliases[var + "CFLAGS"] = pkgconfig.cflags(lib).split() - pc = pkgconfig.parse(lib) + if lib == 'zlib': + try: + pc = pkgconfig.parse('zlib') + except pkgconfig.PackageNotFoundError: + from collections import defaultdict + pc = defaultdict(list, {'libraries': ['z']}) + else: + pc = pkgconfig.parse(lib) # INCDIR should be redundant because the -I options are also # passed in CFLAGS aliases[var + "INCDIR"] = pc['include_dirs'] @@ -434,4 +442,14 @@ def cython_aliases(): # fflas-ffpack and fflas-ffpack does add such a C++11 flag. aliases["LINBOX_CFLAGS"].append("-std=gnu++11") aliases["ARB_LIBRARY"] = ARB_LIBRARY + + # TODO: Remove Cygwin hack by installing a suitable cblas.pc + if os.path.exists('/usr/lib/libblas.dll.a'): + aliases["CBLAS_LIBS"] = ['gslcblas'] + + try: + aliases["M4RI_CFLAGS"].remove("-pedantic") + except ValueError: + pass + return aliases From 346bd8887cc45d189a17174107291c72e8b9ad6a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 May 2020 22:09:00 -0700 Subject: [PATCH 114/300] src/sage/modules: Move Extension options from src/module_list.py to distutils directives --- src/module_list.py | 46 +------------------------- src/sage/modules/vector_mod2_dense.pyx | 5 +++ 2 files changed, 6 insertions(+), 45 deletions(-) diff --git a/src/module_list.py b/src/module_list.py index 3a80eb9a8a9..743e83573ce 100644 --- a/src/module_list.py +++ b/src/module_list.py @@ -776,51 +776,7 @@ def uname_specific(name, value, alternative): ## ################################ - Extension('sage.modules.vector_rational_sparse', - sources = ['sage/modules/vector_rational_sparse.pyx']), - - Extension('sage.modules.vector_integer_sparse', - sources = ['sage/modules/vector_integer_sparse.pyx']), - - Extension('sage.modules.vector_modn_sparse', - sources = ['sage/modules/vector_modn_sparse.pyx']), - - Extension('sage.modules.finite_submodule_iter', - sources = ['sage/modules/finite_submodule_iter.pyx']), - - Extension('sage.modules.free_module_element', - sources = ['sage/modules/free_module_element.pyx']), - - Extension('sage.modules.module', - sources = ['sage/modules/module.pyx']), - - Extension('sage.modules.vector_complex_double_dense', - ['sage/modules/vector_complex_double_dense.pyx']), - - Extension('sage.modules.vector_double_dense', - ['sage/modules/vector_double_dense.pyx']), - - Extension('sage.modules.vector_integer_dense', - sources = ['sage/modules/vector_integer_dense.pyx']), - - Extension('sage.modules.vector_modn_dense', - sources = ['sage/modules/vector_modn_dense.pyx']), - - Extension('sage.modules.vector_mod2_dense', - sources = ['sage/modules/vector_mod2_dense.pyx'], - libraries = m4ri_libs + gd_libs + png_libs, - library_dirs = m4ri_library_dirs + gd_library_dirs + png_library_dirs, - include_dirs = m4ri_include_dirs + gd_include_dirs + png_include_dirs, - extra_compile_args = m4ri_extra_compile_args), - - Extension('sage.modules.vector_rational_dense', - sources = ['sage/modules/vector_rational_dense.pyx']), - - Extension('sage.modules.vector_real_double_dense', - ['sage/modules/vector_real_double_dense.pyx']), - - Extension('sage.modules.with_basis.indexed_element', - sources = ['sage/modules/with_basis/indexed_element.pyx']), + Extension('*', ['sage/modules/**/*.pyx']), ################################ ## diff --git a/src/sage/modules/vector_mod2_dense.pyx b/src/sage/modules/vector_mod2_dense.pyx index 3c12d9e7c1a..026beb08a21 100644 --- a/src/sage/modules/vector_mod2_dense.pyx +++ b/src/sage/modules/vector_mod2_dense.pyx @@ -1,3 +1,8 @@ +# distutils: libraries = M4RI_LIBRARIES GDLIB_LIBRARIES LIBPNG_LIBRARIES +# distutils: library_dirs = M4RI_LIBDIR GDLIB_LIBDIR LIBPNG_LIBDIR +# distutils: include_dirs = M4RI_INCDIR GDLIB_INCDIR LIBPNG_INCDIR +# distutils: extra_compile_args = M4RI_CFLAGS + """ Vectors with elements in GF(2) From 70901ea558546af579693dc17775774922ec7e93 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 17 May 2020 22:54:35 -0700 Subject: [PATCH 115/300] src/sage/env.py (cython_aliases): Update doctest --- src/sage/env.py | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/src/sage/env.py b/src/sage/env.py index 4c290c38931..2bd582c82b1 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -383,31 +383,9 @@ def cython_aliases(): {...} sage: sorted(cython_aliases().keys()) ['ARB_LIBRARY', - 'FFLASFFPACK_CFLAGS', - 'FFLASFFPACK_INCDIR', - 'FFLASFFPACK_LIBDIR', - 'FFLASFFPACK_LIBEXTRA', - 'FFLASFFPACK_LIBRARIES', - 'GIVARO_CFLAGS', - 'GIVARO_INCDIR', - 'GIVARO_LIBDIR', - 'GIVARO_LIBEXTRA', - 'GIVARO_LIBRARIES', - 'GSL_CFLAGS', - 'GSL_INCDIR', - 'GSL_LIBDIR', - 'GSL_LIBEXTRA', - 'GSL_LIBRARIES', - 'LINBOX_CFLAGS', - 'LINBOX_INCDIR', - 'LINBOX_LIBDIR', - 'LINBOX_LIBEXTRA', - 'LINBOX_LIBRARIES', - 'SINGULAR_CFLAGS', - 'SINGULAR_INCDIR', - 'SINGULAR_LIBDIR', - 'SINGULAR_LIBEXTRA', - 'SINGULAR_LIBRARIES'] + 'CBLAS_CFLAGS', + ..., + 'ZLIB_LIBRARIES'] """ import pkgconfig From 387c0bd94ed25057df5003e6ec7ae38018191524 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Tue, 19 May 2020 10:38:15 +0100 Subject: [PATCH 116/300] Minor changes in doc strings --- src/sage/combinat/path_tableaux/catalan.py | 18 ++++++------- .../combinat/path_tableaux/path_tableau.py | 26 ++++++++++--------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/sage/combinat/path_tableaux/catalan.py b/src/sage/combinat/path_tableaux/catalan.py index ea6f4d5cb5d..4f2de2b9e60 100644 --- a/src/sage/combinat/path_tableaux/catalan.py +++ b/src/sage/combinat/path_tableaux/catalan.py @@ -61,7 +61,7 @@ ############################################################################### class CatalanTableau(PathTableau): - """ + r""" An instance is the sequence of nonnegative integers given by the heights of a Dyck word. @@ -117,7 +117,7 @@ def __init__(self, parent, ot, check=True): Can be any of: - * word of nonnegative integers with successive differences $\pm 1$ + * word of nonnegative integers with successive differences '\pm 1' * a DyckWord * a noncrossing perfect matching * a two row standard tableau @@ -274,7 +274,7 @@ def _rule(x): return result def is_skew(self): - """ + r""" Return ``True`` if ``self`` is skew and ``False`` if not. EXAMPLES:: @@ -289,7 +289,7 @@ def is_skew(self): @combinatorial_map(name='to Dyck word') def to_DyckWord(self): - """ + r""" Converts ``self`` to a Dyck word. EXAMPLES:: @@ -301,7 +301,7 @@ def to_DyckWord(self): return DyckWord(heights_sequence = list(self)) def descents(self): - """ + r""" Return the descent set of ``self``. EXAMPLES:: @@ -318,7 +318,7 @@ def descents(self): return result def to_word(self): - """ + r""" Return the word in the alphabet `\{0,1\}` associated to ``self``. EXAMPLES:: @@ -329,7 +329,7 @@ def to_word(self): return [ (self[i+1]-self[i]+1)/2 for i in range(self.size()-1) ] def to_perfect_matching(self): - """ + r""" Return the perfect matching associated to ``self``. EXAMPLES:: @@ -356,7 +356,7 @@ def to_perfect_matching(self): return PerfectMatching(pairs) def to_tableau(self): - """ + r""" Return the skew tableau associated to ``self``. EXAMPLES:: @@ -379,7 +379,7 @@ def to_tableau(self): class CatalanTableaux(PathTableaux): """ - The parent class for CatalanTableau + The parent class for CatalanTableau. """ Element = CatalanTableau diff --git a/src/sage/combinat/path_tableaux/path_tableau.py b/src/sage/combinat/path_tableaux/path_tableau.py index c0581f749a8..8a5f21b9f77 100644 --- a/src/sage/combinat/path_tableaux/path_tableau.py +++ b/src/sage/combinat/path_tableaux/path_tableau.py @@ -19,7 +19,7 @@ .. [Wes2017] Bruce Westbury. *Coboundary categories and local rules*, - :arxiv:`1705.07141` + The Electronic Journal of Combinatorics, *25* (2018) AUTHORS: @@ -56,7 +56,7 @@ class PathTableau(ClonableArray): """ @abstract_method(optional=False) def _local_rule(self,i): - """ + r""" This is the abstract local rule defined in any coboundary category. This has input a list of objects. This method first takes @@ -74,7 +74,7 @@ def _local_rule(self,i): ################################# Book Keeping ############################ def size(self): - """ + r""" Return the size or length of ``self``. EXAMPLES:: @@ -86,7 +86,7 @@ def size(self): return len(self) def initial_shape(self): - """ + r""" Return the initial shape of ``self``. EXAMPLES:: @@ -98,7 +98,7 @@ def initial_shape(self): return self[0] def final_shape(self): - """ + r""" Return the final shape of ``self``. EXAMPLES:: @@ -112,7 +112,7 @@ def final_shape(self): ############################# Jeu de taquin ############################### def promotion(self): - """ + r""" Return the promotion operator applied to ``self``. EXAMPLES:: @@ -128,7 +128,7 @@ def promotion(self): return result def evacuation(self): - """ + r""" Return the evacuation operator applied to ``self``. EXAMPLES:: @@ -151,7 +151,7 @@ def evacuation(self): return self.parent()(result) def commutor(self,other,verbose=False): - """ + r""" Return the commutor of ``self`` with ``other`` If ``verbose=True`` then the function will print @@ -223,7 +223,7 @@ def cactus(self,i,j): r""" Return the action of the generators of the cactus group on ``self``. These generators are involutions and are usually denoted by - $s_{i,j}$. + 's_{i,j}'. INPUT: @@ -356,7 +356,7 @@ def _test_coboundary(self, **options): tester.assertTrue(lhs == rhs) def orbit(self): - """ + r""" Return the orbit of ``self`` under the action of the cactus group. EXAMPLES:: @@ -386,7 +386,7 @@ def orbit(self): return orb def dual_equivalence_graph(self): - """ + r""" Return the graph with vertices the orbit of ``self`` and edges given by the action of the cactus group generators. @@ -439,7 +439,9 @@ def dual_equivalence_graph(self): return G class PathTableaux(UniqueRepresentation,Parent): - """ The abstract parent class for PathTableau.""" + """ + The abstract parent class for PathTableau. + """ def __init__(self): """ Initializes the abstract class of all PathTableaux From 49c60b69b893792fbb6262190fa66637b7a82caa Mon Sep 17 00:00:00 2001 From: vipul79321 Date: Wed, 20 May 2020 02:01:06 +0530 Subject: [PATCH 117/300] added for unweighted graphs --- src/doc/en/reference/references/index.rst | 5 + src/sage/graphs/distances_all_pairs.pyx | 121 +++++++++++++++++++++- 2 files changed, 125 insertions(+), 1 deletion(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 91aeb96553b..949651ff129 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -2526,6 +2526,11 @@ REFERENCES: .. [Ha2005] Gerhard Haring. [Online] Available: http://osdir.com/ml/python.db.pysqlite.user/2005-11/msg00047.html +.. [Habib2018] Feodor Dragan, Michel Habib, Laurent Viennot. + *Revisiting Radius, Diameter, and all Eccentricity Computation + in Graphs through Certificates*. + http://arxiv.org/abs/1803.04660 + .. [Hac2016] \M. Hachimori. http://infoshako.sk.tsukuba.ac.jp/~hachi/math/library/dunce_hat_eng.html .. [Haf2004] Paul R. Hafner. *On the Graphs of Hoffman-Singleton and Higman-Sims*. diff --git a/src/sage/graphs/distances_all_pairs.pyx b/src/sage/graphs/distances_all_pairs.pyx index 802d4a8f6e2..d74e194a6b3 100644 --- a/src/sage/graphs/distances_all_pairs.pyx +++ b/src/sage/graphs/distances_all_pairs.pyx @@ -1267,7 +1267,7 @@ def diameter(G, algorithm=None, source=None): r""" Return the diameter of `G`. - This algorithm returns Infinity if the (di)graph is not connected. It can + This method returns Infinity if the (di)graph is not connected. It can also quickly return a lower bound on the diameter using the ``2sweep``, ``2Dsweep`` and ``multi-sweep`` schemes. @@ -1448,6 +1448,125 @@ def diameter(G, algorithm=None, source=None): else: return int(LB) + +########### +# Radius # +########### + +def radius(G): + r""" + Return radius of unweighted graph `G`. + + This method computes radius of unweighted undirected graph using the + algorithm given in [Habib2018]_. + + This method returns Infinity if graph is not connected. + + EXAMPLES:: + + sage: from sage.graphs.distances_all_pairs import radius + sage: G = graphs.PetersenGraph() + sage: radius(G) + 2 + sage: G = graphs.RandomGNP(100,0.6) + sage: radius(G) + 2 + + TESTS: + + sage: G = Graph() + sage: radius(G) + 0 + sage: G = Graph(1) + sage: radius(G) + 0 + sage: G = Graph(2) + sage: radius(G) + +Infinity + """ + cdef uint32_t n = G.order() + if not n or n == 1: + return 0 + + cdef list int_to_vertex = list(G) + cdef short_digraph sd + init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex) + + cdef list L = [] + cdef list K = [] + cdef uint32_t source = 0 + cdef uint32_t antipode + cdef uint32_t min_L = UINT32_MAX + cdef uint32_t min_K = UINT32_MAX + cdef uint32_t next_source # To store source for next iteration + + cdef MemoryAllocator mem = MemoryAllocator() + cdef uint32_t * distances = mem.malloc(4 * n * sizeof(uint32_t)) + if not distances: + raise MemoryError() + cdef uint32_t * waiting_list = distances + n + # For storing eccentricity of nodes + cdef uint32_t * ecc = distances + 2 * n + # For storing lower bound on eccentricity of nodes + cdef uint32_t * ecc_lower_bound = distances + 3 * n + memset(ecc_lower_bound,0,n * sizeof(uint32_t)) + + cdef bitset_t seen + + # Doing first iteration of do-while loop and intializing values + bitset_init(seen,n) # intializing bitset + ecc[source] = simple_BFS(sd, source, distances, NULL, waiting_list, seen) + + if ecc[source] == UINT32_MAX: # Disconnected graph + from sage.rings.infinity import Infinity + return +Infinity + + antipode = waiting_list[n-1] # last visited vertex in simple_BFS + + if(ecc[source] == ecc_lower_bound[source]): + return ecc[source] # Radius + + bitset_init(seen,n) # Reinitializing bitset + ecc[antipode] = simple_BFS(sd, antipode, distances, NULL, waiting_list, seen) + + L.append(antipode) + K.append(source) + min_K = min(min_K, ecc[source]) + min_L = UINT32_MAX + + for v in range(n): + ecc_lower_bound[v] = max(ecc_lower_bound[v], distances[v]) + if min_L > ecc_lower_bound[v]: + min_L = ecc_lower_bound[v] + next_source = v + + + # Now looping + while min_L < min_K: + source = next_source + bitset_init(seen,n) + ecc[source] = simple_BFS(sd, source, distances, NULL, waiting_list, seen) + antipode = waiting_list[n-1] + + if(ecc[source] == ecc_lower_bound[source]): + return ecc[source] + + bitset_init(seen,n) + ecc[antipode] = simple_BFS(sd, antipode, distances, NULL, waiting_list, seen) + + L.append(antipode) + K.append(source) + min_K = min(min_K, ecc[source]) + min_L = UINT32_MAX + + for v in range(n): + ecc_lower_bound[v] = max(ecc_lower_bound[v], distances[v]) + if min_L > ecc_lower_bound[v]: + min_L = ecc_lower_bound[v] + next_source = v + + return min_K + ################ # Wiener index # ################ From 697276b88fdb0ef50348d8b29b1e27568db76aef Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Wed, 20 May 2020 14:01:17 +0100 Subject: [PATCH 118/300] Initial commit --- src/sage/combinat/path_tableaux/frieze.py | 291 ++++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 src/sage/combinat/path_tableaux/frieze.py diff --git a/src/sage/combinat/path_tableaux/frieze.py b/src/sage/combinat/path_tableaux/frieze.py new file mode 100644 index 00000000000..d89022ea0fb --- /dev/null +++ b/src/sage/combinat/path_tableaux/frieze.py @@ -0,0 +1,291 @@ +r""" +Unimodular Frieze Patterns + +This is an implementation of the abstract base class +:class:`sage.combinat.pathtableau.pathtableaux`. + +In this implementation we have sequences of nonnegative integers. +This follows [CoCo1]_ and [CoCo2]_ + +REFERENCES: + +.. [CoCo1] J.H. Conway and H.S.M. Coxeter + *Triangulated polygons and frieze patterns*, + The Mathematical Gazette (1973) 57 p.87-94 + + +.. [CoCo2] J.H. Conway and H.S.M. Coxeter + *Triangulated polygons and frieze patterns (continued)*, + The Mathematical Gazette (1973) 57 p.175-183 + +.. [TJ18] Thorsten Holm and Peter Jorgensen + *A p-angulated generalisation of Conway and Coxeter's theorem on frieze patterns*, + International Mathematics Research Notices (2018) + + +AUTHORS: + +- Bruce Westbury (2019): initial version +""" +#***************************************************************************** +# Copyright (C) 2019 Bruce Westbury , +# +# 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/ +#***************************************************************************** + +from six import add_metaclass +from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass +from sage.structure.parent import Parent +from sage.categories.sets_cat import Sets +from sage.structure.list_clone import ClonableArray +from sage.combinat.path_tableaux.path_tableau import PathTableau, PathTableaux +#from sage.combinat.combinatorial_map import combinatorial_map +#from sage.combinat.tableau import Tableau, StandardTableau +from sage.rings.integer import Integer +from sage.rings.all import QQ + +############################################################################### + +""" + +EXAMPLES:: + + sage: t = UnimodularFriezePattern([0,1,2,1,2,3,1,0]) + + sage: SkewTableau(t.cylindrical_diagram()).pp() + 0 1 2 1 2 3 1 0 + . 0 1 1 3 5 2 1 0 + . . 0 1 4 7 3 2 1 0 + . . . 0 1 2 1 1 1 1 0 + . . . . 0 1 1 2 3 4 1 0 + . . . . . 0 1 3 5 7 2 1 0 + . . . . . . 0 1 2 3 1 1 1 0 + . . . . . . . 0 1 2 1 2 3 1 0 + + sage: TestSuite(t).run() + + sage: t = UnimodularFriezePattern([0,1,2,7,5,3,7,4,1,0]) + + sage: SkewTableau(t.cylindrical_diagram()).pp() + 0 1 2 7 5 3 7 4 1 0 + . 0 1 4 3 2 5 3 1 1 0 + . . 0 1 1 1 3 2 1 2 1 0 + . . . 0 1 2 7 5 3 7 4 1 0 + . . . . 0 1 4 3 2 5 3 1 1 0 + . . . . . 0 1 1 1 3 2 1 2 1 0 + . . . . . . 0 1 2 7 5 3 7 4 1 0 + . . . . . . . 0 1 4 3 2 5 3 1 1 0 + . . . . . . . . 0 1 1 1 3 2 1 2 1 0 + . . . . . . . . . 0 1 2 7 5 3 7 4 1 0 + + sage: TestSuite(t).run() + + sage: t = UnimodularFriezePattern([0,1,3,4,5,1,0]) + + sage: SkewTableau(t.cylindrical_diagram()).pp() + 0 1 3 4 5 1 0 + . 0 15/37/32/3 1 0 + . . 0 1 2 1 3 1 0 + . . . 0 1 1 45/3 1 0 + . . . . 0 1 57/3 2 1 0 + . . . . . 0 12/3 1 1 1 0 + . . . . . . 0 1 3 4 5 1 0 + + + sage: TestSuite(t).run() + +This constructs the examples from [TJ18]_ + + sage: K. = NumberField(x^2-3) + sage: t = UnimodularFriezePattern([0,1,sqrt3,2,sqrt3,1,1,0], field=K) + + sage: SkewTableau(t.cylindrical_diagram()).pp() + 0 1sqrt3 2sqrt3 1 1 0 + . 0 1sqrt3 2sqrt3sqrt3 + 1 1 0 + . . 0 1sqrt3 2sqrt3 + 2sqrt3 1 0 + . . . 0 1sqrt3sqrt3 + 2 2sqrt3 1 0 + . . . . 0 1sqrt3 + 1sqrt3 2sqrt3 1 0 + . . . . . 0 1 1sqrt3 2sqrt3 1 0 + . . . . . . 0 1sqrt3 + 1sqrt3 + 2sqrt3 + 2sqrt3 + 1 1 0 + . . . . . . . 0 1sqrt3 2sqrt3 1 1 0 + + sage: TestSuite(t).run() + + sage: K. = NumberField(x^2-2) + sage: t = UnimodularFriezePattern([0,1,sqrt2,1,sqrt2,3,2*sqrt2,5,3*sqrt2,1,0], field=K) + + sage: SkewTableau(t.cylindrical_diagram()).pp() + 0 1sqrt2 1sqrt2 32*sqrt2 53*sqrt2 1 0 + . 0 1sqrt2 35*sqrt2 79*sqrt2 112*sqrt2 1 0 + . . 0 12*sqrt2 75*sqrt2 138*sqrt2 3sqrt2 1 0 + . . . 0 12*sqrt2 34*sqrt2 5sqrt2 1sqrt2 1 0 + . . . . 0 1sqrt2 32*sqrt2 1sqrt2 32*sqrt2 1 0 + . . . . . 0 12*sqrt2 3sqrt2 35*sqrt2 72*sqrt2 1 0 + . . . . . . 0 1sqrt2 12*sqrt2 75*sqrt2 3sqrt2 1 0 + . . . . . . . 0 1sqrt2 59*sqrt2 134*sqrt2 32*sqrt2 1 0 + . . . . . . . . 0 13*sqrt2 118*sqrt2 52*sqrt2 3sqrt2 1 0 + . . . . . . . . . 0 12*sqrt2 3sqrt2 1sqrt2 1sqrt2 1 0 + . . . . . . . . . . 0 1sqrt2 1sqrt2 32*sqrt2 53*sqrt2 1 0 + + sage: TestSuite(t).run() +""" + + +@add_metaclass(InheritComparisonClasscallMetaclass) +class UnimodularFriezePattern(PathTableau): + """ + An instance is the sequence of nonnegative + integers. + """ + + @staticmethod + def __classcall_private__(cls, fp, field=QQ): + """This is the preprocessing for creating paths. + + INPUT: + + - a sequence of nonnegative integers + + EXAMPLES:: + + sage: UnimodularFriezePattern([1,2,1,2,3,1]) + [1, 2, 1, 2, 3, 1] + + """ + w = None + + if isinstance(fp, (list,tuple)): + try: + w = tuple([field(a) for a in fp]) + except TypeError: + raise ValueError("%s is not a sequence of integers" % fp) + + if w is None: + raise ValueError("invalid input %s" % fp) + + return UnimodularFriezePatterns(field)(w) + + def check(self): + + n = len(self) + if any(a < 0 for a in self): + raise ValueError( "%s has a negative entry" % (str(self)) ) + + def _local_rule(self,i): + """ + This has input a list of objects. This method first takes + the list of objects of length three consisting of the `(i-1)`-st, + `i`-th and `(i+1)`-term and applies the rule. It then replaces + the `i`-th object by the object returned by the rule. + + EXAMPLES:: + + sage: t = UnimodularFriezePattern([1,2,1,2,3,1]) + sage: t._local_rule(3) + [1, 2, 1, 2, 3, 1] + """ + + def _rule(x): + """ + This is the rule on a sequence of three letters. + """ + return (x[0]*x[2]+1)/x[1] + + if not (i > 0 and i < len(self) ): + raise ValueError("%d is not a valid integer" % i) + + with self.clone() as result: + result[i] = _rule(self[i-1:i+2]) + + return result + + def is_skew(self): + """ + Return ``True`` if ``self`` is skew and ``False`` if not. + + EXAMPLES:: + + sage: UnimodularFriezePattern([1,2,1,2,3,1]).is_skew() + False + + sage: UnimodularFriezePattern([2,2,1,2,3,1]).is_skew() + True + """ + return self[0] != 1 + + def is_integral(self): + """ + Return ``True`` if all entries of the frieze pattern are positive integers and ``False`` if not. + + EXAMPLES:: + + sage: UnimodularFriezePattern([0,1,2,7,5,3,7,4,1,0]).is_integral() + True + + sage: UnimodularFriezePattern([0,1,3,4,5,1,0]).is_integral() + False + + """ + n = len(self) + cd = self.cylindrical_diagram() + for i, a in enumerate(cd): + v = a[i+1:n+i-2] + try: + v = [ Integer(k) for k in v ] + except TypeError: + return False + if any(k <= 0 for k in v): + return False + return True + + def plot(self): + """ + If ``self`` is integral then plot the triangulation. + + EXAMPLES:: + + sage: UnimodularFriezePattern([0,1,2,7,5,3,7,4,1,0]).plot() + Graphics object consisting of 24 graphics primitives + + """ + if not self.is_integral(): + raise ValueError("must be an integral frieze") + n = len(self) + cd = self.cylindrical_diagram() + from sage.plot.plot import Graphics + from sage.plot.line import line + from sage.plot.text import text + from sage.functions.trig import sin, cos + from sage.all import pi + G = Graphics() + G.set_aspect_ratio(1.0) + + vt = [(cos(2*theta*pi/(n-1)), sin(2*theta*pi/(n-1))) for theta in range(n-1)] + for i, p in enumerate(vt): + G += text(str(i),[1.05*p[0],1.05*p[1]]) + + for i, r in enumerate(cd): + for j, a in enumerate(r[:n-1]): + if a == 1: + G += line([vt[i],vt[j]]) + + G.axes(False) + return G + +class UnimodularFriezePatterns(PathTableaux): + + def __init__(self, field): + + self._field = field + + Parent.__init__(self, category=Sets()) + + def field(self): + return self._field + + Element = UnimodularFriezePattern + From 938a54d102b6a802fe17564e01240cb0c863b0c8 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Wed, 20 May 2020 14:08:01 +0100 Subject: [PATCH 119/300] Changed all.py, __init__.py and ../all.py --- src/sage/combinat/all.py | 1 + src/sage/combinat/path_tableaux/__init__.py | 1 + src/sage/combinat/path_tableaux/all.py | 1 + 3 files changed, 3 insertions(+) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 3ae1e8c39a7..16eb11ccb36 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -237,3 +237,4 @@ # Path tableaux lazy_import('sage.combinat.path_tableaux.path_tableau', ['PathTableau', 'PathTableaux', 'CylindricalDiagram']) lazy_import('sage.combinat.path_tableaux.catalan', ['CatalanTableau', 'CatalanTableaux']) +lazy_import('sage.combinat.path_tableaux.frieze', ['UnimodularFriezePattern', 'UnimodularFriezePatterns']) diff --git a/src/sage/combinat/path_tableaux/__init__.py b/src/sage/combinat/path_tableaux/__init__.py index 977ae3aea9b..7bbeb48b033 100644 --- a/src/sage/combinat/path_tableaux/__init__.py +++ b/src/sage/combinat/path_tableaux/__init__.py @@ -4,4 +4,5 @@ - :ref:`sage.combinat.path_tableaux.path_tableau` - :ref:`sage.combinat.path_tableaux.catalan` +- :ref:`sage.combinat.path_tableaux.frieze` """ diff --git a/src/sage/combinat/path_tableaux/all.py b/src/sage/combinat/path_tableaux/all.py index b7f6bf01a5a..f8988526f70 100644 --- a/src/sage/combinat/path_tableaux/all.py +++ b/src/sage/combinat/path_tableaux/all.py @@ -5,3 +5,4 @@ from .path_tableau import PathTableau, PathTableaux, CylindricalDiagram from .catalan import CatalanTableau, CatalanTableaux +from .frieze import UnimodularFriezePattern, UnimodularFriezePatterns From 78ff4ad15a38446d41a1aeafbf35c03c460d90ca Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Wed, 20 May 2020 14:39:51 +0100 Subject: [PATCH 120/300] All tests passed! --- src/sage/combinat/path_tableaux/frieze.py | 130 ++++++++++------------ 1 file changed, 61 insertions(+), 69 deletions(-) diff --git a/src/sage/combinat/path_tableaux/frieze.py b/src/sage/combinat/path_tableaux/frieze.py index d89022ea0fb..4ccf2f34006 100644 --- a/src/sage/combinat/path_tableaux/frieze.py +++ b/src/sage/combinat/path_tableaux/frieze.py @@ -41,8 +41,8 @@ from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.structure.parent import Parent from sage.categories.sets_cat import Sets -from sage.structure.list_clone import ClonableArray -from sage.combinat.path_tableaux.path_tableau import PathTableau, PathTableaux +#from sage.structure.list_clone import ClonableArray +from sage.combinat.path_tableaux.path_tableau import PathTableau, PathTableaux, CylindricalDiagram #from sage.combinat.combinatorial_map import combinatorial_map #from sage.combinat.tableau import Tableau, StandardTableau from sage.rings.integer import Integer @@ -55,46 +55,41 @@ EXAMPLES:: sage: t = UnimodularFriezePattern([0,1,2,1,2,3,1,0]) - - sage: SkewTableau(t.cylindrical_diagram()).pp() - 0 1 2 1 2 3 1 0 - . 0 1 1 3 5 2 1 0 - . . 0 1 4 7 3 2 1 0 - . . . 0 1 2 1 1 1 1 0 - . . . . 0 1 1 2 3 4 1 0 - . . . . . 0 1 3 5 7 2 1 0 - . . . . . . 0 1 2 3 1 1 1 0 - . . . . . . . 0 1 2 1 2 3 1 0 + sage: CylindricalDiagram(t) + [0, 1, 2, 1, 2, 3, 1, 0] + ['', 0, 1, 1, 3, 5, 2, 1, 0] + ['', '', 0, 1, 4, 7, 3, 2, 1, 0] + ['', '', '', 0, 1, 2, 1, 1, 1, 1, 0] + ['', '', '', '', 0, 1, 1, 2, 3, 4, 1, 0] + ['', '', '', '', '', 0, 1, 3, 5, 7, 2, 1, 0] + ['', '', '', '', '', '', 0, 1, 2, 3, 1, 1, 1, 0] + ['', '', '', '', '', '', '', 0, 1, 2, 1, 2, 3, 1, 0] sage: TestSuite(t).run() sage: t = UnimodularFriezePattern([0,1,2,7,5,3,7,4,1,0]) - - sage: SkewTableau(t.cylindrical_diagram()).pp() - 0 1 2 7 5 3 7 4 1 0 - . 0 1 4 3 2 5 3 1 1 0 - . . 0 1 1 1 3 2 1 2 1 0 - . . . 0 1 2 7 5 3 7 4 1 0 - . . . . 0 1 4 3 2 5 3 1 1 0 - . . . . . 0 1 1 1 3 2 1 2 1 0 - . . . . . . 0 1 2 7 5 3 7 4 1 0 - . . . . . . . 0 1 4 3 2 5 3 1 1 0 - . . . . . . . . 0 1 1 1 3 2 1 2 1 0 - . . . . . . . . . 0 1 2 7 5 3 7 4 1 0 - + sage: CylindricalDiagram(t) + [0, 1, 2, 7, 5, 3, 7, 4, 1, 0] + ['', 0, 1, 4, 3, 2, 5, 3, 1, 1, 0] + ['', '', 0, 1, 1, 1, 3, 2, 1, 2, 1, 0] + ['', '', '', 0, 1, 2, 7, 5, 3, 7, 4, 1, 0] + ['', '', '', '', 0, 1, 4, 3, 2, 5, 3, 1, 1, 0] + ['', '', '', '', '', 0, 1, 1, 1, 3, 2, 1, 2, 1, 0] + ['', '', '', '', '', '', 0, 1, 2, 7, 5, 3, 7, 4, 1, 0] + ['', '', '', '', '', '', '', 0, 1, 4, 3, 2, 5, 3, 1, 1, 0] + ['', '', '', '', '', '', '', '', 0, 1, 1, 1, 3, 2, 1, 2, 1, 0] + ['', '', '', '', '', '', '', '', '', 0, 1, 2, 7, 5, 3, 7, 4, 1, 0] sage: TestSuite(t).run() sage: t = UnimodularFriezePattern([0,1,3,4,5,1,0]) - - sage: SkewTableau(t.cylindrical_diagram()).pp() - 0 1 3 4 5 1 0 - . 0 15/37/32/3 1 0 - . . 0 1 2 1 3 1 0 - . . . 0 1 1 45/3 1 0 - . . . . 0 1 57/3 2 1 0 - . . . . . 0 12/3 1 1 1 0 - . . . . . . 0 1 3 4 5 1 0 - + sage: CylindricalDiagram(t) + [0, 1, 3, 4, 5, 1, 0] + ['', 0, 1, 5/3, 7/3, 2/3, 1, 0] + ['', '', 0, 1, 2, 1, 3, 1, 0] + ['', '', '', 0, 1, 1, 4, 5/3, 1, 0] + ['', '', '', '', 0, 1, 5, 7/3, 2, 1, 0] + ['', '', '', '', '', 0, 1, 2/3, 1, 1, 1, 0] + ['', '', '', '', '', '', 0, 1, 3, 4, 5, 1, 0] sage: TestSuite(t).run() @@ -102,34 +97,32 @@ sage: K. = NumberField(x^2-3) sage: t = UnimodularFriezePattern([0,1,sqrt3,2,sqrt3,1,1,0], field=K) - - sage: SkewTableau(t.cylindrical_diagram()).pp() - 0 1sqrt3 2sqrt3 1 1 0 - . 0 1sqrt3 2sqrt3sqrt3 + 1 1 0 - . . 0 1sqrt3 2sqrt3 + 2sqrt3 1 0 - . . . 0 1sqrt3sqrt3 + 2 2sqrt3 1 0 - . . . . 0 1sqrt3 + 1sqrt3 2sqrt3 1 0 - . . . . . 0 1 1sqrt3 2sqrt3 1 0 - . . . . . . 0 1sqrt3 + 1sqrt3 + 2sqrt3 + 2sqrt3 + 1 1 0 - . . . . . . . 0 1sqrt3 2sqrt3 1 1 0 + sage: CylindricalDiagram(t) + [0, 1, sqrt3, 2, sqrt3, 1, 1, 0] + ['', 0, 1, sqrt3, 2, sqrt3, sqrt3 + 1, 1, 0] + ['', '', 0, 1, sqrt3, 2, sqrt3 + 2, sqrt3, 1, 0] + ['', '', '', 0, 1, sqrt3, sqrt3 + 2, 2, sqrt3, 1, 0] + ['', '', '', '', 0, 1, sqrt3 + 1, sqrt3, 2, sqrt3, 1, 0] + ['', '', '', '', '', 0, 1, 1, sqrt3, 2, sqrt3, 1, 0] + ['', '', '', '', '', '', 0, 1, sqrt3 + 1, sqrt3 + 2, sqrt3 + 2, sqrt3 + 1, 1, 0] + ['', '', '', '', '', '', '', 0, 1, sqrt3, 2, sqrt3, 1, 1, 0] sage: TestSuite(t).run() sage: K. = NumberField(x^2-2) sage: t = UnimodularFriezePattern([0,1,sqrt2,1,sqrt2,3,2*sqrt2,5,3*sqrt2,1,0], field=K) - - sage: SkewTableau(t.cylindrical_diagram()).pp() - 0 1sqrt2 1sqrt2 32*sqrt2 53*sqrt2 1 0 - . 0 1sqrt2 35*sqrt2 79*sqrt2 112*sqrt2 1 0 - . . 0 12*sqrt2 75*sqrt2 138*sqrt2 3sqrt2 1 0 - . . . 0 12*sqrt2 34*sqrt2 5sqrt2 1sqrt2 1 0 - . . . . 0 1sqrt2 32*sqrt2 1sqrt2 32*sqrt2 1 0 - . . . . . 0 12*sqrt2 3sqrt2 35*sqrt2 72*sqrt2 1 0 - . . . . . . 0 1sqrt2 12*sqrt2 75*sqrt2 3sqrt2 1 0 - . . . . . . . 0 1sqrt2 59*sqrt2 134*sqrt2 32*sqrt2 1 0 - . . . . . . . . 0 13*sqrt2 118*sqrt2 52*sqrt2 3sqrt2 1 0 - . . . . . . . . . 0 12*sqrt2 3sqrt2 1sqrt2 1sqrt2 1 0 - . . . . . . . . . . 0 1sqrt2 1sqrt2 32*sqrt2 53*sqrt2 1 0 + sage: CylindricalDiagram(t) + [0, 1, sqrt2, 1, sqrt2, 3, 2*sqrt2, 5, 3*sqrt2, 1, 0] + ['', 0, 1, sqrt2, 3, 5*sqrt2, 7, 9*sqrt2, 11, 2*sqrt2, 1, 0] + ['', '', 0, 1, 2*sqrt2, 7, 5*sqrt2, 13, 8*sqrt2, 3, sqrt2, 1, 0] + ['', '', '', 0, 1, 2*sqrt2, 3, 4*sqrt2, 5, sqrt2, 1, sqrt2, 1, 0] + ['', '', '', '', 0, 1, sqrt2, 3, 2*sqrt2, 1, sqrt2, 3, 2*sqrt2, 1, 0] + ['', '', '', '', '', 0, 1, 2*sqrt2, 3, sqrt2, 3, 5*sqrt2, 7, 2*sqrt2, 1, 0] + ['', '', '', '', '', '', 0, 1, sqrt2, 1, 2*sqrt2, 7, 5*sqrt2, 3, sqrt2, 1, 0] + ['', '', '', '', '', '', '', 0, 1, sqrt2, 5, 9*sqrt2, 13, 4*sqrt2, 3, 2*sqrt2, 1, 0] + ['', '', '', '', '', '', '', '', 0, 1, 3*sqrt2, 11, 8*sqrt2, 5, 2*sqrt2, 3, sqrt2, 1, 0] + ['', '', '', '', '', '', '', '', '', 0, 1, 2*sqrt2, 3, sqrt2, 1, sqrt2, 1, sqrt2, 1, 0] + ['', '', '', '', '', '', '', '', '', '', 0, 1, sqrt2, 1, sqrt2, 3, 2*sqrt2, 5, 3*sqrt2, 1, 0] sage: TestSuite(t).run() """ @@ -138,8 +131,7 @@ @add_metaclass(InheritComparisonClasscallMetaclass) class UnimodularFriezePattern(PathTableau): """ - An instance is the sequence of nonnegative - integers. + An instance is the sequence of nonnegative integers. """ @staticmethod @@ -148,7 +140,7 @@ def __classcall_private__(cls, fp, field=QQ): INPUT: - - a sequence of nonnegative integers + - a sequence of nonnegative integers EXAMPLES:: @@ -171,12 +163,12 @@ def __classcall_private__(cls, fp, field=QQ): def check(self): - n = len(self) + #n = len(self) if any(a < 0 for a in self): raise ValueError( "%s has a negative entry" % (str(self)) ) def _local_rule(self,i): - """ + r""" This has input a list of objects. This method first takes the list of objects of length three consisting of the `(i-1)`-st, `i`-th and `(i+1)`-term and applies the rule. It then replaces @@ -204,7 +196,7 @@ def _rule(x): return result def is_skew(self): - """ + r""" Return ``True`` if ``self`` is skew and ``False`` if not. EXAMPLES:: @@ -218,7 +210,7 @@ def is_skew(self): return self[0] != 1 def is_integral(self): - """ + r""" Return ``True`` if all entries of the frieze pattern are positive integers and ``False`` if not. EXAMPLES:: @@ -231,7 +223,7 @@ def is_integral(self): """ n = len(self) - cd = self.cylindrical_diagram() + cd = CylindricalDiagram(self).diagram for i, a in enumerate(cd): v = a[i+1:n+i-2] try: @@ -243,7 +235,7 @@ def is_integral(self): return True def plot(self): - """ + r""" If ``self`` is integral then plot the triangulation. EXAMPLES:: @@ -253,9 +245,9 @@ def plot(self): """ if not self.is_integral(): - raise ValueError("must be an integral frieze") + raise ValueError("{!s} must be an integral frieze".format(self)) n = len(self) - cd = self.cylindrical_diagram() + cd = CylindricalDiagram(self).diagram from sage.plot.plot import Graphics from sage.plot.line import line from sage.plot.text import text From aa2abc1f7380cbaccd0c79874e6f8415a466fa5e Mon Sep 17 00:00:00 2001 From: vipul79321 Date: Wed, 20 May 2020 23:40:25 +0530 Subject: [PATCH 121/300] fixed silly mistakes --- src/sage/graphs/distances_all_pairs.pyx | 80 +++++++++++-------------- 1 file changed, 34 insertions(+), 46 deletions(-) diff --git a/src/sage/graphs/distances_all_pairs.pyx b/src/sage/graphs/distances_all_pairs.pyx index d74e194a6b3..9889815e9ac 100644 --- a/src/sage/graphs/distances_all_pairs.pyx +++ b/src/sage/graphs/distances_all_pairs.pyx @@ -1483,7 +1483,15 @@ def radius(G): sage: G = Graph(2) sage: radius(G) +Infinity + sage: G = DiGraph(1) + sage: radius(G) + Traceback (most recent call last): + ... + TypeError: This method works for unweighted undirected graphs only """ + if G.is_directed() or G.weighted(): + raise TypeError("This method works for unweighted undirected graphs only") + cdef uint32_t n = G.order() if not n or n == 1: return 0 @@ -1492,80 +1500,60 @@ def radius(G): cdef short_digraph sd init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex) - cdef list L = [] - cdef list K = [] - cdef uint32_t source = 0 + cdef uint32_t source cdef uint32_t antipode - cdef uint32_t min_L = UINT32_MAX - cdef uint32_t min_K = UINT32_MAX - cdef uint32_t next_source # To store source for next iteration + cdef uint32_t LB = UINT32_MAX + cdef uint32_t UB = UINT32_MAX + cdef uint32_t next_source = 0 # To store source for next iteration cdef MemoryAllocator mem = MemoryAllocator() cdef uint32_t * distances = mem.malloc(4 * n * sizeof(uint32_t)) if not distances: raise MemoryError() + cdef uint32_t * waiting_list = distances + n + # For storing eccentricity of nodes cdef uint32_t * ecc = distances + 2 * n + # For storing lower bound on eccentricity of nodes cdef uint32_t * ecc_lower_bound = distances + 3 * n memset(ecc_lower_bound,0,n * sizeof(uint32_t)) cdef bitset_t seen + bitset_init(seen,n) # intializing bitset - # Doing first iteration of do-while loop and intializing values - bitset_init(seen,n) # intializing bitset - ecc[source] = simple_BFS(sd, source, distances, NULL, waiting_list, seen) - - if ecc[source] == UINT32_MAX: # Disconnected graph - from sage.rings.infinity import Infinity - return +Infinity - - antipode = waiting_list[n-1] # last visited vertex in simple_BFS - - if(ecc[source] == ecc_lower_bound[source]): - return ecc[source] # Radius - - bitset_init(seen,n) # Reinitializing bitset - ecc[antipode] = simple_BFS(sd, antipode, distances, NULL, waiting_list, seen) - - L.append(antipode) - K.append(source) - min_K = min(min_K, ecc[source]) - min_L = UINT32_MAX - - for v in range(n): - ecc_lower_bound[v] = max(ecc_lower_bound[v], distances[v]) - if min_L > ecc_lower_bound[v]: - min_L = ecc_lower_bound[v] - next_source = v - - - # Now looping - while min_L < min_K: + # Algorithm + while True: source = next_source - bitset_init(seen,n) + bitset_clear(seen) ecc[source] = simple_BFS(sd, source, distances, NULL, waiting_list, seen) - antipode = waiting_list[n-1] + antipode = waiting_list[n-1] # last visited vertex in simple_BFS + + if ecc[source] == UINT32_MAX: + bitset_free(seen) + from sage.rings.infinity import Infinity + return +Infinity if(ecc[source] == ecc_lower_bound[source]): + bitset_free(seen) return ecc[source] - bitset_init(seen,n) + bitset_clear(seen) ecc[antipode] = simple_BFS(sd, antipode, distances, NULL, waiting_list, seen) - L.append(antipode) - K.append(source) - min_K = min(min_K, ecc[source]) - min_L = UINT32_MAX + UB = min(UB, ecc[source]) + LB = UINT32_MAX for v in range(n): ecc_lower_bound[v] = max(ecc_lower_bound[v], distances[v]) - if min_L > ecc_lower_bound[v]: - min_L = ecc_lower_bound[v] + if LB > ecc_lower_bound[v]: + LB = ecc_lower_bound[v] next_source = v - return min_K + if UB <= LB: + bitset_free(seen) + return UB ################ # Wiener index # From 5cc7da82b2df41e58ddc9d88a2ece78c84e11f2a Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Wed, 20 May 2020 20:36:30 +0100 Subject: [PATCH 122/300] Changed to FriezePattern --- src/sage/combinat/all.py | 2 +- src/sage/combinat/path_tableaux/all.py | 2 +- src/sage/combinat/path_tableaux/frieze.py | 71 ++++++++++++++--------- 3 files changed, 47 insertions(+), 28 deletions(-) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 16eb11ccb36..0fe8a2bbe3d 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -237,4 +237,4 @@ # Path tableaux lazy_import('sage.combinat.path_tableaux.path_tableau', ['PathTableau', 'PathTableaux', 'CylindricalDiagram']) lazy_import('sage.combinat.path_tableaux.catalan', ['CatalanTableau', 'CatalanTableaux']) -lazy_import('sage.combinat.path_tableaux.frieze', ['UnimodularFriezePattern', 'UnimodularFriezePatterns']) +lazy_import('sage.combinat.path_tableaux.frieze', ['FriezePattern', 'FriezePatterns']) diff --git a/src/sage/combinat/path_tableaux/all.py b/src/sage/combinat/path_tableaux/all.py index f8988526f70..e77957535e4 100644 --- a/src/sage/combinat/path_tableaux/all.py +++ b/src/sage/combinat/path_tableaux/all.py @@ -5,4 +5,4 @@ from .path_tableau import PathTableau, PathTableaux, CylindricalDiagram from .catalan import CatalanTableau, CatalanTableaux -from .frieze import UnimodularFriezePattern, UnimodularFriezePatterns +from .frieze import FriezePattern, FriezePatterns diff --git a/src/sage/combinat/path_tableaux/frieze.py b/src/sage/combinat/path_tableaux/frieze.py index 4ccf2f34006..7df255bd55b 100644 --- a/src/sage/combinat/path_tableaux/frieze.py +++ b/src/sage/combinat/path_tableaux/frieze.py @@ -1,5 +1,5 @@ r""" -Unimodular Frieze Patterns +Frieze Patterns This is an implementation of the abstract base class :class:`sage.combinat.pathtableau.pathtableaux`. @@ -54,7 +54,7 @@ EXAMPLES:: - sage: t = UnimodularFriezePattern([0,1,2,1,2,3,1,0]) + sage: t = FriezePattern([0,1,2,1,2,3,1,0]) sage: CylindricalDiagram(t) [0, 1, 2, 1, 2, 3, 1, 0] ['', 0, 1, 1, 3, 5, 2, 1, 0] @@ -67,7 +67,7 @@ sage: TestSuite(t).run() - sage: t = UnimodularFriezePattern([0,1,2,7,5,3,7,4,1,0]) + sage: t = FriezePattern([0,1,2,7,5,3,7,4,1,0]) sage: CylindricalDiagram(t) [0, 1, 2, 7, 5, 3, 7, 4, 1, 0] ['', 0, 1, 4, 3, 2, 5, 3, 1, 1, 0] @@ -81,7 +81,7 @@ ['', '', '', '', '', '', '', '', '', 0, 1, 2, 7, 5, 3, 7, 4, 1, 0] sage: TestSuite(t).run() - sage: t = UnimodularFriezePattern([0,1,3,4,5,1,0]) + sage: t = FriezePattern([0,1,3,4,5,1,0]) sage: CylindricalDiagram(t) [0, 1, 3, 4, 5, 1, 0] ['', 0, 1, 5/3, 7/3, 2/3, 1, 0] @@ -96,7 +96,7 @@ This constructs the examples from [TJ18]_ sage: K. = NumberField(x^2-3) - sage: t = UnimodularFriezePattern([0,1,sqrt3,2,sqrt3,1,1,0], field=K) + sage: t = FriezePattern([0,1,sqrt3,2,sqrt3,1,1,0], field=K) sage: CylindricalDiagram(t) [0, 1, sqrt3, 2, sqrt3, 1, 1, 0] ['', 0, 1, sqrt3, 2, sqrt3, sqrt3 + 1, 1, 0] @@ -110,7 +110,7 @@ sage: TestSuite(t).run() sage: K. = NumberField(x^2-2) - sage: t = UnimodularFriezePattern([0,1,sqrt2,1,sqrt2,3,2*sqrt2,5,3*sqrt2,1,0], field=K) + sage: t = FriezePattern([0,1,sqrt2,1,sqrt2,3,2*sqrt2,5,3*sqrt2,1,0], field=K) sage: CylindricalDiagram(t) [0, 1, sqrt2, 1, sqrt2, 3, 2*sqrt2, 5, 3*sqrt2, 1, 0] ['', 0, 1, sqrt2, 3, 5*sqrt2, 7, 9*sqrt2, 11, 2*sqrt2, 1, 0] @@ -127,9 +127,8 @@ sage: TestSuite(t).run() """ - @add_metaclass(InheritComparisonClasscallMetaclass) -class UnimodularFriezePattern(PathTableau): +class FriezePattern(PathTableau): """ An instance is the sequence of nonnegative integers. """ @@ -144,7 +143,7 @@ def __classcall_private__(cls, fp, field=QQ): EXAMPLES:: - sage: UnimodularFriezePattern([1,2,1,2,3,1]) + sage: FriezePattern([1,2,1,2,3,1]) [1, 2, 1, 2, 3, 1] """ @@ -159,10 +158,23 @@ def __classcall_private__(cls, fp, field=QQ): if w is None: raise ValueError("invalid input %s" % fp) - return UnimodularFriezePatterns(field)(w) + return FriezePatterns(field)(w) def check(self): + """ Checks that ``self`` is a valid frieze. + + TESTS:: + + sage: CatalanTableau([0,1,0,-1,0]) # indirect doctest + Traceback (most recent call last): + ... + ValueError: [0, 1, 0, -1, 0] has a negative entry + sage: CatalanTableau([0,1,3,1,0]) # indirect doctest + Traceback (most recent call last): + ... + ValueError: [0, 1, 3, 1, 0] is not a Dyck path + """ #n = len(self) if any(a < 0 for a in self): raise ValueError( "%s has a negative entry" % (str(self)) ) @@ -176,7 +188,7 @@ def _local_rule(self,i): EXAMPLES:: - sage: t = UnimodularFriezePattern([1,2,1,2,3,1]) + sage: t = FriezePattern([1,2,1,2,3,1]) sage: t._local_rule(3) [1, 2, 1, 2, 3, 1] """ @@ -201,10 +213,10 @@ def is_skew(self): EXAMPLES:: - sage: UnimodularFriezePattern([1,2,1,2,3,1]).is_skew() + sage: FriezePattern([1,2,1,2,3,1]).is_skew() False - sage: UnimodularFriezePattern([2,2,1,2,3,1]).is_skew() + sage: FriezePattern([2,2,1,2,3,1]).is_skew() True """ return self[0] != 1 @@ -215,10 +227,10 @@ def is_integral(self): EXAMPLES:: - sage: UnimodularFriezePattern([0,1,2,7,5,3,7,4,1,0]).is_integral() + sage: FriezePattern([0,1,2,7,5,3,7,4,1,0]).is_integral() True - sage: UnimodularFriezePattern([0,1,3,4,5,1,0]).is_integral() + sage: FriezePattern([0,1,3,4,5,1,0]).is_integral() False """ @@ -240,13 +252,13 @@ def plot(self): EXAMPLES:: - sage: UnimodularFriezePattern([0,1,2,7,5,3,7,4,1,0]).plot() + sage: FriezePattern([0,1,2,7,5,3,7,4,1,0]).plot() Graphics object consisting of 24 graphics primitives """ if not self.is_integral(): raise ValueError("{!s} must be an integral frieze".format(self)) - n = len(self) + n = len(self)+1 cd = CylindricalDiagram(self).diagram from sage.plot.plot import Graphics from sage.plot.line import line @@ -256,28 +268,35 @@ def plot(self): G = Graphics() G.set_aspect_ratio(1.0) - vt = [(cos(2*theta*pi/(n-1)), sin(2*theta*pi/(n-1))) for theta in range(n-1)] + vt = [(cos(2*theta*pi/(n)), sin(2*theta*pi/(n))) for theta in range(n+1)] for i, p in enumerate(vt): G += text(str(i),[1.05*p[0],1.05*p[1]]) for i, r in enumerate(cd): for j, a in enumerate(r[:n-1]): if a == 1: - G += line([vt[i],vt[j]]) + G += line([vt[i],vt[j+1]]) G.axes(False) return G -class UnimodularFriezePatterns(PathTableaux): - +class FriezePatterns(PathTableaux): + """ + The parent class for FriezePattern. + """ def __init__(self, field): + """ + Initializes the abstract class of all FriezePatterns - self._field = field + TESTS:: + + sage: FriezePattern([1,1]).parent() # indirect test + + + """ + self.field = field Parent.__init__(self, category=Sets()) - def field(self): - return self._field - - Element = UnimodularFriezePattern + Element = FriezePattern From 0e4685099eeab7a8abd49e1f89cc48eea50f3787 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Wed, 20 May 2020 21:12:15 +0100 Subject: [PATCH 123/300] More testing --- src/sage/combinat/path_tableaux/frieze.py | 77 ++++++++++++++--------- 1 file changed, 49 insertions(+), 28 deletions(-) diff --git a/src/sage/combinat/path_tableaux/frieze.py b/src/sage/combinat/path_tableaux/frieze.py index 7df255bd55b..1ff5314a8be 100644 --- a/src/sage/combinat/path_tableaux/frieze.py +++ b/src/sage/combinat/path_tableaux/frieze.py @@ -4,6 +4,8 @@ This is an implementation of the abstract base class :class:`sage.combinat.pathtableau.pathtableaux`. +This implements the original frieze patterns due to Conway and Coxeter. + In this implementation we have sequences of nonnegative integers. This follows [CoCo1]_ and [CoCo2]_ @@ -46,7 +48,8 @@ #from sage.combinat.combinatorial_map import combinatorial_map #from sage.combinat.tableau import Tableau, StandardTableau from sage.rings.integer import Integer -from sage.rings.all import QQ +from sage.categories.fields import Fields +from sage.rings.all import ZZ, QQ ############################################################################### @@ -130,54 +133,60 @@ @add_metaclass(InheritComparisonClasscallMetaclass) class FriezePattern(PathTableau): """ - An instance is the sequence of nonnegative integers. + An instance is a sequence in the ground field. """ @staticmethod def __classcall_private__(cls, fp, field=QQ): - """This is the preprocessing for creating paths. + """This is the preprocessing for creating friezes. INPUT: - - a sequence of nonnegative integers + - a sequence of elements of the field ''field'' EXAMPLES:: sage: FriezePattern([1,2,1,2,3,1]) [1, 2, 1, 2, 3, 1] + TESTS:: + + sage FriezePattern(2) + Traceback (most recent call last): + ... + TypeError: Unable to coerce sqrt3 to a rational + + sage: K. = NumberField(x^2-3) + sage: t = FriezePattern([0,1,sqrt3,2,sqrt3,1,1,0]) + Traceback (most recent call last): + ... + ValueError: [0, 1, sqrt3, 2, sqrt3, 1, 1, 0] is not a sequence in the field Rational Field + + sage: FriezePattern([1,2,1,2,3,1],field=ZZ) + Traceback (most recent call last): + ... + ValueError: Integer Ring must be a field """ + if not field in Fields: + raise ValueError("{} must be a field".format(field)) + w = None if isinstance(fp, (list,tuple)): try: w = tuple([field(a) for a in fp]) except TypeError: - raise ValueError("%s is not a sequence of integers" % fp) + raise ValueError("{} is not a sequence in the field {}".format(fp, field)) if w is None: - raise ValueError("invalid input %s" % fp) + raise ValueError("invalid input {}".format(fp)) return FriezePatterns(field)(w) def check(self): - """ Checks that ``self`` is a valid frieze. - - TESTS:: - - sage: CatalanTableau([0,1,0,-1,0]) # indirect doctest - Traceback (most recent call last): - ... - ValueError: [0, 1, 0, -1, 0] has a negative entry - - sage: CatalanTableau([0,1,3,1,0]) # indirect doctest - Traceback (most recent call last): - ... - ValueError: [0, 1, 3, 1, 0] is not a Dyck path """ - #n = len(self) - if any(a < 0 for a in self): - raise ValueError( "%s has a negative entry" % (str(self)) ) + There is nothing to check. + """ def _local_rule(self,i): r""" @@ -191,16 +200,22 @@ def _local_rule(self,i): sage: t = FriezePattern([1,2,1,2,3,1]) sage: t._local_rule(3) [1, 2, 1, 2, 3, 1] + + sage: t = FriezePattern([1,2,1,2,3,1]) + sage: t._local_rule(0) + Traceback (most recent call last): + ... + ValueError: 0 is not a valid integer """ def _rule(x): """ - This is the rule on a sequence of three letters. + This is the rule on a sequence of three scalars. """ return (x[0]*x[2]+1)/x[1] if not (i > 0 and i < len(self) ): - raise ValueError("%d is not a valid integer" % i) + raise ValueError("{} is not a valid integer".format(i)) with self.clone() as result: result[i] = _rule(self[i-1:i+2]) @@ -252,9 +267,15 @@ def plot(self): EXAMPLES:: - sage: FriezePattern([0,1,2,7,5,3,7,4,1,0]).plot() - Graphics object consisting of 24 graphics primitives + sage: FriezePattern([1,2,7,5,3,7,4,1]).plot() + Graphics object consisting of 25 graphics primitives + + TESTS:: + sage: FriezePattern([1,2,1/7,5,3]).plot() + Traceback (most recent call last): + ... + ValueError: [1, 2, 1/7, 5, 3] must be an integral frieze """ if not self.is_integral(): raise ValueError("{!s} must be an integral frieze".format(self)) @@ -289,10 +310,10 @@ def __init__(self, field): Initializes the abstract class of all FriezePatterns TESTS:: - + sage: FriezePattern([1,1]).parent() # indirect test - + """ self.field = field From e14a2ed775de8b352642df5b4024d6846f570964 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Wed, 20 May 2020 22:25:42 +0100 Subject: [PATCH 124/300] Tests for positivity --- src/sage/combinat/path_tableaux/frieze.py | 52 ++++++++++++++++++++--- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/path_tableaux/frieze.py b/src/sage/combinat/path_tableaux/frieze.py index 1ff5314a8be..0e06063dcc8 100644 --- a/src/sage/combinat/path_tableaux/frieze.py +++ b/src/sage/combinat/path_tableaux/frieze.py @@ -57,7 +57,7 @@ EXAMPLES:: - sage: t = FriezePattern([0,1,2,1,2,3,1,0]) + sage: t = FriezePattern([1,2,1,2,3,1]) sage: CylindricalDiagram(t) [0, 1, 2, 1, 2, 3, 1, 0] ['', 0, 1, 1, 3, 5, 2, 1, 0] @@ -70,7 +70,7 @@ sage: TestSuite(t).run() - sage: t = FriezePattern([0,1,2,7,5,3,7,4,1,0]) + sage: t = FriezePattern([1,2,7,5,3,7,4,1]) sage: CylindricalDiagram(t) [0, 1, 2, 7, 5, 3, 7, 4, 1, 0] ['', 0, 1, 4, 3, 2, 5, 3, 1, 1, 0] @@ -236,16 +236,58 @@ def is_skew(self): """ return self[0] != 1 + def width(self): + """ + Return the width of ''self''. + + If the first and last terms of 'self'are 1 then this is the length of 'self' + and otherwise is undefined. + + EXAMPLES:: + + sage: FriezePattern([1,2,1,2,3,1]).width() + 6 + + sage: FriezePattern([1,2,1,2,3,4]).width() + + + """ + if self[0] == 1 and self[-1] == 1: + return len(self) + else: + return None + + def is_positive(self): + """ + Return 'true' if all elements of ''self'' are positive. + + This implies that all entries of ''CylindricalDiagram(self)'' are positive. + + EXAMPLES:: + + sage: FriezePattern([1,2,7,5,3,7,4,1]).is_positive() + True + + sage: FriezePattern([1,-3,4,5,1]).is_positive() + False + + sage: K. = NumberField(x^2-3) + sage: FriezePattern([1,sqrt3,1],K).is_positive() + True + + """ + return all(a>0 for a in self) + def is_integral(self): r""" - Return ``True`` if all entries of the frieze pattern are positive integers and ``False`` if not. + Return ``True`` if all entries of the frieze pattern are positive integers. EXAMPLES:: - sage: FriezePattern([0,1,2,7,5,3,7,4,1,0]).is_integral() + sage: FriezePattern([1,2,7,5,3,7,4,1]).is_integral() True - sage: FriezePattern([0,1,3,4,5,1,0]).is_integral() + sage: FriezePattern([1,3,4,5,1]).is_integral() False """ From eed920e167d058b188142612a1f0b8ae670b64bd Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 20 May 2020 21:56:53 -0700 Subject: [PATCH 125/300] src/sage/tests: Move Extension options from src/module_list.py to distutils directives --- src/module_list.py | 6 +----- src/sage/tests/stl_vector.pyx | 2 ++ 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/module_list.py b/src/module_list.py index 743e83573ce..d578441d7c9 100644 --- a/src/module_list.py +++ b/src/module_list.py @@ -1411,10 +1411,6 @@ def uname_specific(name, value, alternative): ## ################################ - Extension('sage.tests.stl_vector', - sources = ['sage/tests/stl_vector.pyx'], - language = 'c++'), + Extension('*', ['sage/tests/**/*.pyx']) - Extension('sage.tests.cython', - sources = ['sage/tests/cython.pyx']), ] diff --git a/src/sage/tests/stl_vector.pyx b/src/sage/tests/stl_vector.pyx index 5eb733dacd3..f3b29b30dfe 100644 --- a/src/sage/tests/stl_vector.pyx +++ b/src/sage/tests/stl_vector.pyx @@ -1,3 +1,5 @@ +# distutils: language = c++ + """ Example of a class wrapping an STL vector From 0d25d1d82c02eb94369326ab345101799488cf9d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 20 May 2020 21:58:52 -0700 Subject: [PATCH 126/300] src/sage/structure: Move Extension options from src/module_list.py to distutils directives --- src/module_list.py | 7 ------- src/sage/structure/element.pyx | 6 ++++++ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/module_list.py b/src/module_list.py index d578441d7c9..b904c74bd48 100644 --- a/src/module_list.py +++ b/src/module_list.py @@ -1388,13 +1388,6 @@ def uname_specific(name, value, alternative): ## ################################ - # Compile this with -Os because it works around a bug with - # GCC-4.7.3 + Cython 0.19 on Itanium, see Trac #14452. Moreover, it - # actually results in faster code than -O3. - Extension('sage.structure.element', - sources = ['sage/structure/element.pyx'], - extra_compile_args=["-Os"]), - Extension('*', ['sage/structure/*.pyx']), ################################ diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index a5fbd555f2d..7e2c1cbed56 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -1,3 +1,9 @@ +# Compile this with -Os because it works around a bug with +# GCC-4.7.3 + Cython 0.19 on Itanium, see Trac #14452. Moreover, it +# actually results in faster code than -O3. +# +# distutils: extra_compile_args = -Os + r""" Elements From 808f46abbbbfcddfee56d72399ab23107301dd57 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 20 May 2020 22:01:27 -0700 Subject: [PATCH 127/300] src/sage/stats: Move Extension options from src/module_list.py to distutils directives --- src/module_list.py | 20 +------------------ .../discrete_gaussian_integer.pyx | 5 +++++ 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/src/module_list.py b/src/module_list.py index b904c74bd48..6939eaab87e 100644 --- a/src/module_list.py +++ b/src/module_list.py @@ -1362,25 +1362,7 @@ def uname_specific(name, value, alternative): ## ################################ - Extension('sage.stats.hmm.util', - sources = ['sage/stats/hmm/util.pyx']), - - Extension('sage.stats.hmm.distributions', - sources = ['sage/stats/hmm/distributions.pyx']), - - Extension('sage.stats.hmm.hmm', - sources = ['sage/stats/hmm/hmm.pyx']), - - Extension('sage.stats.hmm.chmm', - sources = ['sage/stats/hmm/chmm.pyx']), - - Extension('sage.stats.intlist', - sources = ['sage/stats/intlist.pyx']), - - Extension('sage.stats.distributions.discrete_gaussian_integer', - sources = ['sage/stats/distributions/discrete_gaussian_integer.pyx', 'sage/stats/distributions/dgs_gauss_mp.c', 'sage/stats/distributions/dgs_gauss_dp.c', 'sage/stats/distributions/dgs_bern.c'], - depends = ['sage/stats/distributions/dgs_gauss.h', 'sage/stats/distributions/dgs_bern.h', 'sage/stats/distributions/dgs_misc.h'], - extra_compile_args = ["-D_XOPEN_SOURCE=600"]), + Extension('*', ['sage/stats/**/*.pyx']), ################################ ## diff --git a/src/sage/stats/distributions/discrete_gaussian_integer.pyx b/src/sage/stats/distributions/discrete_gaussian_integer.pyx index ac0804b0584..2906b660802 100644 --- a/src/sage/stats/distributions/discrete_gaussian_integer.pyx +++ b/src/sage/stats/distributions/discrete_gaussian_integer.pyx @@ -1,4 +1,9 @@ # -*- coding: utf-8 -*- +# +# distutils: sources = sage/stats/distributions/discrete_gaussian_integer.pyx sage/stats/distributions/dgs_gauss_mp.c sage/stats/distributions/dgs_gauss_dp.c sage/stats/distributions/dgs_bern.c +# distutils: depends = sage/stats/distributions/dgs_gauss.h sage/stats/distributions/dgs_bern.h sage/stats/distributions/dgs_misc.h +# distutils: extra_compile_args = -D_XOPEN_SOURCE=600 + r""" Discrete Gaussian Samplers over the Integers From 10f754224ab62457353dc4385468ef47af413db5 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 20 May 2020 22:06:48 -0700 Subject: [PATCH 128/300] src/sage/schemes: Move Extension options from src/module_list.py to distutils directives --- src/module_list.py | 26 +------------------ .../elliptic_curves/descent_two_isogeny.pyx | 2 ++ .../hyperelliptic_curves/hypellfrob.pyx | 6 +++++ 3 files changed, 9 insertions(+), 25 deletions(-) diff --git a/src/module_list.py b/src/module_list.py index 6939eaab87e..f4b1e599c02 100644 --- a/src/module_list.py +++ b/src/module_list.py @@ -1322,31 +1322,7 @@ def uname_specific(name, value, alternative): ## ################################ - Extension('sage.schemes.elliptic_curves.descent_two_isogeny', - sources = ['sage/schemes/elliptic_curves/descent_two_isogeny.pyx'], - libraries = ['ratpoints']), - - Extension('sage.schemes.elliptic_curves.period_lattice_region', - sources = ['sage/schemes/elliptic_curves/period_lattice_region.pyx']), - - Extension('sage.schemes.elliptic_curves.mod_sym_num', - sources = ['sage/schemes/elliptic_curves/mod_sym_num.pyx']), - - Extension('sage.schemes.hyperelliptic_curves.hypellfrob', - sources = ['sage/schemes/hyperelliptic_curves/hypellfrob.pyx', - 'sage/schemes/hyperelliptic_curves/hypellfrob/hypellfrob.cpp', - 'sage/schemes/hyperelliptic_curves/hypellfrob/recurrences_ntl.cpp', - 'sage/schemes/hyperelliptic_curves/hypellfrob/recurrences_zn_poly.cpp'], - libraries = ['gmp', 'ntl', 'zn_poly'], - depends = ['sage/schemes/hyperelliptic_curves/hypellfrob/hypellfrob.h', - 'sage/schemes/hyperelliptic_curves/hypellfrob/recurrences_ntl.h', - 'sage/schemes/hyperelliptic_curves/hypellfrob/recurrences_zn_poly.h'], - language = 'c++', - include_dirs = ['sage/libs/ntl/', - 'sage/schemes/hyperelliptic_curves/hypellfrob/']), - - Extension('sage.schemes.toric.divisor_class', - sources = ['sage/schemes/toric/divisor_class.pyx']), + Extension('*', ['sage/schemes/**/*.pyx']), ################################ ## diff --git a/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx b/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx index e95cd49c88c..3868c0a73b7 100644 --- a/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx +++ b/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx @@ -1,3 +1,5 @@ +# distutils: libraries = ratpoints + r""" Descent on elliptic curves over `\QQ` with a 2-isogeny """ diff --git a/src/sage/schemes/hyperelliptic_curves/hypellfrob.pyx b/src/sage/schemes/hyperelliptic_curves/hypellfrob.pyx index 810f41c767d..1bbba251032 100644 --- a/src/sage/schemes/hyperelliptic_curves/hypellfrob.pyx +++ b/src/sage/schemes/hyperelliptic_curves/hypellfrob.pyx @@ -1,3 +1,9 @@ +# distutils: language = c++ +# distutils: sources = sage/schemes/hyperelliptic_curves/hypellfrob.pyx sage/schemes/hyperelliptic_curves/hypellfrob/hypellfrob.cpp sage/schemes/hyperelliptic_curves/hypellfrob/recurrences_ntl.cpp sage/schemes/hyperelliptic_curves/hypellfrob/recurrences_zn_poly.cpp +# distutils: depends = sage/schemes/hyperelliptic_curves/hypellfrob/hypellfrob.h sage/schemes/hyperelliptic_curves/hypellfrob/recurrences_ntl.h sage/schemes/hyperelliptic_curves/hypellfrob/recurrences_zn_poly.h +# distutils: include_dirs = sage/libs/ntl/ sage/schemes/hyperelliptic_curves/hypellfrob/ +# distutils: libraries = gmp ntl zn_poly + r""" Frobenius on Monsky-Washnitzer cohomology of a hyperelliptic curve over a largish prime finite field From 870170502124a52fbcf32b85c6a32d4e2b876edb Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Thu, 21 May 2020 10:16:17 +0100 Subject: [PATCH 129/300] Added show method --- src/sage/combinat/path_tableaux/frieze.py | 54 ++++++++++++++++++----- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/src/sage/combinat/path_tableaux/frieze.py b/src/sage/combinat/path_tableaux/frieze.py index 0e06063dcc8..948984f9e9a 100644 --- a/src/sage/combinat/path_tableaux/frieze.py +++ b/src/sage/combinat/path_tableaux/frieze.py @@ -43,13 +43,12 @@ from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.structure.parent import Parent from sage.categories.sets_cat import Sets -#from sage.structure.list_clone import ClonableArray from sage.combinat.path_tableaux.path_tableau import PathTableau, PathTableaux, CylindricalDiagram -#from sage.combinat.combinatorial_map import combinatorial_map -#from sage.combinat.tableau import Tableau, StandardTableau from sage.rings.integer import Integer from sage.categories.fields import Fields -from sage.rings.all import ZZ, QQ +from sage.rings.all import ZZ, QQ # ZZ used in testing +from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane +from sage.plot.all import Graphics ############################################################################### @@ -57,7 +56,7 @@ EXAMPLES:: - sage: t = FriezePattern([1,2,1,2,3,1]) + sage: t = FriezePattern([0,1,2,1,2,3,1,0]) sage: CylindricalDiagram(t) [0, 1, 2, 1, 2, 3, 1, 0] ['', 0, 1, 1, 3, 5, 2, 1, 0] @@ -70,7 +69,7 @@ sage: TestSuite(t).run() - sage: t = FriezePattern([1,2,7,5,3,7,4,1]) + sage: t = FriezePattern([0,1,2,7,5,3,7,4,1,0]) sage: CylindricalDiagram(t) [0, 1, 2, 7, 5, 3, 7, 4, 1, 0] ['', 0, 1, 4, 3, 2, 5, 3, 1, 1, 0] @@ -222,6 +221,18 @@ def _rule(x): return result + def size(self): + r""" + Return the size or length of ``self``. + + EXAMPLES:: + + sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t.size() + 7 + """ + return len(self)+2 + def is_skew(self): r""" Return ``True`` if ``self`` is skew and ``False`` if not. @@ -263,6 +274,10 @@ def is_positive(self): This implies that all entries of ''CylindricalDiagram(self)'' are positive. + Warning: There are orders on all fields. These may not be ordered fields + as they may not be compatible with the field operations. This method is + intended to be used with ordered fields only. + EXAMPLES:: sage: FriezePattern([1,2,7,5,3,7,4,1]).is_positive() @@ -303,18 +318,18 @@ def is_integral(self): return False return True - def plot(self): + def triangulation(self): r""" If ``self`` is integral then plot the triangulation. EXAMPLES:: - sage: FriezePattern([1,2,7,5,3,7,4,1]).plot() + sage: FriezePattern([1,2,7,5,3,7,4,1]).triangulation() Graphics object consisting of 25 graphics primitives TESTS:: - sage: FriezePattern([1,2,1/7,5,3]).plot() + sage: FriezePattern([1,2,1/7,5,3]).triangulation() Traceback (most recent call last): ... ValueError: [1, 2, 1/7, 5, 3] must be an integral frieze @@ -343,13 +358,32 @@ def plot(self): G.axes(False) return G + def show(self): + """ + Plot the frieze as an ideal hyperbolic polygon. + + This is only defined up to isometry of the hyperbolic plane. + + We are identifying the boundary of the hyperbolic plane with the + real projective line. + """ + U = HyperbolicPlane().UHP() + cd = CylindricalDiagram(self).diagram + num = cd[0] + den = cd[1] + num.append(0) + den[0] = 0 + vt = [ x/(x+y) for x,y in zip(num,den) ] + gd = [ U.get_geodesic(vt[i-1],vt[i]) for i in range(len(vt))] + return sum([a.plot() for a in gd],Graphics()) + class FriezePatterns(PathTableaux): """ The parent class for FriezePattern. """ def __init__(self, field): """ - Initializes the abstract class of all FriezePatterns + Initializes the class of all FriezePatterns TESTS:: From 636639bdc29d0aa0e55d2c09a5d6352503a1e20b Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Thu, 21 May 2020 13:31:44 +0100 Subject: [PATCH 130/300] Padded with zeroes --- src/sage/combinat/path_tableaux/frieze.py | 105 +++++++++++------- .../combinat/path_tableaux/path_tableau.py | 4 +- 2 files changed, 66 insertions(+), 43 deletions(-) diff --git a/src/sage/combinat/path_tableaux/frieze.py b/src/sage/combinat/path_tableaux/frieze.py index 948984f9e9a..5aef4555817 100644 --- a/src/sage/combinat/path_tableaux/frieze.py +++ b/src/sage/combinat/path_tableaux/frieze.py @@ -56,7 +56,7 @@ EXAMPLES:: - sage: t = FriezePattern([0,1,2,1,2,3,1,0]) + sage: t = FriezePattern([1,2,1,2,3,1]) sage: CylindricalDiagram(t) [0, 1, 2, 1, 2, 3, 1, 0] ['', 0, 1, 1, 3, 5, 2, 1, 0] @@ -69,7 +69,7 @@ sage: TestSuite(t).run() - sage: t = FriezePattern([0,1,2,7,5,3,7,4,1,0]) + sage: t = FriezePattern([1,2,7,5,3,7,4,1]) sage: CylindricalDiagram(t) [0, 1, 2, 7, 5, 3, 7, 4, 1, 0] ['', 0, 1, 4, 3, 2, 5, 3, 1, 1, 0] @@ -81,9 +81,10 @@ ['', '', '', '', '', '', '', 0, 1, 4, 3, 2, 5, 3, 1, 1, 0] ['', '', '', '', '', '', '', '', 0, 1, 1, 1, 3, 2, 1, 2, 1, 0] ['', '', '', '', '', '', '', '', '', 0, 1, 2, 7, 5, 3, 7, 4, 1, 0] - sage: TestSuite(t).run() - sage: t = FriezePattern([0,1,3,4,5,1,0]) + sage: TestSuite(t).run() + + sage: t = FriezePattern([1,3,4,5,1]) sage: CylindricalDiagram(t) [0, 1, 3, 4, 5, 1, 0] ['', 0, 1, 5/3, 7/3, 2/3, 1, 0] @@ -98,7 +99,7 @@ This constructs the examples from [TJ18]_ sage: K. = NumberField(x^2-3) - sage: t = FriezePattern([0,1,sqrt3,2,sqrt3,1,1,0], field=K) + sage: t = FriezePattern([1,sqrt3,2,sqrt3,1,1], field=K) sage: CylindricalDiagram(t) [0, 1, sqrt3, 2, sqrt3, 1, 1, 0] ['', 0, 1, sqrt3, 2, sqrt3, sqrt3 + 1, 1, 0] @@ -112,7 +113,7 @@ sage: TestSuite(t).run() sage: K. = NumberField(x^2-2) - sage: t = FriezePattern([0,1,sqrt2,1,sqrt2,3,2*sqrt2,5,3*sqrt2,1,0], field=K) + sage: t = FriezePattern([1,sqrt2,1,sqrt2,3,2*sqrt2,5,3*sqrt2,1], field=K) sage: CylindricalDiagram(t) [0, 1, sqrt2, 1, sqrt2, 3, 2*sqrt2, 5, 3*sqrt2, 1, 0] ['', 0, 1, sqrt2, 3, 5*sqrt2, 7, 9*sqrt2, 11, 2*sqrt2, 1, 0] @@ -146,7 +147,7 @@ def __classcall_private__(cls, fp, field=QQ): EXAMPLES:: sage: FriezePattern([1,2,1,2,3,1]) - [1, 2, 1, 2, 3, 1] + [0, 1, 2, 1, 2, 3, 1, 0] TESTS:: @@ -156,10 +157,10 @@ def __classcall_private__(cls, fp, field=QQ): TypeError: Unable to coerce sqrt3 to a rational sage: K. = NumberField(x^2-3) - sage: t = FriezePattern([0,1,sqrt3,2,sqrt3,1,1,0]) + sage: t = FriezePattern([1,sqrt3,2,sqrt3,1,1]) Traceback (most recent call last): ... - ValueError: [0, 1, sqrt3, 2, sqrt3, 1, 1, 0] is not a sequence in the field Rational Field + ValueError: [1, sqrt3, 2, sqrt3, 1, 1] is not a sequence in the field Rational Field sage: FriezePattern([1,2,1,2,3,1],field=ZZ) Traceback (most recent call last): @@ -173,14 +174,16 @@ def __classcall_private__(cls, fp, field=QQ): if isinstance(fp, (list,tuple)): try: - w = tuple([field(a) for a in fp]) + w = [field(a) for a in fp] except TypeError: raise ValueError("{} is not a sequence in the field {}".format(fp, field)) if w is None: raise ValueError("invalid input {}".format(fp)) - return FriezePatterns(field)(w) + w.insert(0,field(0)) + w.append(field(0)) + return FriezePatterns(field)(tuple(w)) def check(self): """ @@ -198,7 +201,7 @@ def _local_rule(self,i): sage: t = FriezePattern([1,2,1,2,3,1]) sage: t._local_rule(3) - [1, 2, 1, 2, 3, 1] + [0, 1, 2, 5, 2, 3, 1, 0] sage: t = FriezePattern([1,2,1,2,3,1]) sage: t._local_rule(0) @@ -213,7 +216,7 @@ def _rule(x): """ return (x[0]*x[2]+1)/x[1] - if not (i > 0 and i < len(self) ): + if not (i > 0 and i < len(self)-1 ): raise ValueError("{} is not a valid integer".format(i)) with self.clone() as result: @@ -221,18 +224,6 @@ def _rule(x): return result - def size(self): - r""" - Return the size or length of ``self``. - - EXAMPLES:: - - sage: t = CatalanTableau([0,1,2,3,2,1,0]) - sage: t.size() - 7 - """ - return len(self)+2 - def is_skew(self): r""" Return ``True`` if ``self`` is skew and ``False`` if not. @@ -245,25 +236,25 @@ def is_skew(self): sage: FriezePattern([2,2,1,2,3,1]).is_skew() True """ - return self[0] != 1 + return self[1] != 1 def width(self): """ Return the width of ''self''. If the first and last terms of 'self'are 1 then this is the length of 'self' - and otherwise is undefined. + plus two and otherwise is undefined. EXAMPLES:: sage: FriezePattern([1,2,1,2,3,1]).width() - 6 + 8 sage: FriezePattern([1,2,1,2,3,4]).width() """ - if self[0] == 1 and self[-1] == 1: + if self[1] == 1 and self[-2] == 1: return len(self) else: return None @@ -291,7 +282,7 @@ def is_positive(self): True """ - return all(a>0 for a in self) + return all(a>0 for a in self[1:-1]) def is_integral(self): r""" @@ -314,8 +305,7 @@ def is_integral(self): v = [ Integer(k) for k in v ] except TypeError: return False - if any(k <= 0 for k in v): - return False + return True def triangulation(self): @@ -325,14 +315,14 @@ def triangulation(self): EXAMPLES:: sage: FriezePattern([1,2,7,5,3,7,4,1]).triangulation() - Graphics object consisting of 25 graphics primitives + Graphics object consisting of 29 graphics primitives TESTS:: sage: FriezePattern([1,2,1/7,5,3]).triangulation() Traceback (most recent call last): ... - ValueError: [1, 2, 1/7, 5, 3] must be an integral frieze + ValueError: [0, 1, 2, 1/7, 5, 3, 0] must be an integral frieze """ if not self.is_integral(): raise ValueError("{!s} must be an integral frieze".format(self)) @@ -358,7 +348,7 @@ def triangulation(self): G.axes(False) return G - def show(self): + def show(self,model='UHP'): """ Plot the frieze as an ideal hyperbolic polygon. @@ -366,15 +356,48 @@ def show(self): We are identifying the boundary of the hyperbolic plane with the real projective line. + + The option ''model'' must be one of + + * UHP, for the upper half plane model + * PD, for the Poincare disk model + * KM, for the Klein model + + The hyperboloid model is not an option as this does not implement + boundary points. + + This can be omitted in which case it is taken to be UHP. + + EXAMPLES:: + + sage: t = FriezePattern([1,2,7,5,3,7,4,1]) + sage: t.show() + Graphics object consisting of 18 graphics primitives + sage: t.show(model='UHP') + Graphics object consisting of 18 graphics primitives + sage: t.show(model='PD') + Traceback (most recent call last): + ... + TypeError: '>' not supported between instances of 'NotANumber' and 'Pi' + sage: t.show(model='KM') + Graphics object consisting of 18 graphics primitives + """ + models = { + 'UHP' : HyperbolicPlane().UHP(), + 'PD' : HyperbolicPlane().PD(), + 'KM' : HyperbolicPlane().KM(), + } + M = models.get(model) + if not M: + raise ValueError("{!s} must be one of ''UHP'', ''PD'', ''KM''".format(model)) + U = HyperbolicPlane().UHP() cd = CylindricalDiagram(self).diagram - num = cd[0] - den = cd[1] - num.append(0) - den[0] = 0 - vt = [ x/(x+y) for x,y in zip(num,den) ] - gd = [ U.get_geodesic(vt[i-1],vt[i]) for i in range(len(vt))] + num = cd[0][:-1] + den = cd[1][2:] + vt = [ M(U.get_point(x/(x+y))) for x,y in zip(num,den) ] + gd = [ M.get_geodesic(vt[i-1],vt[i]) for i in range(len(vt))] return sum([a.plot() for a in gd],Graphics()) class FriezePatterns(PathTableaux): diff --git a/src/sage/combinat/path_tableaux/path_tableau.py b/src/sage/combinat/path_tableaux/path_tableau.py index 8a5f21b9f77..c6fc0968986 100644 --- a/src/sage/combinat/path_tableaux/path_tableau.py +++ b/src/sage/combinat/path_tableaux/path_tableau.py @@ -143,7 +143,7 @@ def evacuation(self): T = self L = list(T) result = [] - for i in range(len(self)): + for i in range(self.size()): T = self.parent()(L).promotion() L = list(T) result.append( L.pop() ) @@ -194,7 +194,7 @@ def commutor(self,other,verbose=False): ... ValueError: [0, 1, 2, 3, 2, 1],[0, 1, 2, 1, 0] is not a composable pair """ - n = len(self) + n = self.size() m = len(other) if n == 0 or m == 0: raise ValueError("this requires nonempty lists") From 05b3546aee289f4fc8188439db8064fcedd5647b Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Thu, 21 May 2020 13:40:22 +0100 Subject: [PATCH 131/300] Removed leading and trailing zeroes from representation --- src/sage/combinat/path_tableaux/frieze.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/path_tableaux/frieze.py b/src/sage/combinat/path_tableaux/frieze.py index 5aef4555817..e78a04796d5 100644 --- a/src/sage/combinat/path_tableaux/frieze.py +++ b/src/sage/combinat/path_tableaux/frieze.py @@ -147,7 +147,7 @@ def __classcall_private__(cls, fp, field=QQ): EXAMPLES:: sage: FriezePattern([1,2,1,2,3,1]) - [0, 1, 2, 1, 2, 3, 1, 0] + [1, 2, 1, 2, 3, 1] TESTS:: @@ -190,6 +190,15 @@ def check(self): There is nothing to check. """ + def _repr_(self): + """ + The representation of ''self''. + + TESTS:: + + """ + return (self[1:-1]).__repr__() + def _local_rule(self,i): r""" This has input a list of objects. This method first takes @@ -201,7 +210,7 @@ def _local_rule(self,i): sage: t = FriezePattern([1,2,1,2,3,1]) sage: t._local_rule(3) - [0, 1, 2, 5, 2, 3, 1, 0] + [1, 2, 5, 2, 3, 1] sage: t = FriezePattern([1,2,1,2,3,1]) sage: t._local_rule(0) @@ -322,7 +331,7 @@ def triangulation(self): sage: FriezePattern([1,2,1/7,5,3]).triangulation() Traceback (most recent call last): ... - ValueError: [0, 1, 2, 1/7, 5, 3, 0] must be an integral frieze + ValueError: [1, 2, 1/7, 5, 3] must be an integral frieze """ if not self.is_integral(): raise ValueError("{!s} must be an integral frieze".format(self)) From 8c30025a0c4fac545ff614384cd35d616e097066 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Thu, 21 May 2020 14:48:59 +0100 Subject: [PATCH 132/300] Minor edits --- src/sage/combinat/path_tableaux/frieze.py | 48 +++++++++++++++-------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/src/sage/combinat/path_tableaux/frieze.py b/src/sage/combinat/path_tableaux/frieze.py index e78a04796d5..7437a854c6e 100644 --- a/src/sage/combinat/path_tableaux/frieze.py +++ b/src/sage/combinat/path_tableaux/frieze.py @@ -46,7 +46,7 @@ from sage.combinat.path_tableaux.path_tableau import PathTableau, PathTableaux, CylindricalDiagram from sage.rings.integer import Integer from sage.categories.fields import Fields -from sage.rings.all import ZZ, QQ # ZZ used in testing +from sage.rings.all import QQ from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane from sage.plot.all import Graphics @@ -151,10 +151,10 @@ def __classcall_private__(cls, fp, field=QQ): TESTS:: - sage FriezePattern(2) + sage: FriezePattern(2) Traceback (most recent call last): ... - TypeError: Unable to coerce sqrt3 to a rational + ValueError: invalid input 2 sage: K. = NumberField(x^2-3) sage: t = FriezePattern([1,sqrt3,2,sqrt3,1,1]) @@ -162,7 +162,7 @@ def __classcall_private__(cls, fp, field=QQ): ... ValueError: [1, sqrt3, 2, sqrt3, 1, 1] is not a sequence in the field Rational Field - sage: FriezePattern([1,2,1,2,3,1],field=ZZ) + sage: FriezePattern([1,2,1,2,3,1],field=Integers()) Traceback (most recent call last): ... ValueError: Integer Ring must be a field @@ -188,17 +188,31 @@ def __classcall_private__(cls, fp, field=QQ): def check(self): """ There is nothing to check. + + TESTS:: + + sage: FriezePattern([1,2,1,2,3,1]) # indirect test + [1, 2, 1, 2, 3, 1] + """ def _repr_(self): """ The representation of ''self''. + This overides the iherited method. + + This removes the leading and trailing zero. + TESTS:: + sage: t = FriezePattern([1,2,1,2,3,1]) + sage: repr(t) == t._repr_() # indirect test + True """ return (self[1:-1]).__repr__() + def _local_rule(self,i): r""" This has input a list of objects. This method first takes @@ -319,23 +333,24 @@ def is_integral(self): def triangulation(self): r""" - If ``self`` is integral then plot the triangulation. + Plot a regular polygon with some diagonals. + + If ''self'' is positive and integral then this will be a triangulation. EXAMPLES:: sage: FriezePattern([1,2,7,5,3,7,4,1]).triangulation() - Graphics object consisting of 29 graphics primitives - - TESTS:: + Graphics object consisting of 25 graphics primitives sage: FriezePattern([1,2,1/7,5,3]).triangulation() - Traceback (most recent call last): - ... - ValueError: [1, 2, 1/7, 5, 3] must be an integral frieze + Graphics object consisting of 12 graphics primitives + + sage: K. = NumberField(x^2-2) + sage: FriezePattern([1,sqrt2,1,sqrt2,3,2*sqrt2,5,3*sqrt2,1], field=K).triangulation() + Graphics object consisting of 24 graphics primitives + """ - if not self.is_integral(): - raise ValueError("{!s} must be an integral frieze".format(self)) - n = len(self)+1 + n = len(self)-1 cd = CylindricalDiagram(self).diagram from sage.plot.plot import Graphics from sage.plot.line import line @@ -350,9 +365,9 @@ def triangulation(self): G += text(str(i),[1.05*p[0],1.05*p[1]]) for i, r in enumerate(cd): - for j, a in enumerate(r[:n-1]): + for j, a in enumerate(r[:n]): if a == 1: - G += line([vt[i],vt[j+1]]) + G += line([vt[i],vt[j]]) G.axes(False) return G @@ -428,4 +443,3 @@ def __init__(self, field): Parent.__init__(self, category=Sets()) Element = FriezePattern - From b86ae754ade5a1b5ad7afcdc684d5d0a6485c52f Mon Sep 17 00:00:00 2001 From: vipul79321 Date: Thu, 21 May 2020 23:42:45 +0530 Subject: [PATCH 133/300] comments updated --- src/sage/graphs/distances_all_pairs.pyx | 31 +++++++++++++++---------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/sage/graphs/distances_all_pairs.pyx b/src/sage/graphs/distances_all_pairs.pyx index 9889815e9ac..c4ca5a9aeef 100644 --- a/src/sage/graphs/distances_all_pairs.pyx +++ b/src/sage/graphs/distances_all_pairs.pyx @@ -1468,9 +1468,9 @@ def radius(G): sage: G = graphs.PetersenGraph() sage: radius(G) 2 - sage: G = graphs.RandomGNP(100,0.6) - sage: radius(G) - 2 + sage: G = graphs.RandomGNP(20,0.3) + sage: radius(G) == G.radius() + True TESTS: @@ -1493,7 +1493,7 @@ def radius(G): raise TypeError("This method works for unweighted undirected graphs only") cdef uint32_t n = G.order() - if not n or n == 1: + if n <= 1: return 0 cdef list int_to_vertex = list(G) @@ -1504,7 +1504,7 @@ def radius(G): cdef uint32_t antipode cdef uint32_t LB = UINT32_MAX cdef uint32_t UB = UINT32_MAX - cdef uint32_t next_source = 0 # To store source for next iteration + cdef uint32_t next_source = 0 # To store source for next iteration cdef MemoryAllocator mem = MemoryAllocator() cdef uint32_t * distances = mem.malloc(4 * n * sizeof(uint32_t)) @@ -1518,38 +1518,45 @@ def radius(G): # For storing lower bound on eccentricity of nodes cdef uint32_t * ecc_lower_bound = distances + 3 * n - memset(ecc_lower_bound,0,n * sizeof(uint32_t)) + memset(ecc_lower_bound, 0, n * sizeof(uint32_t)) cdef bitset_t seen - bitset_init(seen,n) # intializing bitset + bitset_init(seen,n) # intializing bitset # Algorithm while True: + # 1) pick vertex with minimum eccentricity lower bound + # and compute its eccentricity source = next_source bitset_clear(seen) ecc[source] = simple_BFS(sd, source, distances, NULL, waiting_list, seen) - antipode = waiting_list[n-1] # last visited vertex in simple_BFS - if ecc[source] == UINT32_MAX: + if ecc[source] == UINT32_MAX: # Disconnected graph bitset_free(seen) from sage.rings.infinity import Infinity return +Infinity - if(ecc[source] == ecc_lower_bound[source]): + if ecc[source] == ecc_lower_bound[source]: + # we have found minimum eccentricity vertex and hence the radius bitset_free(seen) return ecc[source] + # 2) Take vertex at largest distance from source, called antipode + # Compute its BFS distances + antipode = waiting_list[n-1] # last visited vertex in simple_BFS bitset_clear(seen) ecc[antipode] = simple_BFS(sd, antipode, distances, NULL, waiting_list, seen) - UB = min(UB, ecc[source]) + UB = min(UB, ecc[source]) # minimum among exact computed eccentricities LB = UINT32_MAX + # 3) Use BFS distances from antipode + # to improve eccentricity lower bounds for v in range(n): ecc_lower_bound[v] = max(ecc_lower_bound[v], distances[v]) if LB > ecc_lower_bound[v]: LB = ecc_lower_bound[v] - next_source = v + next_source = v # vertex with minimum eccentricity lower bound if UB <= LB: bitset_free(seen) From d258e4913aeb5225b8dd253ce63ac6b52f588a08 Mon Sep 17 00:00:00 2001 From: Timo Kaufmann Date: Mon, 9 Dec 2019 10:29:20 +0100 Subject: [PATCH 134/300] Make docbuild merging compatible with spinx 2.1 The attributes "todo_all_todos" and "citations" were previously implicitly initialized by sphinx. That changed in sphinx 2.1 due to some refactoring: https://github.com/sphinx-doc/sphinx/commit/9abb4820b18201f63d77fdccb4ef394a21442f7a https://github.com/sphinx-doc/sphinx/commit/885d35e374b56d1d17f5036fe07b74229cdbec7f So now we need to check for the case where they are not initialized yet. We can't actually update to sphinx 2.1 yet, since its python3 only. This is mostly intended to make things easier for distros and allow us to update in the future. --- src/sage_setup/docbuild/ext/multidocs.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/sage_setup/docbuild/ext/multidocs.py b/src/sage_setup/docbuild/ext/multidocs.py index 71a08cd9379..3a3d09ab591 100644 --- a/src/sage_setup/docbuild/ext/multidocs.py +++ b/src/sage_setup/docbuild/ext/multidocs.py @@ -47,24 +47,30 @@ def merge_environment(app, env): - domaindata['py']['modules'] # list of python modules """ logger.info(bold('Merging environment/index files...')) + if not hasattr(env, "todo_all_todos"): + env.todo_all_todos = [] + if not hasattr(env.domaindata["std"], "citations"): + env.domaindata["std"]["citations"] = dict() for curdoc in app.env.config.multidocs_subdoc_list: logger.info(" %s:"%curdoc, nonl=1) docenv = get_env(app, curdoc) if docenv is not None: fixpath = lambda path: os.path.join(curdoc, path) + todos = docenv.todo_all_todos if hasattr(docenv, "todo_all_todos") else [] + citations = docenv.domaindata["std"].get("citations", dict()) logger.info(" %s todos, %s index, %s citations"%( - len(docenv.todo_all_todos), + len(todos), len(docenv.indexentries), - len(docenv.domaindata["std"]["citations"]) + len(citations) ), nonl=1) # merge titles for t in docenv.titles: env.titles[fixpath(t)] = docenv.titles[t] # merge the todo links - for dct in docenv.todo_all_todos: + for dct in todos: dct['docname'] = fixpath(dct['docname']) - env.todo_all_todos += docenv.todo_all_todos + env.todo_all_todos += todos # merge the html index links newindex = {} for ind in docenv.indexentries: @@ -86,8 +92,7 @@ def merge_environment(app, env): env.metadata[ind] = md # merge the citations newcite = {} - citations = docenv.domaindata["std"]["citations"] - for ind, (path, tag, lineno) in six.iteritems(docenv.domaindata["std"]["citations"]): + for ind, (path, tag, lineno) in six.iteritems(citations): # TODO: Warn on conflicts newcite[ind] = (fixpath(path), tag, lineno) env.domaindata["std"]["citations"].update(newcite) @@ -253,7 +258,7 @@ def fetch_citation(app, env): with open(filename, 'rb') as f: cache = cPickle.load(f) logger.info("done (%s citations)."%len(cache)) - cite = env.domaindata["std"]["citations"] + cite = env.domaindata["std"].get("citations", dict()) for ind, (path, tag, lineno) in six.iteritems(cache): if ind not in cite: # don't override local citation cite[ind] = (os.path.join("..", path), tag, lineno) From ba588dafd926fe9d6d42950d9047e0fdabf6f4cf Mon Sep 17 00:00:00 2001 From: Antonio Rojas Date: Sun, 19 Apr 2020 12:01:46 +0200 Subject: [PATCH 135/300] Normalize intersphinx mappings --- src/sage/docs/conf.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sage/docs/conf.py b/src/sage/docs/conf.py index a1212f5839d..a420990abba 100644 --- a/src/sage/docs/conf.py +++ b/src/sage/docs/conf.py @@ -8,6 +8,7 @@ from docutils.transforms import Transform from sphinx.ext.doctest import blankline_re from sphinx import highlighting +import sphinx.ext.intersphinx as intersphinx from IPython.lib.lexers import IPythonConsoleLexer, IPyLexer # If your extensions are in another directory, add it here. @@ -173,13 +174,8 @@ def sphinx_plot(graphics, **kwds): # Cross-links to other project's online documentation. python_version = sys.version_info.major -intersphinx_mapping = { - 'python': ('https://docs.python.org/', - os.path.join(SAGE_DOC_SRC, "common", - "python{}.inv".format(python_version))), - 'pplpy': (PPLPY_DOCS, None)} -def set_intersphinx_mappings(app): +def set_intersphinx_mappings(app, config): """ Add precompiled inventory (the objects.inv) """ @@ -190,7 +186,11 @@ def set_intersphinx_mappings(app): app.config.intersphinx_mapping = {} return - app.config.intersphinx_mapping = intersphinx_mapping + app.config.intersphinx_mapping = { + 'python': ('https://docs.python.org/', + os.path.join(SAGE_DOC_SRC, "common", + "python{}.inv".format(python_version))), + 'pplpy': (PPLPY_DOCS, None)} # Add master intersphinx mapping dst = os.path.join(invpath, 'objects.inv') @@ -205,6 +205,7 @@ def set_intersphinx_mappings(app): dst = os.path.join(invpath, directory, 'objects.inv') app.config.intersphinx_mapping[src] = dst + intersphinx.normalize_intersphinx_mapping(app, config) # By default document are not master. multidocs_is_master = True @@ -673,7 +674,7 @@ def call_intersphinx(app, env, node, contnode): """ debug_inf(app, "???? Trying intersphinx for %s" % node['reftarget']) builder = app.builder - res = sphinx.ext.intersphinx.missing_reference( + res = intersphinx.missing_reference( app, env, node, contnode) if res: # Replace absolute links to $SAGE_DOC by relative links: this @@ -856,11 +857,10 @@ def setup(app): if app.srcdir.startswith(SAGE_DOC_SRC): app.add_config_value('intersphinx_mapping', {}, False) app.add_config_value('intersphinx_cache_limit', 5, False) + app.connect('config-inited', set_intersphinx_mappings) + app.connect('builder-inited', intersphinx.load_mappings) # We do *not* fully initialize intersphinx since we call it by hand # in find_sage_dangling_links. # app.connect('missing-reference', missing_reference) app.connect('missing-reference', find_sage_dangling_links) - import sphinx.ext.intersphinx - app.connect('builder-inited', set_intersphinx_mappings) - app.connect('builder-inited', sphinx.ext.intersphinx.load_mappings) app.connect('builder-inited', nitpick_patch_config) From 36da5ea59c5a9abb532d3b2f9133ab6b1eeb679b Mon Sep 17 00:00:00 2001 From: Antonio Rojas Date: Sun, 19 Apr 2020 12:07:05 +0200 Subject: [PATCH 136/300] Update sphinx to 3.0.1 --- build/pkgs/sphinx/checksums.ini | 6 +++--- build/pkgs/sphinx/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/sphinx/checksums.ini b/build/pkgs/sphinx/checksums.ini index ef7a4b12849..b2eb3e430b5 100644 --- a/build/pkgs/sphinx/checksums.ini +++ b/build/pkgs/sphinx/checksums.ini @@ -1,4 +1,4 @@ tarball=Sphinx-VERSION.tar.gz -sha1=93e715cb5d16d981698caa2d54b3b58596798f5d -md5=554f7a4e752f48b2601e5ef5ab463346 -cksum=2134440192 +sha1=dd040aedbef765189c6a502c4031df023ae51f46 +md5=111982b6ca04130d4e512f59b2e4402f +cksum=4119668724 diff --git a/build/pkgs/sphinx/package-version.txt b/build/pkgs/sphinx/package-version.txt index 991e538f58c..a7590f238f1 100644 --- a/build/pkgs/sphinx/package-version.txt +++ b/build/pkgs/sphinx/package-version.txt @@ -1 +1 @@ -1.8.5.p0 +3.0.1.p0 From 6aea5008564c47a05489b00d6c6c0d7a79535e50 Mon Sep 17 00:00:00 2001 From: Antonio Rojas Date: Sun, 19 Apr 2020 12:08:15 +0200 Subject: [PATCH 137/300] Fix deprecation warnings with sphinx 3 --- src/sage_setup/docbuild/ext/sage_autodoc.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/sage_setup/docbuild/ext/sage_autodoc.py b/src/sage_setup/docbuild/ext/sage_autodoc.py index bba274fe359..179fc25d0e1 100644 --- a/src/sage_setup/docbuild/ext/sage_autodoc.py +++ b/src/sage_setup/docbuild/ext/sage_autodoc.py @@ -35,14 +35,15 @@ from docutils.statemachine import ViewList import sphinx -from sphinx.ext.autodoc.importer import mock, import_object, get_object_members +from sphinx.ext.autodoc import mock +from sphinx.ext.autodoc.importer import import_object, get_object_members, get_module_members from sphinx.locale import _, __ from sphinx.pycode import ModuleAnalyzer from sphinx.errors import PycodeError from sphinx.util import logging from sphinx.util import rpartition, force_decode from sphinx.util.docstrings import prepare_docstring -from sphinx.util.inspect import isdescriptor, safe_getmembers, \ +from sphinx.util.inspect import isdescriptor, \ safe_getattr, object_description, is_builtin_class_method, \ isenumattribute, isclassmethod, isstaticmethod, getdoc @@ -536,7 +537,7 @@ def add_content(self, more_content, no_docstring=False): # add content from docstrings if not no_docstring: - encoding = self.analyzer and self.analyzer.encoding + encoding = self.analyzer and self.analyzer._encoding docstrings = self.get_doc(encoding) if not docstrings: # append at least a dummy docstring, so that the event @@ -882,7 +883,7 @@ def get_object_members(self, want_all): if not hasattr(self.object, '__all__'): # for implicit module members, check __module__ to avoid # documenting imported objects - return True, safe_getmembers(self.object) + return True, get_module_members(self.object) else: memberlist = self.object.__all__ # Sometimes __all__ is broken... @@ -893,7 +894,7 @@ def get_object_members(self, want_all): '(in module %s) -- ignoring __all__' % (memberlist, self.fullname)) # fall back to all members - return True, safe_getmembers(self.object) + return True, get_module_members(self.object) else: memberlist = self.options.members or [] ret = [] From 0f9d4a8e7bbd5d1b086fe0147a58721aaf471a4c Mon Sep 17 00:00:00 2001 From: Antonio Rojas Date: Sun, 19 Apr 2020 12:09:29 +0200 Subject: [PATCH 138/300] Port away from BuildEnvironment.frompickle, removed in sphinx 3 --- src/sage_setup/docbuild/__init__.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/sage_setup/docbuild/__init__.py b/src/sage_setup/docbuild/__init__.py index 128117b960f..5aad13c8c5b 100644 --- a/src/sage_setup/docbuild/__init__.py +++ b/src/sage_setup/docbuild/__init__.py @@ -817,9 +817,13 @@ def __init__(self, dir): env_pickle = os.path.join(self._doctrees_dir(), 'environment.pickle') try: - env = BuildEnvironment.frompickle(env_pickle, FakeApp(self.dir)) - logger.debug("Opened Sphinx environment: %s", env_pickle) - return env + with open(env_pickle, 'rb') as f: + import pickle + env = pickle.load(f) + env.app = FakeApp(self.dir) + env.config.values = env.app.config.values + logger.debug("Opened Sphinx environment: %s", env_pickle) + return env except IOError as err: logger.debug("Failed to open Sphinx environment: %s", err) From e83a8dde2c0f820751afedf89f69aa659cecb081 Mon Sep 17 00:00:00 2001 From: Antonio Rojas Date: Sun, 19 Apr 2020 12:13:41 +0200 Subject: [PATCH 139/300] Use correct citation domain --- src/sage_setup/docbuild/ext/multidocs.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage_setup/docbuild/ext/multidocs.py b/src/sage_setup/docbuild/ext/multidocs.py index 3a3d09ab591..d5426c346a1 100644 --- a/src/sage_setup/docbuild/ext/multidocs.py +++ b/src/sage_setup/docbuild/ext/multidocs.py @@ -49,15 +49,15 @@ def merge_environment(app, env): logger.info(bold('Merging environment/index files...')) if not hasattr(env, "todo_all_todos"): env.todo_all_todos = [] - if not hasattr(env.domaindata["std"], "citations"): - env.domaindata["std"]["citations"] = dict() + if not env.domaindata['citation'].get('citations'): + env.domaindata['citation']['citations'] = dict() for curdoc in app.env.config.multidocs_subdoc_list: logger.info(" %s:"%curdoc, nonl=1) docenv = get_env(app, curdoc) if docenv is not None: fixpath = lambda path: os.path.join(curdoc, path) todos = docenv.todo_all_todos if hasattr(docenv, "todo_all_todos") else [] - citations = docenv.domaindata["std"].get("citations", dict()) + citations = docenv.domaindata['citation'].get('citations', dict()) logger.info(" %s todos, %s index, %s citations"%( len(todos), len(docenv.indexentries), @@ -95,7 +95,7 @@ def merge_environment(app, env): for ind, (path, tag, lineno) in six.iteritems(citations): # TODO: Warn on conflicts newcite[ind] = (fixpath(path), tag, lineno) - env.domaindata["std"]["citations"].update(newcite) + env.domaindata['citation']['citations'].update(newcite) # merge the py:module indexes newmodules = {} for ind,(modpath,v1,v2,v3) in ( @@ -106,9 +106,9 @@ def merge_environment(app, env): logger.info('... done (%s todos, %s index, %s citations, %s modules)'%( len(env.todo_all_todos), len(env.indexentries), - len(env.domaindata["std"]["citations"]), + len(env.domaindata['citation']['citations']), len(env.domaindata['py']['modules']))) - write_citations(app, env.domaindata["std"]["citations"]) + write_citations(app, env.domaindata['citation']['citations']) def get_env(app, curdoc): From c16691f8d1cfef8ba9c38760066830d26c4ddc1f Mon Sep 17 00:00:00 2001 From: Antonio Rojas Date: Sun, 19 Apr 2020 12:14:48 +0200 Subject: [PATCH 140/300] docenv.domaindata['py']['modules'] has one more entry in sphinx 3 --- src/sage_setup/docbuild/ext/multidocs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage_setup/docbuild/ext/multidocs.py b/src/sage_setup/docbuild/ext/multidocs.py index d5426c346a1..3a925ba3b24 100644 --- a/src/sage_setup/docbuild/ext/multidocs.py +++ b/src/sage_setup/docbuild/ext/multidocs.py @@ -98,9 +98,9 @@ def merge_environment(app, env): env.domaindata['citation']['citations'].update(newcite) # merge the py:module indexes newmodules = {} - for ind,(modpath,v1,v2,v3) in ( + for ind,(modpath,v1,v2,v3,v4) in ( six.iteritems(docenv.domaindata['py']['modules'])): - newmodules[ind] = (fixpath(modpath),v1,v2,v3) + newmodules[ind] = (fixpath(modpath),v1,v2,v3,v4) env.domaindata['py']['modules'].update(newmodules) logger.info(", %s modules"%(len(newmodules))) logger.info('... done (%s todos, %s index, %s citations, %s modules)'%( From 65c83f71d2f262eea047ed77b0d9290b8ad7ca70 Mon Sep 17 00:00:00 2001 From: Antonio Rojas Date: Sun, 19 Apr 2020 12:17:12 +0200 Subject: [PATCH 141/300] Port to index domain --- src/sage_setup/docbuild/ext/multidocs.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/sage_setup/docbuild/ext/multidocs.py b/src/sage_setup/docbuild/ext/multidocs.py index 3a925ba3b24..2d170a4ff76 100644 --- a/src/sage_setup/docbuild/ext/multidocs.py +++ b/src/sage_setup/docbuild/ext/multidocs.py @@ -58,9 +58,10 @@ def merge_environment(app, env): fixpath = lambda path: os.path.join(curdoc, path) todos = docenv.todo_all_todos if hasattr(docenv, "todo_all_todos") else [] citations = docenv.domaindata['citation'].get('citations', dict()) + indexentries = docenv.domaindata['index'].get('entries', dict()) logger.info(" %s todos, %s index, %s citations"%( len(todos), - len(docenv.indexentries), + len(indexentries), len(citations) ), nonl=1) @@ -73,12 +74,12 @@ def merge_environment(app, env): env.todo_all_todos += todos # merge the html index links newindex = {} - for ind in docenv.indexentries: + for ind in indexentries: if ind.startswith('sage/'): - newindex[fixpath(ind)] = docenv.indexentries[ind] + newindex[fixpath(ind)] = indexentries[ind] else: - newindex[ind] = docenv.indexentries[ind] - env.indexentries.update(newindex) + newindex[ind] = indexentries[ind] + env.domaindata['index']['entries'].update(newindex) # merge the all_docs links, needed by the js index newalldoc = {} for ind in docenv.all_docs: @@ -105,7 +106,7 @@ def merge_environment(app, env): logger.info(", %s modules"%(len(newmodules))) logger.info('... done (%s todos, %s index, %s citations, %s modules)'%( len(env.todo_all_todos), - len(env.indexentries), + len(env.domaindata['index']['entries']), len(env.domaindata['citation']['citations']), len(env.domaindata['py']['modules']))) write_citations(app, env.domaindata['citation']['citations']) From f4ba17d13d76698c97139290b001c685f51c436e Mon Sep 17 00:00:00 2001 From: Antonio Rojas Date: Sun, 19 Apr 2020 14:05:51 +0200 Subject: [PATCH 142/300] fix WARNING: duplicate object description --- src/sage/combinat/permutation.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py index a68d6734f81..ae644cf28a4 100644 --- a/src/sage/combinat/permutation.py +++ b/src/sage/combinat/permutation.py @@ -415,9 +415,6 @@ class Permutation(CombinatorialElement): [] sage: Permutation( [[], []] ) [] - - .. automethod:: Permutation.left_action_product - .. automethod:: Permutation.right_action_product """ @staticmethod def __classcall_private__(cls, l, check_input = True): From c7eb294d2d5c78e6c8ee3c48d205a12d42e9e8d7 Mon Sep 17 00:00:00 2001 From: Antonio Rojas Date: Sun, 19 Apr 2020 23:27:59 +0200 Subject: [PATCH 143/300] Port to todo domain --- src/sage_setup/docbuild/ext/multidocs.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/sage_setup/docbuild/ext/multidocs.py b/src/sage_setup/docbuild/ext/multidocs.py index 2d170a4ff76..722a2b6f524 100644 --- a/src/sage_setup/docbuild/ext/multidocs.py +++ b/src/sage_setup/docbuild/ext/multidocs.py @@ -47,20 +47,16 @@ def merge_environment(app, env): - domaindata['py']['modules'] # list of python modules """ logger.info(bold('Merging environment/index files...')) - if not hasattr(env, "todo_all_todos"): - env.todo_all_todos = [] - if not env.domaindata['citation'].get('citations'): - env.domaindata['citation']['citations'] = dict() for curdoc in app.env.config.multidocs_subdoc_list: logger.info(" %s:"%curdoc, nonl=1) docenv = get_env(app, curdoc) if docenv is not None: fixpath = lambda path: os.path.join(curdoc, path) - todos = docenv.todo_all_todos if hasattr(docenv, "todo_all_todos") else [] + todos = docenv.domaindata['todo'].get('todos', dict()) citations = docenv.domaindata['citation'].get('citations', dict()) indexentries = docenv.domaindata['index'].get('entries', dict()) logger.info(" %s todos, %s index, %s citations"%( - len(todos), + sum(len(t) for t in todos.values()), len(indexentries), len(citations) ), nonl=1) @@ -70,8 +66,7 @@ def merge_environment(app, env): env.titles[fixpath(t)] = docenv.titles[t] # merge the todo links for dct in todos: - dct['docname'] = fixpath(dct['docname']) - env.todo_all_todos += todos + env.domaindata['todo']['todos'][fixpath(dct)] = todos[dct] # merge the html index links newindex = {} for ind in indexentries: @@ -105,7 +100,7 @@ def merge_environment(app, env): env.domaindata['py']['modules'].update(newmodules) logger.info(", %s modules"%(len(newmodules))) logger.info('... done (%s todos, %s index, %s citations, %s modules)'%( - len(env.todo_all_todos), + sum(len(t) for t in env.domaindata['todo']['todos'].values()), len(env.domaindata['index']['entries']), len(env.domaindata['citation']['citations']), len(env.domaindata['py']['modules']))) From 568f1c760585b921ffbce95249c68a922171bac6 Mon Sep 17 00:00:00 2001 From: Antonio Rojas Date: Tue, 21 Apr 2020 12:14:19 +0200 Subject: [PATCH 144/300] Fix incomplete port to citation domain --- src/sage_setup/docbuild/ext/multidocs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage_setup/docbuild/ext/multidocs.py b/src/sage_setup/docbuild/ext/multidocs.py index 722a2b6f524..ffed722d33a 100644 --- a/src/sage_setup/docbuild/ext/multidocs.py +++ b/src/sage_setup/docbuild/ext/multidocs.py @@ -254,7 +254,7 @@ def fetch_citation(app, env): with open(filename, 'rb') as f: cache = cPickle.load(f) logger.info("done (%s citations)."%len(cache)) - cite = env.domaindata["std"].get("citations", dict()) + cite = env.domaindata['citation'].get('citations', dict()) for ind, (path, tag, lineno) in six.iteritems(cache): if ind not in cite: # don't override local citation cite[ind] = (os.path.join("..", path), tag, lineno) From 3d1403ad8add2f07e8c05cde889756c3f92de997 Mon Sep 17 00:00:00 2001 From: Antonio Rojas Date: Tue, 21 Apr 2020 19:00:42 +0200 Subject: [PATCH 145/300] Remove non-python code from python code block --- src/doc/en/thematic_tutorials/structures_in_coding_theory.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/doc/en/thematic_tutorials/structures_in_coding_theory.rst b/src/doc/en/thematic_tutorials/structures_in_coding_theory.rst index 13f1a83a2b6..4726bce061a 100644 --- a/src/doc/en/thematic_tutorials/structures_in_coding_theory.rst +++ b/src/doc/en/thematic_tutorials/structures_in_coding_theory.rst @@ -721,8 +721,6 @@ derive from the one that follows. .. CODE-BLOCK:: python - :class:`sage.coding.repetition_code.BinaryRepetitionCode ` - #the line above creates a link to the class in the html documentation of coding theory library from sage.coding.repetition_code import BinaryRepetitionCode ``encoders_catalog.py`` (continued): From ed74467dd6072f4fedb7a059506793b523485ad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Wed, 22 Apr 2020 11:13:06 +1200 Subject: [PATCH 146/300] update sphinx to 3.0.2 --- build/pkgs/sphinx/checksums.ini | 6 +++--- build/pkgs/sphinx/dependencies | 2 +- build/pkgs/sphinx/package-version.txt | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/pkgs/sphinx/checksums.ini b/build/pkgs/sphinx/checksums.ini index b2eb3e430b5..0c592dd186c 100644 --- a/build/pkgs/sphinx/checksums.ini +++ b/build/pkgs/sphinx/checksums.ini @@ -1,4 +1,4 @@ tarball=Sphinx-VERSION.tar.gz -sha1=dd040aedbef765189c6a502c4031df023ae51f46 -md5=111982b6ca04130d4e512f59b2e4402f -cksum=4119668724 +sha1=fd8b7655c4a01b3580a2abc216ff24c6776298b0 +md5=20a2f1f67d88fac3743c11def966c9a6 +cksum=2308785561 diff --git a/build/pkgs/sphinx/dependencies b/build/pkgs/sphinx/dependencies index 5d943e8dd5f..16f478530e9 100644 --- a/build/pkgs/sphinx/dependencies +++ b/build/pkgs/sphinx/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) docutils jinja2 pygments six snowballstemmer imagesize babel alabaster requests typing sphinxcontrib_websupport packaging +$(PYTHON) | $(PYTHON_TOOLCHAIN) docutils jinja2 pygments six snowballstemmer imagesize babel alabaster requests typing sphinxcontrib_websupport sphinxcontrib_applehelp sphinxcontrib_devhelp sphinxcontrib_htmlhelp sphinxcontrib_jsmath sphinxcontrib_qthelp sphinxcontrib_serializinghtml packaging ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sphinx/package-version.txt b/build/pkgs/sphinx/package-version.txt index a7590f238f1..16f01e82efb 100644 --- a/build/pkgs/sphinx/package-version.txt +++ b/build/pkgs/sphinx/package-version.txt @@ -1 +1 @@ -3.0.1.p0 +3.0.2.p0 From 8db286b6452db781ea4ff4b42f49a6c6896dffcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Wed, 22 Apr 2020 11:13:59 +1200 Subject: [PATCH 147/300] update sphinx_contribwebsupport --- build/pkgs/sphinxcontrib_websupport/checksums.ini | 6 +++--- build/pkgs/sphinxcontrib_websupport/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/sphinxcontrib_websupport/checksums.ini b/build/pkgs/sphinxcontrib_websupport/checksums.ini index 1f0d8d40396..f6ea886bcdd 100644 --- a/build/pkgs/sphinxcontrib_websupport/checksums.ini +++ b/build/pkgs/sphinxcontrib_websupport/checksums.ini @@ -1,4 +1,4 @@ tarball=sphinxcontrib-websupport-VERSION.tar.gz -sha1=03216c11167b75d2c1b08e34041ad2019c3e7dc9 -md5=ca6435e7b4eb9408df4f54972361e9d3 -cksum=1372914473 +sha1=313f4b764872d36f890e76579985e6aaa732f4ca +md5=4fe4d07afe1556c65182d0437228d7bb +cksum=1830011133 diff --git a/build/pkgs/sphinxcontrib_websupport/package-version.txt b/build/pkgs/sphinxcontrib_websupport/package-version.txt index 9084fa2f716..6085e946503 100644 --- a/build/pkgs/sphinxcontrib_websupport/package-version.txt +++ b/build/pkgs/sphinxcontrib_websupport/package-version.txt @@ -1 +1 @@ -1.1.0 +1.2.1 From d09e96539a5e18c6fb73a59e03bd24fa02ef6662 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Wed, 22 Apr 2020 11:15:54 +1200 Subject: [PATCH 148/300] Add new dependencies of sphinx --- build/pkgs/sphinxcontrib_applehelp/SPKG.txt | 9 +++++++++ build/pkgs/sphinxcontrib_applehelp/checksums.ini | 4 ++++ build/pkgs/sphinxcontrib_applehelp/dependencies | 5 +++++ build/pkgs/sphinxcontrib_applehelp/package-version.txt | 1 + build/pkgs/sphinxcontrib_applehelp/spkg-install.in | 1 + build/pkgs/sphinxcontrib_applehelp/type | 1 + build/pkgs/sphinxcontrib_devhelp/SPKG.txt | 9 +++++++++ build/pkgs/sphinxcontrib_devhelp/checksums.ini | 4 ++++ build/pkgs/sphinxcontrib_devhelp/dependencies | 5 +++++ build/pkgs/sphinxcontrib_devhelp/package-version.txt | 1 + build/pkgs/sphinxcontrib_devhelp/spkg-install.in | 1 + build/pkgs/sphinxcontrib_devhelp/type | 1 + build/pkgs/sphinxcontrib_htmlhelp/SPKG.txt | 9 +++++++++ build/pkgs/sphinxcontrib_htmlhelp/checksums.ini | 4 ++++ build/pkgs/sphinxcontrib_htmlhelp/dependencies | 5 +++++ build/pkgs/sphinxcontrib_htmlhelp/package-version.txt | 1 + build/pkgs/sphinxcontrib_htmlhelp/spkg-install.in | 1 + build/pkgs/sphinxcontrib_htmlhelp/type | 1 + build/pkgs/sphinxcontrib_jsmath/SPKG.txt | 9 +++++++++ build/pkgs/sphinxcontrib_jsmath/checksums.ini | 4 ++++ build/pkgs/sphinxcontrib_jsmath/dependencies | 5 +++++ build/pkgs/sphinxcontrib_jsmath/package-version.txt | 1 + build/pkgs/sphinxcontrib_jsmath/spkg-install.in | 1 + build/pkgs/sphinxcontrib_jsmath/type | 1 + build/pkgs/sphinxcontrib_qthelp/SPKG.txt | 9 +++++++++ build/pkgs/sphinxcontrib_qthelp/checksums.ini | 4 ++++ build/pkgs/sphinxcontrib_qthelp/dependencies | 5 +++++ build/pkgs/sphinxcontrib_qthelp/package-version.txt | 1 + build/pkgs/sphinxcontrib_qthelp/spkg-install.in | 1 + build/pkgs/sphinxcontrib_qthelp/type | 1 + build/pkgs/sphinxcontrib_serializinghtml/SPKG.txt | 9 +++++++++ build/pkgs/sphinxcontrib_serializinghtml/checksums.ini | 4 ++++ build/pkgs/sphinxcontrib_serializinghtml/dependencies | 5 +++++ .../sphinxcontrib_serializinghtml/package-version.txt | 1 + build/pkgs/sphinxcontrib_serializinghtml/spkg-install.in | 1 + build/pkgs/sphinxcontrib_serializinghtml/type | 1 + 36 files changed, 126 insertions(+) create mode 100644 build/pkgs/sphinxcontrib_applehelp/SPKG.txt create mode 100644 build/pkgs/sphinxcontrib_applehelp/checksums.ini create mode 100644 build/pkgs/sphinxcontrib_applehelp/dependencies create mode 100644 build/pkgs/sphinxcontrib_applehelp/package-version.txt create mode 100644 build/pkgs/sphinxcontrib_applehelp/spkg-install.in create mode 100644 build/pkgs/sphinxcontrib_applehelp/type create mode 100644 build/pkgs/sphinxcontrib_devhelp/SPKG.txt create mode 100644 build/pkgs/sphinxcontrib_devhelp/checksums.ini create mode 100644 build/pkgs/sphinxcontrib_devhelp/dependencies create mode 100644 build/pkgs/sphinxcontrib_devhelp/package-version.txt create mode 100644 build/pkgs/sphinxcontrib_devhelp/spkg-install.in create mode 100644 build/pkgs/sphinxcontrib_devhelp/type create mode 100644 build/pkgs/sphinxcontrib_htmlhelp/SPKG.txt create mode 100644 build/pkgs/sphinxcontrib_htmlhelp/checksums.ini create mode 100644 build/pkgs/sphinxcontrib_htmlhelp/dependencies create mode 100644 build/pkgs/sphinxcontrib_htmlhelp/package-version.txt create mode 100644 build/pkgs/sphinxcontrib_htmlhelp/spkg-install.in create mode 100644 build/pkgs/sphinxcontrib_htmlhelp/type create mode 100644 build/pkgs/sphinxcontrib_jsmath/SPKG.txt create mode 100644 build/pkgs/sphinxcontrib_jsmath/checksums.ini create mode 100644 build/pkgs/sphinxcontrib_jsmath/dependencies create mode 100644 build/pkgs/sphinxcontrib_jsmath/package-version.txt create mode 100644 build/pkgs/sphinxcontrib_jsmath/spkg-install.in create mode 100644 build/pkgs/sphinxcontrib_jsmath/type create mode 100644 build/pkgs/sphinxcontrib_qthelp/SPKG.txt create mode 100644 build/pkgs/sphinxcontrib_qthelp/checksums.ini create mode 100644 build/pkgs/sphinxcontrib_qthelp/dependencies create mode 100644 build/pkgs/sphinxcontrib_qthelp/package-version.txt create mode 100644 build/pkgs/sphinxcontrib_qthelp/spkg-install.in create mode 100644 build/pkgs/sphinxcontrib_qthelp/type create mode 100644 build/pkgs/sphinxcontrib_serializinghtml/SPKG.txt create mode 100644 build/pkgs/sphinxcontrib_serializinghtml/checksums.ini create mode 100644 build/pkgs/sphinxcontrib_serializinghtml/dependencies create mode 100644 build/pkgs/sphinxcontrib_serializinghtml/package-version.txt create mode 100644 build/pkgs/sphinxcontrib_serializinghtml/spkg-install.in create mode 100644 build/pkgs/sphinxcontrib_serializinghtml/type diff --git a/build/pkgs/sphinxcontrib_applehelp/SPKG.txt b/build/pkgs/sphinxcontrib_applehelp/SPKG.txt new file mode 100644 index 00000000000..ed59bda33d2 --- /dev/null +++ b/build/pkgs/sphinxcontrib_applehelp/SPKG.txt @@ -0,0 +1,9 @@ += sphinxcontrib-applehelp = + +== Description == + +Sphinx extension which outputs Apple help book + +== License == + +BSD diff --git a/build/pkgs/sphinxcontrib_applehelp/checksums.ini b/build/pkgs/sphinxcontrib_applehelp/checksums.ini new file mode 100644 index 00000000000..15e95c1e08c --- /dev/null +++ b/build/pkgs/sphinxcontrib_applehelp/checksums.ini @@ -0,0 +1,4 @@ +tarball=sphinxcontrib-applehelp-VERSION.tar.gz +sha1=adfd47917f82a86f30bdf356497baf68b47380bc +md5=3f2de7681e12dde031acee0497c3cc2b +cksum=1142149867 diff --git a/build/pkgs/sphinxcontrib_applehelp/dependencies b/build/pkgs/sphinxcontrib_applehelp/dependencies new file mode 100644 index 00000000000..d5dab729e18 --- /dev/null +++ b/build/pkgs/sphinxcontrib_applehelp/dependencies @@ -0,0 +1,5 @@ +$(PYTHON) | pip + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/sphinxcontrib_applehelp/package-version.txt b/build/pkgs/sphinxcontrib_applehelp/package-version.txt new file mode 100644 index 00000000000..6d7de6e6abe --- /dev/null +++ b/build/pkgs/sphinxcontrib_applehelp/package-version.txt @@ -0,0 +1 @@ +1.0.2 diff --git a/build/pkgs/sphinxcontrib_applehelp/spkg-install.in b/build/pkgs/sphinxcontrib_applehelp/spkg-install.in new file mode 100644 index 00000000000..deba1bb42bb --- /dev/null +++ b/build/pkgs/sphinxcontrib_applehelp/spkg-install.in @@ -0,0 +1 @@ +cd src && sdh_pip_install . diff --git a/build/pkgs/sphinxcontrib_applehelp/type b/build/pkgs/sphinxcontrib_applehelp/type new file mode 100644 index 00000000000..a6a7b9cd726 --- /dev/null +++ b/build/pkgs/sphinxcontrib_applehelp/type @@ -0,0 +1 @@ +standard diff --git a/build/pkgs/sphinxcontrib_devhelp/SPKG.txt b/build/pkgs/sphinxcontrib_devhelp/SPKG.txt new file mode 100644 index 00000000000..50e27ba320e --- /dev/null +++ b/build/pkgs/sphinxcontrib_devhelp/SPKG.txt @@ -0,0 +1,9 @@ += sphinxcontrib-devhelp = + +== Description == + +Sphinx extension which outputs Devhelp documents + +== License == + +BSD diff --git a/build/pkgs/sphinxcontrib_devhelp/checksums.ini b/build/pkgs/sphinxcontrib_devhelp/checksums.ini new file mode 100644 index 00000000000..7da268d7933 --- /dev/null +++ b/build/pkgs/sphinxcontrib_devhelp/checksums.ini @@ -0,0 +1,4 @@ +tarball=sphinxcontrib-devhelp-VERSION.tar.gz +sha1=3782815be9e11190fe7c7d697e73369432c56fd6 +md5=94069c5cdb5079c445f5477fa6107016 +cksum=4072264365 diff --git a/build/pkgs/sphinxcontrib_devhelp/dependencies b/build/pkgs/sphinxcontrib_devhelp/dependencies new file mode 100644 index 00000000000..d5dab729e18 --- /dev/null +++ b/build/pkgs/sphinxcontrib_devhelp/dependencies @@ -0,0 +1,5 @@ +$(PYTHON) | pip + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/sphinxcontrib_devhelp/package-version.txt b/build/pkgs/sphinxcontrib_devhelp/package-version.txt new file mode 100644 index 00000000000..6d7de6e6abe --- /dev/null +++ b/build/pkgs/sphinxcontrib_devhelp/package-version.txt @@ -0,0 +1 @@ +1.0.2 diff --git a/build/pkgs/sphinxcontrib_devhelp/spkg-install.in b/build/pkgs/sphinxcontrib_devhelp/spkg-install.in new file mode 100644 index 00000000000..deba1bb42bb --- /dev/null +++ b/build/pkgs/sphinxcontrib_devhelp/spkg-install.in @@ -0,0 +1 @@ +cd src && sdh_pip_install . diff --git a/build/pkgs/sphinxcontrib_devhelp/type b/build/pkgs/sphinxcontrib_devhelp/type new file mode 100644 index 00000000000..a6a7b9cd726 --- /dev/null +++ b/build/pkgs/sphinxcontrib_devhelp/type @@ -0,0 +1 @@ +standard diff --git a/build/pkgs/sphinxcontrib_htmlhelp/SPKG.txt b/build/pkgs/sphinxcontrib_htmlhelp/SPKG.txt new file mode 100644 index 00000000000..ef225d7bf13 --- /dev/null +++ b/build/pkgs/sphinxcontrib_htmlhelp/SPKG.txt @@ -0,0 +1,9 @@ += sphinxcontrib-htmlhelp = + +== Description == + +Sphinx extension which outputs HTML help book + +== License == + +BSD diff --git a/build/pkgs/sphinxcontrib_htmlhelp/checksums.ini b/build/pkgs/sphinxcontrib_htmlhelp/checksums.ini new file mode 100644 index 00000000000..5660ef2eef8 --- /dev/null +++ b/build/pkgs/sphinxcontrib_htmlhelp/checksums.ini @@ -0,0 +1,4 @@ +tarball=sphinxcontrib-htmlhelp-VERSION.tar.gz +sha1=fc695250bc781777203b3a97a7aa7b0eab8a2c51 +md5=f1db7db2a467f08f6292ab0d76e38584 +cksum=1195324208 diff --git a/build/pkgs/sphinxcontrib_htmlhelp/dependencies b/build/pkgs/sphinxcontrib_htmlhelp/dependencies new file mode 100644 index 00000000000..d5dab729e18 --- /dev/null +++ b/build/pkgs/sphinxcontrib_htmlhelp/dependencies @@ -0,0 +1,5 @@ +$(PYTHON) | pip + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/sphinxcontrib_htmlhelp/package-version.txt b/build/pkgs/sphinxcontrib_htmlhelp/package-version.txt new file mode 100644 index 00000000000..21e8796a09d --- /dev/null +++ b/build/pkgs/sphinxcontrib_htmlhelp/package-version.txt @@ -0,0 +1 @@ +1.0.3 diff --git a/build/pkgs/sphinxcontrib_htmlhelp/spkg-install.in b/build/pkgs/sphinxcontrib_htmlhelp/spkg-install.in new file mode 100644 index 00000000000..deba1bb42bb --- /dev/null +++ b/build/pkgs/sphinxcontrib_htmlhelp/spkg-install.in @@ -0,0 +1 @@ +cd src && sdh_pip_install . diff --git a/build/pkgs/sphinxcontrib_htmlhelp/type b/build/pkgs/sphinxcontrib_htmlhelp/type new file mode 100644 index 00000000000..a6a7b9cd726 --- /dev/null +++ b/build/pkgs/sphinxcontrib_htmlhelp/type @@ -0,0 +1 @@ +standard diff --git a/build/pkgs/sphinxcontrib_jsmath/SPKG.txt b/build/pkgs/sphinxcontrib_jsmath/SPKG.txt new file mode 100644 index 00000000000..243e8ad9955 --- /dev/null +++ b/build/pkgs/sphinxcontrib_jsmath/SPKG.txt @@ -0,0 +1,9 @@ += sphinxcontrib-jsmath = + +== Description == + +Sphinx extension which renders display math in HTML via JavaScript + +== License == + +BSD diff --git a/build/pkgs/sphinxcontrib_jsmath/checksums.ini b/build/pkgs/sphinxcontrib_jsmath/checksums.ini new file mode 100644 index 00000000000..de57cfa567e --- /dev/null +++ b/build/pkgs/sphinxcontrib_jsmath/checksums.ini @@ -0,0 +1,4 @@ +tarball=sphinxcontrib-jsmath-VERSION.tar.gz +sha1=70348505f159dca801522d6df68230e3c5e749c7 +md5=e45179f0a3608b6766862e0f34c23b62 +cksum=3778623264 diff --git a/build/pkgs/sphinxcontrib_jsmath/dependencies b/build/pkgs/sphinxcontrib_jsmath/dependencies new file mode 100644 index 00000000000..d5dab729e18 --- /dev/null +++ b/build/pkgs/sphinxcontrib_jsmath/dependencies @@ -0,0 +1,5 @@ +$(PYTHON) | pip + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/sphinxcontrib_jsmath/package-version.txt b/build/pkgs/sphinxcontrib_jsmath/package-version.txt new file mode 100644 index 00000000000..7dea76edb3d --- /dev/null +++ b/build/pkgs/sphinxcontrib_jsmath/package-version.txt @@ -0,0 +1 @@ +1.0.1 diff --git a/build/pkgs/sphinxcontrib_jsmath/spkg-install.in b/build/pkgs/sphinxcontrib_jsmath/spkg-install.in new file mode 100644 index 00000000000..deba1bb42bb --- /dev/null +++ b/build/pkgs/sphinxcontrib_jsmath/spkg-install.in @@ -0,0 +1 @@ +cd src && sdh_pip_install . diff --git a/build/pkgs/sphinxcontrib_jsmath/type b/build/pkgs/sphinxcontrib_jsmath/type new file mode 100644 index 00000000000..a6a7b9cd726 --- /dev/null +++ b/build/pkgs/sphinxcontrib_jsmath/type @@ -0,0 +1 @@ +standard diff --git a/build/pkgs/sphinxcontrib_qthelp/SPKG.txt b/build/pkgs/sphinxcontrib_qthelp/SPKG.txt new file mode 100644 index 00000000000..8c27c1c3003 --- /dev/null +++ b/build/pkgs/sphinxcontrib_qthelp/SPKG.txt @@ -0,0 +1,9 @@ += sphinxcontrib-qthelp = + +== Description == + +Sphinx extension which outputs QtHelp documents + +== License == + +BSD diff --git a/build/pkgs/sphinxcontrib_qthelp/checksums.ini b/build/pkgs/sphinxcontrib_qthelp/checksums.ini new file mode 100644 index 00000000000..098fa44f7af --- /dev/null +++ b/build/pkgs/sphinxcontrib_qthelp/checksums.ini @@ -0,0 +1,4 @@ +tarball=sphinxcontrib-qthelp-VERSION.tar.gz +sha1=3f0d3b111e2a57ae24afc51c518ebc2e9e377cd5 +md5=93216721f3e154cce12d1e9c3307b415 +cksum=3260884791 diff --git a/build/pkgs/sphinxcontrib_qthelp/dependencies b/build/pkgs/sphinxcontrib_qthelp/dependencies new file mode 100644 index 00000000000..d5dab729e18 --- /dev/null +++ b/build/pkgs/sphinxcontrib_qthelp/dependencies @@ -0,0 +1,5 @@ +$(PYTHON) | pip + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/sphinxcontrib_qthelp/package-version.txt b/build/pkgs/sphinxcontrib_qthelp/package-version.txt new file mode 100644 index 00000000000..21e8796a09d --- /dev/null +++ b/build/pkgs/sphinxcontrib_qthelp/package-version.txt @@ -0,0 +1 @@ +1.0.3 diff --git a/build/pkgs/sphinxcontrib_qthelp/spkg-install.in b/build/pkgs/sphinxcontrib_qthelp/spkg-install.in new file mode 100644 index 00000000000..deba1bb42bb --- /dev/null +++ b/build/pkgs/sphinxcontrib_qthelp/spkg-install.in @@ -0,0 +1 @@ +cd src && sdh_pip_install . diff --git a/build/pkgs/sphinxcontrib_qthelp/type b/build/pkgs/sphinxcontrib_qthelp/type new file mode 100644 index 00000000000..a6a7b9cd726 --- /dev/null +++ b/build/pkgs/sphinxcontrib_qthelp/type @@ -0,0 +1 @@ +standard diff --git a/build/pkgs/sphinxcontrib_serializinghtml/SPKG.txt b/build/pkgs/sphinxcontrib_serializinghtml/SPKG.txt new file mode 100644 index 00000000000..bb3c470abf7 --- /dev/null +++ b/build/pkgs/sphinxcontrib_serializinghtml/SPKG.txt @@ -0,0 +1,9 @@ += sphinxcontrib-serializinghtml = + +== Description == + +Sphinx extension which outputs serialized HTML files + +== License == + +BSD diff --git a/build/pkgs/sphinxcontrib_serializinghtml/checksums.ini b/build/pkgs/sphinxcontrib_serializinghtml/checksums.ini new file mode 100644 index 00000000000..90c9bc408cf --- /dev/null +++ b/build/pkgs/sphinxcontrib_serializinghtml/checksums.ini @@ -0,0 +1,4 @@ +tarball=sphinxcontrib-serializinghtml-VERSION.tar.gz +sha1=7d782d9f8fef0a5663fc7732d72847e711f0f18b +md5=518ff437dcb05a74ed32ba19c892ce05 +cksum=3002072803 diff --git a/build/pkgs/sphinxcontrib_serializinghtml/dependencies b/build/pkgs/sphinxcontrib_serializinghtml/dependencies new file mode 100644 index 00000000000..d5dab729e18 --- /dev/null +++ b/build/pkgs/sphinxcontrib_serializinghtml/dependencies @@ -0,0 +1,5 @@ +$(PYTHON) | pip + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/sphinxcontrib_serializinghtml/package-version.txt b/build/pkgs/sphinxcontrib_serializinghtml/package-version.txt new file mode 100644 index 00000000000..65087b4f5ec --- /dev/null +++ b/build/pkgs/sphinxcontrib_serializinghtml/package-version.txt @@ -0,0 +1 @@ +1.1.4 diff --git a/build/pkgs/sphinxcontrib_serializinghtml/spkg-install.in b/build/pkgs/sphinxcontrib_serializinghtml/spkg-install.in new file mode 100644 index 00000000000..deba1bb42bb --- /dev/null +++ b/build/pkgs/sphinxcontrib_serializinghtml/spkg-install.in @@ -0,0 +1 @@ +cd src && sdh_pip_install . diff --git a/build/pkgs/sphinxcontrib_serializinghtml/type b/build/pkgs/sphinxcontrib_serializinghtml/type new file mode 100644 index 00000000000..a6a7b9cd726 --- /dev/null +++ b/build/pkgs/sphinxcontrib_serializinghtml/type @@ -0,0 +1 @@ +standard From 2061379f25e9ddf6f7e00bf3d1672abda6d26b29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Thu, 23 Apr 2020 15:35:58 +1200 Subject: [PATCH 149/300] add upstream_url to all sphinx packages. --- build/pkgs/sphinx/checksums.ini | 1 + build/pkgs/sphinxcontrib_applehelp/checksums.ini | 1 + build/pkgs/sphinxcontrib_devhelp/checksums.ini | 1 + build/pkgs/sphinxcontrib_htmlhelp/checksums.ini | 1 + build/pkgs/sphinxcontrib_jsmath/checksums.ini | 1 + build/pkgs/sphinxcontrib_qthelp/checksums.ini | 1 + build/pkgs/sphinxcontrib_serializinghtml/checksums.ini | 1 + build/pkgs/sphinxcontrib_websupport/checksums.ini | 1 + 8 files changed, 8 insertions(+) diff --git a/build/pkgs/sphinx/checksums.ini b/build/pkgs/sphinx/checksums.ini index 0c592dd186c..8f8c919290f 100644 --- a/build/pkgs/sphinx/checksums.ini +++ b/build/pkgs/sphinx/checksums.ini @@ -2,3 +2,4 @@ tarball=Sphinx-VERSION.tar.gz sha1=fd8b7655c4a01b3580a2abc216ff24c6776298b0 md5=20a2f1f67d88fac3743c11def966c9a6 cksum=2308785561 +upstream_url=https://files.pythonhosted.org/packages/a4/4a/0d48d133675eafb602714b3472b214e63d438e7e6985d41977e617b81f7a/Sphinx-VERSION.tar.gz diff --git a/build/pkgs/sphinxcontrib_applehelp/checksums.ini b/build/pkgs/sphinxcontrib_applehelp/checksums.ini index 15e95c1e08c..0bf12a630cc 100644 --- a/build/pkgs/sphinxcontrib_applehelp/checksums.ini +++ b/build/pkgs/sphinxcontrib_applehelp/checksums.ini @@ -2,3 +2,4 @@ tarball=sphinxcontrib-applehelp-VERSION.tar.gz sha1=adfd47917f82a86f30bdf356497baf68b47380bc md5=3f2de7681e12dde031acee0497c3cc2b cksum=1142149867 +upstream_url=https://files.pythonhosted.org/packages/9f/01/ad9d4ebbceddbed9979ab4a89ddb78c9760e74e6757b1880f1b2760e8295/sphinxcontrib-applehelp-VERSION.tar.gz diff --git a/build/pkgs/sphinxcontrib_devhelp/checksums.ini b/build/pkgs/sphinxcontrib_devhelp/checksums.ini index 7da268d7933..d751730c830 100644 --- a/build/pkgs/sphinxcontrib_devhelp/checksums.ini +++ b/build/pkgs/sphinxcontrib_devhelp/checksums.ini @@ -2,3 +2,4 @@ tarball=sphinxcontrib-devhelp-VERSION.tar.gz sha1=3782815be9e11190fe7c7d697e73369432c56fd6 md5=94069c5cdb5079c445f5477fa6107016 cksum=4072264365 +upstream_url=https://files.pythonhosted.org/packages/98/33/dc28393f16385f722c893cb55539c641c9aaec8d1bc1c15b69ce0ac2dbb3/sphinxcontrib-devhelp-VERSION.tar.gz diff --git a/build/pkgs/sphinxcontrib_htmlhelp/checksums.ini b/build/pkgs/sphinxcontrib_htmlhelp/checksums.ini index 5660ef2eef8..3bf844abaec 100644 --- a/build/pkgs/sphinxcontrib_htmlhelp/checksums.ini +++ b/build/pkgs/sphinxcontrib_htmlhelp/checksums.ini @@ -2,3 +2,4 @@ tarball=sphinxcontrib-htmlhelp-VERSION.tar.gz sha1=fc695250bc781777203b3a97a7aa7b0eab8a2c51 md5=f1db7db2a467f08f6292ab0d76e38584 cksum=1195324208 +upstream_url=https://files.pythonhosted.org/packages/c9/2e/a7a5fef38327b7f643ed13646321d19903a2f54b0a05868e4bc34d729e1f/sphinxcontrib-htmlhelp-VERSION.tar.gz diff --git a/build/pkgs/sphinxcontrib_jsmath/checksums.ini b/build/pkgs/sphinxcontrib_jsmath/checksums.ini index de57cfa567e..c22ac5d1981 100644 --- a/build/pkgs/sphinxcontrib_jsmath/checksums.ini +++ b/build/pkgs/sphinxcontrib_jsmath/checksums.ini @@ -2,3 +2,4 @@ tarball=sphinxcontrib-jsmath-VERSION.tar.gz sha1=70348505f159dca801522d6df68230e3c5e749c7 md5=e45179f0a3608b6766862e0f34c23b62 cksum=3778623264 +upstream_url=https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-VERSION.tar.gz diff --git a/build/pkgs/sphinxcontrib_qthelp/checksums.ini b/build/pkgs/sphinxcontrib_qthelp/checksums.ini index 098fa44f7af..09912de47da 100644 --- a/build/pkgs/sphinxcontrib_qthelp/checksums.ini +++ b/build/pkgs/sphinxcontrib_qthelp/checksums.ini @@ -2,3 +2,4 @@ tarball=sphinxcontrib-qthelp-VERSION.tar.gz sha1=3f0d3b111e2a57ae24afc51c518ebc2e9e377cd5 md5=93216721f3e154cce12d1e9c3307b415 cksum=3260884791 +upstream_url=https://files.pythonhosted.org/packages/b1/8e/c4846e59f38a5f2b4a0e3b27af38f2fcf904d4bfd82095bf92de0b114ebd/sphinxcontrib-qthelp-VERSION.tar.gz diff --git a/build/pkgs/sphinxcontrib_serializinghtml/checksums.ini b/build/pkgs/sphinxcontrib_serializinghtml/checksums.ini index 90c9bc408cf..c2e3c37481b 100644 --- a/build/pkgs/sphinxcontrib_serializinghtml/checksums.ini +++ b/build/pkgs/sphinxcontrib_serializinghtml/checksums.ini @@ -2,3 +2,4 @@ tarball=sphinxcontrib-serializinghtml-VERSION.tar.gz sha1=7d782d9f8fef0a5663fc7732d72847e711f0f18b md5=518ff437dcb05a74ed32ba19c892ce05 cksum=3002072803 +upstream_url=https://files.pythonhosted.org/packages/ac/86/021876a9dd4eac9dae0b1d454d848acbd56d5574d350d0f835043b5ac2cd/sphinxcontrib-serializinghtml-VERSION.tar.gz diff --git a/build/pkgs/sphinxcontrib_websupport/checksums.ini b/build/pkgs/sphinxcontrib_websupport/checksums.ini index f6ea886bcdd..3938e3c7112 100644 --- a/build/pkgs/sphinxcontrib_websupport/checksums.ini +++ b/build/pkgs/sphinxcontrib_websupport/checksums.ini @@ -2,3 +2,4 @@ tarball=sphinxcontrib-websupport-VERSION.tar.gz sha1=313f4b764872d36f890e76579985e6aaa732f4ca md5=4fe4d07afe1556c65182d0437228d7bb cksum=1830011133 +upstream_url=https://files.pythonhosted.org/packages/60/65/78e1514be951a3584df2e27b1b86e22609dd73312461e1af2afb9a53152c/sphinxcontrib-websupport-VERSION.tar.gz From 2b03045e7f1a881fcfec5d14714dbacad6000665 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Thu, 23 Apr 2020 22:27:02 +1200 Subject: [PATCH 150/300] Fix the last two doctests --- src/sage/misc/sagedoc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/misc/sagedoc.py b/src/sage/misc/sagedoc.py index 85ee7644fac..795dfd37fcb 100644 --- a/src/sage/misc/sagedoc.py +++ b/src/sage/misc/sagedoc.py @@ -24,7 +24,7 @@ ....: for line in fobj: ....: if "#sage.symbolic.expression.Expression.numerical_approx" in line: ....: print(line) - numerical_approx(prec=None, digits=None, algorithm=None)... + numerical_approx(prec=None, digits=None, algorithm=None)... Check that sphinx is not imported at Sage start-up:: From 8387b7b0546df138e8318ec679a53dfd5b8dc31c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Fri, 24 Apr 2020 08:00:45 +1200 Subject: [PATCH 151/300] add forgotten doctest fix. --- src/sage/docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/docs/conf.py b/src/sage/docs/conf.py index a420990abba..c4941f0c669 100644 --- a/src/sage/docs/conf.py +++ b/src/sage/docs/conf.py @@ -670,7 +670,7 @@ def call_intersphinx(app, env, node, contnode): sage: for line in open(thematic_index).readlines(): # optional - dochtml ....: if "padics" in line: ....: _ = sys.stdout.write(line) -
  • Introduction to the p-adics
  • +
  • Introduction to the p-adics

  • """ debug_inf(app, "???? Trying intersphinx for %s" % node['reftarget']) builder = app.builder From 2ddcd319979ed4746aba8fc02b3757f623015a70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Fri, 24 Apr 2020 09:24:12 +1200 Subject: [PATCH 152/300] change upstream_url to a (hopefully) more stable and easy to decipher address for sphinx packages --- build/pkgs/sphinx/checksums.ini | 2 +- build/pkgs/sphinxcontrib_applehelp/checksums.ini | 2 +- build/pkgs/sphinxcontrib_devhelp/checksums.ini | 2 +- build/pkgs/sphinxcontrib_htmlhelp/checksums.ini | 2 +- build/pkgs/sphinxcontrib_jsmath/checksums.ini | 2 +- build/pkgs/sphinxcontrib_qthelp/checksums.ini | 2 +- build/pkgs/sphinxcontrib_serializinghtml/checksums.ini | 2 +- build/pkgs/sphinxcontrib_websupport/checksums.ini | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/pkgs/sphinx/checksums.ini b/build/pkgs/sphinx/checksums.ini index 8f8c919290f..37da471e1c9 100644 --- a/build/pkgs/sphinx/checksums.ini +++ b/build/pkgs/sphinx/checksums.ini @@ -2,4 +2,4 @@ tarball=Sphinx-VERSION.tar.gz sha1=fd8b7655c4a01b3580a2abc216ff24c6776298b0 md5=20a2f1f67d88fac3743c11def966c9a6 cksum=2308785561 -upstream_url=https://files.pythonhosted.org/packages/a4/4a/0d48d133675eafb602714b3472b214e63d438e7e6985d41977e617b81f7a/Sphinx-VERSION.tar.gz +upstream_url=https://pypi.io/packages/source/s/sphinx/Sphinx-VERSION.tar.gz diff --git a/build/pkgs/sphinxcontrib_applehelp/checksums.ini b/build/pkgs/sphinxcontrib_applehelp/checksums.ini index 0bf12a630cc..ed55d035f14 100644 --- a/build/pkgs/sphinxcontrib_applehelp/checksums.ini +++ b/build/pkgs/sphinxcontrib_applehelp/checksums.ini @@ -2,4 +2,4 @@ tarball=sphinxcontrib-applehelp-VERSION.tar.gz sha1=adfd47917f82a86f30bdf356497baf68b47380bc md5=3f2de7681e12dde031acee0497c3cc2b cksum=1142149867 -upstream_url=https://files.pythonhosted.org/packages/9f/01/ad9d4ebbceddbed9979ab4a89ddb78c9760e74e6757b1880f1b2760e8295/sphinxcontrib-applehelp-VERSION.tar.gz +upstream_url=https://pypi.io/packages/source/s/sphinxcontrib-applehelp/sphinxcontrib-applehelp-VERSION.tar.gz diff --git a/build/pkgs/sphinxcontrib_devhelp/checksums.ini b/build/pkgs/sphinxcontrib_devhelp/checksums.ini index d751730c830..ec2f9b15bbe 100644 --- a/build/pkgs/sphinxcontrib_devhelp/checksums.ini +++ b/build/pkgs/sphinxcontrib_devhelp/checksums.ini @@ -2,4 +2,4 @@ tarball=sphinxcontrib-devhelp-VERSION.tar.gz sha1=3782815be9e11190fe7c7d697e73369432c56fd6 md5=94069c5cdb5079c445f5477fa6107016 cksum=4072264365 -upstream_url=https://files.pythonhosted.org/packages/98/33/dc28393f16385f722c893cb55539c641c9aaec8d1bc1c15b69ce0ac2dbb3/sphinxcontrib-devhelp-VERSION.tar.gz +upstream_url=https://pypi.io/packages/source/s/sphinxcontrib-devhelp/sphinxcontrib-devhelp-VERSION.tar.gz diff --git a/build/pkgs/sphinxcontrib_htmlhelp/checksums.ini b/build/pkgs/sphinxcontrib_htmlhelp/checksums.ini index 3bf844abaec..818e991207c 100644 --- a/build/pkgs/sphinxcontrib_htmlhelp/checksums.ini +++ b/build/pkgs/sphinxcontrib_htmlhelp/checksums.ini @@ -2,4 +2,4 @@ tarball=sphinxcontrib-htmlhelp-VERSION.tar.gz sha1=fc695250bc781777203b3a97a7aa7b0eab8a2c51 md5=f1db7db2a467f08f6292ab0d76e38584 cksum=1195324208 -upstream_url=https://files.pythonhosted.org/packages/c9/2e/a7a5fef38327b7f643ed13646321d19903a2f54b0a05868e4bc34d729e1f/sphinxcontrib-htmlhelp-VERSION.tar.gz +upstream_url=https://pypi.io/packages/source/s/sphinxcontrib-htmlhelp/sphinxcontrib-htmlhelp-VERSION.tar.gz diff --git a/build/pkgs/sphinxcontrib_jsmath/checksums.ini b/build/pkgs/sphinxcontrib_jsmath/checksums.ini index c22ac5d1981..f2fdba79204 100644 --- a/build/pkgs/sphinxcontrib_jsmath/checksums.ini +++ b/build/pkgs/sphinxcontrib_jsmath/checksums.ini @@ -2,4 +2,4 @@ tarball=sphinxcontrib-jsmath-VERSION.tar.gz sha1=70348505f159dca801522d6df68230e3c5e749c7 md5=e45179f0a3608b6766862e0f34c23b62 cksum=3778623264 -upstream_url=https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-VERSION.tar.gz +upstream_url=https://pypi.io/packages/source/s/sphinxcontrib-jsmath/sphinxcontrib-jsmath-VERSION.tar.gz diff --git a/build/pkgs/sphinxcontrib_qthelp/checksums.ini b/build/pkgs/sphinxcontrib_qthelp/checksums.ini index 09912de47da..e1ff365400e 100644 --- a/build/pkgs/sphinxcontrib_qthelp/checksums.ini +++ b/build/pkgs/sphinxcontrib_qthelp/checksums.ini @@ -2,4 +2,4 @@ tarball=sphinxcontrib-qthelp-VERSION.tar.gz sha1=3f0d3b111e2a57ae24afc51c518ebc2e9e377cd5 md5=93216721f3e154cce12d1e9c3307b415 cksum=3260884791 -upstream_url=https://files.pythonhosted.org/packages/b1/8e/c4846e59f38a5f2b4a0e3b27af38f2fcf904d4bfd82095bf92de0b114ebd/sphinxcontrib-qthelp-VERSION.tar.gz +upstream_url=https://pypi.io/packages/source/s/sphinxcontrib-qthelp/sphinxcontrib-qthelp-VERSION.tar.gz diff --git a/build/pkgs/sphinxcontrib_serializinghtml/checksums.ini b/build/pkgs/sphinxcontrib_serializinghtml/checksums.ini index c2e3c37481b..ea8ac106822 100644 --- a/build/pkgs/sphinxcontrib_serializinghtml/checksums.ini +++ b/build/pkgs/sphinxcontrib_serializinghtml/checksums.ini @@ -2,4 +2,4 @@ tarball=sphinxcontrib-serializinghtml-VERSION.tar.gz sha1=7d782d9f8fef0a5663fc7732d72847e711f0f18b md5=518ff437dcb05a74ed32ba19c892ce05 cksum=3002072803 -upstream_url=https://files.pythonhosted.org/packages/ac/86/021876a9dd4eac9dae0b1d454d848acbd56d5574d350d0f835043b5ac2cd/sphinxcontrib-serializinghtml-VERSION.tar.gz +upstream_url=https://pypi.io/packages/source/s/sphinxcontrib-serializinghtml/sphinxcontrib-serializinghtml-VERSION.tar.gz diff --git a/build/pkgs/sphinxcontrib_websupport/checksums.ini b/build/pkgs/sphinxcontrib_websupport/checksums.ini index 3938e3c7112..5fd49b7e2ac 100644 --- a/build/pkgs/sphinxcontrib_websupport/checksums.ini +++ b/build/pkgs/sphinxcontrib_websupport/checksums.ini @@ -2,4 +2,4 @@ tarball=sphinxcontrib-websupport-VERSION.tar.gz sha1=313f4b764872d36f890e76579985e6aaa732f4ca md5=4fe4d07afe1556c65182d0437228d7bb cksum=1830011133 -upstream_url=https://files.pythonhosted.org/packages/60/65/78e1514be951a3584df2e27b1b86e22609dd73312461e1af2afb9a53152c/sphinxcontrib-websupport-VERSION.tar.gz +upstream_url=https://pypi.io/packages/source/s/sphinxcontrib-websupport/sphinxcontrib-websupport-VERSION.tar.gz From 649289e2f92f7327e0d634540232b9985fc51258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Fri, 24 Apr 2020 09:39:09 +1200 Subject: [PATCH 153/300] move sphinx packages from pip to PYTHON_TOOLCHAIN --- build/pkgs/sphinxcontrib_applehelp/dependencies | 2 +- build/pkgs/sphinxcontrib_devhelp/dependencies | 2 +- build/pkgs/sphinxcontrib_htmlhelp/dependencies | 2 +- build/pkgs/sphinxcontrib_jsmath/dependencies | 2 +- build/pkgs/sphinxcontrib_qthelp/dependencies | 2 +- build/pkgs/sphinxcontrib_serializinghtml/dependencies | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build/pkgs/sphinxcontrib_applehelp/dependencies b/build/pkgs/sphinxcontrib_applehelp/dependencies index d5dab729e18..15df0c4d6d8 100644 --- a/build/pkgs/sphinxcontrib_applehelp/dependencies +++ b/build/pkgs/sphinxcontrib_applehelp/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | pip +$(PYTHON) | $(PYTHON_TOOLCHAIN) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sphinxcontrib_devhelp/dependencies b/build/pkgs/sphinxcontrib_devhelp/dependencies index d5dab729e18..15df0c4d6d8 100644 --- a/build/pkgs/sphinxcontrib_devhelp/dependencies +++ b/build/pkgs/sphinxcontrib_devhelp/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | pip +$(PYTHON) | $(PYTHON_TOOLCHAIN) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sphinxcontrib_htmlhelp/dependencies b/build/pkgs/sphinxcontrib_htmlhelp/dependencies index d5dab729e18..15df0c4d6d8 100644 --- a/build/pkgs/sphinxcontrib_htmlhelp/dependencies +++ b/build/pkgs/sphinxcontrib_htmlhelp/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | pip +$(PYTHON) | $(PYTHON_TOOLCHAIN) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sphinxcontrib_jsmath/dependencies b/build/pkgs/sphinxcontrib_jsmath/dependencies index d5dab729e18..15df0c4d6d8 100644 --- a/build/pkgs/sphinxcontrib_jsmath/dependencies +++ b/build/pkgs/sphinxcontrib_jsmath/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | pip +$(PYTHON) | $(PYTHON_TOOLCHAIN) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sphinxcontrib_qthelp/dependencies b/build/pkgs/sphinxcontrib_qthelp/dependencies index d5dab729e18..15df0c4d6d8 100644 --- a/build/pkgs/sphinxcontrib_qthelp/dependencies +++ b/build/pkgs/sphinxcontrib_qthelp/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | pip +$(PYTHON) | $(PYTHON_TOOLCHAIN) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/sphinxcontrib_serializinghtml/dependencies b/build/pkgs/sphinxcontrib_serializinghtml/dependencies index d5dab729e18..15df0c4d6d8 100644 --- a/build/pkgs/sphinxcontrib_serializinghtml/dependencies +++ b/build/pkgs/sphinxcontrib_serializinghtml/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | pip +$(PYTHON) | $(PYTHON_TOOLCHAIN) ---------- All lines of this file are ignored except the first. From e5415da0fbdb0f40411b977d947760cf88767ea5 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Fri, 24 Apr 2020 16:04:44 -0700 Subject: [PATCH 154/300] trac 28856: fix apostrophes in wikipedia links --- src/sage/categories/semigroups.py | 8 ++++---- src/sage/combinat/partition.py | 2 +- src/sage/combinat/posets/posets.py | 4 ++-- src/sage/combinat/root_system/plot.py | 2 +- src/sage/functions/jacobi.py | 2 +- .../geometry/riemannian_manifolds/surface3d_generators.py | 2 +- src/sage/graphs/base/static_sparse_graph.pyx | 2 +- src/sage/graphs/bipartite_graph.py | 2 +- src/sage/graphs/generators/smallgraphs.py | 2 +- src/sage/graphs/path_enumeration.pyx | 2 +- src/sage/graphs/spanning_tree.pyx | 4 ++-- src/sage/groups/matrix_gps/finitely_generated.py | 2 +- src/sage/matroids/linear_matroid.pyx | 2 +- src/sage/modules/free_module_element.pyx | 5 ++--- src/sage/plot/plot3d/parametric_plot3d.py | 2 +- 15 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/sage/categories/semigroups.py b/src/sage/categories/semigroups.py index 3f9939aeb2a..a24d8c8a4b5 100644 --- a/src/sage/categories/semigroups.py +++ b/src/sage/categories/semigroups.py @@ -543,7 +543,7 @@ def LTrivial(self): .. SEEALSO:: - - :wikipedia:`Green's_relations` + - :wikipedia:`Green%27s_relations` - :class:`Semigroups.SubcategoryMethods.RTrivial` - :class:`Semigroups.SubcategoryMethods.JTrivial` - :class:`Semigroups.SubcategoryMethods.HTrivial` @@ -588,7 +588,7 @@ def RTrivial(self): .. SEEALSO:: - - :wikipedia:`Green's_relations` + - :wikipedia:`Green%27s_relations` - :class:`Semigroups.SubcategoryMethods.LTrivial` - :class:`Semigroups.SubcategoryMethods.JTrivial` - :class:`Semigroups.SubcategoryMethods.HTrivial` @@ -644,7 +644,7 @@ def JTrivial(self): .. SEEALSO:: - - :wikipedia:`Green's_relations` + - :wikipedia:`Green%27s_relations` - :class:`Semigroups.SubcategoryMethods.LTrivial` - :class:`Semigroups.SubcategoryMethods.RTrivial` - :class:`Semigroups.SubcategoryMethods.HTrivial` @@ -680,7 +680,7 @@ def HTrivial(self): .. SEEALSO:: - - :wikipedia:`Green's_relations` + - :wikipedia:`Green%27s_relations` - :class:`Semigroups.SubcategoryMethods.RTrivial` - :class:`Semigroups.SubcategoryMethods.LTrivial` - :class:`Semigroups.SubcategoryMethods.JTrivial` diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index e046474e857..d51f04c0c5a 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -1243,7 +1243,7 @@ def sign(self): REFERENCES: - - :wikipedia:`Zolotarev's_lemma` + - :wikipedia:`Zolotarev%27s_lemma` """ return (-1)**(self.size()-self.length()) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index deac1eff88b..52d05189d74 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -4224,7 +4224,7 @@ def width(self, certificate=False): Return the width of the poset (the size of its longest antichain). It is computed through a matching in a bipartite graph; see - :wikipedia:`Dilworth's_theorem` for more information. The width is + :wikipedia:`Dilworth%27s_theorem` for more information. The width is also called Dilworth number. INPUT: @@ -4276,7 +4276,7 @@ def dilworth_decomposition(self): partitioned into `\alpha` chains, where `\alpha` is the cardinality of its largest antichain. This method returns such a partition. - See :wikipedia:`Dilworth's_theorem`. + See :wikipedia:`Dilworth%27s_theorem`. ALGORITHM: diff --git a/src/sage/combinat/root_system/plot.py b/src/sage/combinat/root_system/plot.py index 627f7875b50..3457339f7c0 100644 --- a/src/sage/combinat/root_system/plot.py +++ b/src/sage/combinat/root_system/plot.py @@ -141,7 +141,7 @@ One can also customize the projection by specifying a function. Here, we display all the roots for type `E_8` using the projection from its eight dimensional ambient space onto 3D described on -:wikipedia:`Wikipedia's E8 3D picture `:: +:wikipedia:`Wikipedia%27s E8 3D picture `:: sage: M = matrix([[0., -0.556793440452, 0.19694925177, -0.19694925177, 0.0805477263944, -0.385290876171, 0., 0.385290876171], ....: [0.180913155536, 0., 0.160212955043, 0.160212955043, 0., 0.0990170516545, 0.766360424875, 0.0990170516545], diff --git a/src/sage/functions/jacobi.py b/src/sage/functions/jacobi.py index 21fbec8bb93..b61892dda09 100644 --- a/src/sage/functions/jacobi.py +++ b/src/sage/functions/jacobi.py @@ -125,7 +125,7 @@ REFERENCES: -- :wikipedia:`Jacobi's_elliptic_functions` +- :wikipedia:`Jacobi%27s_elliptic_functions` - [KS2002]_ diff --git a/src/sage/geometry/riemannian_manifolds/surface3d_generators.py b/src/sage/geometry/riemannian_manifolds/surface3d_generators.py index 8bfbba189cb..078af43b338 100644 --- a/src/sage/geometry/riemannian_manifolds/surface3d_generators.py +++ b/src/sage/geometry/riemannian_manifolds/surface3d_generators.py @@ -114,7 +114,7 @@ def Dini(a=1, b=1, name="Dini's surface"): - ``name`` -- string. Name of the surface. - For more information, see :wikipedia:`Dini's_surface`. + For more information, see :wikipedia:`Dini%27s_surface`. EXAMPLES:: diff --git a/src/sage/graphs/base/static_sparse_graph.pyx b/src/sage/graphs/base/static_sparse_graph.pyx index 79a32ea523f..93c534f89e1 100644 --- a/src/sage/graphs/base/static_sparse_graph.pyx +++ b/src/sage/graphs/base/static_sparse_graph.pyx @@ -682,7 +682,7 @@ def tarjan_strongly_connected_components(G): the lowlink of `v`, that whole subtree is a new SCC. For more information, see the - :wikipedia:`Tarjan's_strongly_connected_components_algorithm`. + :wikipedia:`Tarjan%27s_strongly_connected_components_algorithm`. EXAMPLES:: diff --git a/src/sage/graphs/bipartite_graph.py b/src/sage/graphs/bipartite_graph.py index 744a6399231..b1a72081ecf 100644 --- a/src/sage/graphs/bipartite_graph.py +++ b/src/sage/graphs/bipartite_graph.py @@ -1634,7 +1634,7 @@ def vertex_cover(self, algorithm="Konig", value_only=False, among: - ``"Konig"`` will compute a minimum vertex cover using Konig's - algorithm (:wikipedia:`Kőnig's_theorem_(graph_theory)`) + algorithm (:wikipedia:`Kőnig%27s_theorem_(graph_theory)`) - ``"Cliquer"`` will compute a minimum vertex cover using the Cliquer package diff --git a/src/sage/graphs/generators/smallgraphs.py b/src/sage/graphs/generators/smallgraphs.py index 4f8a6732288..ee3a5a98d30 100644 --- a/src/sage/graphs/generators/smallgraphs.py +++ b/src/sage/graphs/generators/smallgraphs.py @@ -4327,7 +4327,7 @@ def TietzeGraph(): Return the Tietze Graph. For more information on the Tietze Graph, see the - :wikipedia:`Tietze's_graph`. + :wikipedia:`Tietze%27s_graph`. EXAMPLES:: diff --git a/src/sage/graphs/path_enumeration.pyx b/src/sage/graphs/path_enumeration.pyx index 5b252b06285..1cd0f172c46 100644 --- a/src/sage/graphs/path_enumeration.pyx +++ b/src/sage/graphs/path_enumeration.pyx @@ -617,7 +617,7 @@ def yen_k_shortest_simple_paths(self, source, target, weight_function=None, and `m` is the number of edges and `k` is the number of shortest paths needed to find. - See [Yen1970]_ and the :wikipedia:`Yen's_algorithm` for more details on the + See [Yen1970]_ and the :wikipedia:`Yen%27s_algorithm` for more details on the algorithm. EXAMPLES:: diff --git a/src/sage/graphs/spanning_tree.pyx b/src/sage/graphs/spanning_tree.pyx index 1572f35bac4..7c8b2597dec 100644 --- a/src/sage/graphs/spanning_tree.pyx +++ b/src/sage/graphs/spanning_tree.pyx @@ -401,7 +401,7 @@ def filter_kruskal(G, threshold=10000, weight_function=None, bint check=False): .. SEEALSO:: - :meth:`sage.graphs.generic_graph.GenericGraph.min_spanning_tree` - - :wikipedia:`Kruskal's_algorithm` + - :wikipedia:`Kruskal%27s_algorithm` - :func:`kruskal` - :func:`filter_kruskal_iterator` @@ -429,7 +429,7 @@ def filter_kruskal_iterator(G, threshold=10000, weight_function=None, bint check .. SEEALSO:: - :meth:`sage.graphs.generic_graph.GenericGraph.min_spanning_tree` - - :wikipedia:`Kruskal's_algorithm` + - :wikipedia:`Kruskal%27s_algorithm` - :func:`kruskal` - :func:`filter_kruskal` diff --git a/src/sage/groups/matrix_gps/finitely_generated.py b/src/sage/groups/matrix_gps/finitely_generated.py index d356c9cfc14..fec451070a0 100644 --- a/src/sage/groups/matrix_gps/finitely_generated.py +++ b/src/sage/groups/matrix_gps/finitely_generated.py @@ -48,7 +48,7 @@ - Volker Braun (2013-1) port to new Parent, libGAP. - Sebastian Oehms (2018-07): Added _permutation_group_element_ (Trac #25706) -- Sebastian Oehms (2019-01): Revision of :trac:`25706` (:trac:`26903`and :trac:`27143`). +- Sebastian Oehms (2019-01): Revision of :trac:`25706` (:trac:`26903` and :trac:`27143`). """ ############################################################################## diff --git a/src/sage/matroids/linear_matroid.pyx b/src/sage/matroids/linear_matroid.pyx index e72f7748d9e..bf354d86ab7 100644 --- a/src/sage/matroids/linear_matroid.pyx +++ b/src/sage/matroids/linear_matroid.pyx @@ -5870,7 +5870,7 @@ cdef class RegularMatroid(LinearMatroid): ALGORITHM: Since the matroid is regular, we use Kirchhoff's Matrix-Tree Theorem. - See also :wikipedia:`Kirchhoff's_theorem`. + See also :wikipedia:`Kirchhoff%27s_theorem`. """ if self._bases_count is None: R = self._basic_representation()._matrix_() diff --git a/src/sage/modules/free_module_element.pyx b/src/sage/modules/free_module_element.pyx index c0d39da6968..e60ae43cc40 100644 --- a/src/sage/modules/free_module_element.pyx +++ b/src/sage/modules/free_module_element.pyx @@ -2698,15 +2698,14 @@ cdef class FreeModuleElement(Vector): # abstract base class Return the matrix which describes a cross product between ``self`` and some other vector. - This operation is sometimes written using the `hat operator`_. + This operation is sometimes written using the hat operator: + see :wikipedia:`Hat_operator#Cross_product`. It is only defined for vectors of length 3 or 7. For a vector `v` the cross product matrix `\hat{v}` is a matrix which satisfies `\hat{v} \cdot w = v \times w` and also `w \cdot \hat{v} = w \times v` for all vectors `w`. The basis vectors are assumed to be orthonormal. - .. _hat operator: :wikipedia:`Hat_operator#Cross_product` - OUTPUT: The cross product matrix of this vector. diff --git a/src/sage/plot/plot3d/parametric_plot3d.py b/src/sage/plot/plot3d/parametric_plot3d.py index da98407f2a9..ee1a959a7bd 100644 --- a/src/sage/plot/plot3d/parametric_plot3d.py +++ b/src/sage/plot/plot3d/parametric_plot3d.py @@ -416,7 +416,7 @@ def g(x,y): return x, y+sin(y), x**2 + y**2 f_z = cos(u) / (1 + sqrt(2)) sphinx_plot(parametric_plot3d([f_x, f_y, f_z], (u,-pi,pi), (v,-pi,pi), frame=False, color="green")) - Boy's surface (:wikipedia:`Boy's_surface` and https://mathcurve.com/surfaces/boy/boy.shtml):: + Boy's surface (:wikipedia:`Boy%27s_surface` and https://mathcurve.com/surfaces/boy/boy.shtml):: sage: u, v = var('u,v') sage: K = cos(u) / (sqrt(2) - cos(2*u)*sin(3*v)) From 1777fad4b5bedcb34286e6064bf20d2d02231a88 Mon Sep 17 00:00:00 2001 From: vipul79321 Date: Fri, 22 May 2020 16:21:13 +0530 Subject: [PATCH 155/300] reference fixed --- src/doc/en/reference/references/index.rst | 10 +++++----- src/sage/graphs/distances_all_pairs.pyx | 5 +++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 949651ff129..83fb3368376 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1862,6 +1862,11 @@ REFERENCES: .. [DR2002] Joan Daemen, Vincent Rijmen. *The Design of Rijndael*. Springer-Verlag Berlin Heidelberg, 2002. +.. [Dragan2018] Feodor Dragan, Michel Habib, Laurent Viennot. + *Revisiting Radius, Diameter, and all Eccentricity Computation + in Graphs through Certificates*. + http://arxiv.org/abs/1803.04660 + .. [Dro1987] Carl Droms. *Isomorphisms of graph groups*. Proc. of the Amer. Math. Soc. **100** (1987). No 3. http://educ.jmu.edu/~dromscg/vita/preprints/Isomorphisms.pdf @@ -2526,11 +2531,6 @@ REFERENCES: .. [Ha2005] Gerhard Haring. [Online] Available: http://osdir.com/ml/python.db.pysqlite.user/2005-11/msg00047.html -.. [Habib2018] Feodor Dragan, Michel Habib, Laurent Viennot. - *Revisiting Radius, Diameter, and all Eccentricity Computation - in Graphs through Certificates*. - http://arxiv.org/abs/1803.04660 - .. [Hac2016] \M. Hachimori. http://infoshako.sk.tsukuba.ac.jp/~hachi/math/library/dunce_hat_eng.html .. [Haf2004] Paul R. Hafner. *On the Graphs of Hoffman-Singleton and Higman-Sims*. diff --git a/src/sage/graphs/distances_all_pairs.pyx b/src/sage/graphs/distances_all_pairs.pyx index c4ca5a9aeef..4c5f9f97ad9 100644 --- a/src/sage/graphs/distances_all_pairs.pyx +++ b/src/sage/graphs/distances_all_pairs.pyx @@ -1458,7 +1458,7 @@ def radius(G): Return radius of unweighted graph `G`. This method computes radius of unweighted undirected graph using the - algorithm given in [Habib2018]_. + algorithm given in [Dragan2018]_. This method returns Infinity if graph is not connected. @@ -1469,7 +1469,8 @@ def radius(G): sage: radius(G) 2 sage: G = graphs.RandomGNP(20,0.3) - sage: radius(G) == G.radius() + sage: from sage.graphs.distances_all_pairs import eccentricity + sage: radius(G) == min(eccentricity(G, algorithm='bounds')) True TESTS: From 386c82509edf30560e83fa38e3c6e0011e4fa89e Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 22 May 2020 13:26:48 +0100 Subject: [PATCH 156/300] Added tests for CylindricalDiagram --- .../combinat/path_tableaux/path_tableau.py | 57 +++++++++++++++++-- 1 file changed, 52 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/path_tableaux/path_tableau.py b/src/sage/combinat/path_tableaux/path_tableau.py index c6fc0968986..fcdf188859c 100644 --- a/src/sage/combinat/path_tableaux/path_tableau.py +++ b/src/sage/combinat/path_tableaux/path_tableau.py @@ -501,14 +501,19 @@ def __init__(self,T): self.diagram = result - def __repr__(self): + def _repr_(self): """ Return a string representation of ``self`` TESTS:: - sage: print(CatalanTableau([0,1,2,1,2,1,0])) # indirect test - [0, 1, 2, 1, 2, 1, 0] + sage: cd = CylindricalDiagram(CatalanTableau([0,1,2,1,2,1,0])) + sage: repr(cd) == cd._repr_() # indirect test + True + + sage: cd = CylindricalDiagram(FriezePattern([1,3,4,5,1])) + sage: repr(cd) == cd._repr_() # indirect test + True """ dg = self.diagram return ' '+str(dg[0])+''.join('\n ' + str(x) for x in dg[1:]) @@ -530,6 +535,19 @@ def _latex_(self): & & & & & 0 & 1 & 0 & 1 & 2 & 1 & 0\\ & & & & & & 0 & 1 & 2 & 3 & 2 & 1 & 0 \end{array} + + sage: t = FriezePattern([1,3,4,5,1]) + sage: latex(CylindricalDiagram(t)) + \begin{array}{ccccccccccccc} + 0 & 1 & 3 & 4 & 5 & 1 & 0\\ + & 0 & 1 & \frac{5}{3} & \frac{7}{3} & \frac{2}{3} & 1 & 0\\ + & & 0 & 1 & 2 & 1 & 3 & 1 & 0\\ + & & & 0 & 1 & 1 & 4 & \frac{5}{3} & 1 & 0\\ + & & & & 0 & 1 & 5 & \frac{7}{3} & 2 & 1 & 0\\ + & & & & & 0 & 1 & \frac{2}{3} & 1 & 1 & 1 & 0\\ + & & & & & & 0 & 1 & 3 & 4 & 5 & 1 & 0 + \end{array} + """ D = self.diagram m = len(D[-1]) @@ -564,6 +582,16 @@ def _ascii_art_(self): 0 1 2 1 0 1 0 0 1 0 1 2 1 0 0 1 2 3 2 1 0 + + sage: t = FriezePattern([1,3,4,5,1]) + sage: ascii_art(CylindricalDiagram(t)) + 0 1 3 4 5 1 0 + 0 1 5/3 7/3 2/3 1 0 + 0 1 2 1 3 1 0 + 0 1 1 4 5/3 1 0 + 0 1 5 7/3 2 1 0 + 0 1 2/3 1 1 1 0 + 0 1 3 4 5 1 0 """ from sage.typeset.ascii_art import AsciiArt D = [ map(str,x) for x in self.diagram ] @@ -585,6 +613,16 @@ def _unicode_art_(self): 0 1 2 1 0 1 0 0 1 0 1 2 1 0 0 1 2 3 2 1 0 + + sage: t = FriezePattern([1,3,4,5,1]) + sage: unicode_art(CylindricalDiagram(t)) + 0 1 3 4 5 1 0 + 0 1 5/3 7/3 2/3 1 0 + 0 1 2 1 3 1 0 + 0 1 1 4 5/3 1 0 + 0 1 5 7/3 2 1 0 + 0 1 2/3 1 1 1 0 + 0 1 3 4 5 1 0 """ from sage.typeset.unicode_art import UnicodeArt D = [ map(str,x) for x in self.diagram ] @@ -607,5 +645,14 @@ def pp(self): 0 1 0 1 2 1 0 0 1 2 3 2 1 0 - """ - print('\n'.join(' '.join('{:0<}'.format(a) for a in x) for x in self.diagram )) + sage: t = FriezePattern([1,3,4,5,1]) + sage: CylindricalDiagram(t).pp() + 0 1 3 4 5 1 0 + 0 1 5/3 7/3 2/3 1 0 + 0 1 2 1 3 1 0 + 0 1 1 4 5/3 1 0 + 0 1 5 7/3 2 1 0 + 0 1 2/3 1 1 1 0 + 0 1 3 4 5 1 0 + """ + print('\n'.join(' '.join('{!s}'.format(a) for a in x) for x in self.diagram )) From 0bc80845f0c939dd27f9fc99a29572c3da1d4e3f Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 22 May 2020 16:20:42 +0100 Subject: [PATCH 157/300] Added change_ring --- src/sage/combinat/path_tableaux/frieze.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/sage/combinat/path_tableaux/frieze.py b/src/sage/combinat/path_tableaux/frieze.py index 7437a854c6e..3b2474fa360 100644 --- a/src/sage/combinat/path_tableaux/frieze.py +++ b/src/sage/combinat/path_tableaux/frieze.py @@ -424,6 +424,28 @@ def show(self,model='UHP'): gd = [ M.get_geodesic(vt[i-1],vt[i]) for i in range(len(vt))] return sum([a.plot() for a in gd],Graphics()) + def change_ring(self, R): + r""" + Return ''self'' as a frieze pattern with coefficients in ''R'' + assuming there is a canonical coerce map from the base ring of ''self'' + to ''R''. + + EXAMPLES:: + + sage: FriezePattern([1,2,7,5,3,7,4,1]).change_ring(RealField()) + [0.000000000000000, 1.00000000000000, ... 4.00000000000000, 1.00000000000000, 0.000000000000000] + sage: FriezePattern([1,2,7,5,3,7,4,1]).change_ring(GF(7)) + Traceback (most recent call last): + ... + TypeError: no base extension defined + """ + from sage.structure.element import parent + + if R.has_coerce_map_from(parent(self).field): + return FriezePattern(list(self), field = R) + else: + raise TypeError("no base extension defined") + class FriezePatterns(PathTableaux): """ The parent class for FriezePattern. From 8f66113223b4925deea44bcdfc2f3bb6c58fa697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Sat, 23 May 2020 17:10:05 +1200 Subject: [PATCH 158/300] Minor upgdrade to Sphinx 3.0.3 --- build/pkgs/sphinx/checksums.ini | 6 +++--- build/pkgs/sphinx/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/sphinx/checksums.ini b/build/pkgs/sphinx/checksums.ini index 37da471e1c9..a2150308444 100644 --- a/build/pkgs/sphinx/checksums.ini +++ b/build/pkgs/sphinx/checksums.ini @@ -1,5 +1,5 @@ tarball=Sphinx-VERSION.tar.gz -sha1=fd8b7655c4a01b3580a2abc216ff24c6776298b0 -md5=20a2f1f67d88fac3743c11def966c9a6 -cksum=2308785561 +sha1=781b9233902d92244be8f9537db3a4bd79a90df0 +md5=d5d0f61059c8ddb01b12e80a9e61adcb +cksum=3158798019 upstream_url=https://pypi.io/packages/source/s/sphinx/Sphinx-VERSION.tar.gz diff --git a/build/pkgs/sphinx/package-version.txt b/build/pkgs/sphinx/package-version.txt index 16f01e82efb..e8c8fdf4b74 100644 --- a/build/pkgs/sphinx/package-version.txt +++ b/build/pkgs/sphinx/package-version.txt @@ -1 +1 @@ -3.0.2.p0 +3.0.3.p0 From 25f72302aabc364e87d5c9e4c473d6f0ffa5b3da Mon Sep 17 00:00:00 2001 From: vipul79321 Date: Sun, 24 May 2020 01:15:13 +0530 Subject: [PATCH 159/300] added radius method for weighted graphs --- src/sage/graphs/base/boost_graph.pyx | 89 +++++++++++++++++++++++++ src/sage/graphs/distances_all_pairs.pyx | 2 +- 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/base/boost_graph.pyx b/src/sage/graphs/base/boost_graph.pyx index 6ba0a44c9af..eff8ef6cbd6 100644 --- a/src/sage/graphs/base/boost_graph.pyx +++ b/src/sage/graphs/base/boost_graph.pyx @@ -1603,3 +1603,92 @@ cpdef min_cycle_basis(g_sage, weight_function=None, by_weight=False): if len(orth_set[j] & new_cycle) % 2: orth_set[j] = orth_set[j] ^ base return cycle_basis + +cpdef radius(g, weight_function=None): + r""" + Return radius of weighted graph `g`. + """ + if g.is_directed(): + raise TypeError("This method works for undirected graphs only") + + cdef int n = g.order() + if n <= 1: + return 0 + + cdef int negative_weight = 0 + + if weight_function is not None: + for e in g.edge_iterator(): + if float(weight_function(e)) < 0: + negative_weight = 1 + break + else: + for _,_,w in g.edge_iterator(): + if w and float(w) < 0: + negative_weight = 1 + break + + cdef dict v_to_int = {vv: vi for vi, vv in enumerate(g)} + cdef BoostVecWeightedGraph g_boost + boost_weighted_graph_from_sage_graph(&g_boost, g, v_to_int, weight_function) + + import sys + cdef int source + cdef int next_source = 0 + cdef int antipode + cdef double LB = sys.float_info.max + cdef double UB = sys.float_info.max + cdef result_distances result + cdef vector[double] ecc = {0 for i in range(n)} + cdef vector[double] ecc_lower_bound = {0 for i in range(n)} + cdef double eccentricity + + while True: + source = next_source + + if negative_weight: + sig_on() + result = g_boost.bellman_ford_shortest_paths(source) + sig_off() + if not result.distances.size(): + raise ValueError("the graph contains a negative cycle") + else: + sig_on() + result = g_boost.dijkstra_shortest_paths(source) + sig_off() + + eccentricity = 0 + for v in range(n): + if eccentricity <= result.distances[v]: + eccentricity = result.distances[v] + antipode = v + + if eccentricity == sys.float_info.max: + from sage.rings.infinity import Infinity + return +Infinity + + ecc[source] = eccentricity + + if ecc[source] == ecc_lower_bound[source]: + return ecc[source] + + if negative_weight: + sig_on() + result = g_boost.bellman_ford_shortest_paths(antipode) + sig_off() + else: + sig_on() + result = g_boost.dijkstra_shortest_paths(antipode) + sig_off() + + UB = min(UB, ecc[source]) + LB = sys.float_info.max + + for v in range(n): + ecc_lower_bound[v] = max(ecc_lower_bound[v], result.distances[v]) + if LB > ecc_lower_bound[v]: + LB = ecc_lower_bound[v] + next_source = v + + if UB <= LB: + return UB \ No newline at end of file diff --git a/src/sage/graphs/distances_all_pairs.pyx b/src/sage/graphs/distances_all_pairs.pyx index 4c5f9f97ad9..85729d6216d 100644 --- a/src/sage/graphs/distances_all_pairs.pyx +++ b/src/sage/graphs/distances_all_pairs.pyx @@ -1490,7 +1490,7 @@ def radius(G): ... TypeError: This method works for unweighted undirected graphs only """ - if G.is_directed() or G.weighted(): + if G.is_directed(): raise TypeError("This method works for unweighted undirected graphs only") cdef uint32_t n = G.order() From abdabce90fd9cb623753c1e5fcde4b00b39b46b9 Mon Sep 17 00:00:00 2001 From: vipul79321 Date: Mon, 25 May 2020 00:17:05 +0530 Subject: [PATCH 160/300] Documentation completed --- src/sage/graphs/base/boost_graph.pyx | 96 +++++++++++++++++++------ src/sage/graphs/distances_all_pairs.pyx | 4 +- 2 files changed, 78 insertions(+), 22 deletions(-) diff --git a/src/sage/graphs/base/boost_graph.pyx b/src/sage/graphs/base/boost_graph.pyx index eff8ef6cbd6..2b360b4233f 100644 --- a/src/sage/graphs/base/boost_graph.pyx +++ b/src/sage/graphs/base/boost_graph.pyx @@ -1607,15 +1607,55 @@ cpdef min_cycle_basis(g_sage, weight_function=None, by_weight=False): cpdef radius(g, weight_function=None): r""" Return radius of weighted graph `g`. + + This method computes radius of undirected graph using the + algorithm given in [Dragan2018]_. + + This method returns Infinity if graph is not connected. + + INPUT: + + - ``g`` -- the input Sage graph + + - ``weight_function`` -- function (default: ``None``); a function that + associates a weight to each edge. If ``None`` (default), the weights of + ``g`` are used, if available, otherwise all edges have weight 1. + + EXAMPLES:: + + sage: from sage.graphs.base.boost_graph import radius + sage: G = Graph([(0,1,1), (1,2,1), (0,2,3)]) + sage: radius(G) + 1.0 + sage: G = graphs.PathGraph(7) + sage: radius(G) == G.radius(algorithm='Dijkstra_Boost') + True + + TESTS: + + sage: G = Graph() + sage: radius(G) + 0 + sage: G = Graph(1) + sage: radius(G) + 0 + sage: G = Graph(2) + sage: radius(G) + +Infinity + sage: G = DiGraph(1) + sage: radius(G) + Traceback (most recent call last): + ... + TypeError: this method works for undirected graphs only """ if g.is_directed(): - raise TypeError("This method works for undirected graphs only") + raise TypeError("this method works for undirected graphs only") cdef int n = g.order() if n <= 1: return 0 - cdef int negative_weight = 0 + cdef bint negative_weight = 0 if weight_function is not None: for e in g.edge_iterator(): @@ -1628,67 +1668,83 @@ cpdef radius(g, weight_function=None): negative_weight = 1 break + # These variables are automatically deleted when the function terminates. cdef dict v_to_int = {vv: vi for vi, vv in enumerate(g)} cdef BoostVecWeightedGraph g_boost boost_weighted_graph_from_sage_graph(&g_boost, g, v_to_int, weight_function) import sys - cdef int source - cdef int next_source = 0 - cdef int antipode + cdef v_index source + cdef v_index next_source = 0 # To store source for next iteration + cdef v_index antipode cdef double LB = sys.float_info.max cdef double UB = sys.float_info.max - cdef result_distances result - cdef vector[double] ecc = {0 for i in range(n)} - cdef vector[double] ecc_lower_bound = {0 for i in range(n)} + # For storing distances of all nodes from source + cdef vector[double] distances + # For storing eccentricity of nodes + cdef vector[double] ecc + # For storing lower bound on eccentricity of nodes + cdef vector[double] ecc_lower_bound cdef double eccentricity + # Initializing + for i in range(n): + ecc_lower_bound.push_back(0) + ecc.push_back(0) + + # Algorithm while True: + # 1) pick vertex with minimum eccentricity lower bound + # and compute its eccentricity source = next_source if negative_weight: sig_on() - result = g_boost.bellman_ford_shortest_paths(source) + distances = g_boost.bellman_ford_shortest_paths(source).distances sig_off() - if not result.distances.size(): + if not distances.size(): raise ValueError("the graph contains a negative cycle") else: sig_on() - result = g_boost.dijkstra_shortest_paths(source) + distances = g_boost.dijkstra_shortest_paths(source).distances sig_off() eccentricity = 0 for v in range(n): - if eccentricity <= result.distances[v]: - eccentricity = result.distances[v] - antipode = v + if eccentricity < distances[v]: + eccentricity = distances[v] + antipode = v # vertex at largest distance from source - if eccentricity == sys.float_info.max: + if eccentricity == sys.float_info.max: # Disconnected graph from sage.rings.infinity import Infinity return +Infinity ecc[source] = eccentricity if ecc[source] == ecc_lower_bound[source]: + # we have found minimum eccentricity vertex and hence the radius return ecc[source] + # 2) Compute distances from antipode of source if negative_weight: sig_on() - result = g_boost.bellman_ford_shortest_paths(antipode) + distances = g_boost.bellman_ford_shortest_paths(antipode).distances sig_off() else: sig_on() - result = g_boost.dijkstra_shortest_paths(antipode) + distances = g_boost.dijkstra_shortest_paths(antipode).distances sig_off() - UB = min(UB, ecc[source]) + UB = min(UB, ecc[source]) # minimum among exact computed eccentricities LB = sys.float_info.max + # 3) Use distances from antipode to + # improve eccentricity lower bounds for v in range(n): - ecc_lower_bound[v] = max(ecc_lower_bound[v], result.distances[v]) + ecc_lower_bound[v] = max(ecc_lower_bound[v], distances[v]) if LB > ecc_lower_bound[v]: LB = ecc_lower_bound[v] - next_source = v + next_source = v # vertex with minimum eccentricity lower bound if UB <= LB: return UB \ No newline at end of file diff --git a/src/sage/graphs/distances_all_pairs.pyx b/src/sage/graphs/distances_all_pairs.pyx index 85729d6216d..fce75ec7b72 100644 --- a/src/sage/graphs/distances_all_pairs.pyx +++ b/src/sage/graphs/distances_all_pairs.pyx @@ -1488,10 +1488,10 @@ def radius(G): sage: radius(G) Traceback (most recent call last): ... - TypeError: This method works for unweighted undirected graphs only + TypeError: this method works for unweighted undirected graphs only """ if G.is_directed(): - raise TypeError("This method works for unweighted undirected graphs only") + raise TypeError("this method works for unweighted undirected graphs only") cdef uint32_t n = G.order() if n <= 1: From 8a395fecd78cc8da448956e94101c81489b35c3f Mon Sep 17 00:00:00 2001 From: Antonio Rojas Date: Mon, 25 May 2020 09:53:28 +0200 Subject: [PATCH 161/300] Update sympy to 1.6 --- build/pkgs/sympy/checksums.ini | 7 ++++--- build/pkgs/sympy/package-version.txt | 2 +- src/sage/calculus/test_sympy.py | 2 +- src/sage/manifolds/calculus_method.py | 2 +- src/sage/symbolic/relation.py | 3 ++- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/build/pkgs/sympy/checksums.ini b/build/pkgs/sympy/checksums.ini index 1b98ad8879c..e5b80927ab8 100644 --- a/build/pkgs/sympy/checksums.ini +++ b/build/pkgs/sympy/checksums.ini @@ -1,4 +1,5 @@ tarball=sympy-VERSION.tar.gz -sha1=be2e740860f7900f0ee2a8102d2943fded44125c -md5=fa9ad424535075312df022964ede21bc -cksum=3298250000 +sha1=067078df2d0401f3c4b49ee2e50a4105f92c5272 +md5=dbb7b21d2972c41f37d48f744b6189a3 +cksum=575244204 +upstream_url=https://github.com/sympy/sympy/releases/download/sympy-VERSION/sympy-VERSION.tar.gz diff --git a/build/pkgs/sympy/package-version.txt b/build/pkgs/sympy/package-version.txt index c239c60cba2..810ee4e91e2 100644 --- a/build/pkgs/sympy/package-version.txt +++ b/build/pkgs/sympy/package-version.txt @@ -1 +1 @@ -1.5 +1.6 diff --git a/src/sage/calculus/test_sympy.py b/src/sage/calculus/test_sympy.py index 9fb9358cb2b..86f93667040 100644 --- a/src/sage/calculus/test_sympy.py +++ b/src/sage/calculus/test_sympy.py @@ -109,7 +109,7 @@ sage: e = (1/cos(x)^3)._sympy_(); e cos(x)**(-3) - sage: f = e.series(x, 0, 10); f + sage: f = e.series(x, 0, int(10)); f 1 + 3*x**2/2 + 11*x**4/8 + 241*x**6/240 + 8651*x**8/13440 + O(x**10) And the pretty-printer. Since unicode characters are not working on diff --git a/src/sage/manifolds/calculus_method.py b/src/sage/manifolds/calculus_method.py index 7042afe77a5..a658551ee9f 100644 --- a/src/sage/manifolds/calculus_method.py +++ b/src/sage/manifolds/calculus_method.py @@ -65,7 +65,7 @@ def _SR_to_Sympy(expression): """ # Nothing to do if expression is already a SymPy object: - if type(expression) in sympy.core.all_classes: + if type(expression) in sympy.core.core.all_classes: return expression return SR(expression)._sympy_() diff --git a/src/sage/symbolic/relation.py b/src/sage/symbolic/relation.py index 028f6287971..d252434d523 100644 --- a/src/sage/symbolic/relation.py +++ b/src/sage/symbolic/relation.py @@ -914,7 +914,8 @@ def solve(f, *args, **kwds): print them:: sage: solve(sinh(x) - 2*cosh(x),x,algorithm='sympy') - ConditionSet(x, Eq((-exp(2*x) - 3)*exp(-x)/2, 0), Reals) + [ImageSet(Lambda(_n, I*(2*_n*pi + pi/2) + log(sqrt(3))), Integers), + ImageSet(Lambda(_n, I*(2*_n*pi - pi/2) + log(sqrt(3))), Integers)] sage: solve(2*sin(x) - 2*sin(2*x), x,algorithm='sympy') [ImageSet(Lambda(_n, 2*_n*pi), Integers), ImageSet(Lambda(_n, 2*_n*pi + pi), Integers), From ef23d2f124004b586ee5b3b06aaf1f9077677968 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Mon, 25 May 2020 15:08:20 +0100 Subject: [PATCH 162/300] Changed syntax for formatting error messages --- src/sage/combinat/path_tableaux/frieze.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/path_tableaux/frieze.py b/src/sage/combinat/path_tableaux/frieze.py index 3b2474fa360..dadde9affaa 100644 --- a/src/sage/combinat/path_tableaux/frieze.py +++ b/src/sage/combinat/path_tableaux/frieze.py @@ -176,10 +176,10 @@ def __classcall_private__(cls, fp, field=QQ): try: w = [field(a) for a in fp] except TypeError: - raise ValueError("{} is not a sequence in the field {}".format(fp, field)) + raise ValueError(f"{fp} is not a sequence in the field {field}") if w is None: - raise ValueError("invalid input {}".format(fp)) + raise ValueError(f"invalid input {fp}") w.insert(0,field(0)) w.append(field(0)) @@ -414,7 +414,7 @@ def show(self,model='UHP'): } M = models.get(model) if not M: - raise ValueError("{!s} must be one of ''UHP'', ''PD'', ''KM''".format(model)) + raise ValueError(f"{model} must be one of ''UHP'', ''PD'', ''KM''") U = HyperbolicPlane().UHP() cd = CylindricalDiagram(self).diagram @@ -434,6 +434,7 @@ def change_ring(self, R): sage: FriezePattern([1,2,7,5,3,7,4,1]).change_ring(RealField()) [0.000000000000000, 1.00000000000000, ... 4.00000000000000, 1.00000000000000, 0.000000000000000] + sage: FriezePattern([1,2,7,5,3,7,4,1]).change_ring(GF(7)) Traceback (most recent call last): ... From 83c8c552880559f445159b12d49fac657d350c84 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Mon, 25 May 2020 15:11:14 +0100 Subject: [PATCH 163/300] Removed need to import parent --- src/sage/combinat/path_tableaux/frieze.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/path_tableaux/frieze.py b/src/sage/combinat/path_tableaux/frieze.py index dadde9affaa..68a2e5b9025 100644 --- a/src/sage/combinat/path_tableaux/frieze.py +++ b/src/sage/combinat/path_tableaux/frieze.py @@ -440,9 +440,9 @@ def change_ring(self, R): ... TypeError: no base extension defined """ - from sage.structure.element import parent + #from sage.structure.element import parent - if R.has_coerce_map_from(parent(self).field): + if R.has_coerce_map_from(self.parent().field): return FriezePattern(list(self), field = R) else: raise TypeError("no base extension defined") From 8ec934fcc2b995c5eac225cdcc599fe93a9fc0f5 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Tue, 26 May 2020 10:20:21 +0100 Subject: [PATCH 164/300] Minor edits --- src/sage/combinat/path_tableaux/frieze.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/combinat/path_tableaux/frieze.py b/src/sage/combinat/path_tableaux/frieze.py index 68a2e5b9025..c03458f4164 100644 --- a/src/sage/combinat/path_tableaux/frieze.py +++ b/src/sage/combinat/path_tableaux/frieze.py @@ -440,7 +440,6 @@ def change_ring(self, R): ... TypeError: no base extension defined """ - #from sage.structure.element import parent if R.has_coerce_map_from(self.parent().field): return FriezePattern(list(self), field = R) From e5e50fd8a3a397a29576d36c850ee57d8c17224b Mon Sep 17 00:00:00 2001 From: Dave Witte Morris Date: Wed, 27 May 2020 23:38:36 -0600 Subject: [PATCH 165/300] change error to ValueError --- src/sage/graphs/line_graph.pyx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/sage/graphs/line_graph.pyx b/src/sage/graphs/line_graph.pyx index 714e2531272..a1807662a37 100644 --- a/src/sage/graphs/line_graph.pyx +++ b/src/sage/graphs/line_graph.pyx @@ -497,10 +497,6 @@ def root_graph(g, verbose=False): # From now on we can assume (thanks to Beineke) that no edge belongs to two # even triangles at once. - error_message = ("It looks like there is a problem somewhere. You" - "found a bug here ! Please report it on sage-devel," - "our google group !") - # Better to work on integers... Everything takes more time otherwise. G = g.relabel(inplace=False) @@ -620,7 +616,7 @@ def root_graph(g, verbose=False): is_isom, isom = g.is_isomorphic(R.line_graph(labels=False), certificate=True) if not is_isom: - raise Exception(error_message) + raise ValueError("This graph is not a line graph !") return R, isom From 3a634d0b79f38e8c6542aa7ba647d48889e4128f Mon Sep 17 00:00:00 2001 From: Dave Witte Morris Date: Thu, 28 May 2020 16:31:08 -0600 Subject: [PATCH 166/300] revise documentation and error handling --- src/sage/graphs/line_graph.pyx | 80 ++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 37 deletions(-) diff --git a/src/sage/graphs/line_graph.pyx b/src/sage/graphs/line_graph.pyx index a1807662a37..b81b87ab81f 100644 --- a/src/sage/graphs/line_graph.pyx +++ b/src/sage/graphs/line_graph.pyx @@ -129,7 +129,7 @@ Functions def is_line_graph(g, certificate=False): r""" - Tests wether the graph is a line graph. + Test whether the graph `g` is a line graph. INPUT: @@ -203,6 +203,11 @@ def is_line_graph(g, certificate=False): sage: new_g = gl.is_line_graph(certificate=True)[1] sage: g.line_graph().is_isomorphic(gl) True + + Verify that :trac:`29740` is fixed:: + sage: g = Graph('O{e[{}^~z`MDZBZBkXzE^') + sage: g.is_line_graph() + False """ g._scream_if_not_simple() @@ -219,31 +224,36 @@ def is_line_graph(g, certificate=False): if g.is_connected(): try: + # we test whether g is a line graph by trying to construct its root graph R, isom = root_graph(g) if certificate: return True, R, isom else: return True - except ValueError: - # g is not a line graph - if certificate: - return False, get_certificate(g) - else: - return False + except ValueError as VE: + if str(VE) == "This graph is not a line graph !": + # g is not a line graph + if certificate: + return False, get_certificate(g) + else: + return False + raise VE - # g is not connected. + # g is not connected, so we apply the above procedure to each connected component from sage.graphs.graph import Graph R = Graph() for gg in g.connected_components_subgraphs(): try: RR, isom = root_graph(gg) R += RR - except ValueError: - # gg is not a line graph - if certificate: - return False, get_certificate(gg) - else: - return False + except ValueError as VE: + if str(VE) == "This graph is not a line graph !": + # gg is not a line graph + if certificate: + return False, get_certificate(gg) + else: + return False + raise VE if certificate: _, isom = g.is_isomorphic(R.line_graph(labels=False), certificate=True) @@ -252,9 +262,9 @@ def is_line_graph(g, certificate=False): return True -def line_graph(self, labels=True): +def line_graph(g, labels=True): """ - Returns the line graph of the (di)graph. + Return the line graph of the (di)graph ``g``. INPUT: @@ -402,7 +412,7 @@ def line_graph(self, labels=True): def root_graph(g, verbose=False): r""" - Computes the root graph corresponding to the given graph + Compute the root graph corresponding to the given graph ``g`` See the documentation of :mod:`sage.graphs.line_graph` to know how it works. @@ -413,16 +423,10 @@ def root_graph(g, verbose=False): - ``verbose`` -- boolean (default: ``False``); display some information about what is happening inside of the algorithm. - .. NOTE:: - - It is best to use this code through - :meth:`~sage.graphs.graph.Graph.is_line_graph`, which first checks that - the graph is indeed a line graph, and deals with the disconnected - case. But if you are sure of yourself, dig in ! - .. WARNING:: - * This code assumes that the graph is connected. + This code assumes that `g` is a line graph, and is a connected, undirected graph + without multiple edges. TESTS: @@ -444,6 +448,11 @@ def root_graph(g, verbose=False): ... ValueError: This graph is not a line graph ! + sage: root_graph(Graph('O{e[{}^~z`MDZBZBkXzE^')) + Traceback (most recent call last): + ... + ValueError: This graph is not a line graph ! + Small corner-cases:: sage: from sage.graphs.line_graph import root_graph @@ -464,6 +473,8 @@ def root_graph(g, verbose=False): raise ValueError("g cannot have multiple edges !") if not g.is_connected(): raise ValueError("g is not connected !") + # is_line_graph expects a particular error message when g is not a line graph + not_line_graph = "This graph is not a line graph !" # Complete Graph ? if g.is_clique(): @@ -542,7 +553,7 @@ def root_graph(g, verbose=False): # We now associate the clique to all the vertices it contains. for v in S: if len(v_cliques[v]) == 2: - raise ValueError("This graph is not a line graph !") + raise ValueError(not_line_graph) v_cliques[v].append(tuple(S)) if verbose: @@ -606,19 +617,14 @@ def root_graph(g, verbose=False): # We now build R R.add_edges(vertex_to_map.values()) - # Even if whatever is written above is complete nonsense, here we make sure - # that we do not return gibberish. Is the line graph of R isomorphic to the - # input ? If so, we return R, and the isomorphism. Else, we panic and - # scream. - # - # It's actually "just to make sure twice". This can be removed later if it - # turns out to be too costly. + # If g is a line graph, then it is isomorphic to the line graph of the graph R that + # we have constructed, so we return R (and the isomorphism). is_isom, isom = g.is_isomorphic(R.line_graph(labels=False), certificate=True) + if is_isom: + return R, isom + else: + raise ValueError(not_line_graph) - if not is_isom: - raise ValueError("This graph is not a line graph !") - - return R, isom From 1267467269fc838d5c385e13973b6791b1dc3d79 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 29 May 2020 15:07:11 +1000 Subject: [PATCH 167/300] Fixing failures and allowing echelon_form to handle oo-dim modules. --- .../finite_dimensional_modules_with_basis.py | 124 ++++++----- src/sage/categories/modules_with_basis.py | 200 ++++++++++++------ src/sage/modules/with_basis/subquotient.py | 2 +- 3 files changed, 210 insertions(+), 116 deletions(-) diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index afd0d4808a1..e09c9b1f6e1 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -11,6 +11,7 @@ import operator from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring +from sage.categories.fields import Fields from sage.misc.cachefunc import cached_method class FiniteDimensionalModulesWithBasis(CategoryWithAxiom_over_base_ring): @@ -233,61 +234,6 @@ def annihilator_basis(self, S, action=operator.mul, side='right'): [action(s, b)._vector_() for b in self.basis()])) return tuple(map(self.from_vector, mat.left_kernel().basis())) - def quotient_module(self, submodule, check=True, already_echelonized=False, category=None): - r""" - Construct the quotient module ``self``/``submodule``. - - INPUT: - - - ``submodule`` -- a submodule with basis of ``self``, or - something that can be turned into one via - ``self.submodule(submodule)``. - - - ``check``, ``already_echelonized`` -- passed down to - :meth:`ModulesWithBasis.ParentMethods.submodule`. - - .. WARNING:: - - At this point, this only supports quotients by free - submodules admitting a basis in unitriangular echelon - form. In this case, the quotient is also a free - module, with a basis consisting of the retract of a - subset of the basis of ``self``. - - EXAMPLES:: - - sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x") - sage: x = X.basis() - sage: Y = X.quotient_module([x[0]-x[1], x[1]-x[2]], already_echelonized=True) - sage: Y.print_options(prefix='y'); Y - Free module generated by {2} over Rational Field - sage: y = Y.basis() - sage: y[2] - y[2] - sage: y[2].lift() - x[2] - sage: Y.retract(x[0]+2*x[1]) - 3*y[2] - - sage: R. = QQ[] - sage: C = CombinatorialFreeModule(R, range(3), prefix='x') - sage: x = C.basis() - sage: gens = [x[0] - x[1], 2*x[1] - 2*x[2], x[0] - x[2]] - sage: Y = X.quotient_module(gens) - - .. SEEALSO:: - - - :meth:`Modules.WithBasis.ParentMethods.submodule` - - :meth:`Rings.ParentMethods.quotient` - - :class:`sage.modules.with_basis.subquotient.QuotientModuleWithBasis` - """ - from sage.modules.with_basis.subquotient import SubmoduleWithBasis, QuotientModuleWithBasis - if not isinstance(submodule, SubmoduleWithBasis): - submodule = self.submodule(submodule, check=check, - unitriangular=True, - already_echelonized=already_echelonized) - return QuotientModuleWithBasis(submodule, category=category) - @cached_method def _dense_free_module(self, base_ring=None): """ @@ -339,6 +285,74 @@ def from_vector(self, vector, order=None): order = range(self.dimension()) return self._from_dict({order[i]: c for i,c in vector.iteritems()}) + def echelon_form(self, elements, row_reduced=False, support_order=None): + r""" + Return a basis in echelon form of the subspace spanned by + a finite set of elements. + + INPUT: + + - ``elements`` -- a list or finite iterable of elements of ``self`` + - ``row_reduced`` -- (default: ``False``) whether to compute the + basis for the row reduced echelon form + + OUTPUT: + + A list of elements of ``self`` whose expressions as vectors + form a matrix in echelon form. If ``base_ring`` is specified, + then the calculation is achieved in this base ring. + + EXAMPLES:: + + sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x") + sage: x = X.basis() + sage: V = X.echelon_form([x[0]-x[1], x[0]-x[2],x[1]-x[2]]); V + [x[0] - x[2], x[1] - x[2]] + sage: matrix(list(map(vector, V))) + [ 1 0 -1] + [ 0 1 -1] + + :: + + sage: F = CombinatorialFreeModule(ZZ, [1,2,3,4]) + sage: B = F.basis() + sage: elements = [B[1]-17*B[2]+6*B[3], B[1]-17*B[2]+B[4]] + sage: F.echelon_form(elements) + [B[1] - 17*B[2] + B[4], 6*B[3] - B[4]] + + :: + + sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) + sage: a,b,c = F.basis() + sage: F.echelon_form([8*a+b+10*c, -3*a+b-c, a-b-c]) + [B['a'] + B['c'], B['b'] + 2*B['c']] + + :: + + sage: R. = QQ[] + sage: C = CombinatorialFreeModule(R, range(3), prefix='x') + sage: x = C.basis() + sage: C.echelon_form([x[0] - x[1], 2*x[1] - 2*x[2], x[0] - x[2]]) + [x[0] - x[2], x[1] - x[2]] + """ + order = self.get_order() + if support_order is not None: + self.set_order(self._support_order(support_order)) + from sage.matrix.constructor import matrix + mat = matrix(self.base_ring(), [g._vector_() for g in elements]) + # Echelonizing a matrix over a field returned the rref + if row_reduced and self.base_ring() not in Fields(): + try: + mat = mat.rref().change_ring(self.base_ring()) + except (ValueError, TypeError): + raise ValueError("unable to compute the row reduced echelon form") + else: + mat.echelonize() + ret = [self.from_vector(vec) for vec in mat if vec] + if support_order is not None: + self.set_order(order) + return ret + class ElementMethods: def dense_coefficient_list(self, order=None): """ diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index eaf9386ebfc..d7233a723f0 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -594,7 +594,64 @@ def _repr_(self): name = "Free module generated by {}".format(self.basis().keys()) return name + " over {}".format(self.base_ring()) - def echelon_form(self, elements, row_reduced=False): + def _support_order(self, elements, support_order=None): + """ + Return the support of a set of elements in ``self`` sorted + in some order. + + INPUT: + + - ``elements`` -- the list of elements + - ``support_order`` -- (optional) either something that can + be converted into a tuple or a key function + + EXAMPLES: + + A finite dimensional module:: + + sage: V = CombinatorialFreeModule(QQ, range(10), prefix='x') + sage: B = V.basis() + sage: elts = [B[0] - 2*B[3], B[5] + 2*B[0], B[2], B[3], B[1] + B[2] + B[8]] + sage: V._support_order(elts) + (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) + sage: V._support_order(elts, [1,2,0,4,3,5,9,8,7,6]) + (1, 2, 0, 4, 3, 5, 9, 8, 7, 6) + sage: V._support_order(elts, lambda x: -x) + (8, 5, 3, 2, 1, 0) + + An infinite dimensional module:: + + sage: V = CombinatorialFreeModule(QQ, ZZ, prefix='z') + sage: B = V.basis() + sage: elts = [B[0] - 2*B[3], B[5] + 2*B[0], B[2], B[3], B[1] + B[2] + B[8]] + sage: V._support_order(elts) + (0, 1, 2, 3, 5, 8) + sage: V._support_order(elts, [1,2,0,4,3,5,9,8,7,6]) + (1, 2, 0, 4, 3, 5, 9, 8, 7, 6) + sage: V._support_order(elts, lambda x: -x) + (8, 5, 3, 2, 1, 0) + """ + if support_order is None: + try: + support_order = self.get_order() + except (ValueError, TypeError, NotImplementedError): + support_order = set() + for y in elements: + support_order.update(y.support()) + try: # Try to sort to make the output more consistent + support_order = sorted(support_order) + except (ValueError, TypeError): + pass + try: + support_order = tuple(support_order) + except (ValueError, TypeError, NotImplementedError): + support = set() + for y in elements: + support.update(y.support()) + support_order = sorted(support, key=support_order) + return tuple(support_order) + + def echelon_form(self, elements, row_reduced=False, support_order=None): r""" Return a basis in echelon form of the subspace spanned by a finite set of elements. @@ -604,58 +661,38 @@ def echelon_form(self, elements, row_reduced=False): - ``elements`` -- a list or finite iterable of elements of ``self`` - ``row_reduced`` -- (default: ``False``) whether to compute the basis for the row reduced echelon form + - ``support_order`` -- (optional) either something that can + be converted into a tuple or a key function OUTPUT: - A list of elements of ``self`` whose expressions as - vectors form a matrix in echelon form. If ``base_ring`` is - specified, then the calculation is achieved in this base - ring. + A list of elements of ``self`` whose expressions as vectors + form a matrix in echelon form. If ``base_ring`` is specified, + then the calculation is achieved in this base ring. EXAMPLES:: - sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x") - sage: x = X.basis() - sage: V = X.echelon_form([x[0]-x[1], x[0]-x[2],x[1]-x[2]]); V - [x[0] - x[2], x[1] - x[2]] - sage: matrix(list(map(vector, V))) - [ 1 0 -1] - [ 0 1 -1] - - :: - - sage: F = CombinatorialFreeModule(ZZ, [1,2,3,4]) - sage: B = F.basis() - sage: elements = [B[1]-17*B[2]+6*B[3], B[1]-17*B[2]+B[4]] - sage: F.echelon_form(elements) - [B[1] - 17*B[2] + B[4], 6*B[3] - B[4]] - - :: - - sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) - sage: a,b,c = F.basis() - sage: F.echelon_form([8*a+b+10*c, -3*a+b-c, a-b-c]) - [B['a'] + B['c'], B['b'] + 2*B['c']] - - :: - sage: R. = QQ[] - sage: C = CombinatorialFreeModule(R, range(3), prefix='x') - sage: x = C.basis() - sage: C.echelon_form([x[0] - x[1], 2*x[1] - 2*x[2], x[0] - x[2]]) - [x[0] - x[2], x[1] - x[2]] + sage: C = CombinatorialFreeModule(R, ZZ, prefix='z') + sage: z = C.basis() + sage: C.echelon_form([z[0] - z[1], 2*z[1] - 2*z[2], z[0] - z[2]]) + [z[0] - z[2], z[1] - z[2]] """ + support_order = self._support_order(elements, support_order) + from sage.matrix.constructor import matrix - mat = matrix(self.base_ring(), [g._vector_() for g in elements]) + mat = matrix(self.base_ring(), [[g[s] for s in support_order] for g in elements]) # Echelonizing a matrix over a field returned the rref - if row_reduced and self.base_ring() not in Fields: + if row_reduced and self.base_ring() not in Fields(): try: mat = mat.rref().change_ring(self.base_ring()) except (ValueError, TypeError): raise ValueError("unable to compute the row reduced echelon form") else: mat.echelonize() - return [self.from_vector(vec) for vec in mat if vec] + return [self._from_dict({support_order[i]: c for i, c in enumerate(vec) if c}, + remove_zeros=False) + for vec in mat if vec] def submodule(self, gens, check=True, already_echelonized=False, unitriangular=False, support_order=None, category=None, @@ -677,9 +714,8 @@ def submodule(self, gens, check=True, already_echelonized=False, - ``unitriangular`` -- (default: ``False``) whether the lift morphism is unitriangular - - ``support_order`` -- (optional) either an instance of class - with an ``index`` method (ex. a list), which returns an index - of an element in `\ZZ`, or a comparison function + - ``support_order`` -- (optional) either something that can + be converted into a tuple or a key function If ``already_echelonized`` is ``False``, then the generators are put in reduced echelon form using @@ -810,34 +846,23 @@ def submodule(self, gens, check=True, already_echelonized=False, [-1 -1] We now construct a (finite-dimensional) submodule of an - infinite-dimensional free module. Due to current implementation - limitations, we must pass an echelonized basis:: + infinite dimensional free module:: - sage: R. = QQ[] - sage: C = CombinatorialFreeModule(R, range(3), prefix='x') - sage: x = C.basis() - sage: gens = [x[0] - x[1], 2*x[1] - 2*x[2], x[0] - x[2]] - sage: Y = C.submodule(gens, unitriangular=True) - sage: Y.lift.matrix() - [ 1 0] - [ 0 1] - [-1 -1] + sage: C = CombinatorialFreeModule(QQ, ZZ, prefix='z') + sage: z = C.basis() + sage: gens = [z[0] - z[1], 2*z[1] - 2*z[2], z[0] - z[2]] + sage: Y = C.submodule(gens) + sage: [Y.lift(b) for b in Y.basis()] + [z[0] - z[2], z[1] - z[2]] TESTS:: sage: TestSuite(Y).run() sage: TestSuite(center).run() """ + support_order = self._support_order(gens, support_order) if not already_echelonized: - gens = self.echelon_form(gens, unitriangular) - if support_order is None: - try: - support_order = self.get_order() - except NotImplementedError: - support_order = list(reduce( lambda x,y: x.union(y.support()), - gens, set() )) - elif not hasattr(support_order, 'index') and callable(support_order): - support_order = sorted(gens, cmp=support_order) + gens = self.echelon_form(gens, unitriangular, support_order=support_order) from sage.modules.with_basis.subquotient import SubmoduleWithBasis return SubmoduleWithBasis(gens, ambient=self, @@ -845,6 +870,61 @@ def submodule(self, gens, check=True, already_echelonized=False, unitriangular=unitriangular, category=category, *args, **opts) + def quotient_module(self, submodule, check=True, already_echelonized=False, category=None): + r""" + Construct the quotient module ``self`` / ``submodule``. + + INPUT: + + - ``submodule`` -- a submodule with basis of ``self``, or + something that can be turned into one via + ``self.submodule(submodule)`` + + - ``check``, ``already_echelonized`` -- passed down to + :meth:`ModulesWithBasis.ParentMethods.submodule` + + .. WARNING:: + + At this point, this only supports quotients by free + submodules admitting a basis in unitriangular echelon + form. In this case, the quotient is also a free + module, with a basis consisting of the retract of a + subset of the basis of ``self``. + + EXAMPLES:: + + sage: X = CombinatorialFreeModule(QQ, range(3), prefix="x") + sage: x = X.basis() + sage: Y = X.quotient_module([x[0]-x[1], x[1]-x[2]], already_echelonized=True) + sage: Y.print_options(prefix='y'); Y + Free module generated by {2} over Rational Field + sage: y = Y.basis() + sage: y[2] + y[2] + sage: y[2].lift() + x[2] + sage: Y.retract(x[0]+2*x[1]) + 3*y[2] + + sage: R. = QQ[] + sage: C = CombinatorialFreeModule(R, range(3), prefix='x') + sage: x = C.basis() + sage: gens = [x[0] - x[1], 2*x[1] - 2*x[2], x[0] - x[2]] + sage: Y = X.quotient_module(gens) + + .. SEEALSO:: + + - :meth:`Modules.WithBasis.ParentMethods.submodule` + - :meth:`Rings.ParentMethods.quotient` + - :class:`sage.modules.with_basis.subquotient.QuotientModuleWithBasis` + """ + from sage.modules.with_basis.subquotient import SubmoduleWithBasis, QuotientModuleWithBasis + if not isinstance(submodule, SubmoduleWithBasis): + submodule = self.submodule(submodule, check=check, + unitriangular=True, + already_echelonized=already_echelonized) + return QuotientModuleWithBasis(submodule, category=category) + def tensor(*parents, **kwargs): """ Return the tensor product of the parents. diff --git a/src/sage/modules/with_basis/subquotient.py b/src/sage/modules/with_basis/subquotient.py index ad7b3088f11..5b5c52b2752 100644 --- a/src/sage/modules/with_basis/subquotient.py +++ b/src/sage/modules/with_basis/subquotient.py @@ -175,7 +175,7 @@ class SubmoduleWithBasis(CombinatorialFreeModule): can be converted into such a family - ``support_order`` -- an ordering of the support of ``basis`` - expressed in ``ambient`` + expressed in ``ambient`` given as a list - ``unitriangular`` -- if the lift morphism is unitriangular From 4747bd6d65d2ed3cd25c35a22fe0dcb0f0908693 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 29 May 2020 13:31:21 +0100 Subject: [PATCH 168/300] Added catalog.py and changed name --- src/sage/combinat/path_tableaux/catalog.py | 19 +++++ .../{catalan.py => dyck_path.py} | 78 +++++++++---------- 2 files changed, 58 insertions(+), 39 deletions(-) create mode 100644 src/sage/combinat/path_tableaux/catalog.py rename src/sage/combinat/path_tableaux/{catalan.py => dyck_path.py} (82%) diff --git a/src/sage/combinat/path_tableaux/catalog.py b/src/sage/combinat/path_tableaux/catalog.py new file mode 100644 index 00000000000..958a4f8b08b --- /dev/null +++ b/src/sage/combinat/path_tableaux/catalog.py @@ -0,0 +1,19 @@ +r""" +Catalog of Path Tableaux + +The ``path_tableaux`` object may be used to access examples of various algebras +currently implemented in Sage. Using tab-completion on this object is an +easy way to discover and quickly create the path tableaux that are available +(as listed here). + +Let ```` indicate pressing the tab key. So begin by typing +``algebras.`` to the see the currently implemented named path tableaux. + +- :class:`algebras.ArikiKoike +""" + +from sage.combinat.path_tableaux.dyck_path import DyckPaths, DyckPath + +from sage.misc.lazy_import import lazy_import + +lazy_import('sage.combinat.path_tableaux.dyck_path', 'DyckPaths', 'DyckPath') \ No newline at end of file diff --git a/src/sage/combinat/path_tableaux/catalan.py b/src/sage/combinat/path_tableaux/dyck_path.py similarity index 82% rename from src/sage/combinat/path_tableaux/catalan.py rename to src/sage/combinat/path_tableaux/dyck_path.py index 4f2de2b9e60..0fdb825dcd4 100644 --- a/src/sage/combinat/path_tableaux/catalan.py +++ b/src/sage/combinat/path_tableaux/dyck_path.py @@ -1,5 +1,5 @@ r""" -Catalan Tableaux +Dyck Paths This is an implementation of the abstract base class :class:`sage.combinat.pathtableau.pathtableaux`. @@ -20,7 +20,7 @@ EXAMPLES:: - sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t = DyckPath([0,1,2,3,2,1,0]) sage: t.to_perfect_matching() [(0, 5), (1, 4), (2, 3)] @@ -60,7 +60,7 @@ ############################################################################### -class CatalanTableau(PathTableau): +class DyckPath(PathTableau): r""" An instance is the sequence of nonnegative integers given by the heights of a Dyck word. @@ -74,19 +74,19 @@ class CatalanTableau(PathTableau): EXAMPLES:: - sage: CatalanTableau([0,1,2,1,0]) + sage: DyckPath([0,1,2,1,0]) [0, 1, 2, 1, 0] sage: w = DyckWord([1,1,0,0]) - sage: CatalanTableau(w) + sage: DyckPath(w) [0, 1, 2, 1, 0] sage: p = PerfectMatching([(1,2),(3,4)]) - sage: CatalanTableau(p) + sage: DyckPath(p) [0, 1, 0, 1, 0] sage: t = Tableau([[1,2],[3,4]]) - sage: CatalanTableau(t) + sage: DyckPath(t) [0, 1, 2, 1, 0] """ @@ -98,16 +98,16 @@ def __classcall_private__(cls, ot): TESTS:: - sage: t = CatalanTableau([0,1,2,1,0]) + sage: t = DyckPath([0,1,2,1,0]) sage: t.parent() - + sage: t.category() - Category of elements of + Category of elements of sage: type(t) - + """ - return CatalanTableaux()(ot) + return DyckPaths()(ot) def __init__(self, parent, ot, check=True): r""" @@ -125,37 +125,37 @@ def __init__(self, parent, ot, check=True): TESTS:: - sage: CatalanTableau([0,1,2,1,0]) + sage: DyckPath([0,1,2,1,0]) [0, 1, 2, 1, 0] - sage: CatalanTableau(DyckWord([1, 0, 1, 0])) + sage: DyckPath(DyckWord([1, 0, 1, 0])) [0, 1, 0, 1, 0] - sage: CatalanTableau(PerfectMatching([(1, 4), (2, 3), (5, 6)])) + sage: DyckPath(PerfectMatching([(1, 4), (2, 3), (5, 6)])) [0, 1, 2, 1, 0, 1, 0] - sage: CatalanTableau(Tableau([[1,2,4],[3,5,6]])) + sage: DyckPath(Tableau([[1,2,4],[3,5,6]])) [0, 1, 2, 1, 2, 1, 0] - sage: CatalanTableau(SkewTableau([[None, 1,4],[2,3]])) + sage: DyckPath(SkewTableau([[None, 1,4],[2,3]])) [1, 2, 1, 0, 1] - sage: CatalanTableau(PerfectMatching([(1, 3), (2, 4), (5, 6)])) + sage: DyckPath(PerfectMatching([(1, 3), (2, 4), (5, 6)])) Traceback (most recent call last): ... ValueError: the perfect matching must be non crossing - sage: CatalanTableau(Tableau([[1,2,5],[3,5,6]])) + sage: DyckPath(Tableau([[1,2,5],[3,5,6]])) Traceback (most recent call last): ... ValueError: the tableau must be standard - sage: CatalanTableau(Tableau([[1,2,4],[3,5,6],[7]])) + sage: DyckPath(Tableau([[1,2,4],[3,5,6],[7]])) Traceback (most recent call last): ... ValueError: the tableau must have at most two rows - sage: CatalanTableau(SkewTableau([[None, 1,4],[2,3],[5]])) + sage: DyckPath(SkewTableau([[None, 1,4],[2,3],[5]])) Traceback (most recent call last): ... ValueError: the skew tableau must have at most two rows - sage: CatalanTableau([0,1,2.5,1,0]) + sage: DyckPath([0,1,2.5,1,0]) Traceback (most recent call last): ... ValueError: [0, 1, 2.50000000000000, 1, 0] is not a sequence of integers - sage: CatalanTableau(Partition([3,2,1])) + sage: DyckPath(Partition([3,2,1])) Traceback (most recent call last): ... ValueError: invalid input [3, 2, 1] @@ -214,12 +214,12 @@ def check(self): TESTS:: - sage: CatalanTableau([0,1,0,-1,0]) # indirect doctest + sage: DyckPath([0,1,0,-1,0]) # indirect doctest Traceback (most recent call last): ... ValueError: [0, 1, 0, -1, 0] has a negative entry - sage: CatalanTableau([0,1,3,1,0]) # indirect doctest + sage: DyckPath([0,1,3,1,0]) # indirect doctest Traceback (most recent call last): ... ValueError: [0, 1, 3, 1, 0] is not a Dyck path @@ -240,13 +240,13 @@ def _local_rule(self,i): EXAMPLES:: - sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t = DyckPath([0,1,2,3,2,1,0]) sage: t._local_rule(3) [0, 1, 2, 1, 2, 1, 0] TESTS:: - sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t = DyckPath([0,1,2,3,2,1,0]) sage: t._local_rule(0) Traceback (most recent call last): ... @@ -279,10 +279,10 @@ def is_skew(self): EXAMPLES:: - sage: CatalanTableau([0,1,2,1]).is_skew() + sage: DyckPath([0,1,2,1]).is_skew() False - sage: CatalanTableau([1,0,1,2,1]).is_skew() + sage: DyckPath([1,0,1,2,1]).is_skew() True """ return self[0] != 0 @@ -294,7 +294,7 @@ def to_DyckWord(self): EXAMPLES:: - sage: c = CatalanTableau([0,1,2,1,0]) + sage: c = DyckPath([0,1,2,1,0]) sage: c.to_DyckWord() [1, 1, 0, 0] """ @@ -306,7 +306,7 @@ def descents(self): EXAMPLES:: - sage: CatalanTableau([0,1,2,1,2,1,0,1,0]).descents() + sage: DyckPath([0,1,2,1,2,1,0,1,0]).descents() {3, 6} """ result = set() @@ -323,7 +323,7 @@ def to_word(self): EXAMPLES:: - sage: CatalanTableau([1,0,1,2,1]).to_word() + sage: DyckPath([1,0,1,2,1]).to_word() [0, 1, 1, 0] """ return [ (self[i+1]-self[i]+1)/2 for i in range(self.size()-1) ] @@ -334,12 +334,12 @@ def to_perfect_matching(self): EXAMPLES:: - sage: CatalanTableau([0,1,2,1,2,1,0,1,0]).to_perfect_matching() + sage: DyckPath([0,1,2,1,2,1,0,1,0]).to_perfect_matching() [(0, 5), (1, 2), (3, 4), (6, 7)] TESTS:: - sage: CatalanTableau([1,2,1,2,1,0,1]).to_perfect_matching() + sage: DyckPath([1,2,1,2,1,0,1]).to_perfect_matching() Traceback (most recent call last): ... ValueError: [1, 2, 1, 2, 1, 0, 1] does not start at 0 @@ -361,11 +361,11 @@ def to_tableau(self): EXAMPLES:: - sage: T = CatalanTableau([0,1,2,3,2,3]) + sage: T = DyckPath([0,1,2,3,2,3]) sage: T.to_tableau() [[1, 2, 3, 5], [4]] - sage: U = CatalanTableau([2,3,2,3]) + sage: U = DyckPath([2,3,2,3]) sage: U.to_tableau() [[None, None, 1, 3], [2]] """ @@ -377,9 +377,9 @@ def to_tableau(self): else: return StandardTableau([top,bot]) -class CatalanTableaux(PathTableaux): +class DyckPaths(PathTableaux): """ - The parent class for CatalanTableau. + The parent class for DyckPath. """ - Element = CatalanTableau + Element = DyckPath From 8567a47bfadc4494cb8204ac69b520ec54ba2b53 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 29 May 2020 13:33:15 +0100 Subject: [PATCH 169/300] Changed _local_rule to local_rule --- .../combinat/path_tableaux/path_tableau.py | 70 +++++++++---------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/src/sage/combinat/path_tableaux/path_tableau.py b/src/sage/combinat/path_tableaux/path_tableau.py index 8a5f21b9f77..1b94089e4ff 100644 --- a/src/sage/combinat/path_tableaux/path_tableau.py +++ b/src/sage/combinat/path_tableaux/path_tableau.py @@ -55,7 +55,7 @@ class PathTableau(ClonableArray): This is the abstract base class for path tableaux. """ @abstract_method(optional=False) - def _local_rule(self,i): + def local_rule(self,i): r""" This is the abstract local rule defined in any coboundary category. @@ -66,7 +66,7 @@ def _local_rule(self,i): EXAMPLES:: - sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t = DyckPath([0,1,2,3,2,1,0]) sage: t._local_rule(3) [0, 1, 2, 1, 2, 1, 0] """ @@ -79,7 +79,7 @@ def size(self): EXAMPLES:: - sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t = DyckPath([0,1,2,3,2,1,0]) sage: t.size() 7 """ @@ -91,7 +91,7 @@ def initial_shape(self): EXAMPLES:: - sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t = DyckPath([0,1,2,3,2,1,0]) sage: t.initial_shape() 0 """ @@ -103,7 +103,7 @@ def final_shape(self): EXAMPLES:: - sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t = DyckPath([0,1,2,3,2,1,0]) sage: t.final_shape() 0 """ @@ -117,7 +117,7 @@ def promotion(self): EXAMPLES:: - sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t = DyckPath([0,1,2,3,2,1,0]) sage: t.promotion() [0, 1, 2, 1, 0, 1, 0] """ @@ -133,7 +133,7 @@ def evacuation(self): EXAMPLES:: - sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t = DyckPath([0,1,2,3,2,1,0]) sage: t.evacuation() [0, 1, 2, 3, 2, 1, 0] """ @@ -159,8 +159,8 @@ def commutor(self,other,verbose=False): EXAMPLES:: - sage: t1 = CatalanTableau([0,1,2,3,2,1,0]) - sage: t2 = CatalanTableau([0,1,2,1,0]) + sage: t1 = DyckPath([0,1,2,3,2,1,0]) + sage: t2 = DyckPath([0,1,2,1,0]) sage: t1.commutor(t2) ([0, 1, 2, 1, 0], [0, 1, 2, 3, 2, 1, 0]) sage: t1.commutor(t2,verbose=True) @@ -175,20 +175,20 @@ def commutor(self,other,verbose=False): TESTS:: - sage: t1 = CatalanTableau([]) - sage: t2 = CatalanTableau([0,1,2,1,0]) + sage: t1 = DyckPath([]) + sage: t2 = DyckPath([0,1,2,1,0]) sage: t1.commutor(t2) Traceback (most recent call last): ... ValueError: this requires nonempty lists - sage: t1 = CatalanTableau([0,1,2,3,2,1,0]) - sage: t2 = CatalanTableau([]) + sage: t1 = DyckPath([0,1,2,3,2,1,0]) + sage: t2 = DyckPath([]) sage: t1.commutor(t2) Traceback (most recent call last): ... ValueError: this requires nonempty lists - sage: t1 = CatalanTableau([0,1,2,3,2,1]) - sage: t2 = CatalanTableau([0,1,2,1,0]) + sage: t1 = DyckPath([0,1,2,3,2,1]) + sage: t2 = DyckPath([0,1,2,1,0]) sage: t1.commutor(t2) Traceback (most recent call last): ... @@ -234,7 +234,7 @@ def cactus(self,i,j): EXAMPLES:: - sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t = DyckPath([0,1,2,3,2,1,0]) sage: t.cactus(1,5) [0, 1, 0, 1, 2, 1, 0] @@ -248,7 +248,7 @@ def cactus(self,i,j): TESTS:: - sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t = DyckPath([0,1,2,3,2,1,0]) sage: t.cactus(1,8) Traceback (most recent call last): ... @@ -281,7 +281,7 @@ def _test_involution_rule(self, **options): TESTS:: - sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t = DyckPath([0,1,2,3,2,1,0]) sage: t._test_involution_rule() """ tester = self._tester(**options) @@ -295,7 +295,7 @@ def _test_involution_cactus(self, **options): TESTS:: - sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t = DyckPath([0,1,2,3,2,1,0]) sage: t._test_involution_cactus() """ tester = self._tester(**options) @@ -308,7 +308,7 @@ def _test_promotion(self, **options): TESTS:: - sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t = DyckPath([0,1,2,3,2,1,0]) sage: t._test_promotion() """ tester = self._tester(**options) @@ -321,7 +321,7 @@ def _test_commutation(self, **options): TESTS:: - sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t = DyckPath([0,1,2,3,2,1,0]) sage: t._test_commutation() """ from itertools import combinations @@ -341,7 +341,7 @@ def _test_coboundary(self, **options): TESTS:: - sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t = DyckPath([0,1,2,3,2,1,0]) sage: t._test_coboundary() """ from itertools import combinations @@ -361,7 +361,7 @@ def orbit(self): EXAMPLES:: - sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t = DyckPath([0,1,2,3,2,1,0]) sage: t.orbit() {[0, 1, 0, 1, 0, 1, 0], [0, 1, 0, 1, 2, 1, 0], @@ -397,7 +397,7 @@ def dual_equivalence_graph(self): EXAMPLES:: - sage: s = CatalanTableau([0,1,2,3,2,3,2,1,0]) + sage: s = DyckPath([0,1,2,3,2,3,2,1,0]) sage: s.dual_equivalence_graph().adjacency_matrix() [0 1 1 1 0 1 0 1 1 0 0 0 0 0] [1 0 1 1 1 1 1 0 1 0 0 1 1 0] @@ -413,7 +413,7 @@ def dual_equivalence_graph(self): [0 1 1 1 0 0 1 1 1 1 1 0 1 1] [0 1 0 1 1 1 0 1 1 1 1 1 0 1] [0 0 0 0 1 0 1 0 0 1 1 1 1 0] - sage: s = CatalanTableau([0,1,2,3,2,1,0]) + sage: s = DyckPath([0,1,2,3,2,1,0]) sage: sorted(s.dual_equivalence_graph().edges()) [([0, 1, 0, 1, 0, 1, 0], [0, 1, 0, 1, 2, 1, 0], '4,7'), ([0, 1, 0, 1, 0, 1, 0], [0, 1, 2, 1, 0, 1, 0], '2,5'), @@ -448,9 +448,9 @@ def __init__(self): TESTS:: - sage: t = CatalanTableau([0,1,2,1,0]) + sage: t = DyckPath([0,1,2,1,0]) sage: t.parent() # indirect test - + """ Parent.__init__(self, category=Sets()) @@ -460,7 +460,7 @@ def _element_constructor_(self, *args, **kwds): TESTS:: - sage: CatalanTableau([0,1,2,1,0]) # indirect doctest + sage: DyckPath([0,1,2,1,0]) # indirect doctest [0, 1, 2, 1, 0] """ return self.element_class(self, *args, **kwds) @@ -476,7 +476,7 @@ def __init__(self,T): TESTS:: - sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t = DyckPath([0,1,2,3,2,1,0]) sage: CylindricalDiagram(t) [0, 1, 2, 3, 2, 1, 0] ['', 0, 1, 2, 1, 0, 1, 0] @@ -507,7 +507,7 @@ def __repr__(self): TESTS:: - sage: print(CatalanTableau([0,1,2,1,2,1,0])) # indirect test + sage: print(DyckPath([0,1,2,1,2,1,0])) # indirect test [0, 1, 2, 1, 2, 1, 0] """ dg = self.diagram @@ -519,7 +519,7 @@ def _latex_(self): EXAMPLES:: - sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t = DyckPath([0,1,2,3,2,1,0]) sage: latex(CylindricalDiagram(t)) \begin{array}{ccccccccccccc} 0 & 1 & 2 & 3 & 2 & 1 & 0\\ @@ -543,7 +543,7 @@ def __len__(self): TESTS:: - sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t = DyckPath([0,1,2,3,2,1,0]) sage: len(CylindricalDiagram(t)) 7 """ @@ -555,7 +555,7 @@ def _ascii_art_(self): TESTS:: - sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t = DyckPath([0,1,2,3,2,1,0]) sage: ascii_art(CylindricalDiagram(t)) 0 1 2 3 2 1 0 0 1 2 1 0 1 0 @@ -576,7 +576,7 @@ def _unicode_art_(self): TESTS:: - sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t = DyckPath([0,1,2,3,2,1,0]) sage: unicode_art(CylindricalDiagram(t)) 0 1 2 3 2 1 0 0 1 2 1 0 1 0 @@ -597,7 +597,7 @@ def pp(self): EXAMPLES:: - sage: t = CatalanTableau([0,1,2,3,2,1,0]) + sage: t = DyckPath([0,1,2,3,2,1,0]) sage: CylindricalDiagram(t).pp() 0 1 2 3 2 1 0 0 1 2 1 0 1 0 From 767405c654f189c298b6f5da035d68db4de72219 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Fri, 29 May 2020 15:49:26 +0100 Subject: [PATCH 170/300] Tried to write catalog.py --- src/sage/combinat/all.py | 2 +- src/sage/combinat/path_tableaux/all.py | 13 +++++++++++-- src/sage/combinat/path_tableaux/dyck_path.py | 18 +++++++++--------- .../combinat/path_tableaux/path_tableau.py | 10 +++++----- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 3ae1e8c39a7..5ebb96135ae 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -236,4 +236,4 @@ # Path tableaux lazy_import('sage.combinat.path_tableaux.path_tableau', ['PathTableau', 'PathTableaux', 'CylindricalDiagram']) -lazy_import('sage.combinat.path_tableaux.catalan', ['CatalanTableau', 'CatalanTableaux']) +lazy_import('sage.combinat.path_tableaux.dyck_path', ['DyckPath', 'DyckPaths']) diff --git a/src/sage/combinat/path_tableaux/all.py b/src/sage/combinat/path_tableaux/all.py index b7f6bf01a5a..5bc0f2fae5a 100644 --- a/src/sage/combinat/path_tableaux/all.py +++ b/src/sage/combinat/path_tableaux/all.py @@ -1,7 +1,16 @@ r""" -PathTableau features that are imported by default in the interpreter namespace +PathTableaux """ from __future__ import absolute_import +from sage.misc.lazy_import import lazy_import + +import sage.combinat.path_tableaux.catalog as path_tableaux + from .path_tableau import PathTableau, PathTableaux, CylindricalDiagram -from .catalan import CatalanTableau, CatalanTableaux +from .dyck_path import DyckPath, DyckPaths + +lazy_import('sage.combinat.path_tableaux.path_tableau', ['PathTableau', 'PathTableaux', 'CylindricalDiagram']) +lazy_import('sage.combinat.path_tableaux.dyck_path', ['DyckPath','DyckPaths']) + +del absolute_import diff --git a/src/sage/combinat/path_tableaux/dyck_path.py b/src/sage/combinat/path_tableaux/dyck_path.py index 0fdb825dcd4..5a0ee63aaca 100644 --- a/src/sage/combinat/path_tableaux/dyck_path.py +++ b/src/sage/combinat/path_tableaux/dyck_path.py @@ -101,17 +101,17 @@ def __classcall_private__(cls, ot): sage: t = DyckPath([0,1,2,1,0]) sage: t.parent() - + sage: t.category() - Category of elements of + Category of elements of sage: type(t) - + """ return DyckPaths()(ot) def __init__(self, parent, ot, check=True): r""" - Initialize a Catalan tableau. + Initialize a Dyck path. INPUT: @@ -231,7 +231,7 @@ def check(self): if abs(self[i+1]-self[i]) != 1: raise ValueError( "%s is not a Dyck path" % str(self) ) - def _local_rule(self,i): + def local_rule(self,i): """ This has input a list of objects. This method first takes the list of objects of length three consisting of the `(i-1)`-st, @@ -241,19 +241,19 @@ def _local_rule(self,i): EXAMPLES:: sage: t = DyckPath([0,1,2,3,2,1,0]) - sage: t._local_rule(3) + sage: t.local_rule(3) [0, 1, 2, 1, 2, 1, 0] TESTS:: sage: t = DyckPath([0,1,2,3,2,1,0]) - sage: t._local_rule(0) + sage: t.local_rule(0) Traceback (most recent call last): ... ValueError: 0 is not a valid integer - sage: t._local_rule(5) + sage: t.local_rule(5) [0, 1, 2, 3, 2, 1, 0] - sage: t._local_rule(6) + sage: t.local_rule(6) Traceback (most recent call last): ... ValueError: 6 is not a valid integer diff --git a/src/sage/combinat/path_tableaux/path_tableau.py b/src/sage/combinat/path_tableaux/path_tableau.py index 1b94089e4ff..1713ef76c57 100644 --- a/src/sage/combinat/path_tableaux/path_tableau.py +++ b/src/sage/combinat/path_tableaux/path_tableau.py @@ -67,7 +67,7 @@ def local_rule(self,i): EXAMPLES:: sage: t = DyckPath([0,1,2,3,2,1,0]) - sage: t._local_rule(3) + sage: t.local_rule(3) [0, 1, 2, 1, 2, 1, 0] """ @@ -123,7 +123,7 @@ def promotion(self): """ with self.clone() as result: for i in range(1,len(result)-1): - result = result._local_rule(i) + result = result.local_rule(i) return result @@ -212,7 +212,7 @@ def commutor(self,other,verbose=False): if verbose: print(path[n-i:n+m-i]) for j in range(m-1): - path = path._local_rule(n+j-i) + path = path.local_rule(n+j-i) if verbose: print(path[:m]) @@ -286,7 +286,7 @@ def _test_involution_rule(self, **options): """ tester = self._tester(**options) for i in range(self.size()-2): - tester.assertTrue(self._local_rule(i+1)._local_rule(i+1) == self) + tester.assertTrue(self.local_rule(i+1).local_rule(i+1) == self) def _test_involution_cactus(self, **options): @@ -450,7 +450,7 @@ def __init__(self): sage: t = DyckPath([0,1,2,1,0]) sage: t.parent() # indirect test - + """ Parent.__init__(self, category=Sets()) From 0942d3b700614cb819491e423984f1f4c09dafc9 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sat, 30 May 2020 09:21:29 +0100 Subject: [PATCH 171/300] Edited combinat/all.py all.py etc. to import from catalog --- src/sage/combinat/all.py | 3 +-- src/sage/combinat/path_tableaux/all.py | 13 ------------- src/sage/combinat/path_tableaux/catalog.py | 9 +++++---- 3 files changed, 6 insertions(+), 19 deletions(-) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 5ebb96135ae..80b4201e601 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -235,5 +235,4 @@ 'GrowthDiagramYoungFibonacci', 'GrowthDiagramSylvester']) # Path tableaux -lazy_import('sage.combinat.path_tableaux.path_tableau', ['PathTableau', 'PathTableaux', 'CylindricalDiagram']) -lazy_import('sage.combinat.path_tableaux.dyck_path', ['DyckPath', 'DyckPaths']) +from .path_tableaux.catalog import * diff --git a/src/sage/combinat/path_tableaux/all.py b/src/sage/combinat/path_tableaux/all.py index 5bc0f2fae5a..9ae4469b28d 100644 --- a/src/sage/combinat/path_tableaux/all.py +++ b/src/sage/combinat/path_tableaux/all.py @@ -1,16 +1,3 @@ r""" PathTableaux """ -from __future__ import absolute_import - -from sage.misc.lazy_import import lazy_import - -import sage.combinat.path_tableaux.catalog as path_tableaux - -from .path_tableau import PathTableau, PathTableaux, CylindricalDiagram -from .dyck_path import DyckPath, DyckPaths - -lazy_import('sage.combinat.path_tableaux.path_tableau', ['PathTableau', 'PathTableaux', 'CylindricalDiagram']) -lazy_import('sage.combinat.path_tableaux.dyck_path', ['DyckPath','DyckPaths']) - -del absolute_import diff --git a/src/sage/combinat/path_tableaux/catalog.py b/src/sage/combinat/path_tableaux/catalog.py index 958a4f8b08b..534af80a45d 100644 --- a/src/sage/combinat/path_tableaux/catalog.py +++ b/src/sage/combinat/path_tableaux/catalog.py @@ -9,11 +9,12 @@ Let ```` indicate pressing the tab key. So begin by typing ``algebras.`` to the see the currently implemented named path tableaux. -- :class:`algebras.ArikiKoike +- :class:`path_tableaux.DyckPaths """ -from sage.combinat.path_tableaux.dyck_path import DyckPaths, DyckPath - from sage.misc.lazy_import import lazy_import -lazy_import('sage.combinat.path_tableaux.dyck_path', 'DyckPaths', 'DyckPath') \ No newline at end of file +lazy_import('sage.combinat.path_tableaux.path_tableau', ['PathTableau', 'PathTableaux', 'CylindricalDiagram']) +lazy_import('sage.combinat.path_tableaux.dyck_path', ['DyckPath','DyckPaths']) + +#del absolute_import From 62e7e6312a7d527aa811db7f9686201bab5ad716 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sat, 30 May 2020 09:25:24 +0100 Subject: [PATCH 172/300] Minor edits --- src/sage/combinat/all.py | 2 +- src/sage/combinat/path_tableaux/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 80b4201e601..40d38df2674 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -234,5 +234,5 @@ 'GrowthDiagramBinWord', 'GrowthDiagramDomino', 'GrowthDiagramYoungFibonacci', 'GrowthDiagramSylvester']) -# Path tableaux +# Path Tableaux from .path_tableaux.catalog import * diff --git a/src/sage/combinat/path_tableaux/__init__.py b/src/sage/combinat/path_tableaux/__init__.py index 977ae3aea9b..56171bce5a0 100644 --- a/src/sage/combinat/path_tableaux/__init__.py +++ b/src/sage/combinat/path_tableaux/__init__.py @@ -3,5 +3,5 @@ ============= - :ref:`sage.combinat.path_tableaux.path_tableau` -- :ref:`sage.combinat.path_tableaux.catalan` +- :ref:`sage.combinat.path_tableaux.dyck_path` """ From 8acd0a1dca2c9a6baeb3e0c178122936b1e62006 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sat, 30 May 2020 09:43:19 +0100 Subject: [PATCH 173/300] Minor edits --- src/sage/combinat/path_tableaux/catalog.py | 1 + src/sage/combinat/path_tableaux/frieze.py | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/path_tableaux/catalog.py b/src/sage/combinat/path_tableaux/catalog.py index 534af80a45d..ba17d88407c 100644 --- a/src/sage/combinat/path_tableaux/catalog.py +++ b/src/sage/combinat/path_tableaux/catalog.py @@ -16,5 +16,6 @@ lazy_import('sage.combinat.path_tableaux.path_tableau', ['PathTableau', 'PathTableaux', 'CylindricalDiagram']) lazy_import('sage.combinat.path_tableaux.dyck_path', ['DyckPath','DyckPaths']) +lazy_import('sage.combinat.path_tableaux.frieze', ['FriezePattern','FriezePatterns']) #del absolute_import diff --git a/src/sage/combinat/path_tableaux/frieze.py b/src/sage/combinat/path_tableaux/frieze.py index c03458f4164..ab3fca12d21 100644 --- a/src/sage/combinat/path_tableaux/frieze.py +++ b/src/sage/combinat/path_tableaux/frieze.py @@ -213,7 +213,7 @@ def _repr_(self): return (self[1:-1]).__repr__() - def _local_rule(self,i): + def local_rule(self,i): r""" This has input a list of objects. This method first takes the list of objects of length three consisting of the `(i-1)`-st, @@ -223,11 +223,11 @@ def _local_rule(self,i): EXAMPLES:: sage: t = FriezePattern([1,2,1,2,3,1]) - sage: t._local_rule(3) + sage: t.local_rule(3) [1, 2, 5, 2, 3, 1] sage: t = FriezePattern([1,2,1,2,3,1]) - sage: t._local_rule(0) + sage: t.local_rule(0) Traceback (most recent call last): ... ValueError: 0 is not a valid integer From a2a246c18c2acb897c266ae3ab1bfe88253ab0ba Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 29 Apr 2020 12:46:56 -0400 Subject: [PATCH 174/300] Trac #29345: fix most autotools bashisms. Our autotools macros commit two main bashisms: * The use of FOO+="${BAR}" to concatenate the strings FOO and BAR; and * the use of $'\n' as a literal newline character. The first is easy to address, by using FOO="${FOO} ${BAR}". The latter is a bit more tricky, since the "obvious" way to add a newline into the variable FOO is with FOO="... $(printf '\n')", but the specification states that any newlines should be stripped from the end of the subshell's output! To work around that difficulty, this commit reworks the way a few of our variables are constructed. Instead of appending new stuff to the variable followed by a backslash and a newline, we now append the newline followed by some spaces and the new stuff. The end result is more or less the same -- it's the stuff we want separated by newlines and backslashes -- but with one important practical difference. Since the newlines are printed at the beginning (followed by some spaces), the output from e.g. $(printf '\n ') is left untouched. This looks a bit crazy when you see it, but it generates the correct output in the Makefiles. --- configure.ac | 5 ++--- m4/sage_spkg_collect.m4 | 43 +++++++++++++++++++---------------------- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/configure.ac b/configure.ac index 0d09c6fbc74..b5b39197790 100644 --- a/configure.ac +++ b/configure.ac @@ -447,13 +447,12 @@ SAGE_SPKG_COLLECT() # TODO: fix this in Trac #21524 touch "$SAGE_SRC/bin/sage-env-config" -SAGE_SCRIPTS='\ -' +SAGE_SCRIPTS='' for file in "$SAGE_SRC/bin/"*; do # Skip files with ".in" extension ext=${file##*.} if test "$ext" != in; then - SAGE_SCRIPTS+=" \$(SAGE_LOCAL)${file#$SAGE_SRC} \\"$'\n' + SAGE_SCRIPTS="${SAGE_SCRIPTS} \\$(printf '\n ')\$(SAGE_LOCAL)${file#$SAGE_SRC}" fi done diff --git a/m4/sage_spkg_collect.m4 b/m4/sage_spkg_collect.m4 index 2a128e0b21b..762e4918283 100644 --- a/m4/sage_spkg_collect.m4 +++ b/m4/sage_spkg_collect.m4 @@ -100,34 +100,31 @@ newest_version() { # not required on this platform or that can be taken from the underlying system # installation. Note that this contains packages that are not actually going to # be installed by most users because they are optional/experimental. -SAGE_BUILT_PACKAGES='\ -' +SAGE_BUILT_PACKAGES='' + # The complement of SAGE_BUILT_PACKAGES, i.e., packages that are not required # on this platform or packages where we found a suitable package on the # underlying system. -SAGE_DUMMY_PACKAGES='\ -' +SAGE_DUMMY_PACKAGES='' + # Standard packages -SAGE_STANDARD_PACKAGES='\ -' +SAGE_STANDARD_PACKAGES='' + # List of currently installed and to-be-installed optional packages - filled in SAGE_SPKG_ENABLE #SAGE_OPTIONAL_INSTALLED_PACKAGES # List of optional packages to be uninstalled - filled in SAGE_SPKG_ENABLE #SAGE_OPTIONAL_CLEANED_PACKAGES # List of all packages that should be downloaded -SAGE_SDIST_PACKAGES='\ -' +SAGE_SDIST_PACKAGES='' + # Generate package version and dependency lists SAGE_PACKAGE_VERSIONS="" SAGE_PACKAGE_DEPENDENCIES="" # Lists of packages categorized according to their build rules -SAGE_NORMAL_PACKAGES='\ -' -SAGE_PIP_PACKAGES='\ -' -SAGE_SCRIPT_PACKAGES='\ -' +SAGE_NORMAL_PACKAGES='' +SAGE_PIP_PACKAGES='' +SAGE_SCRIPT_PACKAGES='' SAGE_NEED_SYSTEM_PACKAGES="" @@ -159,7 +156,7 @@ for DIR in $SAGE_ROOT/build/pkgs/*; do message="came preinstalled with the SageMath tarball" ;; standard) - SAGE_STANDARD_PACKAGES+=" $SPKG_NAME \\"$'\n' + SAGE_STANDARD_PACKAGES="${SAGE_STANDARD_PACKAGES} \\$(printf '\n ')${SPKG_NAME}" in_sdist=yes message="will be installed as an SPKG" ;; @@ -202,7 +199,7 @@ for DIR in $SAGE_ROOT/build/pkgs/*; do uninstall_message="$SPKG_TYPE pip package (installed)" fi - SAGE_PACKAGE_VERSIONS+="vers_$SPKG_NAME = $SPKG_VERSION"$'\n' + SAGE_PACKAGE_VERSIONS="${SAGE_PACKAGE_VERSIONS}$(printf '\nvers_')${SPKG_NAME} = ${SPKG_VERSION}" AS_VAR_PUSHDEF([sage_spkg_install], [sage_spkg_install_${SPKG_NAME}])dnl AS_VAR_PUSHDEF([sage_require], [sage_require_${SPKG_NAME}])dnl @@ -213,13 +210,13 @@ for DIR in $SAGE_ROOT/build/pkgs/*; do # "./sage -i SPKG_NAME" will still install the package. AS_VAR_IF([sage_spkg_install], [no], [ dnl We will use the system package (or not required for this platform.) - SAGE_DUMMY_PACKAGES+=" $SPKG_NAME \\"$'\n' + SAGE_DUMMY_PACKAGES="${SAGE_DUMMY_PACKAGES} \\$(printf '\n ')${SPKG_NAME}" AS_VAR_IF([sage_require], [yes], [ message="using system package; SPKG will not be installed" ], [ message="not required on your platform; SPKG will not be installed" ]) ], [ dnl We won't use the system package. - SAGE_BUILT_PACKAGES+=" $SPKG_NAME \\"$'\n' + SAGE_BUILT_PACKAGES="${SAGE_BUILT_PACKAGES} \\$(printf '\n ')${SPKG_NAME}" AS_VAR_SET_IF([sage_use_system], [ AS_VAR_COPY([reason], [sage_use_system]) AS_CASE([$reason], @@ -249,7 +246,7 @@ for DIR in $SAGE_ROOT/build/pkgs/*; do esac if test "$in_sdist" = yes; then - SAGE_SDIST_PACKAGES+=" $SPKG_NAME \\"$'\n' + SAGE_SDIST_PACKAGES="${SAGE_SDIST_PACKAGES} \\$(printf '\n ')${SPKG_NAME}" fi # Determine package source @@ -282,18 +279,18 @@ for DIR in $SAGE_ROOT/build/pkgs/*; do fi fi - SAGE_PACKAGE_DEPENDENCIES+="deps_$SPKG_NAME = $DEPS"$'\n' + SAGE_PACKAGE_DEPENDENCIES="${SAGE_PACKAGE_DEPENDENCIES}$(printf '\ndeps_')${SPKG_NAME} = ${DEPS}" # Determine package build rules case "$SPKG_SOURCE" in pip) - SAGE_PIP_PACKAGES+=" $SPKG_NAME \\"$'\n' + SAGE_PIP_PACKAGES="${SAGE_PIP_PACKAGES} \\$(printf '\n ')${SPKG_NAME}" ;; script) - SAGE_SCRIPT_PACKAGES+=" $SPKG_NAME \\"$'\n' + SAGE_SCRIPT_PACKAGES="${SAGE_SCRIPT_PACKAGES} \\$(printf '\n ')${SPKG_NAME}" ;; normal) - SAGE_NORMAL_PACKAGES+=" $SPKG_NAME \\"$'\n' + SAGE_NORMAL_PACKAGES="${SAGE_NORMAL_PACKAGES} \\$(printf '\n ')${SPKG_NAME}" ;; esac done From bc3ea8e7448a3501a92bf4d800e19303154c6a75 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 29 Apr 2020 13:28:36 -0400 Subject: [PATCH 175/300] Trac #29345: fix one more newline-constant bashism in SAGE_SPKG_ENABLE. This is essentially the same fix used in SAGE_SPKG_COLLECT and in our configure.ac file. It reorders some things to print newlines followed by the stuff we want, rather than the other way around. This prevents the newlines from being stripped out of the subshell's output entirely. This macro was previously using AS_VAR_SET for this purpose, but for clarity I have reduced it to a standard shell-variable definition. The name of the variable itself is not dynamic, and this saves us from needing to think about m4 whitespace quoting and escaping rules. --- build/make/Makefile.in | 6 ++---- m4/sage_spkg_enable.m4 | 3 ++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/build/make/Makefile.in b/build/make/Makefile.in index da88e97fd84..9034fbaa712 100644 --- a/build/make/Makefile.in +++ b/build/make/Makefile.in @@ -85,14 +85,12 @@ STANDARD_PACKAGE_INSTS = \ $(foreach pkgname,$(STANDARD_PACKAGES),$(inst_$(pkgname))) # All optional installed packages (triggers the auto-update) -OPTIONAL_INSTALLED_PACKAGES = \ -@SAGE_OPTIONAL_INSTALLED_PACKAGES@ +OPTIONAL_INSTALLED_PACKAGES = @SAGE_OPTIONAL_INSTALLED_PACKAGES@ OPTIONAL_INSTALLED_PACKAGE_INSTS = \ $(foreach pkgname,$(OPTIONAL_INSTALLED_PACKAGES),$(inst_$(pkgname))) # All previously installed optional packages that are to be uninstalled -OPTIONAL_CLEANED_PACKAGES = \ -@SAGE_OPTIONAL_CLEANED_PACKAGES@ +OPTIONAL_CLEANED_PACKAGES = @SAGE_OPTIONAL_CLEANED_PACKAGES@ OPTIONAL_CLEANED_PACKAGES_CLEANS = $(OPTIONAL_CLEANED_PACKAGES:%=%-clean) # All packages which should be downloaded diff --git a/m4/sage_spkg_enable.m4 b/m4/sage_spkg_enable.m4 index 820ff5cf3a5..c349aab5f9a 100644 --- a/m4/sage_spkg_enable.m4 +++ b/m4/sage_spkg_enable.m4 @@ -19,7 +19,8 @@ AS_HELP_STRING([--disable-]SPKG_NAME, AS_IF([test "$want_spkg" = if_installed], [AS_VAR_SET([want_spkg], $is_installed)]) - AS_VAR_SET([spkg_line], [" ]SPKG_NAME[ \\"$'\n']) + + spkg_line=" \\$(printf '\n ')SPKG_NAME" AS_CASE([$is_installed-$want_spkg], [*-yes], [AS_VAR_APPEND(SAGE_OPTIONAL_INSTALLED_PACKAGES, "$spkg_line")], [yes-no], [AS_VAR_APPEND(SAGE_OPTIONAL_CLEANED_PACKAGES, "$spkg_line")]) From fb475f3311972d819723c0d8f7d8a4cb3036b74c Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 29 Apr 2020 17:08:06 -0400 Subject: [PATCH 176/300] Trac #29345: replace a few obsolete "-a" tests with "-e". The "-a" test in bash means "file exists," but the standard POSIX "-e" is more portable and works in bash anyway, so let's use that. --- src/bin/sage-env | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bin/sage-env b/src/bin/sage-env index 51beb29a090..99968a6b5d2 100644 --- a/src/bin/sage-env +++ b/src/bin/sage-env @@ -463,7 +463,7 @@ unset R_PROFILE if [ -d "$SAGE_LOCAL/lib/R/share" ] ; then R_MAKEVARS_SITE="$SAGE_LOCAL/lib/R/share/Makevars.site" && export R_MAKEVARS_SITE if ! [ -f "$R_MAKEVARS_SITE" ] ; then - if ! [ -a "$R_MAKEVARS_SITE" ] ; then + if ! [ -e "$R_MAKEVARS_SITE" ] ; then echo "## Empty site-wide Makevars file for Sage's R" > "$R_MAKEVARS_SITE" else >&2 echo "Warning: $R_MAKEVARS_SITE exists and is not a file : trouble ahead..." @@ -472,7 +472,7 @@ if [ -d "$SAGE_LOCAL/lib/R/share" ] ; then fi if [ -d "$DOT_SAGE" ] ; then if ! [ -d "$DOT_SAGE/R" ] ; then - if ! [ -a "$DOT_SAGE/R" ] ; then + if ! [ -e "$DOT_SAGE/R" ] ; then mkdir -p "$DOT_SAGE/R" else >&2 echo "Warning: $DOT_SAGE/R exists and is not a directory : trouble ahead..." @@ -480,7 +480,7 @@ if [ -d "$DOT_SAGE" ] ; then fi R_MAKEVARS_USER="$DOT_SAGE/R/Makevars.user" && export R_MAKEVARS_USER if ! [ -f "$R_MAKEVARS_USER" ] ; then - if ! [ -a "$R_MAKEVARS_USER" ] ; then + if ! [ -e "$R_MAKEVARS_USER" ] ; then echo "## Empty user-specific Makevars file for Sage's R" > "$R_MAKEVARS_USER" else >&2 echo "Warning: $R_MAKEVARS_USER exists and is not a file : trouble ahead..." From 305d8cfac37e6b110710d6b0892f00c3abce1a98 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 29 Apr 2020 17:19:46 -0400 Subject: [PATCH 177/300] Trac #29345: replace a bash array with something portable. Instead of storing the output of sage-num-threads.py in a bash array, this commit stores it as a string. There are three "components" to the output, and to get at the first and second components, we now use the POSIX shortest prefix/suffix parameter expansions to strip off the stuff before/after the first/last space. --- src/bin/sage-env | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/bin/sage-env b/src/bin/sage-env index 99968a6b5d2..46da767ec79 100644 --- a/src/bin/sage-env +++ b/src/bin/sage-env @@ -603,9 +603,10 @@ ECLDIR="$SAGE_LOCAL/lib/ecl/" && export ECLDIR # First, figure out the right values for SAGE_NUM_THREADS (default # number of threads) and SAGE_NUM_THREADS_PARALLEL (default number of # threads when parallel execution is asked explicitly). -sage_num_threads_array=(`sage-num-threads.py 2>/dev/null || echo 1 2 1`) -SAGE_NUM_THREADS=${sage_num_threads_array[0]} -SAGE_NUM_THREADS_PARALLEL=${sage_num_threads_array[1]} +sage_num_threads_array=$(sage-num-threads.py 2>/dev/null || echo 1 2 1) +sage_num_threads_array="${sage_num_threads_array% *}" # strip third item +SAGE_NUM_THREADS="${sage_num_threads_array% *}" # keep first item +SAGE_NUM_THREADS_PARALLEL="${sage_num_threads_array#* }" # keep second item export SAGE_NUM_THREADS export SAGE_NUM_THREADS_PARALLEL From d0dff56f6bb004b32f07c067b653f966bd1f7569 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 29 Apr 2020 17:41:21 -0400 Subject: [PATCH 178/300] Trac #29345: replace a few uses of "source" with "." Using "source" to include another script file is a bashism; the portable option is to use the dot "." to do it. --- build/make/Makefile.in | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build/make/Makefile.in b/build/make/Makefile.in index 9034fbaa712..16396e3e9ec 100644 --- a/build/make/Makefile.in +++ b/build/make/Makefile.in @@ -335,7 +335,7 @@ sagelib-build-deps: \ sagelib: sagelib-build-deps $(AM_V_at)if [ -z "$$SAGE_INSTALL_FETCH_ONLY" ]; then \ - cd $(SAGE_SRC) && source bin/sage-env && source $(SAGE_ROOT)/build/bin/sage-build-env-config && \ + cd $(SAGE_SRC) && . bin/sage-env && . $(SAGE_ROOT)/build/bin/sage-build-env-config && \ sage-logger -p 'time $(MAKE) sage' '$(SAGE_LOGS)/sagelib-$(SAGE_VERSION).log'; \ fi @@ -558,14 +558,14 @@ endif # # $(INST)/-: # $(AM_V_at)cd '$SAGE_ROOT' && \\ -# source '$SAGE_ROOT/src/bin/sage-env' && \\ +# . '$SAGE_ROOT/src/bin/sage-env' && \\ # sage-logger -p '$SAGE_ROOT/build/pkgs//spkg-install' '$(SAGE_LOGS)/.log' # # : $(INST)/- # # -clean: # -$(AM_V_at)cd '$SAGE_ROOT' && \\ -# source '$SAGE_ROOT/src/bin/sage-env' && \\ +# . '$SAGE_ROOT/src/bin/sage-env' && \\ # '$SAGE_ROOT/build/pkgs/$PKG_NAME/spkg-uninstall' # Positional arguments: @@ -575,7 +575,7 @@ endif define SCRIPT_PACKAGE_templ $$(INST)/$(1)-$(2): $(3) $(AM_V_at)cd '$$(SAGE_ROOT)' && \ - source '$$(SAGE_ROOT)/src/bin/sage-env' && source '$$(SAGE_ROOT)/build/bin/sage-build-env-config' && \ + . '$$(SAGE_ROOT)/src/bin/sage-env' && . '$$(SAGE_ROOT)/build/bin/sage-build-env-config' && \ sage-logger -p '$$(SAGE_ROOT)/build/pkgs/$(1)/spkg-install' '$$(SAGE_LOGS)/$(1).log' touch "$$@" @@ -583,7 +583,7 @@ $(1): $$(INST)/$(1)-$(2) $(1)-clean: -$(AM_V_at)cd '$$(SAGE_ROOT)' && \ - source '$$(SAGE_ROOT)/src/bin/sage-env' && source '$$(SAGE_ROOT)/build/bin/sage-build-env-config' && \ + . '$$(SAGE_ROOT)/src/bin/sage-env' && . '$$(SAGE_ROOT)/build/bin/sage-build-env-config' && \ '$$(SAGE_ROOT)/build/pkgs/$(1)/spkg-uninstall' -rm -f "$$(INST)/$(1)-$(2)" From 5ac420b15ac0e561e5e8f7f64bb9566a1b6e7890 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 29 Apr 2020 17:43:02 -0400 Subject: [PATCH 179/300] Trac #29345: fix some bashisms in sage-env's resolvelinks() function. This function was using bash-specific parameter expansions to find- and-replace substrings. Fortunately, most of the substrings were at the beginning of the big string, where the POSIX shortest-prefix strip, followed by a prepend, accomplishes the same thing. The other instance was replacing multiple slashes by a single slash in a path, which is now implemented with a call to sed. --- src/bin/sage-env | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/bin/sage-env b/src/bin/sage-env index 46da767ec79..f3a005f573a 100644 --- a/src/bin/sage-env +++ b/src/bin/sage-env @@ -44,12 +44,10 @@ resolvelinks() { # Move stuff from $in to $out while [ -n "$in" ]; do # Normalize $in by replacing consecutive slashes by one slash - while { in_single_slash=${in//\/\//\/}; [ "$in" != "$in_single_slash" ]; }; do - in=$in_single_slash - done + in=$(echo "${in}" | sed 's://*:/:g') # If $in starts with a slash, remove it and set $out to the root - in_without_slash=${in/#\//} + in_without_slash=${in#/} if [ "$in" != "$in_without_slash" ]; then in=$in_without_slash out="/" @@ -71,7 +69,7 @@ resolvelinks() { out="$out$f" # If the new $in starts with a slash, move it to $out - in_without_slash=${in/#\//} + in_without_slash=${in#/} if [ "$in" != "$in_without_slash" ]; then in=$in_without_slash out="$out/" @@ -103,7 +101,8 @@ resolvelinks() { fi # In $in, replace $f by $f_resolved (leave $out alone) - in=${in/#"$f"/"$f_resolved"} + in="${in#${f}}" + in="${f_resolved}${in}" done # Return $out From 0a617950488b3945fb6f494cec8b50e8486bd9dd Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 29 Apr 2020 13:31:14 -0400 Subject: [PATCH 180/300] Trac #29345: don't force SHELL=bash any longer. Our build system (the autotools parts, anyway) are now compatible with any POSIX shell. This commit deletes the hunk of code in configure.ac that insisted on bash. --- configure.ac | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/configure.ac b/configure.ac index b5b39197790..aade46804be 100644 --- a/configure.ac +++ b/configure.ac @@ -28,31 +28,6 @@ AC_PREREQ([2.69]) AC_DEFUN([SAGE_VERSION], m4_esyscmd_s([. src/bin/sage-version.sh && echo $SAGE_VERSION])) AC_INIT([Sage], SAGE_VERSION, [sage-devel@googlegroups.com]) -# The following needs to be immediately after calling AC_INIT -#------------------------------------------------------------ -# We need to run this configure script with bash -if test -z "$BASH_VERSION" -then - CONFIG_SHELL=`command -v bash` - export CONFIG_SHELL - if $CONFIG_SHELL -c "exit 0" - then - exec $CONFIG_SHELL $0 "$@" - else - AC_MSG_NOTICE([The 'bash' shell is needed to build AC_PACKAGE_NAME]) - AC_MSG_NOTICE([All modern systems will have the 'bash' shell installed somewhere]) - if test -d /opt/OpenSource/bin - then - AC_MSG_NOTICE([On HP-UX you may try adding /opt/OpenSource/bin to your path]) - fi - if test -d /opt/pware/bin - then - AC_MSG_NOTICE([On AIX you may try adding /opt/pware/bin to your path]) - fi - AC_MSG_ERROR(['bash' not found]) - fi -fi - AC_COPYRIGHT([GPL version 3]) AC_CONFIG_SRCDIR([configure.ac]) From 5db53186b9ae9a546bc78fc9107cc1af713b7e24 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Fri, 8 May 2020 11:57:29 -0400 Subject: [PATCH 181/300] Trac #29345: remove "break" statements from AC_SEARCH_LIBS. The AC_CHECK_HEADERS macro allows you to specify "break" for the action-if-found, but AC_SEARCH_LIBS does not. And zsh especially does not like seeing a "break" statement out of context. --- build/pkgs/mpc/spkg-configure.m4 | 2 +- build/pkgs/mpfr/spkg-configure.m4 | 2 +- build/pkgs/mpir/spkg-configure.m4 | 2 +- build/pkgs/ncurses/spkg-configure.m4 | 4 ++-- build/pkgs/readline/spkg-configure.m4 | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build/pkgs/mpc/spkg-configure.m4 b/build/pkgs/mpc/spkg-configure.m4 index 9ec14a7c980..32aca4ada1b 100644 --- a/build/pkgs/mpc/spkg-configure.m4 +++ b/build/pkgs/mpc/spkg-configure.m4 @@ -8,7 +8,7 @@ SAGE_SPKG_CONFIGURE([mpc], [ AC_MSG_RESULT([no]) AC_CHECK_HEADER(mpc.h, [], [sage_spkg_install_mpc=yes]) dnl mpc_cmp_abs appeared in MPC 1.1.0 - AC_SEARCH_LIBS([mpc_cmp_abs], [mpc], [break], [sage_spkg_install_mpc=yes]) + AC_SEARCH_LIBS([mpc_cmp_abs], [mpc], [], [sage_spkg_install_mpc=yes]) fi ], [], [], [ if test x$sage_spkg_install_mpc = xyes; then diff --git a/build/pkgs/mpfr/spkg-configure.m4 b/build/pkgs/mpfr/spkg-configure.m4 index 0d0ef933027..0c15b56df43 100644 --- a/build/pkgs/mpfr/spkg-configure.m4 +++ b/build/pkgs/mpfr/spkg-configure.m4 @@ -8,7 +8,7 @@ SAGE_SPKG_CONFIGURE([mpfr], [ AC_MSG_RESULT([no]) AC_CHECK_HEADER(mpfr.h, [], [sage_spkg_install_mpfr=yes]) dnl mpfr_free_pool appeared in r11922 (Dec 2017) on MPFR svn - AC_SEARCH_LIBS([mpfr_free_pool], [mpfr], [break], [sage_spkg_install_mpfr=yes]) + AC_SEARCH_LIBS([mpfr_free_pool], [mpfr], [], [sage_spkg_install_mpfr=yes]) fi ], [], [], [ if test x$sage_spkg_install_mpfr = xyes; then diff --git a/build/pkgs/mpir/spkg-configure.m4 b/build/pkgs/mpir/spkg-configure.m4 index c4f9c432e2a..01afff14621 100644 --- a/build/pkgs/mpir/spkg-configure.m4 +++ b/build/pkgs/mpir/spkg-configure.m4 @@ -5,7 +5,7 @@ dnl Implement cases for what to do on different options here AC_CHECK_HEADER(gmp.h, [], [sage_spkg_install_mpir=yes]) AC_CHECK_HEADER(gmpxx.h, [], [sage_spkg_install_mpir=yes]) dnl mpq_cmp_z appeared in GMP 6.1.0 and is used by pynac - AC_SEARCH_LIBS([__gmpq_cmp_z], [gmp], [break], + AC_SEARCH_LIBS([__gmpq_cmp_z], [gmp], [], [sage_spkg_install_mpir=yes]) SAGE_MP_LIBRARY=mpir ;; diff --git a/build/pkgs/ncurses/spkg-configure.m4 b/build/pkgs/ncurses/spkg-configure.m4 index 8fe619cbefd..c706d4091d5 100644 --- a/build/pkgs/ncurses/spkg-configure.m4 +++ b/build/pkgs/ncurses/spkg-configure.m4 @@ -2,8 +2,8 @@ SAGE_SPKG_CONFIGURE([ncurses], [ dnl First try checking for ncurses with pkg-config PKG_CHECK_MODULES([NCURSES], [ncurses >= 6.0], [], [AC_CHECK_HEADERS([ncurses.h], - [AC_SEARCH_LIBS([wresize], [ncurses tinfo], [break], - [sage_spkg_install_ncurses=yes])], + [AC_SEARCH_LIBS([wresize], [ncurses tinfo], [], + [sage_spkg_install_ncurses=yes])], [sage_spkg_install_ncurses=yes])], [sage_spkg_install_ncurses=yes]) ]) diff --git a/build/pkgs/readline/spkg-configure.m4 b/build/pkgs/readline/spkg-configure.m4 index 4d82c6d77be..68aab0a36ad 100644 --- a/build/pkgs/readline/spkg-configure.m4 +++ b/build/pkgs/readline/spkg-configure.m4 @@ -11,7 +11,7 @@ SAGE_SPKG_CONFIGURE([readline], [ [AC_CHECK_HEADERS([readline/readline.h], dnl rl_bind_keyseq is not present in macos's readline dnl and is not present in readline version 4 (the one in OpenBSD) - [AC_SEARCH_LIBS([rl_bind_keyseq], [readline], [break], + [AC_SEARCH_LIBS([rl_bind_keyseq], [readline], [], [sage_spkg_install_readline=yes])], [sage_spkg_install_readline=yes])], [sage_spkg_install_readline=yes]) From e810ad1596d527c832bf43d3aac745407c9ba98d Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Fri, 8 May 2020 12:02:58 -0400 Subject: [PATCH 182/300] Trac #29345: don't use sage's config.status for the lrcalc build. The lrcalc SPKG has some outdated autotools, and we worked around that in Trac ticket 19725 (commit 75de776ab) with the line, cp "$SAGE_ROOT"/config/config.* . that is intended to import only config.guess and config.sub, judging by the comment above it. However, it's also mistakenly copying in the sage version of config.status, causing build problems when sage was configured with a non-bash shell. --- build/pkgs/lrcalc/spkg-install.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/pkgs/lrcalc/spkg-install.in b/build/pkgs/lrcalc/spkg-install.in index 46b765298c6..d6665bfb427 100644 --- a/build/pkgs/lrcalc/spkg-install.in +++ b/build/pkgs/lrcalc/spkg-install.in @@ -1,7 +1,8 @@ cd src # Use newer version of config.guess and config.sub (see Trac #19725) -cp "$SAGE_ROOT"/config/config.* . +cp "$SAGE_ROOT"/config/config.guess . +cp "$SAGE_ROOT"/config/config.sub . sdh_configure sdh_make From 93c9921cc5ff461cd1f02f441b46cea4400dcd85 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Wed, 13 May 2020 16:57:34 -0400 Subject: [PATCH 183/300] Trac #29345: replace the function that populates the CVXOPT_* variables. Our existing function, borrowed from Gentoo, to populate the CVXOPT_* variables from pkg-config was brittle. It didn't handle -lpthread and -lm the way it was intended to, and didn't always work with a non-bash shell. The new version (which has also been upstreamed to Gentoo) should fix both of those problems. It also suppors getting the -L and -I flags from pkg-config in the future, which will likely be necessary to support system installations of some cvxopt dependencies. --- build/pkgs/cvxopt/spkg-install.in | 67 ++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 9 deletions(-) diff --git a/build/pkgs/cvxopt/spkg-install.in b/build/pkgs/cvxopt/spkg-install.in index 980eddf1493..bed0f34ceee 100644 --- a/build/pkgs/cvxopt/spkg-install.in +++ b/build/pkgs/cvxopt/spkg-install.in @@ -1,20 +1,69 @@ cd src -# Stolen from Gentoo -pkg_libs() { - pkg-config --libs-only-l $* | \ - sed -e 's:[ ]-l*\(pthread\|m\)\([ ]\|$\)::g' -e 's:[ ]*$::' | \ - tr ' ' '\n' | sort -u | sed -e "s:^-l\(.*\):\1:g" | \ - tr '\n' ';' | sed -e 's:;$::' -} +# This is a POSIX (non-bash) compatible version of the same function +# in the Gentoo cvxopt package. It's more general than it needs to +# be right now because we may need to use the "L" and "I" modes in +# the future to support system installations of e.g. suitesparse. +# +# The BLAS_LIB and LAPACK_LIB variables (among others) in cvxopt's +# setup.py are passed in as colon-delimited strings. So, for example, +# if your blas "l" flags are "-lblas -lcblas", then cvxopt wants +# "blas;cblas" for BLAS_LIB. +# +# The following function takes a flag type ("l", "L", or "I") as its +# first argument and a list of packages as its remaining arguments. It +# outputs a list of libraries, library paths, or include paths, +# respectively, for the given packages, retrieved using pkg-config and +# deduplicated, in the appropriate format. +# +cvxopt_output() { + FLAGNAME="${1}" + shift + PACKAGES="${@}" + + case "${FLAGNAME}" in + l) PKGCONFIG_MODE="--libs-only-l";; + L) PKGCONFIG_MODE="--libs-only-L";; + I) PKGCONFIG_MODE="--cflags-only-I";; + *) echo "invalid flag name: ${FLAGNAME}"; exit 1;; + esac + + CVXOPT_OUTPUT="" + for PKGCONFIG_ITEM in $(pkg-config ${PKGCONFIG_MODE} ${PACKAGES}); do + # First strip off the leading "-l", "-L", or "-I", and replace + # it with a semicolon... + PKGCONFIG_ITEM=";${PKGCONFIG_ITEM#-${FLAGNAME}}" + # Now check to see if this element is already present in the + # list, and skip it if it is. This eliminates multiple entries + # from winding up in the list when multiple package arguments are + # passed to this function. + if [ "${CVXOPT_OUTPUT}" != "${CVXOPT_OUTPUT%${PKGCONFIG_ITEM}}" ] + then + # It was already the last entry in the list, so skip it. + continue + elif [ "${CVXOPT_OUTPUT}" != "${CVXOPT_OUTPUT%${PKGCONFIG_ITEM};*}" ] + then + # It was an earlier entry in the list. These two cases are + # separate to ensure that we can e.g. find ";m" at the end + # of the list, but that we don't find ";metis" in the process. + continue + fi + + # It isn't in the list yet, so append it. + CVXOPT_OUTPUT="${CVXOPT_OUTPUT}${PKGCONFIG_ITEM}" + done + + # Strip the leading ";" from ";foo;bar" before output. + echo "${CVXOPT_OUTPUT#;}" +} # configure cvxopt by variables # Note that *_INC_DIR variables have to be non-empty. # Compilers don't like "-I ". -export CVXOPT_BLAS_LIB="$(pkg_libs blas)" +export CVXOPT_BLAS_LIB="$(cvxopt_output l blas)" export CVXOPT_BLAS_LIB_DIR="$(pkg-config --variable=libdir blas)" -export CVXOPT_LAPACK_LIB="$(pkg_libs lapack)" +export CVXOPT_LAPACK_LIB="$(cvxopt_output l lapack)" if test "x$SAGE_SUITESPARSE_LOCALINSTALL" != "x"; then export CVXOPT_SUITESPARSE_LIB_DIR="${SAGE_LOCAL}" From 0e66a0abc00d5bf5ac1496e13f4d2f4ef7fe29dc Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Fri, 15 May 2020 06:36:41 -0400 Subject: [PATCH 184/300] Trac #29345: add Dima's SPKG patches for ksh compatibility. Without these three patches, the *.pc files for givaro, linbox, and fflas-ffpack cause problems with the ksh shell. Since we are removing the code in configure.ac that sets the shell to bash as part of the same ticket, these patches are needed to avoid introducing new problems. --- .../patches/fix-ksh-pkgconfig.patch | 28 +++++++++++++++++++ .../givaro/patches/fix-ksh-pkgconfig.patch | 27 ++++++++++++++++++ .../linbox/patches/fix-ksh-pkgconfig.patch | 28 +++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 build/pkgs/fflas_ffpack/patches/fix-ksh-pkgconfig.patch create mode 100644 build/pkgs/givaro/patches/fix-ksh-pkgconfig.patch create mode 100644 build/pkgs/linbox/patches/fix-ksh-pkgconfig.patch diff --git a/build/pkgs/fflas_ffpack/patches/fix-ksh-pkgconfig.patch b/build/pkgs/fflas_ffpack/patches/fix-ksh-pkgconfig.patch new file mode 100644 index 00000000000..fdaed2eebee --- /dev/null +++ b/build/pkgs/fflas_ffpack/patches/fix-ksh-pkgconfig.patch @@ -0,0 +1,28 @@ +From 33a5ec4977f36ce3a24c9ee824d9dd053b8cea04 Mon Sep 17 00:00:00 2001 +From: Dima Pasechnik +Date: Fri, 8 May 2020 15:55:27 +0100 +Subject: [PATCH 1/1] remove 1st and last file in .pc file + +this causes problem if building with ksh, as they remain, causing a broken .pc file. +--- + fflas-ffpack.pc.in | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/fflas-ffpack.pc.in b/fflas-ffpack.pc.in +index a2618d6..e34a744 100644 +--- a/fflas-ffpack.pc.in ++++ b/fflas-ffpack.pc.in +@@ -1,4 +1,3 @@ +-/------------------ fflas-ffpack.pc ------------------------ + prefix=@prefix@ + exec_prefix=@prefix@ + libdir=@prefix@/lib +@@ -11,4 +10,3 @@ Version: @VERSION@ + Requires: givaro >= 4.0.3 + Libs: @PARLIBS@ @PRECOMPILE_LIBS@ @BLAS_LIBS@ + Cflags: -I@includedir@ @BLAS_CFLAGS@ @PARFLAGS@ @PRECOMPILE_FLAGS@ @REQUIRED_FLAGS@ +-\------------------------------------------------------- +\ No newline at end of file +-- +2.26.2 + diff --git a/build/pkgs/givaro/patches/fix-ksh-pkgconfig.patch b/build/pkgs/givaro/patches/fix-ksh-pkgconfig.patch new file mode 100644 index 00000000000..28fd95088c8 --- /dev/null +++ b/build/pkgs/givaro/patches/fix-ksh-pkgconfig.patch @@ -0,0 +1,27 @@ +From 91dcba743e15288abe69966a5f71704d9adcc57c Mon Sep 17 00:00:00 2001 +From: Dima Pasechnik +Date: Fri, 8 May 2020 10:22:57 +0100 +Subject: [PATCH 1/1] remove 1st and last lines in givaro.pc.in + +--- + givaro.pc.in | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/givaro.pc.in b/givaro.pc.in +index 285b854..af38bf3 100644 +--- a/givaro.pc.in ++++ b/givaro.pc.in +@@ -1,4 +1,3 @@ +-/------------------ givaro.pc ------------------------ + prefix=@prefix@ + exec_prefix=@prefix@ + libdir=@prefix@/lib +@@ -11,4 +10,3 @@ Version: @VERSION@ + Requires: + Libs: -L@libdir@ -lgivaro @LIBS@ + Cflags: -I@includedir@ @REQUIRED_FLAGS@ +-\------------------------------------------------------- +\ No newline at end of file +-- +2.26.2 + diff --git a/build/pkgs/linbox/patches/fix-ksh-pkgconfig.patch b/build/pkgs/linbox/patches/fix-ksh-pkgconfig.patch new file mode 100644 index 00000000000..e0cb575b1a1 --- /dev/null +++ b/build/pkgs/linbox/patches/fix-ksh-pkgconfig.patch @@ -0,0 +1,28 @@ +From 52c78df67a08de074991a93b57946b7bd5ea7196 Mon Sep 17 00:00:00 2001 +From: Dima Pasechnik +Date: Fri, 8 May 2020 15:53:25 +0100 +Subject: [PATCH 1/1] remove redundant 1st and last lines + +they remain if the script is run under ksh, leading to broken .pc file +--- + linbox.pc.in | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/linbox.pc.in b/linbox.pc.in +index f54285e..eb6835b 100644 +--- a/linbox.pc.in ++++ b/linbox.pc.in +@@ -1,4 +1,3 @@ +-/------------------ linbox.pc ------------------------ + prefix=@prefix@ + exec_prefix=@prefix@ + libdir=@libdir@ +@@ -11,4 +10,4 @@ Version: @VERSION@ + Requires: fflas-ffpack >= 2.4.0, givaro >= 4.1.0 + Libs: -L${libdir} -llinbox @LINBOXSAGE_LIBS@ @NTL_LIBS@ @MPFR_LIBS@ @FPLLL_LIBS@ @IML_LIBS@ @FLINT_LIBS@ @OCL_LIBS@ + Cflags: @DEFAULT_CFLAGS@ -DDISABLE_COMMENTATOR -I${includedir} @NTL_CFLAGS@ @MPFR_CFLAGS@ @FPLLL_CFLAGS@ @IML_CFLAGS@ @FLINT_CFLAGS@ +-\------------------------------------------------------- ++ +-- +2.26.2 + From e4d3598ea1e261cd7db9ba71fdd7da9b5b23746a Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 31 May 2020 16:10:48 +1000 Subject: [PATCH 185/300] Implement the Jucys-Murphy elements for the partition algebra. --- src/doc/en/reference/references/index.rst | 5 +- src/sage/combinat/diagram_algebras.py | 257 ++++++++++++++++++++++ 2 files changed, 261 insertions(+), 1 deletion(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 644ac84d23c..384af43680d 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1533,7 +1533,10 @@ REFERENCES: Curves*. Cambridge University Press, 1997. .. [Cre2003] Cressman, Ross. *Evolutionary dynamics and extensive form - games*. MIT Press, 2003. + games*. MIT Press, 2003. + +.. [Cre2020] Creedon, Samuel. *The center of the partition algebra*. + Preprint, :arxiv:`2005.00600` (2020). .. [Cro1983] \M. Crochemore, Recherche linéaire d'un carré dans un mot, C. R. Acad. Sci. Paris Sér. I Math. 296 (1983) 14 diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 5037c6062fa..b1c596a9a82 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -506,6 +506,19 @@ def is_planar(self): """ return is_planar(self) + def dual(self): + """ + Return the dual diagram of ``self`` by flipping it top-to-bottom. + + EXAMPLES:: + + sage: from sage.combinat.diagram_algebras import PartitionDiagram + sage: D = PartitionDiagram([[1,-1],[2,-2,-3],[3]]) + sage: D.dual() + {{-3}, {-2, 2, 3}, {-1, 1}} + """ + return self.parent([[-i for i in part] for part in self]) + class IdealDiagram(AbstractPartitionDiagram): r""" The element class for a ideal diagram. @@ -2682,6 +2695,230 @@ def _orbit_to_diagram_on_basis(self, d): * self([sum((list(d[i-1]) for i in p),[]) for p in sp]) for sp in SPd) + @cached_method + def e(self, i): + r""" + Return the element `e_i` in ``self``. + + EXAMPLES:: + + sage: R. = QQ[] + sage: P3 = PartitionAlgebra(3, n) + sage: P3.e(1) + P{{-3, 3}, {-2, -1, 1, 2}} + sage: P3.e(2) + P{{-3, -2, 2, 3}, {-1, 1}} + sage: P3.e(1/2) + P{{-3, 3}, {-2, 2}, {-1}, {1}} + sage: P3.e(5/2) + P{{-3}, {-2, 2}, {-1, 1}, {3}} + sage: P3.e(0) + Traceback (most recent call last): + ... + ValueError: i must be an (half) integer between 1/2 and 5/2 + sage: P3.e(3) + Traceback (most recent call last): + ... + ValueError: i must be an (half) integer between 1/2 and 5/2 + """ + if i <= 0 or i >= self._k: + raise ValueError("i must be an (half) integer between 1/2 and {}".format((2*self._k-1)/2)) + B = self.basis() + SP = B.keys() + if i in ZZ: + i -= 1 + D = [[-j, j] for j in range(1, self._k+1)] + D[i] += D.pop(i+1) + return B[SP(D)] + else: + i = ceil(i) + D = [[-j, j] for j in range(1, self._k+1)] + D[i-1] = [-i] + D.append([i]) + return B[SP(D)] + + @cached_method + def s(self, i): + r""" + Return the ``i``-th simple transposition `s_i` in ``self``. + + EXAMPLES:: + + sage: R. = QQ[] + sage: P3 = PartitionAlgebra(3, n) + sage: P3.s(1) + P{{-3, 3}, {-2, 1}, {-1, 2}} + sage: P3.s(2) + P{{-3, 2}, {-2, 3}, {-1, 1}} + sage: P3.s(3) + Traceback (most recent call last): + ... + ValueError: i must be an integer between 1 and 2 + """ + if i < 1 or i >= self._k: + raise ValueError("i must be an integer between 1 and {}".format(self._k-1)) + B = self.basis() + SP = B.keys() + D = [[-j, j] for j in range(1, self._k+1)] + D[i-1] = [-(i+1), i] + D[i] = [-i, i+1] + return B[SP(D)] + + @cached_method + def sigma(self, i): + r""" + Return the element `\sigma_i` from [Cre2020]_ + (with the index `i` divided by 2). + + EXAMPLES:: + + sage: R. = QQ[] + sage: P3 = PartitionAlgebra(3, n) + sage: P3.sigma(1) + P{{-3, 3}, {-2, 2}, {-1, 1}} + sage: P3.sigma(3/2) + P{{-3, 3}, {-2, 1}, {-1, 2}} + sage: P3.sigma(2) + -P{{-3, -1, 1, 3}, {-2, 2}} + P{{-3, -1, 3}, {-2, 1, 2}} + + P{{-3, 1, 3}, {-2, -1, 2}} - P{{-3, 3}, {-2, -1, 1, 2}} + + P{{-3, 3}, {-2, 2}, {-1, 1}} + sage: P3.sigma(5/2) + -P{{-3, -1, 1, 2}, {-2, 3}} + P{{-3, -1, 2}, {-2, 1, 3}} + + P{{-3, 1, 2}, {-2, -1, 3}} - P{{-3, 2}, {-2, -1, 1, 3}} + + P{{-3, 2}, {-2, 3}, {-1, 1}} + + We test the relations in Lemma 2.2.3(1) in [Cre2020]_:: + + sage: k = 4 + sage: R. = QQ[] + sage: P = PartitionAlgebra(k, x) + sage: all(P.sigma(i/2).dual() == P.sigma(i/2) + ....: for i in range(1,2*k)) + True + sage: all(P.sigma(i)*P.sigma(i+1/2) == P.sigma(i+1/2)*P.sigma(i) == P.s(i) + ....: for i in range(1,k)) + True + sage: all(P.sigma(i)*P.e(i) == P.e(i)*P.sigma(i) == P.e(i) + ....: for i in range(1,k)) + True + sage: all(P.sigma(i+1/2)*P.e(i) == P.e(i)*P.sigma(i+1/2) == P.e(i) + ....: for i in range(1,k)) + True + """ + half = QQ.one() / 2 + if i in ZZ: + if i == 1: + return self.one() + si = self.s(i) + sim = self.s(i-1) + x = self.e(i-1) * self.jucys_murphy_element(i-1) * si * self.e(i-1) + return (sim * si * self.sigma(i-1) * si * sim + + x * si + si * x + - self.e(i-1) * self.jucys_murphy_element(i-1) * sim + * self.e(i) * self.e(i-half) * self.e(i-1) + - si * self.e(i-1) * self.e(i-half) * self.e(i) * sim + * self.jucys_murphy_element(i-1) * self.e(i-1) * si) + else: + j = ceil(i) - 1 + if j == 0: + return self.zero() + if j == 1: + return self.s(1) + si = self.s(j) + sim = self.s(j-1) + x = self.e(j-1) * self.jucys_murphy_element(j-1) * si * self.e(j-1) + return (sim * si * self.sigma(i-1) * si * sim + + si * x * si + x + - si * self.e(j-1) * self.jucys_murphy_element(j-1) * sim + * self.e(j) * self.e(i-1) * self.e(j-1) + - self.e(j-1) * self.e(i-1) * self.e(j) * sim + * self.jucys_murphy_element(j-1) * self.e(j-1) * si) + + @cached_method + def jucys_murphy_element(self, i): + r""" + Return the ``i``-th Jucys-Murphy element `L_i` of ``self``. + + ALGORITHM: + + We use the recursive definition given in [Cre2020]_ + (except we divide the indices by 2). + + EXAMPLES: + + sage: R. = QQ[] + sage: P3 = PartitionAlgebra(3, n) + sage: P3.jucys_murphy_element(1) + P{{-3, 3}, {-2, 2}, {-1}, {1}} + sage: P3.jucys_murphy_element(2) + P{{-3, 3}, {-2}, {-1, 1}, {2}} - P{{-3, 3}, {-2}, {-1, 1, 2}} + + P{{-3, 3}, {-2, -1}, {1, 2}} - P{{-3, 3}, {-2, -1, 1}, {2}} + + P{{-3, 3}, {-2, 1}, {-1, 2}} + sage: P3.jucys_murphy_element(3/2) + n*P{{-3, 3}, {-2, -1, 1, 2}} - P{{-3, 3}, {-2, -1, 2}, {1}} + - P{{-3, 3}, {-2, 1, 2}, {-1}} + P{{-3, 3}, {-2, 2}, {-1, 1}} + sage: P3.L(3/2) * P3.L(2) == P3.L(2) * P3.L(3/2) + True + + We test the relations in Lemma 2.2.3(2) in [Cre2020]_:: + + sage: k = 4 + sage: R. = QQ[] + sage: P = PartitionAlgebra(k, n) + sage: L = [P.L(i/2) for i in range(1,2*k+1)] + sage: all(x.dual() == x for x in L) + True + sage: all(x * y == y * x for x in L for y in L) # long time + True + sage: Lsum = sum(L) + sage: gens = [P.s(i) for i in range(1,k)] + sage: gens += [P.e(i/2) for i in range(1,2*k)] + sage: all(x * Lsum == Lsum * x for x in gens) + True + + Also the relations in Lemma 2.2.3(3) in [Cre2020]_:: + + sage: all(P.e((2*i+1)/2) * P.sigma(2*i/2) * P.e((2*i+1)/2) + ....: == (n - P.L((2*i-1)/2)) * P.e((2*i+1)/2) for i in range(1,k)) + True + sage: all(P.e(i/2) * (P.L(i/2) + P.L((i+1)/2)) + ....: == (P.L(i/2) + P.L((i+1)/2)) * P.e(i/2) + ....: == n * P.e(i/2) for i in range(1,2*k)) + True + sage: all(P.sigma(2*i/2) * P.e((2*i-1)/2) * P.e(2*i/2) + ....: == P.L(2*i/2) * P.e(2*i/2) for i in range(1,k)) + True + sage: all(P.e(2*i/2) * P.e((2*i-1)/2) * P.sigma(2*i/2) + ....: == P.e(2*i/2) * P.L(2*i/2) for i in range(1,k)) + True + sage: all(P.sigma((2*i+1)/2) * P.e((2*i+1)/2) * P.e(2*i/2) + ....: == P.L(2*i/2) * P.e(2*i/2) for i in range(1,k)) + True + sage: all(P.e(2*i/2) * P.e((2*i+1)/2) * P.sigma((2*i+1)/2) + ....: == P.e(2*i/2) * P.L(2*i/2) for i in range(1,k)) + True + """ + half = QQ.one() / 2 + if i in ZZ: + if i == 1: + return self.e(half) + i -= 1 + L = self.jucys_murphy_element + return ((self.s(i) * L(i)) * (self.s(i) - self.e(i)) + - (self.e(i) * L(i)) * (self.s(i) - self.e(i+half)*self.e(i)) + + self.sigma(i+half)) + else: + j = ceil(i) - 1 + if j == 0: + return self.zero() + L = self.jucys_murphy_element + return (self.s(j) * L(i-1) * self.s(j) + - L(j)*self.e(j) - self.e(j)*L(j) + + (self._q*self.one() - L(i-1))*self.e(j) + + self.sigma(j)) + + L = jucys_murphy_element + class Element(DiagramBasis.Element): def to_orbit_basis(self): """ @@ -2704,6 +2941,26 @@ def to_orbit_basis(self): OP = self.parent().orbit_basis() return OP(self) + def dual(self): + r""" + Return the dual of ``self``. + + The dual of an element in the partition algebra is formed + by taking the dual of each diagram in the support. + + EXAMPLES:: + + sage: R. = QQ[] + sage: P = PartitionAlgebra(2, x, R) + sage: elt = P.an_element(); elt + 3*P{{-2}, {-1, 1, 2}} + 2*P{{-2, -1, 1, 2}} + 2*P{{-2, 1, 2}, {-1}} + sage: elt.dual() + 3*P{{-2, -1, 1}, {2}} + 2*P{{-2, -1, 1, 2}} + 2*P{{-2, -1, 2}, {1}} + """ + P = self.parent() + return P._from_dict({D.dual(): c for D, c in self._monomial_coefficients.items()}, + remove_zeros=False) + class OrbitBasis(DiagramAlgebra): r""" The orbit basis of the partition algebra. From b248c6ab182d2d237d071a1acb4ad0cedee0d1d7 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sun, 31 May 2020 09:46:11 +0100 Subject: [PATCH 186/300] Changed to one line if --- src/sage/combinat/path_tableaux/dyck_path.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/sage/combinat/path_tableaux/dyck_path.py b/src/sage/combinat/path_tableaux/dyck_path.py index 5a0ee63aaca..a15aa10ea19 100644 --- a/src/sage/combinat/path_tableaux/dyck_path.py +++ b/src/sage/combinat/path_tableaux/dyck_path.py @@ -185,7 +185,6 @@ def __init__(self, parent, ot, check=True): else: raise ValueError("the tableau must be standard") - elif isinstance(ot, SkewTableau): if len(ot) > 2: raise ValueError("the skew tableau must have at most two rows") @@ -193,10 +192,7 @@ def __init__(self, parent, ot, check=True): c = ot.to_chain() w = [0]*len(c) for i,a in enumerate(c): - if len(a) == 1: - w[i] = a[0] - else: - w[i] = a[0]-a[1] + w[i] = a[0] if len(a) == 1 else a[0]-a[1] elif isinstance(ot, (list,tuple)): try: From c0f5f74a490daf7ea8b7fe6234f8dd5b23d46889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 31 May 2020 17:58:23 +0200 Subject: [PATCH 187/300] convert some code in finitely generated groups from gap to libgap --- .../groups/matrix_gps/finitely_generated.py | 145 ++++++++---------- 1 file changed, 68 insertions(+), 77 deletions(-) diff --git a/src/sage/groups/matrix_gps/finitely_generated.py b/src/sage/groups/matrix_gps/finitely_generated.py index d356c9cfc14..a9b3fc83b36 100644 --- a/src/sage/groups/matrix_gps/finitely_generated.py +++ b/src/sage/groups/matrix_gps/finitely_generated.py @@ -65,7 +65,6 @@ from sage.rings.all import ZZ from sage.rings.all import QQbar -from sage.interfaces.gap import gap from sage.structure.element import is_Matrix from sage.matrix.matrix_space import MatrixSpace, is_MatrixSpace from sage.matrix.all import matrix @@ -79,8 +78,8 @@ from sage.rings.number_field.number_field import CyclotomicField from sage.combinat.integer_vector import IntegerVectors -from sage.groups.matrix_gps.matrix_group import ( - MatrixGroup_generic, MatrixGroup_gap ) +from sage.groups.matrix_gps.matrix_group import (MatrixGroup_generic, + MatrixGroup_gap) from sage.groups.matrix_gps.group_element import is_MatrixGroupElement @@ -128,7 +127,7 @@ def normalize_square_matrices(matrices): degree = ZZ(len(m)) else: degree, rem = ZZ(len(m)).sqrtrem() - if rem!=0: + if rem != 0: raise ValueError('list of plain numbers must have square integer length') deg.append(degree) gens.append(matrix(degree, degree, m)) @@ -309,6 +308,7 @@ def MatrixGroup(*gens, **kwds): # ################################################################### + class FinitelyGeneratedMatrixGroup_generic(MatrixGroup_generic): """ TESTS:: @@ -479,6 +479,7 @@ def _test_matrix_generators(self, **options): # ################################################################### + class FinitelyGeneratedMatrixGroup_gap(MatrixGroup_gap): """ Matrix group generated by a finite number of matrices. @@ -553,7 +554,7 @@ def as_permutation_group(self, algorithm=None, seed=None): A finite subgroup of GL(12,Z) as a permutation group:: - sage: imf=libgap.function_factory('ImfMatrixGroup') + sage: imf = libgap.function_factory('ImfMatrixGroup') sage: GG = imf( 12, 3 ) sage: G = MatrixGroup(GG.GeneratorsOfGroup()) sage: G.cardinality() @@ -624,7 +625,7 @@ def as_permutation_group(self, algorithm=None, seed=None): sage: PG = MG.as_permutation_group() sage: mg = MG.an_element() sage: PG(mg) - (1,2,6,19,35,33)(3,9,26,14,31,23)(4,13,5)(7,22,17)(8,24,12)(10,16,32,27,20,28)(11,30,18)(15,25,36,34,29,21) + (1,2,6,19,35,33)(3,9,26,14,31,23)(4,13,5)(7,22,17)(8,24,12)(10,16,32,27,20,28)(11,30,18)(15,25,36,34,29,21) """ # Note that the output of IsomorphismPermGroup() depends on # memory locations and will change if you change the order of @@ -635,12 +636,11 @@ def as_permutation_group(self, algorithm=None, seed=None): if seed is not None: from sage.libs.gap.libgap import libgap libgap.set_seed(ZZ(seed)) - iso=self._libgap_().IsomorphismPermGroup() + iso = self._libgap_().IsomorphismPermGroup() if algorithm == "smaller": - iso=iso.Image().SmallerDegreePermutationRepresentation() - return PermutationGroup(iso.Image().GeneratorsOfGroup().sage(), \ - canonicalize=False) - + iso = iso.Image().SmallerDegreePermutationRepresentation() + return PermutationGroup(iso.Image().GeneratorsOfGroup().sage(), + canonicalize=False) def module_composition_factors(self, algorithm=None): r""" @@ -651,8 +651,8 @@ def module_composition_factors(self, algorithm=None): EXAMPLES:: - sage: F=GF(3);MS=MatrixSpace(F,4,4) - sage: M=MS(0) + sage: F = GF(3); MS = MatrixSpace(F,4,4) + sage: M = MS(0) sage: M[0,1]=1;M[1,2]=1;M[2,3]=1;M[3,0]=1 sage: G = MatrixGroup([M]) sage: G.module_composition_factors() @@ -669,34 +669,25 @@ def module_composition_factors(self, algorithm=None): more verbose version. For more on MeatAxe notation, see - http://www.gap-system.org/Manuals/doc/ref/chap69.html + https://www.gap-system.org/Manuals/doc/ref/chap69.html """ - from sage.misc.sage_eval import sage_eval + from sage.libs.gap.libgap import libgap F = self.base_ring() - if not(F.is_finite()): + if not F.is_finite(): raise NotImplementedError("Base ring must be finite.") - q = F.cardinality() - gens = self.gens() n = self.degree() MS = MatrixSpace(F, n, n) - mats = [] # initializing list of mats by which the gens act on self - for g in gens: - p = MS(g.matrix()) - m = p.rows() - mats.append(m) - mats_str = str(gap([[list(r) for r in ma] for ma in mats])) - gap.eval("M:=GModuleByMats("+mats_str+", GF("+str(q)+"))") - gap.eval("MCFs := MTX.CompositionFactors( M )") - N = eval(gap.eval("Length(MCFs)")) + mats = [MS(g.matrix()) for g in self.gens()] + # initializing list of mats by which the gens act on self + mats_gap = libgap(mats) + M = mats_gap.GModuleByMats(F) + compo = libgap.function_factory('MTX.CompositionFactors') + MCFs = compo(M) if algorithm == "verbose": - print(gap.eval('MCFs') + "\n") - L = [] - for i in range(1, N + 1): - gap.eval("MCF := MCFs[%s]" % i) - L.append(tuple([sage_eval(gap.eval("MCF.field")), - eval(gap.eval("MCF.dimension")), - sage_eval(gap.eval("MCF.IsIrreducible")) ])) - return sorted(L) + print(str(MCFs) + "\n") + return sorted((MCF['field'].sage(), + MCF['dimension'].sage(), + MCF['IsIrreducible'].sage()) for MCF in MCFs) def invariant_generators(self): r""" @@ -767,21 +758,22 @@ def invariant_generators(self): from sage.interfaces.singular import singular gens = self.gens() singular.LIB("finvar.lib") - n = self.degree() #len((gens[0].matrix()).rows()) + n = self.degree() # len((gens[0].matrix()).rows()) F = self.base_ring() q = F.characteristic() - ## test if the field is admissible - if F.gen()==1: # we got the rationals or GF(prime) + # test if the field is admissible + if F.gen() == 1: # we got the rationals or GF(prime) FieldStr = str(F.characteristic()) - elif hasattr(F,'polynomial'): # we got an algebraic extension - if len(F.gens())>1: + elif hasattr(F,'polynomial'): # we got an algebraic extension + if len(F.gens()) > 1: raise NotImplementedError("can only deal with finite fields and (simple algebraic extensions of) the rationals") - FieldStr = '(%d,%s)'%(F.characteristic(),str(F.gen())) - else: # we have a transcendental extension - FieldStr = '(%d,%s)'%(F.characteristic(),','.join([str(p) for p in F.gens()])) + FieldStr = '(%d,%s)' % (F.characteristic(), str(F.gen())) + else: # we have a transcendental extension + FieldStr = '(%d,%s)' % (F.characteristic(), + ','.join(str(p) for p in F.gens())) - ## Setting Singular's variable names - ## We need to make sure that field generator and variables get different names. + # Setting Singular's variable names + # We need to make sure that field generator and variables get different names. if str(F.gen())[0] == 'x': VarStr = 'y' else: @@ -805,7 +797,8 @@ def invariant_generators(self): elements if elements is not None: ReyName = 't'+singular._next_var_name() - singular.eval('matrix %s[%d][%d]'%(ReyName,self.cardinality(),n)) + singular.eval('matrix %s[%d][%d]' % (ReyName, + self.cardinality(), n)) for i in range(1,self.cardinality()+1): M = Matrix(F, elements[i-1]) D = [{} for foobar in range(self.degree())] @@ -814,28 +807,26 @@ def invariant_generators(self): for row in range(self.degree()): for t in D[row].items(): singular.eval('%s[%d,%d]=%s[%d,%d]+(%s)*var(%d)' - %(ReyName,i,row+1,ReyName,i,row+1, repr(t[1]),t[0]+1)) + % (ReyName,i,row+1,ReyName,i,row+1, repr(t[1]),t[0]+1)) IRName = 't'+singular._next_var_name() - singular.eval('matrix %s = invariant_algebra_reynolds(%s)'%(IRName,ReyName)) + singular.eval('matrix %s = invariant_algebra_reynolds(%s)' % (IRName,ReyName)) else: ReyName = 't'+singular._next_var_name() - singular.eval('list %s=group_reynolds((%s))'%(ReyName,Lgens)) + singular.eval('list %s=group_reynolds((%s))' % (ReyName, Lgens)) IRName = 't'+singular._next_var_name() - singular.eval('matrix %s = invariant_algebra_reynolds(%s[1])'%(IRName,ReyName)) + singular.eval('matrix %s = invariant_algebra_reynolds(%s[1])' % (IRName, ReyName)) - OUT = [singular.eval(IRName+'[1,%d]'%(j)) + OUT = [singular.eval(IRName+'[1,%d]' % (j)) for j in range(1, 1+int(singular('ncols('+IRName+')')))] return [PR(gen) for gen in OUT] if self.cardinality() % q == 0: PName = 't' + singular._next_var_name() SName = 't' + singular._next_var_name() - singular.eval('matrix %s,%s=invariant_ring(%s)'%(PName,SName,Lgens)) - OUT = [ - singular.eval(PName+'[1,%d]'%(j)) - for j in range(1,1+singular('ncols('+PName+')')) - ] + [ - singular.eval(SName+'[1,%d]'%(j)) for j in range(2,1+singular('ncols('+SName+')')) - ] + singular.eval('matrix %s,%s=invariant_ring(%s)' % (PName, SName, Lgens)) + OUT = [singular.eval(PName+'[1,%d]' % (j)) + for j in range(1,1+singular('ncols('+PName+')'))] + OUT += [singular.eval(SName+'[1,%d]' % (j)) + for j in range(2,1+singular('ncols('+SName+')'))] return [PR(gen) for gen in OUT] def molien_series(self, chi=None, return_series=True, prec=20, variable='t'): @@ -972,7 +963,7 @@ def molien_series(self, chi=None, return_series=True, prec=20, variable='t'): if R.characteristic() == 0: P = PolynomialRing(R, variable) t = P.gen() - #it is possible the character is over a larger cyclotomic field + # it is possible the character is over a larger cyclotomic field K = chi.values()[0].parent() if K.degree() != 1: if R.degree() != 1: @@ -986,32 +977,32 @@ def molien_series(self, chi=None, return_series=True, prec=20, variable='t'): mol += L(chi(g)) / (M.identity_matrix()-t*g.matrix()).det().change_ring(L) elif R.characteristic().divides(N): raise NotImplementedError("characteristic cannot divide group order") - else: #char p>0 - #find primitive Nth roots of unity over base ring and QQ + else: # char p>0 + # find primitive Nth roots of unity over base ring and QQ F = cyclotomic_polynomial(N).change_ring(R) w = F.roots(ring=R.algebraic_closure(), multiplicities=False)[0] - #don't need to extend further in this case since the order of - #the roots of unity in the character divide the order of the group + # don't need to extend further in this case since the order of + # the roots of unity in the character divide the order of the group L = CyclotomicField(N, 'v') v = L.gen() - #construct Molien series + # construct Molien series P = PolynomialRing(L, variable) t = P.gen() mol = P(0) for g in self: - #construct Phi + # construct Phi phi = L(chi(g)) for e in g.matrix().eigenvalues(): - #find power such that w**n = e + # find power such that w**n = e n = 1 while w**n != e and n < N+1: n += 1 - #raise v to that power + # raise v to that power phi *= (1-t*v**n) mol += P(1)/phi - #We know the coefficients will be integers + # We know the coefficients will be integers mol = mol.numerator().change_ring(ZZ) / mol.denominator().change_ring(ZZ) - #divide by group order + # divide by group order mol /= N if return_series: PS = PowerSeriesRing(ZZ, variable, default_prec=prec) @@ -1168,14 +1159,14 @@ def reynolds_operator(self, poly, chi=None): raise TypeError("number of variables in polynomial must match size of matrices") R = FractionField(poly.base_ring()) C = FractionField(self.base_ring()) - if chi is None: #then this is the trivial character + if chi is None: # then this is the trivial character if R.characteristic() == 0: - #non-modular case + # non-modular case if C == QQbar or R == QQbar: L = QQbar elif not C.is_absolute() or not R.is_absolute(): raise NotImplementedError("only implemented for absolute fields") - else: #create the compositum + else: # create the compositum if C.absolute_degree() == 1: L = R elif R.absolute_degree() == 1: @@ -1199,10 +1190,10 @@ def reynolds_operator(self, poly, chi=None): F += poly(*g.matrix()*vector(poly.parent().gens())) F /= self.order() return F - #non-trivial character case + # non-trivial character case K = chi.values()[0].parent() if R.characteristic() == 0: - #extend base_ring to compositum + # extend base_ring to compositum if C == QQbar or K == QQbar or R == QQbar: L = QQbar elif not C.is_absolute() or not K.is_absolute() or not R.is_absolute(): @@ -1217,13 +1208,13 @@ def reynolds_operator(self, poly, chi=None): # all are QQ L = R elif l == 1: - #only one is an extension + # only one is an extension L = fields[0] elif l == 2: - #only two are extensions + # only two are extensions L = fields[0].composite_fields(fields[1])[0] else: - #all three are extensions + # all three are extensions L1 = fields[0].composite_fields(fields[1])[0] L = L1.composite_fields(fields[2])[0] else: From e39cffdeec34349b16ac2412da406a005034b3df Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sat, 30 May 2020 09:22:39 -0400 Subject: [PATCH 188/300] Trac #29493: add sanity checks for GLPK's variable bound methods. A crash was reported in Trac #10232, affecting in particular the variable_lower_bound() and variable_upper_bound() methods of the GLPK backend. These crashes were fixed by wrapping them in sig_on() and sig_off(), and then throwing a GLPKError in the event that GLPK crashes. That approach is slightly perverse: in both cases, we know what variable indices are valid at the beginning of the function. This commit adds a sanity check to those methods that throws a ValueError if the variable index is out of bounds. This avoids crashing GLPK and thus partially eliminates our reliance on a custom GLPK error-handling patch that is persona non grata. --- src/sage/numerical/backends/glpk_backend.pyx | 26 +++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/sage/numerical/backends/glpk_backend.pyx b/src/sage/numerical/backends/glpk_backend.pyx index b1acf12a281..20c45b2ad04 100644 --- a/src/sage/numerical/backends/glpk_backend.pyx +++ b/src/sage/numerical/backends/glpk_backend.pyx @@ -1459,11 +1459,17 @@ cdef class GLPKBackend(GenericBackend): sage: p.variable_upper_bound(2) Traceback (most recent call last): ... - GLPKError: ... + ValueError: invalid variable index 2 + + sage: p.variable_upper_bound(-1) + Traceback (most recent call last): + ... + ValueError: invalid variable index -1 + sage: p.variable_upper_bound(3, 5) Traceback (most recent call last): ... - GLPKError: ... + ValueError: invalid variable index 3 sage: p.add_variable() 0 @@ -1480,6 +1486,9 @@ cdef class GLPKBackend(GenericBackend): cdef double min cdef double dvalue + if index < 0 or index > (self.ncols() - 1): + raise ValueError("invalid variable index %d" % index) + if value is False: sig_on() x = glp_get_col_ub(self.lp, index +1) @@ -1554,11 +1563,17 @@ cdef class GLPKBackend(GenericBackend): sage: p.variable_lower_bound(2) Traceback (most recent call last): ... - GLPKError: ... + ValueError: invalid variable index 2 + + sage: p.variable_lower_bound(-1) + Traceback (most recent call last): + ... + ValueError: invalid variable index -1 + sage: p.variable_lower_bound(3, 5) Traceback (most recent call last): ... - GLPKError: ... + ValueError: invalid variable index 3 sage: p.add_variable() 0 @@ -1575,6 +1590,9 @@ cdef class GLPKBackend(GenericBackend): cdef double max cdef double dvalue + if index < 0 or index > (self.ncols() - 1): + raise ValueError("invalid variable index %d" % index) + if value is False: sig_on() x = glp_get_col_lb(self.lp, index +1) From 3fec6171cc6cc6e1b3e010730245c8c6ad2470d0 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 31 May 2020 08:38:56 -0400 Subject: [PATCH 189/300] Trac #29493: add missing bounds checks for other GLPK backend methods. Several GLPK backend methods were missed in Trac #10232, and as a result it's still fairly easy to crash SageMath by passing an invalid variable, column, or row index to GLPK. This commit adds a basic bounds check to the functions that take such an index and pass it unmodified to GLPK. --- src/sage/numerical/backends/glpk_backend.pyx | 177 +++++++++++++++++++ 1 file changed, 177 insertions(+) diff --git a/src/sage/numerical/backends/glpk_backend.pyx b/src/sage/numerical/backends/glpk_backend.pyx index 20c45b2ad04..eaf1bccd14e 100644 --- a/src/sage/numerical/backends/glpk_backend.pyx +++ b/src/sage/numerical/backends/glpk_backend.pyx @@ -261,7 +261,21 @@ cdef class GLPKBackend(GenericBackend): sage: p.set_variable_type(0,1) sage: p.is_variable_integer(0) True + + TESTS: + + We sanity check the input that will be passed to GLPK:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="GLPK") + sage: p.set_variable_type(2,0) + Traceback (most recent call last): + ... + ValueError: invalid variable index 2 + """ + if variable < 0 or variable > (self.ncols() - 1): + raise ValueError("invalid variable index %d" % variable) if vtype==1: glp_set_col_kind(self.lp, variable+1, GLP_IV) @@ -320,7 +334,22 @@ cdef class GLPKBackend(GenericBackend): sage: p.objective_coefficient(0,2) sage: p.objective_coefficient(0) 2.0 + + TESTS: + + We sanity check the input that will be passed to GLPK:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="GLPK") + sage: p.objective_coefficient(2) + Traceback (most recent call last): + ... + ValueError: invalid variable index 2 + """ + if variable < 0 or variable > (self.ncols() - 1): + raise ValueError("invalid variable index %d" % variable) + if coeff is None: return glp_get_obj_coef(self.lp, variable + 1) else: @@ -695,7 +724,22 @@ cdef class GLPKBackend(GenericBackend): ([4, 3, 2, 1], [4.0, 3.0, 2.0, 1.0]) sage: p.row_bounds(0) (2.0, 2.0) + + TESTS: + + We sanity check the input that will be passed to GLPK:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="GLPK") + sage: p.row(2) + Traceback (most recent call last): + ... + ValueError: invalid row index 2 + """ + if index < 0 or index > (self.nrows() - 1): + raise ValueError("invalid row index %d" % index) + cdef int n = glp_get_num_cols(self.lp) cdef MemoryAllocator mem = MemoryAllocator() cdef int * c_indices = mem.allocarray(n+1, sizeof(int)) @@ -736,10 +780,25 @@ cdef class GLPKBackend(GenericBackend): ([4, 3, 2, 1], [4.0, 3.0, 2.0, 1.0]) sage: p.row_bounds(0) (2.0, 2.0) + + TESTS: + + We sanity check the input that will be passed to GLPK:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="GLPK") + sage: p.row_bounds(2) + Traceback (most recent call last): + ... + ValueError: invalid row index 2 + """ cdef double ub cdef double lb + if index < 0 or index > (self.nrows() - 1): + raise ValueError("invalid row index %d" % index) + ub = glp_get_row_ub(self.lp, index + 1) lb = glp_get_row_lb(self.lp, index +1) @@ -773,11 +832,26 @@ cdef class GLPKBackend(GenericBackend): sage: p.variable_upper_bound(0, 5) sage: p.col_bounds(0) (0.0, 5.0) + + TESTS: + + We sanity check the input that will be passed to GLPK:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="GLPK") + sage: p.col_bounds(2) + Traceback (most recent call last): + ... + ValueError: invalid column index 2 + """ cdef double ub cdef double lb + if index < 0 or index > (self.ncols() - 1): + raise ValueError("invalid column index %d" % index) + ub = glp_get_col_ub(self.lp, index +1) lb = glp_get_col_lb(self.lp, index +1) @@ -1205,7 +1279,22 @@ cdef class GLPKBackend(GenericBackend): 0.0 sage: p.get_variable_value(1) 1.5 + + TESTS: + + We sanity check the input that will be passed to GLPK:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="GLPK") + sage: p.get_variable_value(2) + Traceback (most recent call last): + ... + ValueError: invalid variable index 2 + """ + if variable < 0 or variable > (self.ncols() - 1): + raise ValueError("invalid variable index %d" % variable) + if (self.simplex_or_intopt != glp_simplex_only and self.simplex_or_intopt != glp_exact_simplex_only): return glp_mip_col_val(self.lp, variable+1) @@ -1242,7 +1331,22 @@ cdef class GLPKBackend(GenericBackend): 20.0 sage: lp.get_row_prim(2) 8.0 + + TESTS: + + We sanity check the input that will be passed to GLPK:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="GLPK") + sage: p.get_row_prim(2) + Traceback (most recent call last): + ... + ValueError: invalid row index 2 + """ + if i < 0 or i > (self.nrows() - 1): + raise ValueError("invalid row index %d" % i) + return glp_get_row_prim(self.lp, i+1) cpdef int ncols(self): @@ -1295,9 +1399,24 @@ cdef class GLPKBackend(GenericBackend): 0 sage: p.col_name(0) 'I am a variable' + + TESTS: + + We sanity check the input that will be passed to GLPK:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="GLPK") + sage: p.col_name(2) + Traceback (most recent call last): + ... + ValueError: invalid column index 2 + """ cdef char * s + if index < 0 or index > (self.ncols() - 1): + raise ValueError("invalid column index %d" % index) + glp_create_index(self.lp) s = glp_get_col_name(self.lp, index + 1) @@ -1321,9 +1440,24 @@ cdef class GLPKBackend(GenericBackend): sage: p.add_linear_constraints(1, 2, None, names=['Empty constraint 1']) sage: p.row_name(0) 'Empty constraint 1' + + TESTS: + + We sanity check the input that will be passed to GLPK:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="GLPK") + sage: p.row_name(2) + Traceback (most recent call last): + ... + ValueError: invalid row index 2 + """ cdef char * s + if index < 0 or index > (self.nrows() - 1): + raise ValueError("invalid row index %d" % index) + glp_create_index(self.lp) s = glp_get_row_name(self.lp, index + 1) @@ -1352,7 +1486,21 @@ cdef class GLPKBackend(GenericBackend): sage: p.is_variable_binary(0) True + TESTS: + + We sanity check the input that will be passed to GLPK:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="GLPK") + sage: p.is_variable_binary(2) + False + """ + if index < 0 or index > (self.ncols() - 1): + # This is how the other backends behave, and this method is + # unable to raise a python exception as currently defined. + return False + return glp_get_col_kind(self.lp, index + 1) == GLP_BV cpdef bint is_variable_integer(self, int index): @@ -1374,7 +1522,22 @@ cdef class GLPKBackend(GenericBackend): sage: p.set_variable_type(0,1) sage: p.is_variable_integer(0) True + + TESTS: + + We sanity check the input that will be passed to GLPK:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="GLPK") + sage: p.is_variable_integer(2) + False + """ + if index < 0 or index > (self.ncols() - 1): + # This is how the other backends behave, and this method is + # unable to raise a python exception as currently defined. + return False + return glp_get_col_kind(self.lp, index + 1) == GLP_IV cpdef bint is_variable_continuous(self, int index): @@ -1399,7 +1562,21 @@ cdef class GLPKBackend(GenericBackend): sage: p.is_variable_continuous(0) False + TESTS: + + We sanity check the input that will be passed to GLPK:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="GLPK") + sage: p.is_variable_continuous(2) + False + """ + if index < 0 or index > (self.ncols() - 1): + # This is how the other backends behave, and this method is + # unable to raise a python exception as currently defined. + return False + return glp_get_col_kind(self.lp, index + 1) == GLP_CV cpdef bint is_maximization(self): From 3a1b74118bdc75d8683b78ea68e71328236da1ff Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 31 May 2020 09:31:49 -0400 Subject: [PATCH 190/300] Trac #29493: add bounds checks to GLPK's add_linear_constraint() method. This commit ensures that all of the variable indices passed to GLPK's add_linear_constraint() method are valid. This was partially addressed in Trac #19525, but that approach requires us to let GLPK to first crash on the invalid input. The new bounds check catches the mistake before GLPK sees it, and now returns a ValueError mentioning the invalid index rather than a GLPKError. --- src/sage/numerical/backends/glpk_backend.pyx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/sage/numerical/backends/glpk_backend.pyx b/src/sage/numerical/backends/glpk_backend.pyx index eaf1bccd14e..453e989d3c3 100644 --- a/src/sage/numerical/backends/glpk_backend.pyx +++ b/src/sage/numerical/backends/glpk_backend.pyx @@ -609,12 +609,19 @@ cdef class GLPKBackend(GenericBackend): sage: q.add_constraint(p.new_variable()[0] <= 1) Traceback (most recent call last): ... - GLPKError: glp_set_mat_row: i = 1; len = 1; invalid row length - Error detected in file api/prob1.c at line ... + ValueError: invalid variable index 0 + """ if lower_bound is None and upper_bound is None: raise ValueError("At least one of 'upper_bound' or 'lower_bound' must be set.") + # We're going to iterate through this more than once. + coefficients = list(coefficients) + + for (index,_) in coefficients: + if index < 0 or index > (self.ncols() - 1): + raise ValueError("invalid variable index %d" % index) + glp_add_rows(self.lp, 1) cdef int n = glp_get_num_rows(self.lp) @@ -622,7 +629,6 @@ cdef class GLPKBackend(GenericBackend): cdef int * row_i cdef double * row_values - coefficients = list(coefficients) cdef int n_coeff = len(coefficients) row_i = mem.allocarray(n_coeff + 1, sizeof(int)) row_values = mem.allocarray(n_coeff + 1, sizeof(double)) From 3b75fc09da94a9797b50b478bf8ab64fda5f7034 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 31 May 2020 10:16:37 -0400 Subject: [PATCH 191/300] Trac #29493: add bounds checks to GLPK's get_col_dual() method. The get_col_dual() method of the GLPK backend would crash if it received an invalid column index, because that index is passed directly to GLPK. I have added "except? -1" to the method signature, because otherwise it (being a C method that returns a C type) would be unable to raise a Python exception. The question mark is needed to avoid a conflict with the otherwise-valid dedicated return value -1. Afterwards, the added bounds check that raises a ValueError is completely standard. --- src/sage/numerical/backends/glpk_backend.pxd | 2 +- src/sage/numerical/backends/glpk_backend.pyx | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/sage/numerical/backends/glpk_backend.pxd b/src/sage/numerical/backends/glpk_backend.pxd index 80f8f9faeaf..03dbe2c8688 100644 --- a/src/sage/numerical/backends/glpk_backend.pxd +++ b/src/sage/numerical/backends/glpk_backend.pxd @@ -29,7 +29,7 @@ cdef class GLPKBackend(GenericBackend): cpdef __copy__(self) cpdef int print_ranges(self, filename = *) except -1 cpdef double get_row_dual(self, int variable) - cpdef double get_col_dual(self, int variable) + cpdef double get_col_dual(self, int variable) except? -1 cpdef int get_row_stat(self, int variable) except? -1 cpdef int get_col_stat(self, int variable) except? -1 cpdef eval_tab_row(self, int k) diff --git a/src/sage/numerical/backends/glpk_backend.pyx b/src/sage/numerical/backends/glpk_backend.pyx index 453e989d3c3..23d920c5085 100644 --- a/src/sage/numerical/backends/glpk_backend.pyx +++ b/src/sage/numerical/backends/glpk_backend.pyx @@ -2585,7 +2585,7 @@ cdef class GLPKBackend(GenericBackend): else: return 0.0 - cpdef double get_col_dual(self, int variable): + cpdef double get_col_dual(self, int variable) except? -1: """ Returns the dual value (reduced cost) of a variable @@ -2621,7 +2621,21 @@ cdef class GLPKBackend(GenericBackend): sage: p.get_col_dual(1) -5.0 + TESTS: + + We sanity check the input that will be passed to GLPK:: + + sage: from sage.numerical.backends.generic_backend import get_solver + sage: p = get_solver(solver="GLPK") + sage: p.get_col_dual(2) + Traceback (most recent call last): + ... + ValueError: invalid column index 2 + """ + if variable < 0 or variable > (self.ncols() - 1): + raise ValueError("invalid column index %d" % variable) + if self.simplex_or_intopt == simplex_only: return glp_get_col_dual(self.lp, variable+1) else: From 51824a638343fa3fd1eba23fb77cfcdbc910a8a9 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 31 May 2020 19:11:34 -0400 Subject: [PATCH 192/300] Trac #29493: verify input to GLPK row/column tableaux methods. The eval_tab_row() and eval_tab_col() methods of the GLPK backend require a basis factorization to exist, and the indicated variable to be basic or non-basic, respectively. In the past we have relied upon GLPK crashing to indicate that one of these conditions was not met. This commit uses the existing is_variable_basic() and is_slack_variable_basic() methods to verify that the given index is (non-)basic, and uses a new GLPK function glp_bf_exists() to check that the basis factorization exists. This should prevent GLPK from crashing, and reduces our dependence on custom GLPK patches. --- src/sage/libs/glpk/lp.pxd | 2 + src/sage/numerical/backends/glpk_backend.pyx | 62 ++++++++++++-------- 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/src/sage/libs/glpk/lp.pxd b/src/sage/libs/glpk/lp.pxd index 1911fb13561..cc4f05e5368 100644 --- a/src/sage/libs/glpk/lp.pxd +++ b/src/sage/libs/glpk/lp.pxd @@ -90,3 +90,5 @@ cdef extern from "glpk.h": double glp_ios_mip_gap(glp_tree *T) int glp_ios_best_node(glp_tree *tree) double glp_ios_node_bound(glp_tree *T, int p) + + int glp_bf_exists(glp_prob *lp) diff --git a/src/sage/numerical/backends/glpk_backend.pyx b/src/sage/numerical/backends/glpk_backend.pyx index 23d920c5085..e171c0432c1 100644 --- a/src/sage/numerical/backends/glpk_backend.pyx +++ b/src/sage/numerical/backends/glpk_backend.pyx @@ -2856,8 +2856,9 @@ cdef class GLPKBackend(GenericBackend): .. NOTE:: - The basis factorization must exist. - Otherwise, a ``MIPSolverException`` will be raised. + The basis factorization must exist and the variable with + index ``k`` must be basic. Otherwise, a ``ValueError`` is + be raised. INPUT: @@ -2890,7 +2891,7 @@ cdef class GLPKBackend(GenericBackend): sage: lp.eval_tab_row(0) Traceback (most recent call last): ... - MIPSolverException: ... + ValueError: basis factorization does not exist sage: lp.solve() 0 sage: lp.eval_tab_row(0) @@ -2902,29 +2903,35 @@ cdef class GLPKBackend(GenericBackend): sage: lp.eval_tab_row(1) Traceback (most recent call last): ... - MIPSolverException: ... + ValueError: slack variable 1 is not basic sage: lp.eval_tab_row(-1) Traceback (most recent call last): ... ValueError: ... """ - cdef int n = glp_get_num_cols(self.lp) + cdef int m = self.nrows() + cdef int n = self.ncols() cdef int i,j - if k < 0 or k >= n + glp_get_num_rows(self.lp): + if k < 0 or k >= n + m: raise ValueError("k = %s; Variable number out of range" % k) + if glp_bf_exists(self.lp) == 0: + raise ValueError("basis factorization does not exist") + + if k < m: + if not self.is_slack_variable_basic(k): + raise ValueError("slack variable %d is not basic" % k) + else: + if not self.is_variable_basic(k-m): + raise ValueError("variable %d is not basic" % (k-m) ) + cdef MemoryAllocator mem = MemoryAllocator() cdef int * c_indices = mem.allocarray(n+1, sizeof(int)) cdef double * c_values = mem.allocarray(n+1, sizeof(double)) - try: - sig_on() # to catch GLPKError - i = glp_eval_tab_row(self.lp, k + 1, c_indices, c_values) - sig_off() - except GLPKError: - raise MIPSolverException('GLPK: basis factorization does not exist; or variable must be basic') + i = glp_eval_tab_row(self.lp, k + 1, c_indices, c_values) indices = [c_indices[j+1] - 1 for j in range(i)] values = [c_values[j+1] for j in range(i)] @@ -2948,8 +2955,9 @@ cdef class GLPKBackend(GenericBackend): .. NOTE:: - The basis factorization must exist. - Otherwise a ``MIPSolverException`` will be raised. + The basis factorization must exist and the variable with + index ``k`` must not be basic. Otherwise, a ``ValueError`` is + be raised. INPUT: @@ -2982,7 +2990,7 @@ cdef class GLPKBackend(GenericBackend): sage: lp.eval_tab_col(1) Traceback (most recent call last): ... - MIPSolverException: ... + ValueError: basis factorization does not exist sage: lp.solve() 0 sage: lp.eval_tab_col(1) @@ -2994,29 +3002,35 @@ cdef class GLPKBackend(GenericBackend): sage: lp.eval_tab_col(0) Traceback (most recent call last): ... - MIPSolverException: ... + ValueError: slack variable 0 is basic sage: lp.eval_tab_col(-1) Traceback (most recent call last): ... ValueError: ... """ - cdef int m = glp_get_num_rows(self.lp) + cdef int m = self.nrows() + cdef int n = self.ncols() cdef int i,j - if k < 0 or k >= m + glp_get_num_cols(self.lp): + if k < 0 or k >= m + n: raise ValueError("k = %s; Variable number out of range" % k) + if glp_bf_exists(self.lp) == 0: + raise ValueError("basis factorization does not exist") + + if k < m: + if self.is_slack_variable_basic(k): + raise ValueError("slack variable %d is basic" % k) + else: + if self.is_variable_basic(k-m): + raise ValueError("variable %d is basic" % (k-m) ) + cdef MemoryAllocator mem = MemoryAllocator() cdef int * c_indices = mem.allocarray(m+1, sizeof(int)) cdef double * c_values = mem.allocarray(m+1, sizeof(double)) - try: - sig_on() # To catch GLPKError - i = glp_eval_tab_col(self.lp, k + 1, c_indices, c_values) - sig_off() - except GLPKError: - raise MIPSolverException('GLPK: basis factorization does not exist; or variable must be non-basic') + i = glp_eval_tab_col(self.lp, k + 1, c_indices, c_values) indices = [c_indices[j+1] - 1 for j in range(i)] values = [c_values[j+1] for j in range(i)] From 90679c38dca8f770ff8227d8fdf2d3ac9d86ed83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 1 Jun 2020 14:59:16 +0200 Subject: [PATCH 193/300] trac 28656 some fix for derivative of integrals wrt bound --- src/sage/symbolic/integration/integral.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/sage/symbolic/integration/integral.py b/src/sage/symbolic/integration/integral.py index 3828760bd42..306793d1eb2 100644 --- a/src/sage/symbolic/integration/integral.py +++ b/src/sage/symbolic/integration/integral.py @@ -262,15 +262,27 @@ def _tderivative_(self, f, x, a, b, diff_param=None): -f(a) sage: h.diff(b) f(b) + + TESTS: + + Check for :trac:`28656`:: + + sage: t = var("t") + sage: f = function("f") + sage: F(x) = integrate(f(t),t,0,x) + sage: F(x).diff(x) + f(x) """ if not x.has(diff_param): # integration variable != differentiation variable ans = definite_integral(f.diff(diff_param), x, a, b) else: ans = SR.zero() - return (ans - + f.subs(x == b) * b.diff(diff_param) - - f.subs(x == a) * a.diff(diff_param)) + if hasattr(b, 'diff'): + ans += f.subs(x == b) * b.diff(diff_param) + if hasattr(a, 'diff'): + ans -= f.subs(x == a) * a.diff(diff_param) + return ans def _print_latex_(self, f, x, a, b): r""" From e002e8aa65e1584af1d0c881dc8e21cae842f8e1 Mon Sep 17 00:00:00 2001 From: vipul79321 Date: Mon, 1 Jun 2020 18:32:21 +0530 Subject: [PATCH 194/300] added in graph.py --- src/sage/graphs/base/boost_graph.pyx | 16 +++++++-------- src/sage/graphs/distances_all_pairs.pyx | 16 +++++++-------- src/sage/graphs/graph.py | 27 ++++++++++++++++++++++--- 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/sage/graphs/base/boost_graph.pyx b/src/sage/graphs/base/boost_graph.pyx index 2b360b4233f..836b47bb018 100644 --- a/src/sage/graphs/base/boost_graph.pyx +++ b/src/sage/graphs/base/boost_graph.pyx @@ -1604,7 +1604,7 @@ cpdef min_cycle_basis(g_sage, weight_function=None, by_weight=False): orth_set[j] = orth_set[j] ^ base return cycle_basis -cpdef radius(g, weight_function=None): +cpdef radius_DHV(g, weight_function=None): r""" Return radius of weighted graph `g`. @@ -1623,27 +1623,27 @@ cpdef radius(g, weight_function=None): EXAMPLES:: - sage: from sage.graphs.base.boost_graph import radius + sage: from sage.graphs.base.boost_graph import radius_DHV sage: G = Graph([(0,1,1), (1,2,1), (0,2,3)]) - sage: radius(G) + sage: radius_DHV(G) 1.0 sage: G = graphs.PathGraph(7) - sage: radius(G) == G.radius(algorithm='Dijkstra_Boost') + sage: radius_DHV(G) == G.radius(algorithm='Dijkstra_Boost') True TESTS: sage: G = Graph() - sage: radius(G) + sage: radius_DHV(G) 0 sage: G = Graph(1) - sage: radius(G) + sage: radius_DHV(G) 0 sage: G = Graph(2) - sage: radius(G) + sage: radius_DHV(G) +Infinity sage: G = DiGraph(1) - sage: radius(G) + sage: radius_DHV(G) Traceback (most recent call last): ... TypeError: this method works for undirected graphs only diff --git a/src/sage/graphs/distances_all_pairs.pyx b/src/sage/graphs/distances_all_pairs.pyx index fce75ec7b72..b2e7806bb8e 100644 --- a/src/sage/graphs/distances_all_pairs.pyx +++ b/src/sage/graphs/distances_all_pairs.pyx @@ -1453,7 +1453,7 @@ def diameter(G, algorithm=None, source=None): # Radius # ########### -def radius(G): +def radius_DHV(G): r""" Return radius of unweighted graph `G`. @@ -1464,28 +1464,28 @@ def radius(G): EXAMPLES:: - sage: from sage.graphs.distances_all_pairs import radius + sage: from sage.graphs.distances_all_pairs import radius_DHV sage: G = graphs.PetersenGraph() - sage: radius(G) + sage: radius_DHV(G) 2 sage: G = graphs.RandomGNP(20,0.3) sage: from sage.graphs.distances_all_pairs import eccentricity - sage: radius(G) == min(eccentricity(G, algorithm='bounds')) + sage: radius_DHV(G) == min(eccentricity(G, algorithm='bounds')) True TESTS: sage: G = Graph() - sage: radius(G) + sage: radius_DHV(G) 0 sage: G = Graph(1) - sage: radius(G) + sage: radius_DHV(G) 0 sage: G = Graph(2) - sage: radius(G) + sage: radius_DHV(G) +Infinity sage: G = DiGraph(1) - sage: radius(G) + sage: radius_DHV(G) Traceback (most recent call last): ... TypeError: this method works for unweighted undirected graphs only diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 97321a3b74a..1daca0c4077 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -5420,7 +5420,7 @@ def weight_function(e): return [ecc[u] for u in v] @doc_index("Distances") - def radius(self, by_weight=False, algorithm=None, weight_function=None, + def radius(self, by_weight=False, algorithm='DHV', weight_function=None, check_weight=True): r""" Return the radius of the graph. @@ -5436,8 +5436,15 @@ def radius(self, by_weight=False, algorithm=None, weight_function=None, - ``by_weight`` -- boolean (default: ``False``); if ``True``, edge weights are taken into account; if False, all edges have weight 1 - - ``algorithm`` -- string (default: ``None``); see method - :meth:`eccentricity` for the list of available algorithms + - ``algorithm`` -- string (default: ``'DHV'``). + + - ``'DHV'`` - Radius computation is done using algorithm proposed + in [Dragan2018]_. For more information see method + :func:`sage.graphs.distances_all_pairs.radius_DHV` and + :func:`sage.graphs.base.boost_graph.radius_DHV`. + + - see method + :meth:`eccentricity` for the list of remaining algorithms - ``weight_function`` -- function (default: ``None``); a function that takes as input an edge ``(u, v, l)`` and outputs its weight. If not @@ -5477,6 +5484,20 @@ def radius(self, by_weight=False, algorithm=None, weight_function=None, if not self.order(): raise ValueError("radius is not defined for the empty graph") + if weight_function is not None: + by_weight = True + + if not algorithm: + algorithm = 'DHV' + + if algorithm == 'DHV': + if by_weight: + from sage.graphs.base.boost_graph import radius_DHV + return radius_DHV(self, weight_function) + else: + from sage.graphs.distances_all_pairs import radius_DHV + return radius_DHV(self) + return min(self.eccentricity(v=list(self), by_weight=by_weight, weight_function=weight_function, check_weight=check_weight, From 453dcc5dec5c539595cab5352521d2b065c8635a Mon Sep 17 00:00:00 2001 From: dcoudert Date: Mon, 1 Jun 2020 16:21:23 +0200 Subject: [PATCH 195/300] trac #29715: review edit for unweighted graphs --- src/sage/graphs/distances_all_pairs.pyx | 69 ++++++++++++------------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/src/sage/graphs/distances_all_pairs.pyx b/src/sage/graphs/distances_all_pairs.pyx index b2e7806bb8e..0d595571e00 100644 --- a/src/sage/graphs/distances_all_pairs.pyx +++ b/src/sage/graphs/distances_all_pairs.pyx @@ -1455,9 +1455,9 @@ def diameter(G, algorithm=None, source=None): def radius_DHV(G): r""" - Return radius of unweighted graph `G`. + Return the radius of unweighted graph `G`. - This method computes radius of unweighted undirected graph using the + This method computes the radius of unweighted undirected graph using the algorithm given in [Dragan2018]_. This method returns Infinity if graph is not connected. @@ -1484,6 +1484,9 @@ def radius_DHV(G): sage: G = Graph(2) sage: radius_DHV(G) +Infinity + sage: G = graphs.PathGraph(2) + sage: radius_DHV(G) + 1 sage: G = DiGraph(1) sage: radius_DHV(G) Traceback (most recent call last): @@ -1501,67 +1504,61 @@ def radius_DHV(G): cdef short_digraph sd init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex) - cdef uint32_t source - cdef uint32_t antipode - cdef uint32_t LB = UINT32_MAX + cdef uint32_t source, ecc_source + cdef uint32_t antipode, ecc_antipode cdef uint32_t UB = UINT32_MAX - cdef uint32_t next_source = 0 # To store source for next iteration + cdef uint32_t LB = 0 cdef MemoryAllocator mem = MemoryAllocator() - cdef uint32_t * distances = mem.malloc(4 * n * sizeof(uint32_t)) + cdef uint32_t * distances = mem.malloc(3 * n * sizeof(uint32_t)) if not distances: raise MemoryError() cdef uint32_t * waiting_list = distances + n - # For storing eccentricity of nodes - cdef uint32_t * ecc = distances + 2 * n - # For storing lower bound on eccentricity of nodes - cdef uint32_t * ecc_lower_bound = distances + 3 * n + cdef uint32_t * ecc_lower_bound = distances + 2 * n memset(ecc_lower_bound, 0, n * sizeof(uint32_t)) cdef bitset_t seen - bitset_init(seen,n) # intializing bitset + bitset_init(seen, n) # Algorithm - while True: + source = 0 + while LB < UB: # 1) pick vertex with minimum eccentricity lower bound # and compute its eccentricity - source = next_source - bitset_clear(seen) - ecc[source] = simple_BFS(sd, source, distances, NULL, waiting_list, seen) + ecc_source = simple_BFS(sd, source, distances, NULL, waiting_list, seen) - if ecc[source] == UINT32_MAX: # Disconnected graph - bitset_free(seen) - from sage.rings.infinity import Infinity - return +Infinity + if ecc_source == UINT32_MAX: # Disconnected graph + break - if ecc[source] == ecc_lower_bound[source]: + UB = min(UB, ecc_source) # minimum among exact computed eccentricities + if ecc_source == ecc_lower_bound[source]: # we have found minimum eccentricity vertex and hence the radius - bitset_free(seen) - return ecc[source] + break - # 2) Take vertex at largest distance from source, called antipode - # Compute its BFS distances - antipode = waiting_list[n-1] # last visited vertex in simple_BFS - bitset_clear(seen) - ecc[antipode] = simple_BFS(sd, antipode, distances, NULL, waiting_list, seen) + # 2) Take vertex at largest distance from source, called antipode (last + # vertex visited in simple_BFS), and compute its BFS distances. + # By definition of antipode, we have ecc_antipode >= ecc_source. + antipode = waiting_list[n-1] + ecc_antipode = simple_BFS(sd, antipode, distances, NULL, waiting_list, seen) - UB = min(UB, ecc[source]) # minimum among exact computed eccentricities + # 3) Use distances from antipode to improve eccentricity lower bounds. + # We also determine the next source LB = UINT32_MAX - - # 3) Use BFS distances from antipode - # to improve eccentricity lower bounds for v in range(n): ecc_lower_bound[v] = max(ecc_lower_bound[v], distances[v]) if LB > ecc_lower_bound[v]: LB = ecc_lower_bound[v] - next_source = v # vertex with minimum eccentricity lower bound + source = v # vertex with minimum eccentricity lower bound - if UB <= LB: - bitset_free(seen) - return UB + bitset_free(seen) + if UB == UINT32_MAX: + from sage.rings.infinity import Infinity + return +Infinity + + return UB ################ # Wiener index # From 045022ce569dd392edca6025a5c75dc523fcb0ea Mon Sep 17 00:00:00 2001 From: dcoudert Date: Mon, 1 Jun 2020 16:21:57 +0200 Subject: [PATCH 196/300] trac #29715: review edit for weighted graphs --- src/sage/graphs/base/boost_graph.pyx | 69 ++++++++++++++-------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/src/sage/graphs/base/boost_graph.pyx b/src/sage/graphs/base/boost_graph.pyx index 836b47bb018..8a18d3eb6c2 100644 --- a/src/sage/graphs/base/boost_graph.pyx +++ b/src/sage/graphs/base/boost_graph.pyx @@ -1606,10 +1606,10 @@ cpdef min_cycle_basis(g_sage, weight_function=None, by_weight=False): cpdef radius_DHV(g, weight_function=None): r""" - Return radius of weighted graph `g`. + Return the radius of weighted graph `g`. - This method computes radius of undirected graph using the - algorithm given in [Dragan2018]_. + This method computes the radius of undirected graph using the algorithm + given in [Dragan2018]_. This method returns Infinity if graph is not connected. @@ -1642,6 +1642,9 @@ cpdef radius_DHV(g, weight_function=None): sage: G = Graph(2) sage: radius_DHV(G) +Infinity + sage: G = Graph([(0, 1, 1)]) + sage: radius_DHV(G) + 1.0 sage: G = DiGraph(1) sage: radius_DHV(G) Traceback (most recent call last): @@ -1655,17 +1658,17 @@ cpdef radius_DHV(g, weight_function=None): if n <= 1: return 0 - cdef bint negative_weight = 0 + cdef bint negative_weight = False if weight_function is not None: for e in g.edge_iterator(): if float(weight_function(e)) < 0: - negative_weight = 1 + negative_weight = True break else: for _,_,w in g.edge_iterator(): if w and float(w) < 0: - negative_weight = 1 + negative_weight = True break # These variables are automatically deleted when the function terminates. @@ -1674,30 +1677,25 @@ cpdef radius_DHV(g, weight_function=None): boost_weighted_graph_from_sage_graph(&g_boost, g, v_to_int, weight_function) import sys - cdef v_index source - cdef v_index next_source = 0 # To store source for next iteration + cdef v_index source = 0 cdef v_index antipode - cdef double LB = sys.float_info.max + cdef v_index v + cdef double ecc_source cdef double UB = sys.float_info.max + cdef double LB = 0 # For storing distances of all nodes from source cdef vector[double] distances - # For storing eccentricity of nodes - cdef vector[double] ecc # For storing lower bound on eccentricity of nodes cdef vector[double] ecc_lower_bound - cdef double eccentricity # Initializing for i in range(n): ecc_lower_bound.push_back(0) - ecc.push_back(0) # Algorithm - while True: + while LB < UB: # 1) pick vertex with minimum eccentricity lower bound # and compute its eccentricity - source = next_source - if negative_weight: sig_on() distances = g_boost.bellman_ford_shortest_paths(source).distances @@ -1709,23 +1707,23 @@ cpdef radius_DHV(g, weight_function=None): distances = g_boost.dijkstra_shortest_paths(source).distances sig_off() - eccentricity = 0 + # Determine the eccentricity of source and its antipode, that is a + # vertex at largest distance from source + ecc_source = 0 for v in range(n): - if eccentricity < distances[v]: - eccentricity = distances[v] - antipode = v # vertex at largest distance from source + if ecc_source < distances[v]: + ecc_source = distances[v] + antipode = v - if eccentricity == sys.float_info.max: # Disconnected graph - from sage.rings.infinity import Infinity - return +Infinity + if ecc_source == sys.float_info.max: # Disconnected graph + break - ecc[source] = eccentricity - - if ecc[source] == ecc_lower_bound[source]: + UB = min(UB, ecc_source) # minimum among exact computed eccentricities + if ecc_source == ecc_lower_bound[source]: # we have found minimum eccentricity vertex and hence the radius - return ecc[source] + break - # 2) Compute distances from antipode of source + # 2) Compute distances from antipode if negative_weight: sig_on() distances = g_boost.bellman_ford_shortest_paths(antipode).distances @@ -1735,16 +1733,17 @@ cpdef radius_DHV(g, weight_function=None): distances = g_boost.dijkstra_shortest_paths(antipode).distances sig_off() - UB = min(UB, ecc[source]) # minimum among exact computed eccentricities + # 3) Use distances from antipode to improve eccentricity lower bounds. + # We also determine the next source LB = sys.float_info.max - - # 3) Use distances from antipode to - # improve eccentricity lower bounds for v in range(n): ecc_lower_bound[v] = max(ecc_lower_bound[v], distances[v]) if LB > ecc_lower_bound[v]: LB = ecc_lower_bound[v] - next_source = v # vertex with minimum eccentricity lower bound + source = v # vertex with minimum eccentricity lower bound + + if UB == sys.float_info.max: + from sage.rings.infinity import Infinity + return +Infinity - if UB <= LB: - return UB \ No newline at end of file + return UB From 0a642271bb637ccc57611610115191aea814b8d0 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Mon, 1 Jun 2020 16:23:15 +0200 Subject: [PATCH 197/300] trac #29715: review edit in graph.py --- src/sage/graphs/graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 1daca0c4077..42fdb1ab79b 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -5493,7 +5493,7 @@ def radius(self, by_weight=False, algorithm='DHV', weight_function=None, if algorithm == 'DHV': if by_weight: from sage.graphs.base.boost_graph import radius_DHV - return radius_DHV(self, weight_function) + return radius_DHV(self, weight_function=weight_function) else: from sage.graphs.distances_all_pairs import radius_DHV return radius_DHV(self) From ad0dc039713e3664b89f198ae96d508697652dd6 Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Fri, 22 May 2020 20:00:42 +0200 Subject: [PATCH 198/300] 9792: ring homomorphism: inverse_image, kernel, is_injective --- src/doc/en/reference/references/index.rst | 12 +- src/sage/categories/rings.py | 32 +- src/sage/categories/sets_cat.py | 10 - .../rings/finite_rings/hom_finite_field.pyx | 2 +- src/sage/rings/morphism.pxd | 1 + src/sage/rings/morphism.pyx | 449 +++++++++++++++++- src/sage/schemes/generic/morphism.py | 3 +- 7 files changed, 468 insertions(+), 41 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index fdac52eda90..0b487c3b835 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1869,10 +1869,6 @@ REFERENCES: .. [DS1994] J. Dalbec and B. Sturmfels. Invariant methods in discrete and computational geometry, chapter Introduction to Chow forms, pages 37-58. Springer Netherlands, 1994. -.. [DS2010] \K. Duggal, B. Sahin, - *Differential Geometry of Lightlike Submanifolds*, - Frontiers in Mathematics, 2010. - .. [DS2004] Dan Gusfield, Jens Stoye, Linear time algorithms for finding and representing all the tandem repeats in a string, Journal of Computer and System Sciences, @@ -1881,6 +1877,14 @@ REFERENCES: Pages 525-546, https://doi.org/10.1016/j.jcss.2004.03.004. +.. [DS2009] \W. Decker, F.-O. Schreyer, + *Varieties, Gröbner Bases, and Algebraic Curves*, 2009. + https://www.math.uni-sb.de/ag/schreyer/images/PDFs/teaching/ws1617ag/book.pdf + +.. [DS2010] \K. Duggal, B. Sahin, + *Differential Geometry of Lightlike Submanifolds*, + Frontiers in Mathematics, 2010. + .. [Du2001] \I. Duursma, "From weight enumerators to zeta functions", in Discrete Applied Mathematics, vol. 111, no. 1-2, pp. 55-73, 2001. diff --git a/src/sage/categories/rings.py b/src/sage/categories/rings.py index ff0f66b3aeb..efb906f3098 100644 --- a/src/sage/categories/rings.py +++ b/src/sage/categories/rings.py @@ -65,19 +65,20 @@ def is_injective(self): """ Return whether or not this morphism is injective. - EXAMPLES: - - This often raises a ``NotImplementedError`` as many homomorphisms do - not implement this method:: + EXAMPLES:: - sage: R. = QQ[] - sage: f = R.hom([x + 1]); f - Ring endomorphism of Univariate Polynomial Ring in x over Rational Field - Defn: x |--> x + 1 - sage: f.is_injective() - Traceback (most recent call last): - ... - NotImplementedError + sage: R. = QQ[] + sage: R.hom([x, y^2], R).is_injective() + True + sage: R.hom([x, x^2], R).is_injective() + False + sage: S. = R.quotient(x^3*y) + sage: R.hom([v, u], S).is_injective() + False + sage: S.hom([-u, v], S).is_injective() + True + sage: S.cover().is_injective() + False If the domain is a field, the homomorphism is injective:: @@ -148,6 +149,13 @@ def is_injective(self): # homomorphism must send the 1 element to the 1 element return True + try: + ker = self.kernel() + except (NotImplementedError, AttributeError): + pass + else: + return ker.is_zero() + if self.domain().characteristic() == 0: if self.codomain().characteristic() != 0: return False diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 8a5f2e38884..53c2da3400e 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -1716,16 +1716,6 @@ def is_injective(self): To: Finite Field of size 3 sage: f.is_injective() False - - Note that many maps do not implement this method:: - - sage: R. = ZZ[] - sage: f = R.hom([x]) - sage: f.is_injective() - Traceback (most recent call last): - ... - NotImplementedError - """ if self.domain().cardinality() <= 1: return True diff --git a/src/sage/rings/finite_rings/hom_finite_field.pyx b/src/sage/rings/finite_rings/hom_finite_field.pyx index bb216a813ea..e0368c1fe27 100644 --- a/src/sage/rings/finite_rings/hom_finite_field.pyx +++ b/src/sage/rings/finite_rings/hom_finite_field.pyx @@ -386,7 +386,7 @@ cdef class FiniteFieldHomomorphism_generic(RingHomomorphism_im_gens): raise NotImplementedError return self._section_class(self) - def inverse_image(self, b): + def _inverse_image_element(self, b): """ Return the unique ``a`` such that ``self(a) = b`` if one such exists. diff --git a/src/sage/rings/morphism.pxd b/src/sage/rings/morphism.pxd index c5587a99378..ea6089f29b4 100644 --- a/src/sage/rings/morphism.pxd +++ b/src/sage/rings/morphism.pxd @@ -14,6 +14,7 @@ cdef class RingMap_lift(RingMap): cdef class RingHomomorphism(RingMap): cdef Morphism _lift + cdef public dict __cached_methods cdef class RingHomomorphism_im_gens(RingHomomorphism): cdef _im_gens diff --git a/src/sage/rings/morphism.pyx b/src/sage/rings/morphism.pyx index c3c69164507..6f46ea59eba 100644 --- a/src/sage/rings/morphism.pyx +++ b/src/sage/rings/morphism.pyx @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- r""" Homomorphisms of rings @@ -389,8 +390,8 @@ from cpython.object cimport Py_EQ, Py_NE from . import ideal import sage.structure.all -from sage.structure.richcmp cimport (richcmp, rich_to_bool, - richcmp_not_equal) +from sage.structure.richcmp cimport (richcmp, rich_to_bool, richcmp_not_equal) +from sage.misc.cachefunc import cached_method def is_RingHomomorphism(phi): @@ -670,7 +671,7 @@ cdef class RingHomomorphism(RingMap): def _set_lift(self, lift): r""" - Used internally to define a lifting homomorphism associated to + Used internally to define a lifting map associated to this homomorphism, which goes in the other direction. I.e., if ``self`` is from `R` to `S`, then the lift must be a set-theoretic map from `S` to `R` such that ``self(lift(x)) == x``. @@ -898,24 +899,237 @@ cdef class RingHomomorphism(RingMap): def inverse_image(self, I): """ - Return the inverse image of the ideal `I` under this ring - homomorphism. + Return the inverse image of an ideal or an element in the codomain + of this ring homomorphism. - EXAMPLES: + INPUT: + + - ``I`` -- an ideal or element in the codomain + + OUTPUT: + + For an ideal `I` in the codomain, this returns the largest ideal in the + domain whose image is contained in `I`. + + Given an element `b` in the codomain, this returns an arbitrary element + `a` in the domain such that ``self(a) = b`` if one such exists. + The element `a` is unique if this ring homomorphism is injective. + + EXAMPLES:: + + sage: R. = QQ[] + sage: S. = QQ[] + sage: f = R.hom([u^2, u*v, v^2], S) + sage: I = S.ideal([u^6, u^5*v, u^4*v^2, u^3*v^3]) + sage: J = f.inverse_image(I); J + Ideal (y^2 - x*z, x*y*z, x^2*z, x^2*y, x^3) + of Multivariate Polynomial Ring in x, y, z over Rational Field + sage: f(J) == I + True + + Under the above homomorphism, there exists an inverse image for + every element that only involves monomials of even degree:: + + sage: [f.inverse_image(p) for p in [u^2, u^4, u*v + u^3*v^3]] + [x, x^2, x*y*z + y] + sage: f.inverse_image(u*v^2) + Traceback (most recent call last): + ... + ValueError: element u*v^2 does not have preimage + + The image of the inverse image ideal can be strictly smaller than the + original ideal:: + + sage: S. = QQ['u,v'].quotient('v^2 - 2') + sage: f = QuadraticField(2).hom([v], S) + sage: I = S.ideal(u + v) + sage: J = f.inverse_image(I) + sage: J.is_zero() + True + sage: f(J) < I + True + + Fractional ideals are not yet fully supported:: + + sage: K. = NumberField(QQ['x']('x^2+2')) + sage: f = K.hom([-a], K) + sage: I = K.ideal([a + 1]) + sage: f.inverse_image(I) + Traceback (most recent call last): + ... + NotImplementedError: inverse image not implemented... + sage: f.inverse_image(K.ideal(0)).is_zero() + True + + ALGORITHM: + + By default, this computes a Gröbner basis of an ideal related to the + graph of the ring homomorphism. + + REFERENCES: + + - Proposition 2.5.12 [DS2009]_ + + TESTS:: + + sage: ZZ.hom(Zp(2)).inverse_image(ZZ.ideal(2)) + Traceback (most recent call last): + ... + ValueError: not an ideal or element in codomain 2-adic Ring + with capped relative precision 20 + + :: + + sage: ZZ.hom(Zp(2)).inverse_image(Zp(2).ideal(2)) + Traceback (most recent call last): + ... + NotImplementedError: base rings must be equal + """ + from sage.categories.ring_ideals import RingIdeals + B = self.codomain() + if I in RingIdeals(B): + return self._inverse_image_ideal(I) + elif I in B: + return self._inverse_image_element(I) + else: + raise ValueError("not an ideal or element in codomain %s" % B) + + def _inverse_image_ideal(self, I): + """ + Return the inverse image of an ideal under this ring homomorphism. + + EXAMPLES:: + + sage: R. = QQbar[] + sage: f = R.hom([x, QQbar(i) * x + y^2], R) + sage: I = R.ideal(y^3) + sage: J = f._inverse_image_ideal(I); J + Ideal (x^2 + 2*I*x*y - y^2) + of Multivariate Polynomial Ring in x, y over Algebraic Field + sage: f(J) <= I + True + """ + from .polynomial.polynomial_quotient_ring import is_PolynomialQuotientRing + from .quotient_ring import is_QuotientRing + from .polynomial.multi_polynomial_ring import is_MPolynomialRing + from .polynomial.polynomial_ring import is_PolynomialRing + B = self.codomain() + graph, from_B, to_A = self._graph_ideal() + Q = graph.ring() + gens_B = Q.gens()[:B.ngens()] + if I.is_zero(): + # avoid adding the 0-ideal to the graph ideal in order to benefit + # from a cached Gröbner basis + graph_I = graph + elif (is_MPolynomialRing(B) or is_PolynomialRing(B) + or is_QuotientRing(B) or is_PolynomialQuotientRing(B)): + graph_I = graph + from_B(I) + else: + # non-zero fractional ideals of number fields not yet supported + raise NotImplementedError("inverse image not implemented " + "for ideals in %s" % B) + if is_QuotientRing(Q): + # elimination_ideal does not work with quotient rings, so + # switch to the cover ring + preimage = (Q.cover()._inverse_image_ideal(graph_I) + .elimination_ideal([y.lift() for y in gens_B])) + _, ambient_to_A = to_A + return ambient_to_A(preimage) + else: + preimage = graph_I.elimination_ideal(gens_B) + return to_A(preimage) + + def _inverse_image_element(self, b): + """ + Return an element `a` such that ``self(a) = b`` if one such exists. + + TESTS: + + A degenerate case:: + + sage: R. = QQ['x,y'].quotient(1) + sage: f = R.hom([y, x], R) + sage: f.inverse_image(x), f.inverse_image(y) # indirect doctest + (0, 0) + """ + graph, from_B, to_A = self._graph_ideal() + gens_B = graph.ring().gens()[:self.codomain().ngens()] + a = graph.reduce(from_B(b)) + if not (a.lm() < min(gens_B)) and not a.is_zero(): + raise ValueError(f"element {b} does not have preimage") + return to_A(a) + + @cached_method + def kernel(self): + """ + Return the kernel ideal of this ring homomorphism. + + EXAMPLES:: + + sage: A. = QQ[] + sage: B. = QQ[] + sage: f = A.hom([t^4, t^3 - t^2], B) + sage: f.kernel() + Ideal (y^4 - x^3 + 4*x^2*y - 2*x*y^2 + x^2) + of Multivariate Polynomial Ring in x, y over Rational Field + + We express a Veronese subring of a polynomial ring as a quotient ring:: + + sage: A. = QQ[] + sage: B. = QQ[] + sage: f = A.hom([u^3, u^2*v, u*v^2, v^3],B) + sage: f.kernel() == A.ideal(matrix.hankel([a, b, c], [d]).minors(2)) + True + sage: Q = A.quotient(f.kernel()) + sage: Q.hom(f.im_gens(), B).is_injective() + True + + The Steiner-Roman surface:: - This is not implemented in any generality yet:: + sage: R. = QQ[] + sage: S = R.quotient(x^2 + y^2 + z^2 - 1) + sage: f = R.hom([x*y, x*z, y*z], S) + sage: f.kernel() + Ideal (x^2*y^2 + x^2*z^2 + y^2*z^2 - x*y*z) + of Multivariate Polynomial Ring in x, y, z over Rational Field + + TESTS: - sage: f = ZZ.hom(Zp(2)) - sage: f.inverse_image(ZZ.ideal(2)) + The results are cached:: + + sage: f.kernel() is f.kernel() + True + + A degenerate case:: + + sage: R. = QQ[] + sage: f = R.hom([0, 0], R.quotient(1)) + sage: f.kernel().is_one() + True + + :: + + sage: K. = QuadraticField(2) + sage: K.hom([-sqrt2], K).kernel().is_zero() + True + + :: + + sage: A. = QuadraticField(2) + sage: B. = A.extension(A['b']('b^2-3')) + sage: C. = B.absolute_field() + sage: A.hom([B(a)], C).kernel().is_zero() + True + sage: A.hom([a], B).kernel() Traceback (most recent call last): ... - NotImplementedError + NotImplementedError: base rings must be equal """ - raise NotImplementedError + return self._inverse_image_ideal(self.codomain().ideal()) def lift(self, x=None): """ - Return a lifting homomorphism associated to this homomorphism, if + Return a lifting map associated to this homomorphism, if it has been defined. If ``x`` is not ``None``, return the value of the lift morphism on @@ -944,6 +1158,97 @@ cdef class RingHomomorphism(RingMap): return self._lift return self._lift(x) + @cached_method + def _graph_ideal(self): + """ + Return the ideal corresponding to the graph of this ring homomorphism. + + OUTPUT: + + - the graph as an ideal in the tensor product of codomain and domain + - a map from the codomain to the ring of the graph ideal + - a map from the ring of the graph ideal to the domain + + The second map is only meaningful for those elements that involve only + variables of the domain of ``self``. + + EXAMPLES:: + + sage: R. = QQ[] + sage: QQ['t'].hom([x*y^2], R)._graph_ideal() + (Ideal (x*y^2 - t) of Multivariate Polynomial Ring in x, y, t over + Rational Field, + Ring morphism: + From: Multivariate Polynomial Ring in x, y over Rational Field + To: Multivariate Polynomial Ring in x, y, t over Rational Field + Defn: x |--> x + y |--> y, + Ring morphism: + From: Multivariate Polynomial Ring in x, y, t over Rational Field + To: Univariate Polynomial Ring in t over Rational Field + Defn: x |--> 0 + y |--> 0 + t |--> t) + + TESTS: + + Ideals in quotient rings over ``QQbar`` do not support reduction yet, + so the graph is constructed in the ambient ring instead:: + + sage: A. = QQbar['z,w'].quotient('z*w - 1') + sage: B. = QQbar['x,y'].quotient('2*x^2 + y^2 - 1') + sage: f = A.hom([QQbar(2).sqrt()*x + QQbar(I)*y, + ....: QQbar(2).sqrt()*x - QQbar(I)*y], B) + sage: f._graph_ideal()[0] + Ideal (z*w - 1, 2*x^2 + y^2 - 1, + 1.414213562373095?*x + I*y - z, + 1.414213562373095?*x + (-I)*y - w) + of Multivariate Polynomial Ring in x, y, z, w over Algebraic Field + + Non-trivial base maps are not supported:: + + sage: K. = QuadraticField(2) + sage: R. = K[] + sage: f = R.hom([x, a*x + y], R, base_map=K.hom([-a], K)) + sage: f._graph_ideal() + Traceback (most recent call last): + ... + NotImplementedError: base map must be trivial + """ + from .quotient_ring import is_QuotientRing + from .ideal import Ideal_generic + A = self.domain() + B = self.codomain() + if A.base_ring() != B.base_ring(): + raise NotImplementedError("base rings must be equal") + try: + base_map = self.base_map() + except AttributeError: + pass + else: + if base_map is not None: + raise NotImplementedError("base map must be trivial") + Q = _tensor_product_ring(B, A) + A_to_Q = A.hom(Q.gens()[B.ngens():], Q, check=False) + B_to_Q = B.hom(Q.gens()[:B.ngens()], Q, check=False) + graph = Q.ideal([B_to_Q(self(x)) - A_to_Q(x) for x in A.gens()]) + R = Q.cover_ring() if is_QuotientRing(Q) else Q + R_to_A = R.hom(tuple([0] * B.ngens()) + A.gens(), A, check=False) + Q_to_A = R_to_A if R is Q else R_to_A * Q.lifting_map() + + # Since we compute normal forms modulo the graph ideal, check that + # the default `reduce` method has been overwritten + if graph.reduce.__func__ is Ideal_generic.reduce: + if Q is not R: + # Although the graph naturally lives in the quotient Q, we try + # to lift it to the ambient R as a workaround, since in some + # cases (e.g. over QQbar) reduction is supported in R + graph_R = Q.cover()._inverse_image_ideal(graph) + if graph_R.reduce.__func__ is not Ideal_generic.reduce: + return graph_R, (Q.lifting_map() * B_to_Q), R_to_A + raise NotImplementedError('"reduce" not implemented for %s' % Q) + return graph, B_to_Q, Q_to_A + cdef class RingHomomorphism_coercion(RingHomomorphism): r""" @@ -1136,7 +1441,6 @@ cdef class RingHomomorphism_im_gens(RingHomomorphism): if base_map.codomain() is not self.codomain(): base_map = base_map.extend_codomain(self.codomain()) tkwds = {'base_map': base_map} - tkwds = {} if base_map is None else {'base_map': base_map} t = parent.domain()._is_valid_homomorphism_(parent.codomain(), im_gens, **tkwds) if not t: raise ValueError("relations do not all (canonically) map to 0 under map determined by images of generators") @@ -1892,6 +2196,40 @@ cdef class RingHomomorphism_cover(RingHomomorphism): """ return hash((self.domain(), self.codomain())) + def _inverse_image_ideal(self, I): + """ + Return the inverse image of the ideal `I` under this covering morphism. + + INPUT: + + - ``I`` -- an ideal in the quotient ring + + EXAMPLES:: + + sage: R. = QQ['x,y'].quotient('x^2 * y^2') + sage: R.cover().inverse_image(R.ideal(x^3, y^3 + 1)) + Ideal (x^2*y^2, x^3, y^3 + 1) of Multivariate Polynomial Ring + in x, y over Rational Field + sage: S. = QQbar['u,v'].quotient('u^4 - 1') + sage: S.cover().inverse_image(S.ideal(u^2 - 1)) + Ideal (u^4 - 1, u^2 - 1) of Multivariate Polynomial Ring in u, v + over Algebraic Field + """ + if I.is_zero(): + return self.kernel() + return self.kernel() + [f.lift() for f in I.gens()] + + def _inverse_image_element(self, b): + """ + Lift an element from the quotient to the cover ring of this ring + homomorphism. + + sage: Q. = QQ['x,y'].quotient('x + y') + sage: Q.cover().inverse_image(x) + -y + """ + return b.lift() + cdef class RingHomomorphism_from_quotient(RingHomomorphism): r""" @@ -2309,3 +2647,88 @@ cdef class FrobeniusEndomorphism_generic(RingHomomorphism): domain = self.domain() codomain = self.codomain() return hash((domain, codomain, ('Frob', self._power))) + + +def _tensor_product_ring(B, A): + """ + Construct a quotient ring representating the tensor product of two rings + over a common base ring. + + Allowed arguments are polynomial rings, quotient rings, number fields and + finite fields. + + EXAMPLES:: + + sage: from sage.rings.morphism import _tensor_product_ring + sage: R. = QQ[] + sage: S. = R.quotient(x^2 + y^2) + sage: Q = _tensor_product_ring(S, R); Q + Quotient of Multivariate Polynomial Ring in u, v, x, y over + Rational Field by the ideal (u^2 + v^2) + sage: Q.term_order() + Block term order with blocks: + (Degree reverse lexicographic term order of length 2, + Degree reverse lexicographic term order of length 2) + sage: _tensor_product_ring(R, R) + Multivariate Polynomial Ring in y0, y1, x0, x1 over Rational Field + + TESTS: + + Local orderings are not supported:: + + sage: R = PolynomialRing(QQ, 'x,y', order='negdeglex') + sage: _tensor_product_ring(R, R) + Traceback (most recent call last): + ... + ValueError: term ordering must be global + """ + from .finite_rings.finite_field_base import is_FiniteField + from .number_field.number_field_base import is_NumberField + from .polynomial.multi_polynomial_ring import is_MPolynomialRing + from .polynomial.polynomial_quotient_ring import is_PolynomialQuotientRing + from .polynomial.polynomial_ring import is_PolynomialRing + from .polynomial.polynomial_ring_constructor import PolynomialRing + from .polynomial.term_order import TermOrder + from .quotient_ring import is_QuotientRing + + if set(B.variable_names()).isdisjoint(A.variable_names()): + names = B.variable_names() + A.variable_names() + else: + names = (['y%d' % d for d in range(B.ngens())] + + ['x%d' % d for d in range(A.ngens())]) + def term_order(A): + # univariate rings do not have a term order + if (is_PolynomialRing(A) or is_PolynomialQuotientRing(A) + or ((is_NumberField(A) or is_FiniteField(A)) + and not A.is_prime_field())): + return TermOrder('lex', 1) + try: + t = A.term_order() + except AttributeError: + raise NotImplementedError("inverse not implemented for " + "morphisms of %s" % A) + if not t.is_global(): + raise ValueError("term ordering must be global") + return t + R = PolynomialRing(A.base_ring(), names=names, + order=term_order(B) + term_order(A)) + + def relations(A, R_gens_A): + if is_MPolynomialRing(A) or is_PolynomialRing(A): + return [] + elif is_PolynomialQuotientRing(A): + to_R = A.ambient().hom(R_gens_A, R, check=False) + return [to_R(A.modulus())] + elif is_QuotientRing(A): + to_R = A.ambient().hom(R_gens_A, R, check=False) + return list(to_R(A.defining_ideal()).gens()) + elif ((is_NumberField(A) or is_FiniteField(A)) + and not A.is_prime_field()): + to_R = A.polynomial_ring().hom(R_gens_A, R, check=False) + return [to_R(A.polynomial())] + else: + raise NotImplementedError("inverse not implemented for " + "morphisms of %s" % A) + rels_A = relations(A, R.gens()[B.ngens():]) + rels_B = relations(B, R.gens()[:B.ngens()]) + return R.quotient(rels_A + rels_B, names=R.variable_names()) diff --git a/src/sage/schemes/generic/morphism.py b/src/sage/schemes/generic/morphism.py index f6468d90b59..86c25edc73f 100644 --- a/src/sage/schemes/generic/morphism.py +++ b/src/sage/schemes/generic/morphism.py @@ -784,7 +784,8 @@ def _call_(self, x): sage: f(X.an_element()) # indirect doctest Traceback (most recent call last): ... - NotImplementedError + NotImplementedError: inverse not implemented for morphisms of + Rational Field """ # By virtue of argument preprocessing in __call__, we can assume that # x is a topological scheme point of self From 20e92efc7775e1fe8246e8a5d1b3cdfcfdc9db09 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 31 May 2020 20:05:01 -0400 Subject: [PATCH 199/300] Trac #29493: make simplex_then_intopt the default GLPK method. Much of the GLPK error handling that requires custom patching is due to the tendency of the "glp_intonly" method to crash on problems it can't solve. The upstream recommendation is to run any suspicious problems through the (continuous) simplex solver first to e.g. detect infeasibility. That process is already implemented in SageMath via the "simplex_then_intopt" solver parameter. This commit changes "simplex_then_intopt" to be the default. Users can still set the parameter to "intonly" (or anything else) if they're sure that the problem is solvable, but this commit also updates the documentation with the relevant warnings against doing so blindly. --- src/sage/numerical/backends/glpk_backend.pyx | 55 +++++++++++--------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/src/sage/numerical/backends/glpk_backend.pyx b/src/sage/numerical/backends/glpk_backend.pyx index e171c0432c1..8050311d048 100644 --- a/src/sage/numerical/backends/glpk_backend.pyx +++ b/src/sage/numerical/backends/glpk_backend.pyx @@ -55,7 +55,7 @@ cdef class GLPKBackend(GenericBackend): sage: p = MixedIntegerLinearProgram(solver="GLPK") """ self.lp = glp_create_prob() - self.simplex_or_intopt = glp_intopt_only + self.simplex_or_intopt = glp_simplex_then_intopt self.smcp = sig_malloc(sizeof(glp_smcp)) glp_init_smcp(self.smcp) self.iocp = sig_malloc(sizeof(glp_iocp)) @@ -434,6 +434,7 @@ cdef class GLPKBackend(GenericBackend): sage: p.solve() 0.30000000000000004 sage: p.get_backend().set_verbosity(3) + sage: p.solver_parameter("simplex_or_intopt", "intopt_only") sage: p.solve() GLPK Integer Optimizer... 2 rows, 2 columns, 2 non-zeros @@ -925,12 +926,15 @@ cdef class GLPKBackend(GenericBackend): """ Solve the problem. - Sage uses GLPK's implementation of the branch-and-cut algorithm - (``glp_intopt``) to solve the mixed-integer linear program. - This algorithm can be requested explicitly by setting the solver - parameter "simplex_or_intopt" to "intopt_only". - (If all variables are continuous, the algorithm reduces to solving the - linear program by the simplex method.) + Sage uses GLPK's implementation of the branch-and-cut + algorithm (``glp_intopt``) to solve the mixed-integer linear + program. This algorithm can be requested explicitly by + setting the solver parameter "simplex_or_intopt" to + "intopt_only". By default, the simplex method will be used + first to detect pathological problems that the integer solver + cannot handle. If all variables are continuous, the integer + algorithm reduces to solving the linear program by the simplex + method. EXAMPLES:: @@ -969,15 +973,14 @@ cdef class GLPKBackend(GenericBackend): .. WARNING:: - Sage uses GLPK's ``glp_intopt`` to find solutions. - This routine sometimes FAILS CATASTROPHICALLY - when given a system it cannot solve. (:trac:`12309`.) - Here, "catastrophic" can mean either "infinite loop" or - segmentation fault. Upstream considers this behavior - "essentially innate" to their design, and suggests - preprocessing it with ``glp_simplex`` first. - Thus, if you suspect that your system is infeasible, - set the ``preprocessing`` option first. + GLPK's ``glp_intopt`` sometimes fails catastrophically + when given a system it cannot solve (:trac:`12309`). It + can loop indefinitely, or just plain segfault. Upstream + considers this behavior "essentially innate" to the + current design, and suggests preprocessing with + ``glp_simplex``, which is what SageMath does by default. + Set the ``simplex_or_intopt`` solver parameter to + ``glp_intopt_only`` at your own risk. EXAMPLES:: @@ -989,6 +992,7 @@ cdef class GLPKBackend(GenericBackend): sage: lp.solve() 0.0 sage: lp.add_constraint(v[0] +4.0 *v[1] -v[2] +v[3], max=-1.0) + sage: lp.solver_parameter("simplex_or_intopt", "intopt_only") sage: lp.solve() Traceback (most recent call last): ... @@ -1935,16 +1939,15 @@ cdef class GLPKBackend(GenericBackend): * - ``simplex_or_intopt`` - - specify which of ``simplex``, ``exact`` and ``intopt`` routines - in GLPK to use. - This is controlled by setting ``simplex_or_intopt`` to - ``glp_simplex_only``, ``glp_exact_simplex_only``, - ``glp_intopt_only`` and ``glp_simplex_then_intopt``, respectively. - The latter is useful to deal with a problem in GLPK where - problems with no solution hang when using integer optimization; - if you specify ``glp_simplex_then_intopt``, - sage will try simplex first, then perform integer optimization - only if a solution of the LP relaxation exists. + - specify which solution routines in GLPK to use. Set this + to either ``simplex_only``, ``exact_simplex_only``, + ``intopt_only``, or ``simplex_then_intopt`` (the + default). The ``simplex_then_intopt`` option does some + extra work, but avoids hangs/crashes in GLPK on problems + with no solution; SageMath will try simplex first, then + perform integer optimization only if a solution of the LP + relaxation exists. If you know that your system is not + pathological, one of the other options will be faster. * - ``verbosity_intopt`` and ``verbosity_simplex`` From 83ea75a999a56327232e8a11ed0c00e1b93c5666 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 31 May 2020 20:08:49 -0400 Subject: [PATCH 200/300] Trac #29493: remove doctest that intentionally crashes GLPK. With the custom GLPK error handling being removed, we now warn users against telling the solver to use the "intonly" method, because it can crash on problems it doesn't know how to solve. Since the relevant safety nets are endangered species, this commit removes a doctest for such a problem that is now unsupported and would crash GLPK. --- src/sage/numerical/backends/glpk_backend.pyx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/sage/numerical/backends/glpk_backend.pyx b/src/sage/numerical/backends/glpk_backend.pyx index 8050311d048..8f44144d8ef 100644 --- a/src/sage/numerical/backends/glpk_backend.pyx +++ b/src/sage/numerical/backends/glpk_backend.pyx @@ -26,7 +26,6 @@ from sage.cpython.string cimport char_to_str, str_to_bytes from sage.cpython.string import FS_ENCODING from sage.ext.memory_allocator cimport MemoryAllocator from sage.numerical.mip import MIPSolverException -from sage.libs.glpk.error import GLPKError from sage.libs.glpk.constants cimport * from sage.libs.glpk.lp cimport * from libc.float cimport DBL_MAX @@ -992,12 +991,6 @@ cdef class GLPKBackend(GenericBackend): sage: lp.solve() 0.0 sage: lp.add_constraint(v[0] +4.0 *v[1] -v[2] +v[3], max=-1.0) - sage: lp.solver_parameter("simplex_or_intopt", "intopt_only") - sage: lp.solve() - Traceback (most recent call last): - ... - GLPKError: Assertion failed: ... - sage: lp.solver_parameter("simplex_or_intopt", "simplex_then_intopt") sage: lp.solve() Traceback (most recent call last): ... From 5867c054f9605ecb740120ef9e22d5e3c9b6a5e2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 1 Jun 2020 16:57:12 -0700 Subject: [PATCH 201/300] src/sage/modular/pollack_stevens/dist.pyx: Add missing distutils directives --- src/sage/modular/pollack_stevens/dist.pyx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/modular/pollack_stevens/dist.pyx b/src/sage/modular/pollack_stevens/dist.pyx index f7025f2dec3..1bcb3406539 100644 --- a/src/sage/modular/pollack_stevens/dist.pyx +++ b/src/sage/modular/pollack_stevens/dist.pyx @@ -1,4 +1,6 @@ # -*- coding: utf-8 -*- +# distutils: libraries = gmp zn_poly +# distutils: extra_compile_args = -D_XPG6 """ `p`-adic distributions spaces From c536daa32dcc69adbc7b37d9a170e22fd733bca8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 1 Jun 2020 17:09:33 -0700 Subject: [PATCH 202/300] Remove self-listing in distutils sources directive --- src/sage/geometry/triangulation/base.pyx | 2 +- src/sage/schemes/hyperelliptic_curves/hypellfrob.pyx | 2 +- src/sage/stats/distributions/discrete_gaussian_integer.pyx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/geometry/triangulation/base.pyx b/src/sage/geometry/triangulation/base.pyx index df958418391..5e062327e23 100644 --- a/src/sage/geometry/triangulation/base.pyx +++ b/src/sage/geometry/triangulation/base.pyx @@ -1,4 +1,4 @@ -# distutils: sources = sage/geometry/triangulation/base.pyx sage/geometry/triangulation/functions.cc sage/geometry/triangulation/data.cc sage/geometry/triangulation/triangulations.cc +# distutils: sources = sage/geometry/triangulation/functions.cc sage/geometry/triangulation/data.cc sage/geometry/triangulation/triangulations.cc # distutils: depends = sage/geometry/triangulation/functions.h sage/geometry/triangulation/data.h sage/geometry/triangulation/triangulations.h # distutils: language = c++ diff --git a/src/sage/schemes/hyperelliptic_curves/hypellfrob.pyx b/src/sage/schemes/hyperelliptic_curves/hypellfrob.pyx index 1bbba251032..f60b85e3bd9 100644 --- a/src/sage/schemes/hyperelliptic_curves/hypellfrob.pyx +++ b/src/sage/schemes/hyperelliptic_curves/hypellfrob.pyx @@ -1,5 +1,5 @@ # distutils: language = c++ -# distutils: sources = sage/schemes/hyperelliptic_curves/hypellfrob.pyx sage/schemes/hyperelliptic_curves/hypellfrob/hypellfrob.cpp sage/schemes/hyperelliptic_curves/hypellfrob/recurrences_ntl.cpp sage/schemes/hyperelliptic_curves/hypellfrob/recurrences_zn_poly.cpp +# distutils: sources = sage/schemes/hyperelliptic_curves/hypellfrob/hypellfrob.cpp sage/schemes/hyperelliptic_curves/hypellfrob/recurrences_ntl.cpp sage/schemes/hyperelliptic_curves/hypellfrob/recurrences_zn_poly.cpp # distutils: depends = sage/schemes/hyperelliptic_curves/hypellfrob/hypellfrob.h sage/schemes/hyperelliptic_curves/hypellfrob/recurrences_ntl.h sage/schemes/hyperelliptic_curves/hypellfrob/recurrences_zn_poly.h # distutils: include_dirs = sage/libs/ntl/ sage/schemes/hyperelliptic_curves/hypellfrob/ # distutils: libraries = gmp ntl zn_poly diff --git a/src/sage/stats/distributions/discrete_gaussian_integer.pyx b/src/sage/stats/distributions/discrete_gaussian_integer.pyx index 2906b660802..ae6ec8a0f6a 100644 --- a/src/sage/stats/distributions/discrete_gaussian_integer.pyx +++ b/src/sage/stats/distributions/discrete_gaussian_integer.pyx @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# distutils: sources = sage/stats/distributions/discrete_gaussian_integer.pyx sage/stats/distributions/dgs_gauss_mp.c sage/stats/distributions/dgs_gauss_dp.c sage/stats/distributions/dgs_bern.c +# distutils: sources = sage/stats/distributions/dgs_gauss_mp.c sage/stats/distributions/dgs_gauss_dp.c sage/stats/distributions/dgs_bern.c # distutils: depends = sage/stats/distributions/dgs_gauss.h sage/stats/distributions/dgs_bern.h sage/stats/distributions/dgs_misc.h # distutils: extra_compile_args = -D_XOPEN_SOURCE=600 From 4334f103aaf2634c5bfc18eddb1ee1ab5c2db439 Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Mon, 1 Jun 2020 18:33:24 -0700 Subject: [PATCH 203/300] Raise correct exception for too large parameters --- src/sage/modular/hypergeometric_motive.py | 25 ++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index 645c3a3542e..169f211209a 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -1210,6 +1210,16 @@ def padic_H_value(self, p, f, t, prec=None, cache_p=False): sage: H.padic_H_value(101, 2, 2) -1560629 + Check issue from :trac:`29778`:: + + sage: H = Hyp(alpha_beta=([1/5,2/5,3/5,4/5,1/5,2/5,3/5,4/5], [1/4,3/4,1/7,2/7,3/7,4/7,5/7,6/7])) + sage: try: + ....: print(H.padic_H_value(373, 4, 2)) + ....: except ValueError: + ....: print("Overflow detected") + ....: + Overflow detected + REFERENCES: - [MagmaHGM]_ @@ -1221,7 +1231,7 @@ def padic_H_value(self, p, f, t, prec=None, cache_p=False): return self._swap.padic_H_value(p, f, ~t, prec) q = p ** f if q > 2 ** 31: - return ValueError("p^f cannot exceed 2^31") + raise ValueError("p^f cannot exceed 2^31") m = array.array('i', [0]) * int(q - 1) for b in beta: @@ -1493,6 +1503,16 @@ def euler_factor(self, t, p, cache_p=False): sage: H.euler_factor(2, 11, cache_p=True) -T^4 + T^3 - T + 1 + Check issue from :trac:`29778`:: + + sage: H = Hyp(alpha_beta=([1/5,2/5,3/5,4/5,1/5,2/5,3/5,4/5], [1/4,3/4,1/7,2/7,3/7,4/7,5/7,6/7])) + sage: try: + ....: print(H.euler_factor(2, 373)) + ....: except ValueError: + ....: print("Overflow detected") + ....: + Overflow detected + REFERENCES: - [Roberts2015]_ @@ -1513,6 +1533,9 @@ def euler_factor(self, t, p, cache_p=False): # now p is good d = self.degree() bound = d // 2 + if p ** bound > 2 ** 31: + raise ValueError("p^f cannot exceed 2^31") + traces = [self.padic_H_value(p, i + 1, t, cache_p=cache_p) for i in range(bound)] From 963737e8651811a0a4d337912bbd9d60073c2eed Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 1 Jun 2020 20:13:22 -0700 Subject: [PATCH 204/300] build/pkgs/autotools: Remove --- build/pkgs/autotools/Makefile.build | 890 ------------------ build/pkgs/autotools/SPKG.rst | 76 -- build/pkgs/autotools/autofoo | 25 - build/pkgs/autotools/checksums.ini | 4 - build/pkgs/autotools/dependencies | 5 - .../pkgs/autotools/install-info.exe.manifest | 18 - build/pkgs/autotools/latest_version | 68 -- build/pkgs/autotools/package-version.txt | 1 - .../autotools/patches/texinfo-libtinfo.patch | 15 - build/pkgs/autotools/spkg-install.in | 120 --- build/pkgs/autotools/spkg-src | 40 - build/pkgs/autotools/spkg-write-makefile | 227 ----- build/pkgs/autotools/type | 1 - build/pkgs/autotools/version-list | 23 - 14 files changed, 1513 deletions(-) delete mode 100644 build/pkgs/autotools/Makefile.build delete mode 100644 build/pkgs/autotools/SPKG.rst delete mode 100644 build/pkgs/autotools/autofoo delete mode 100644 build/pkgs/autotools/checksums.ini delete mode 100644 build/pkgs/autotools/dependencies delete mode 100755 build/pkgs/autotools/install-info.exe.manifest delete mode 100755 build/pkgs/autotools/latest_version delete mode 100644 build/pkgs/autotools/package-version.txt delete mode 100644 build/pkgs/autotools/patches/texinfo-libtinfo.patch delete mode 100644 build/pkgs/autotools/spkg-install.in delete mode 100755 build/pkgs/autotools/spkg-src delete mode 100755 build/pkgs/autotools/spkg-write-makefile delete mode 100644 build/pkgs/autotools/type delete mode 100644 build/pkgs/autotools/version-list diff --git a/build/pkgs/autotools/Makefile.build b/build/pkgs/autotools/Makefile.build deleted file mode 100644 index 5420dd66890..00000000000 --- a/build/pkgs/autotools/Makefile.build +++ /dev/null @@ -1,890 +0,0 @@ -######################################################################## -# This file is automatically generated by ./spkg-write-makefile -######################################################################## - -all: autoconf-all automake-all libtool-all tools-all - -######################################################################## - -tools-all: $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/help2man - -$(SAGE_LOCAL)/bin/makeinfo: $(SRC)/texinfo-4.13 - if [ "$$UNAME" = CYGWIN ] ; then cp -p "$(SRC)/../install-info.exe.manifest" "$(SAGE_LOCAL)/bin" ; fi - cd $< && ./configure --prefix="$(SAGE_LOCAL)" && $(MAKE) && $(MAKE) install - -$(SAGE_LOCAL)/bin/m4: $(SRC)/m4-1.4.17 $(SAGE_LOCAL)/bin/makeinfo - cd $< && ./configure --prefix="$(SAGE_LOCAL)" && $(MAKE) && $(MAKE) install - -$(SAGE_LOCAL)/bin/help2man: $(SRC)/help2man-1.46.4 $(SAGE_LOCAL)/bin/makeinfo - cd $< && ./configure --prefix="$(SAGE_LOCAL)" && $(MAKE) && $(MAKE) install - -######################################################################## - -# Extract sources from git repository serially -autoconf-2.13.rc1/.tarball-version: - ( cd $(SRC)/autoconf && git archive --format=tar --prefix=autoconf-2.13.rc1/ autoconf-2-13-rc1 ) | tar xf - - echo 2.13.rc1 >autoconf-2.13.rc1/.tarball-version - -$(SAGE_LOCAL)/autoconf-2.13.rc1: autoconf-2.13.rc1/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo - export MAKE='$(MAKE) -j1' ; \ - cd autoconf-2.13.rc1 && touch autoupdate.sh && \ - ./configure --prefix="$(SAGE_LOCAL)/autoconf-2.13.rc1" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf autoconf-2.13.rc1/* - -# Extract sources from git repository serially -autoconf-2.57/.tarball-version: autoconf-2.13.rc1/.tarball-version - ( cd $(SRC)/autoconf && git archive --format=tar --prefix=autoconf-2.57/ AUTOCONF-2.57 ) | tar xf - - echo 2.57 >autoconf-2.57/.tarball-version - -$(SAGE_LOCAL)/autoconf-2.57: autoconf-2.57/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man - export MAKE='$(MAKE) -j1' ; \ - cd autoconf-2.57 && \ - ./configure --prefix="$(SAGE_LOCAL)/autoconf-2.57" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf autoconf-2.57/* - -# Extract sources from git repository serially -autoconf-2.58/.tarball-version: autoconf-2.57/.tarball-version - ( cd $(SRC)/autoconf && git archive --format=tar --prefix=autoconf-2.58/ AUTOCONF-2.58 ) | tar xf - - echo 2.58 >autoconf-2.58/.tarball-version - -$(SAGE_LOCAL)/autoconf-2.58: autoconf-2.58/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man - export MAKE='$(MAKE) -j1' ; \ - cd autoconf-2.58 && \ - ./configure --prefix="$(SAGE_LOCAL)/autoconf-2.58" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf autoconf-2.58/* - -# Extract sources from git repository serially -autoconf-2.59/.tarball-version: autoconf-2.58/.tarball-version - ( cd $(SRC)/autoconf && git archive --format=tar --prefix=autoconf-2.59/ AUTOCONF-2.59 ) | tar xf - - echo 2.59 >autoconf-2.59/.tarball-version - -$(SAGE_LOCAL)/autoconf-2.59: autoconf-2.59/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man - export MAKE='$(MAKE) -j1' ; \ - cd autoconf-2.59 && \ - ./configure --prefix="$(SAGE_LOCAL)/autoconf-2.59" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf autoconf-2.59/* - -# Extract sources from git repository serially -autoconf-2.60/.tarball-version: autoconf-2.59/.tarball-version - ( cd $(SRC)/autoconf && git archive --format=tar --prefix=autoconf-2.60/ AUTOCONF-2.60 ) | tar xf - - echo 2.60 >autoconf-2.60/.tarball-version - -$(SAGE_LOCAL)/autoconf-2.60: autoconf-2.60/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man - export MAKE='$(MAKE) -j1' ; \ - cd autoconf-2.60 && \ - ./configure --prefix="$(SAGE_LOCAL)/autoconf-2.60" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf autoconf-2.60/* - -# Extract sources from git repository serially -autoconf-2.61/.tarball-version: autoconf-2.60/.tarball-version - ( cd $(SRC)/autoconf && git archive --format=tar --prefix=autoconf-2.61/ AUTOCONF-2.61 ) | tar xf - - echo 2.61 >autoconf-2.61/.tarball-version - -$(SAGE_LOCAL)/autoconf-2.61: autoconf-2.61/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man - export MAKE='$(MAKE) -j1' ; \ - cd autoconf-2.61 && \ - ./configure --prefix="$(SAGE_LOCAL)/autoconf-2.61" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf autoconf-2.61/* - -# Extract sources from git repository serially -autoconf-2.62/.tarball-version: autoconf-2.61/.tarball-version - ( cd $(SRC)/autoconf && git archive --format=tar --prefix=autoconf-2.62/ v2.62 ) | tar xf - - echo 2.62 >autoconf-2.62/.tarball-version - -$(SAGE_LOCAL)/autoconf-2.62: autoconf-2.62/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man $(SAGE_LOCAL)/autoconf-2.60 $(SAGE_LOCAL)/automake-1.10 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.60 ; \ - export AUTOMAKE_VERSION=1.10 ; \ - cd autoconf-2.62 && autoreconf -i -I m4 && \ - ./configure --prefix="$(SAGE_LOCAL)/autoconf-2.62" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf autoconf-2.62/* - -# Extract sources from git repository serially -autoconf-2.63/.tarball-version: autoconf-2.62/.tarball-version - ( cd $(SRC)/autoconf && git archive --format=tar --prefix=autoconf-2.63/ v2.63 ) | tar xf - - echo 2.63 >autoconf-2.63/.tarball-version - -$(SAGE_LOCAL)/autoconf-2.63: autoconf-2.63/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man $(SAGE_LOCAL)/autoconf-2.60 $(SAGE_LOCAL)/automake-1.10 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.60 ; \ - export AUTOMAKE_VERSION=1.10 ; \ - cd autoconf-2.63 && autoreconf -i -I m4 && \ - ./configure --prefix="$(SAGE_LOCAL)/autoconf-2.63" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf autoconf-2.63/* - -# Extract sources from git repository serially -autoconf-2.64/.tarball-version: autoconf-2.63/.tarball-version - ( cd $(SRC)/autoconf && git archive --format=tar --prefix=autoconf-2.64/ v2.64 ) | tar xf - - echo 2.64 >autoconf-2.64/.tarball-version - -$(SAGE_LOCAL)/autoconf-2.64: autoconf-2.64/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man $(SAGE_LOCAL)/autoconf-2.60 $(SAGE_LOCAL)/automake-1.10 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.60 ; \ - export AUTOMAKE_VERSION=1.10 ; \ - cd autoconf-2.64 && autoreconf -i -I m4 && \ - ./configure --prefix="$(SAGE_LOCAL)/autoconf-2.64" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf autoconf-2.64/* - -# Extract sources from git repository serially -autoconf-2.65/.tarball-version: autoconf-2.64/.tarball-version - ( cd $(SRC)/autoconf && git archive --format=tar --prefix=autoconf-2.65/ v2.65 ) | tar xf - - echo 2.65 >autoconf-2.65/.tarball-version - -$(SAGE_LOCAL)/autoconf-2.65: autoconf-2.65/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man $(SAGE_LOCAL)/autoconf-2.60 $(SAGE_LOCAL)/automake-1.10 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.60 ; \ - export AUTOMAKE_VERSION=1.10 ; \ - cd autoconf-2.65 && autoreconf -i -I m4 && \ - ./configure --prefix="$(SAGE_LOCAL)/autoconf-2.65" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf autoconf-2.65/* - -# Extract sources from git repository serially -autoconf-2.66/.tarball-version: autoconf-2.65/.tarball-version - ( cd $(SRC)/autoconf && git archive --format=tar --prefix=autoconf-2.66/ v2.66 ) | tar xf - - echo 2.66 >autoconf-2.66/.tarball-version - -$(SAGE_LOCAL)/autoconf-2.66: autoconf-2.66/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man $(SAGE_LOCAL)/autoconf-2.62 $(SAGE_LOCAL)/automake-1.11 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.62 ; \ - export AUTOMAKE_VERSION=1.11 ; \ - cd autoconf-2.66 && autoreconf -i -I m4 && \ - ./configure --prefix="$(SAGE_LOCAL)/autoconf-2.66" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf autoconf-2.66/* - -# Extract sources from git repository serially -autoconf-2.67/.tarball-version: autoconf-2.66/.tarball-version - ( cd $(SRC)/autoconf && git archive --format=tar --prefix=autoconf-2.67/ v2.67 ) | tar xf - - echo 2.67 >autoconf-2.67/.tarball-version - -$(SAGE_LOCAL)/autoconf-2.67: autoconf-2.67/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man $(SAGE_LOCAL)/autoconf-2.62 $(SAGE_LOCAL)/automake-1.11 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.62 ; \ - export AUTOMAKE_VERSION=1.11 ; \ - cd autoconf-2.67 && autoreconf -i -I m4 && \ - ./configure --prefix="$(SAGE_LOCAL)/autoconf-2.67" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf autoconf-2.67/* - -# Extract sources from git repository serially -autoconf-2.68/.tarball-version: autoconf-2.67/.tarball-version - ( cd $(SRC)/autoconf && git archive --format=tar --prefix=autoconf-2.68/ v2.68 ) | tar xf - - echo 2.68 >autoconf-2.68/.tarball-version - -$(SAGE_LOCAL)/autoconf-2.68: autoconf-2.68/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man $(SAGE_LOCAL)/autoconf-2.62 $(SAGE_LOCAL)/automake-1.11 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.62 ; \ - export AUTOMAKE_VERSION=1.11 ; \ - cd autoconf-2.68 && autoreconf -i -I m4 && \ - ./configure --prefix="$(SAGE_LOCAL)/autoconf-2.68" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf autoconf-2.68/* - -# Extract sources from git repository serially -autoconf-2.69/.tarball-version: autoconf-2.68/.tarball-version - ( cd $(SRC)/autoconf && git archive --format=tar --prefix=autoconf-2.69/ v2.69 ) | tar xf - - echo 2.69 >autoconf-2.69/.tarball-version - -$(SAGE_LOCAL)/autoconf-2.69: autoconf-2.69/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man $(SAGE_LOCAL)/autoconf-2.62 $(SAGE_LOCAL)/automake-1.11 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.62 ; \ - export AUTOMAKE_VERSION=1.11 ; \ - cd autoconf-2.69 && autoreconf -i -I m4 && \ - ./configure --prefix="$(SAGE_LOCAL)/autoconf-2.69" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf autoconf-2.69/* - -autoconf-all: $(SAGE_LOCAL)/autoconf-2.13.rc1 $(SAGE_LOCAL)/autoconf-2.57 $(SAGE_LOCAL)/autoconf-2.58 $(SAGE_LOCAL)/autoconf-2.59 $(SAGE_LOCAL)/autoconf-2.60 $(SAGE_LOCAL)/autoconf-2.61 $(SAGE_LOCAL)/autoconf-2.62 $(SAGE_LOCAL)/autoconf-2.63 $(SAGE_LOCAL)/autoconf-2.64 $(SAGE_LOCAL)/autoconf-2.65 $(SAGE_LOCAL)/autoconf-2.66 $(SAGE_LOCAL)/autoconf-2.67 $(SAGE_LOCAL)/autoconf-2.68 $(SAGE_LOCAL)/autoconf-2.69 - -######################################################################## - -# Extract sources from git repository serially -automake-1.9/.tarball-version: autoconf-2.69/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.9/ Release-1-9 ) | tar xf - - echo 1.9 >automake-1.9/.tarball-version - -$(SAGE_LOCAL)/automake-1.9: automake-1.9/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.59 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.59 ; \ - cd automake-1.9 && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.9" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.9/* - -# Extract sources from git repository serially -automake-1.9.1/.tarball-version: automake-1.9/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.9.1/ Release-1-9-1 ) | tar xf - - echo 1.9.1 >automake-1.9.1/.tarball-version - -$(SAGE_LOCAL)/automake-1.9.1: automake-1.9.1/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.59 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.59 ; \ - cd automake-1.9.1 && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.9.1" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.9.1/* - -# Extract sources from git repository serially -automake-1.9.2/.tarball-version: automake-1.9.1/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.9.2/ Release-1-9-2 ) | tar xf - - echo 1.9.2 >automake-1.9.2/.tarball-version - -$(SAGE_LOCAL)/automake-1.9.2: automake-1.9.2/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.59 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.59 ; \ - cd automake-1.9.2 && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.9.2" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.9.2/* - -# Extract sources from git repository serially -automake-1.9.3/.tarball-version: automake-1.9.2/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.9.3/ Release-1-9-3 ) | tar xf - - echo 1.9.3 >automake-1.9.3/.tarball-version - -$(SAGE_LOCAL)/automake-1.9.3: automake-1.9.3/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.59 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.59 ; \ - cd automake-1.9.3 && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.9.3" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.9.3/* - -# Extract sources from git repository serially -automake-1.9.4/.tarball-version: automake-1.9.3/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.9.4/ Release-1-9-4 ) | tar xf - - echo 1.9.4 >automake-1.9.4/.tarball-version - -$(SAGE_LOCAL)/automake-1.9.4: automake-1.9.4/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.59 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.59 ; \ - cd automake-1.9.4 && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.9.4" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.9.4/* - -# Extract sources from git repository serially -automake-1.9.5/.tarball-version: automake-1.9.4/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.9.5/ Release-1-9-5 ) | tar xf - - echo 1.9.5 >automake-1.9.5/.tarball-version - -$(SAGE_LOCAL)/automake-1.9.5: automake-1.9.5/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.59 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.59 ; \ - cd automake-1.9.5 && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.9.5" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.9.5/* - -# Extract sources from git repository serially -automake-1.9.6/.tarball-version: automake-1.9.5/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.9.6/ Release-1-9-6 ) | tar xf - - echo 1.9.6 >automake-1.9.6/.tarball-version - -$(SAGE_LOCAL)/automake-1.9.6: automake-1.9.6/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.59 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.59 ; \ - cd automake-1.9.6 && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.9.6" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.9.6/* - -# Extract sources from git repository serially -automake-1.10/.tarball-version: automake-1.9.6/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.10/ Release-1-10 ) | tar xf - - echo 1.10 >automake-1.10/.tarball-version - -$(SAGE_LOCAL)/automake-1.10: automake-1.10/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.60 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.60 ; \ - cd automake-1.10 && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.10" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.10/* - -# Extract sources from git repository serially -automake-1.10.1/.tarball-version: automake-1.10/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.10.1/ Release-1-10-1 ) | tar xf - - echo 1.10.1 >automake-1.10.1/.tarball-version - -$(SAGE_LOCAL)/automake-1.10.1: automake-1.10.1/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.60 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.60 ; \ - cd automake-1.10.1 && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.10.1" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.10.1/* - -# Extract sources from git repository serially -automake-1.10.2/.tarball-version: automake-1.10.1/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.10.2/ v1.10.2 ) | tar xf - - echo 1.10.2 >automake-1.10.2/.tarball-version - -$(SAGE_LOCAL)/automake-1.10.2: automake-1.10.2/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.60 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.60 ; \ - cd automake-1.10.2 && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.10.2" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.10.2/* - -# Extract sources from git repository serially -automake-1.10.3/.tarball-version: automake-1.10.2/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.10.3/ v1.10.3 ) | tar xf - - echo 1.10.3 >automake-1.10.3/.tarball-version - -$(SAGE_LOCAL)/automake-1.10.3: automake-1.10.3/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.60 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.60 ; \ - cd automake-1.10.3 && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.10.3" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.10.3/* - -# Extract sources from git repository serially -automake-1.11/.tarball-version: automake-1.10.3/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.11/ v1.11 ) | tar xf - - echo 1.11 >automake-1.11/.tarball-version - -$(SAGE_LOCAL)/automake-1.11: automake-1.11/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man $(SAGE_LOCAL)/autoconf-2.62 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.62 ; \ - cd automake-1.11 && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.11" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.11/* - -# Extract sources from git repository serially -automake-1.11.1/.tarball-version: automake-1.11/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.11.1/ v1.11.1 ) | tar xf - - echo 1.11.1 >automake-1.11.1/.tarball-version - -$(SAGE_LOCAL)/automake-1.11.1: automake-1.11.1/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man $(SAGE_LOCAL)/autoconf-2.62 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.62 ; \ - cd automake-1.11.1 && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.11.1" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.11.1/* - -# Extract sources from git repository serially -automake-1.11.2/.tarball-version: automake-1.11.1/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.11.2/ v1.11.2 ) | tar xf - - echo 1.11.2 >automake-1.11.2/.tarball-version - -$(SAGE_LOCAL)/automake-1.11.2: automake-1.11.2/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man $(SAGE_LOCAL)/autoconf-2.62 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.62 ; \ - cd automake-1.11.2 && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.11.2" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.11.2/* - -# Extract sources from git repository serially -automake-1.11.3/.tarball-version: automake-1.11.2/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.11.3/ v1.11.3 ) | tar xf - - echo 1.11.3 >automake-1.11.3/.tarball-version - -$(SAGE_LOCAL)/automake-1.11.3: automake-1.11.3/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man $(SAGE_LOCAL)/autoconf-2.68 $(SAGE_LOCAL)/automake-1.10 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.68 ; \ - export AUTOMAKE_VERSION=1.10 ; \ - cd automake-1.11.3 && bash -c 'set -e; source bootstrap' && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.11.3" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.11.3/* - -# Extract sources from git repository serially -automake-1.11.4/.tarball-version: automake-1.11.3/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.11.4/ v1.11.4 ) | tar xf - - echo 1.11.4 >automake-1.11.4/.tarball-version - -$(SAGE_LOCAL)/automake-1.11.4: automake-1.11.4/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man $(SAGE_LOCAL)/autoconf-2.68 $(SAGE_LOCAL)/automake-1.10 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.68 ; \ - export AUTOMAKE_VERSION=1.10 ; \ - cd automake-1.11.4 && bash -c 'set -e; source bootstrap' && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.11.4" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.11.4/* - -# Extract sources from git repository serially -automake-1.11.5/.tarball-version: automake-1.11.4/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.11.5/ v1.11.5 ) | tar xf - - echo 1.11.5 >automake-1.11.5/.tarball-version - -$(SAGE_LOCAL)/automake-1.11.5: automake-1.11.5/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man $(SAGE_LOCAL)/autoconf-2.68 $(SAGE_LOCAL)/automake-1.10 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.68 ; \ - export AUTOMAKE_VERSION=1.10 ; \ - cd automake-1.11.5 && bash -c 'set -e; source bootstrap' && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.11.5" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.11.5/* - -# Extract sources from git repository serially -automake-1.11.6/.tarball-version: automake-1.11.5/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.11.6/ v1.11.6 ) | tar xf - - echo 1.11.6 >automake-1.11.6/.tarball-version - -$(SAGE_LOCAL)/automake-1.11.6: automake-1.11.6/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man $(SAGE_LOCAL)/autoconf-2.68 $(SAGE_LOCAL)/automake-1.10 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.68 ; \ - export AUTOMAKE_VERSION=1.10 ; \ - cd automake-1.11.6 && bash -c 'set -e; source bootstrap' && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.11.6" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.11.6/* - -# Extract sources from git repository serially -automake-1.12/.tarball-version: automake-1.11.6/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.12/ v1.12 ) | tar xf - - echo 1.12 >automake-1.12/.tarball-version - -$(SAGE_LOCAL)/automake-1.12: automake-1.12/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.68 $(SAGE_LOCAL)/automake-1.10 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.68 ; \ - export AUTOMAKE_VERSION=1.10 ; \ - cd automake-1.12 && bash -c 'set -e; source bootstrap' && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.12" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.12/* - -# Extract sources from git repository serially -automake-1.12.1/.tarball-version: automake-1.12/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.12.1/ v1.12.1 ) | tar xf - - echo 1.12.1 >automake-1.12.1/.tarball-version - -$(SAGE_LOCAL)/automake-1.12.1: automake-1.12.1/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.69 $(SAGE_LOCAL)/automake-1.9.6 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.69 ; \ - export AUTOMAKE_VERSION=1.9.6 ; \ - cd automake-1.12.1 && bash -c 'set -e; source bootstrap.sh' && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.12.1" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.12.1/* - -# Extract sources from git repository serially -automake-1.12.2/.tarball-version: automake-1.12.1/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.12.2/ v1.12.2 ) | tar xf - - echo 1.12.2 >automake-1.12.2/.tarball-version - -$(SAGE_LOCAL)/automake-1.12.2: automake-1.12.2/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.69 $(SAGE_LOCAL)/automake-1.9.6 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.69 ; \ - export AUTOMAKE_VERSION=1.9.6 ; \ - cd automake-1.12.2 && bash -c 'set -e; source bootstrap.sh' && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.12.2" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.12.2/* - -# Extract sources from git repository serially -automake-1.12.3/.tarball-version: automake-1.12.2/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.12.3/ v1.12.3 ) | tar xf - - echo 1.12.3 >automake-1.12.3/.tarball-version - -$(SAGE_LOCAL)/automake-1.12.3: automake-1.12.3/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.69 $(SAGE_LOCAL)/automake-1.9.6 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.69 ; \ - export AUTOMAKE_VERSION=1.9.6 ; \ - cd automake-1.12.3 && bash -c 'set -e; source bootstrap.sh' && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.12.3" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.12.3/* - -# Extract sources from git repository serially -automake-1.12.4/.tarball-version: automake-1.12.3/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.12.4/ v1.12.4 ) | tar xf - - echo 1.12.4 >automake-1.12.4/.tarball-version - -$(SAGE_LOCAL)/automake-1.12.4: automake-1.12.4/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.69 $(SAGE_LOCAL)/automake-1.9.6 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.69 ; \ - export AUTOMAKE_VERSION=1.9.6 ; \ - cd automake-1.12.4 && bash -c 'set -e; source bootstrap.sh' && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.12.4" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.12.4/* - -# Extract sources from git repository serially -automake-1.12.5/.tarball-version: automake-1.12.4/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.12.5/ v1.12.5 ) | tar xf - - echo 1.12.5 >automake-1.12.5/.tarball-version - -$(SAGE_LOCAL)/automake-1.12.5: automake-1.12.5/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.69 $(SAGE_LOCAL)/automake-1.9.6 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.69 ; \ - export AUTOMAKE_VERSION=1.9.6 ; \ - cd automake-1.12.5 && bash -c 'set -e; source bootstrap.sh' && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.12.5" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.12.5/* - -# Extract sources from git repository serially -automake-1.12.6/.tarball-version: automake-1.12.5/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.12.6/ v1.12.6 ) | tar xf - - echo 1.12.6 >automake-1.12.6/.tarball-version - -$(SAGE_LOCAL)/automake-1.12.6: automake-1.12.6/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.69 $(SAGE_LOCAL)/automake-1.9.6 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.69 ; \ - export AUTOMAKE_VERSION=1.9.6 ; \ - cd automake-1.12.6 && bash -c 'set -e; source bootstrap.sh' && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.12.6" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.12.6/* - -# Extract sources from git repository serially -automake-1.13/.tarball-version: automake-1.12.6/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.13/ v1.13 ) | tar xf - - echo 1.13 >automake-1.13/.tarball-version - -$(SAGE_LOCAL)/automake-1.13: automake-1.13/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.69 $(SAGE_LOCAL)/automake-1.9.6 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.69 ; \ - export AUTOMAKE_VERSION=1.9.6 ; \ - cd automake-1.13 && bash -c 'set -e; source bootstrap.sh' && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.13" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.13/* - -# Extract sources from git repository serially -automake-1.13.1/.tarball-version: automake-1.13/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.13.1/ v1.13.1 ) | tar xf - - echo 1.13.1 >automake-1.13.1/.tarball-version - -$(SAGE_LOCAL)/automake-1.13.1: automake-1.13.1/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.69 $(SAGE_LOCAL)/automake-1.9.6 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.69 ; \ - export AUTOMAKE_VERSION=1.9.6 ; \ - cd automake-1.13.1 && bash -c 'set -e; source bootstrap.sh' && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.13.1" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.13.1/* - -# Extract sources from git repository serially -automake-1.13.2/.tarball-version: automake-1.13.1/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.13.2/ v1.13.2 ) | tar xf - - echo 1.13.2 >automake-1.13.2/.tarball-version - -$(SAGE_LOCAL)/automake-1.13.2: automake-1.13.2/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.69 $(SAGE_LOCAL)/automake-1.9.6 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.69 ; \ - export AUTOMAKE_VERSION=1.9.6 ; \ - cd automake-1.13.2 && bash -c 'set -e; source bootstrap.sh' && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.13.2" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.13.2/* - -# Extract sources from git repository serially -automake-1.13.3/.tarball-version: automake-1.13.2/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.13.3/ v1.13.3 ) | tar xf - - echo 1.13.3 >automake-1.13.3/.tarball-version - -$(SAGE_LOCAL)/automake-1.13.3: automake-1.13.3/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.69 $(SAGE_LOCAL)/automake-1.9.6 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.69 ; \ - export AUTOMAKE_VERSION=1.9.6 ; \ - cd automake-1.13.3 && bash -c 'set -e; source bootstrap.sh' && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.13.3" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.13.3/* - -# Extract sources from git repository serially -automake-1.13.4/.tarball-version: automake-1.13.3/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.13.4/ v1.13.4 ) | tar xf - - echo 1.13.4 >automake-1.13.4/.tarball-version - -$(SAGE_LOCAL)/automake-1.13.4: automake-1.13.4/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.69 $(SAGE_LOCAL)/automake-1.9.6 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.69 ; \ - export AUTOMAKE_VERSION=1.9.6 ; \ - cd automake-1.13.4 && bash -c 'set -e; source bootstrap.sh' && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.13.4" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.13.4/* - -# Extract sources from git repository serially -automake-1.14/.tarball-version: automake-1.13.4/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.14/ v1.14 ) | tar xf - - echo 1.14 >automake-1.14/.tarball-version - -$(SAGE_LOCAL)/automake-1.14: automake-1.14/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.69 $(SAGE_LOCAL)/automake-1.9.6 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.69 ; \ - export AUTOMAKE_VERSION=1.9.6 ; \ - cd automake-1.14 && bash -c 'set -e; source bootstrap.sh' && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.14" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.14/* - -# Extract sources from git repository serially -automake-1.14.1/.tarball-version: automake-1.14/.tarball-version - ( cd $(SRC)/automake && git archive --format=tar --prefix=automake-1.14.1/ v1.14.1 ) | tar xf - - echo 1.14.1 >automake-1.14.1/.tarball-version - -$(SAGE_LOCAL)/automake-1.14.1: automake-1.14.1/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.69 $(SAGE_LOCAL)/automake-1.9.6 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.69 ; \ - export AUTOMAKE_VERSION=1.9.6 ; \ - cd automake-1.14.1 && bash -c 'set -e; source bootstrap.sh' && \ - ./configure --prefix="$(SAGE_LOCAL)/automake-1.14.1" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf automake-1.14.1/* - -automake-all: $(SAGE_LOCAL)/automake-1.9 $(SAGE_LOCAL)/automake-1.9.1 $(SAGE_LOCAL)/automake-1.9.2 $(SAGE_LOCAL)/automake-1.9.3 $(SAGE_LOCAL)/automake-1.9.4 $(SAGE_LOCAL)/automake-1.9.5 $(SAGE_LOCAL)/automake-1.9.6 $(SAGE_LOCAL)/automake-1.10 $(SAGE_LOCAL)/automake-1.10.1 $(SAGE_LOCAL)/automake-1.10.2 $(SAGE_LOCAL)/automake-1.10.3 $(SAGE_LOCAL)/automake-1.11 $(SAGE_LOCAL)/automake-1.11.1 $(SAGE_LOCAL)/automake-1.11.2 $(SAGE_LOCAL)/automake-1.11.3 $(SAGE_LOCAL)/automake-1.11.4 $(SAGE_LOCAL)/automake-1.11.5 $(SAGE_LOCAL)/automake-1.11.6 $(SAGE_LOCAL)/automake-1.12 $(SAGE_LOCAL)/automake-1.12.1 $(SAGE_LOCAL)/automake-1.12.2 $(SAGE_LOCAL)/automake-1.12.3 $(SAGE_LOCAL)/automake-1.12.4 $(SAGE_LOCAL)/automake-1.12.5 $(SAGE_LOCAL)/automake-1.12.6 $(SAGE_LOCAL)/automake-1.13 $(SAGE_LOCAL)/automake-1.13.1 $(SAGE_LOCAL)/automake-1.13.2 $(SAGE_LOCAL)/automake-1.13.3 $(SAGE_LOCAL)/automake-1.13.4 $(SAGE_LOCAL)/automake-1.14 $(SAGE_LOCAL)/automake-1.14.1 - -######################################################################## - -# Extract sources from git repository serially -libtool-1.5.20/.tarball-version: automake-1.14.1/.tarball-version - ( cd $(SRC)/libtool && git archive --format=tar --prefix=libtool-1.5.20/ release-1-5-20 ) | tar xf - - echo 1.5.20 >libtool-1.5.20/.tarball-version - echo 1886 > libtool-1.5.20/.serial - -$(SAGE_LOCAL)/libtool-1.5.20: libtool-1.5.20/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.59 $(SAGE_LOCAL)/automake-1.9.6 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.59 ; \ - export AUTOMAKE_VERSION=1.9.6 ; \ - cd libtool-1.5.20 && bash -c 'set -e; source bootstrap' && \ - ./configure --prefix="$(SAGE_LOCAL)/libtool-1.5.20" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf libtool-1.5.20/* - -# Extract sources from git repository serially -libtool-1.5.22/.tarball-version: libtool-1.5.20/.tarball-version - ( cd $(SRC)/libtool && git archive --format=tar --prefix=libtool-1.5.22/ release-1-5-22 ) | tar xf - - echo 1.5.22 >libtool-1.5.22/.tarball-version - echo 1965 > libtool-1.5.22/.serial - -$(SAGE_LOCAL)/libtool-1.5.22: libtool-1.5.22/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.59 $(SAGE_LOCAL)/automake-1.9.6 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.59 ; \ - export AUTOMAKE_VERSION=1.9.6 ; \ - cd libtool-1.5.22 && bash -c 'set -e; source bootstrap' && \ - ./configure --prefix="$(SAGE_LOCAL)/libtool-1.5.22" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf libtool-1.5.22/* - -# Extract sources from git repository serially -libtool-1.5.24/.tarball-version: libtool-1.5.22/.tarball-version - ( cd $(SRC)/libtool && git archive --format=tar --prefix=libtool-1.5.24/ release-1-5-24 ) | tar xf - - echo 1.5.24 >libtool-1.5.24/.tarball-version - echo 2056 > libtool-1.5.24/.serial - -$(SAGE_LOCAL)/libtool-1.5.24: libtool-1.5.24/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.59 $(SAGE_LOCAL)/automake-1.9.6 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.59 ; \ - export AUTOMAKE_VERSION=1.9.6 ; \ - cd libtool-1.5.24 && bash -c 'set -e; source bootstrap' && \ - ./configure --prefix="$(SAGE_LOCAL)/libtool-1.5.24" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf libtool-1.5.24/* - -# Extract sources from git repository serially -libtool-1.5.26/.tarball-version: libtool-1.5.24/.tarball-version - ( cd $(SRC)/libtool && git archive --format=tar --prefix=libtool-1.5.26/ release-1-5-26 ) | tar xf - - echo 1.5.26 >libtool-1.5.26/.tarball-version - echo 2093 > libtool-1.5.26/.serial - -$(SAGE_LOCAL)/libtool-1.5.26: libtool-1.5.26/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.59 $(SAGE_LOCAL)/automake-1.9.6 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.59 ; \ - export AUTOMAKE_VERSION=1.9.6 ; \ - cd libtool-1.5.26 && bash -c 'set -e; source bootstrap' && \ - ./configure --prefix="$(SAGE_LOCAL)/libtool-1.5.26" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf libtool-1.5.26/* - -# Extract sources from git repository serially -libtool-2.2.4/.tarball-version: libtool-1.5.26/.tarball-version - ( cd $(SRC)/libtool && git archive --format=tar --prefix=libtool-2.2.4/ v2.2.4 ) | tar xf - - echo 2.2.4 >libtool-2.2.4/.tarball-version - echo 3070 > libtool-2.2.4/.serial - -$(SAGE_LOCAL)/libtool-2.2.4: libtool-2.2.4/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.59 $(SAGE_LOCAL)/automake-1.9.6 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.59 ; \ - export AUTOMAKE_VERSION=1.9.6 ; \ - cd libtool-2.2.4 && bash -c 'set -e; source bootstrap' && \ - ./configure --prefix="$(SAGE_LOCAL)/libtool-2.2.4" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf libtool-2.2.4/* - -# Extract sources from git repository serially -libtool-2.2.6/.tarball-version: libtool-2.2.4/.tarball-version - ( cd $(SRC)/libtool && git archive --format=tar --prefix=libtool-2.2.6/ v2.2.6 ) | tar xf - - echo 2.2.6 >libtool-2.2.6/.tarball-version - echo 3117 > libtool-2.2.6/.serial - -$(SAGE_LOCAL)/libtool-2.2.6: libtool-2.2.6/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.60 $(SAGE_LOCAL)/automake-1.10.1 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.60 ; \ - export AUTOMAKE_VERSION=1.10.1 ; \ - cd libtool-2.2.6 && bash -c 'set -e; source bootstrap' && \ - ./configure --prefix="$(SAGE_LOCAL)/libtool-2.2.6" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf libtool-2.2.6/* - -# Extract sources from git repository serially -libtool-2.2.6b/.tarball-version: libtool-2.2.6/.tarball-version - ( cd $(SRC)/libtool && git archive --format=tar --prefix=libtool-2.2.6b/ v2.2.6b ) | tar xf - - echo 2.2.6b >libtool-2.2.6b/.tarball-version - echo 3123 > libtool-2.2.6b/.serial - -$(SAGE_LOCAL)/libtool-2.2.6b: libtool-2.2.6b/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/autoconf-2.60 $(SAGE_LOCAL)/automake-1.10.1 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.60 ; \ - export AUTOMAKE_VERSION=1.10.1 ; \ - cd libtool-2.2.6b && bash -c 'set -e; source bootstrap' && \ - ./configure --prefix="$(SAGE_LOCAL)/libtool-2.2.6b" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf libtool-2.2.6b/* - -# Extract sources from git repository serially -libtool-2.2.8/.tarball-version: libtool-2.2.6b/.tarball-version - ( cd $(SRC)/libtool && git archive --format=tar --prefix=libtool-2.2.8/ v2.2.8 ) | tar xf - - echo 2.2.8 >libtool-2.2.8/.tarball-version - echo 3328 > libtool-2.2.8/.serial - -$(SAGE_LOCAL)/libtool-2.2.8: libtool-2.2.8/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man $(SAGE_LOCAL)/autoconf-2.62 $(SAGE_LOCAL)/automake-1.10.1 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.62 ; \ - export AUTOMAKE_VERSION=1.10.1 ; \ - cd libtool-2.2.8 && bash -c 'set -e; source bootstrap' && \ - ./configure --prefix="$(SAGE_LOCAL)/libtool-2.2.8" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf libtool-2.2.8/* - -# Extract sources from git repository serially -libtool-2.2.10/.tarball-version: libtool-2.2.8/.tarball-version - ( cd $(SRC)/libtool && git archive --format=tar --prefix=libtool-2.2.10/ v2.2.10 ) | tar xf - - echo 2.2.10 >libtool-2.2.10/.tarball-version - echo 3349 > libtool-2.2.10/.serial - -$(SAGE_LOCAL)/libtool-2.2.10: libtool-2.2.10/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man $(SAGE_LOCAL)/autoconf-2.62 $(SAGE_LOCAL)/automake-1.10.1 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.62 ; \ - export AUTOMAKE_VERSION=1.10.1 ; \ - cd libtool-2.2.10 && bash -c 'set -e; source bootstrap' && \ - ./configure --prefix="$(SAGE_LOCAL)/libtool-2.2.10" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf libtool-2.2.10/* - -# Extract sources from git repository serially -libtool-2.4/.tarball-version: libtool-2.2.10/.tarball-version - ( cd $(SRC)/libtool && git archive --format=tar --prefix=libtool-2.4/ v2.4 ) | tar xf - - echo 2.4 >libtool-2.4/.tarball-version - echo 3560 > libtool-2.4/.serial - -$(SAGE_LOCAL)/libtool-2.4: libtool-2.4/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man $(SAGE_LOCAL)/autoconf-2.62 $(SAGE_LOCAL)/automake-1.11.1 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.62 ; \ - export AUTOMAKE_VERSION=1.11.1 ; \ - cd libtool-2.4 && bash -c 'set -e; source bootstrap' && \ - ./configure --prefix="$(SAGE_LOCAL)/libtool-2.4" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf libtool-2.4/* - -# Extract sources from git repository serially -libtool-2.4.2/.tarball-version: libtool-2.4/.tarball-version - ( cd $(SRC)/libtool && git archive --format=tar --prefix=libtool-2.4.2/ v2.4.2 ) | tar xf - - echo 2.4.2 >libtool-2.4.2/.tarball-version - echo 3620 > libtool-2.4.2/.serial - -$(SAGE_LOCAL)/libtool-2.4.2: libtool-2.4.2/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man $(SAGE_LOCAL)/autoconf-2.62 $(SAGE_LOCAL)/automake-1.11.1 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.62 ; \ - export AUTOMAKE_VERSION=1.11.1 ; \ - cd libtool-2.4.2 && bash -c 'set -e; source bootstrap' && \ - ./configure --prefix="$(SAGE_LOCAL)/libtool-2.4.2" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf libtool-2.4.2/* - -# Extract sources from git repository serially -libtool-2.4.3/.tarball-version: libtool-2.4.2/.tarball-version - ( cd $(SRC)/libtool && git archive --format=tar --prefix=libtool-2.4.3/ v2.4.3 ) | tar xf - - echo 2.4.3 >libtool-2.4.3/.tarball-version - echo 4105 > libtool-2.4.3/.serial - -$(SAGE_LOCAL)/libtool-2.4.3: libtool-2.4.3/.tarball-version $(SAGE_LOCAL)/bin/m4 $(SAGE_LOCAL)/bin/makeinfo $(SAGE_LOCAL)/bin/help2man $(SAGE_LOCAL)/autoconf-2.62 $(SAGE_LOCAL)/automake-1.11.1 - export MAKE='$(MAKE) -j1' ; \ - export AUTOCONF_VERSION=2.62 ; \ - export AUTOMAKE_VERSION=1.11.1 ; \ - cd libtool-2.4.3 && bash bootstrap --skip-git --skip-po --gnulib-srcdir=../../src/gnulib && \ - ./configure --prefix="$(SAGE_LOCAL)/libtool-2.4.3" && \ - $$MAKE && $$MAKE install - # Remove all files except for the .* files - [ "$$SAGE_KEEP_BUILT_SPKGS" = yes ] || rm -rf libtool-2.4.3/* - -libtool-all: $(SAGE_LOCAL)/libtool-1.5.20 $(SAGE_LOCAL)/libtool-1.5.22 $(SAGE_LOCAL)/libtool-1.5.24 $(SAGE_LOCAL)/libtool-1.5.26 $(SAGE_LOCAL)/libtool-2.2.4 $(SAGE_LOCAL)/libtool-2.2.6 $(SAGE_LOCAL)/libtool-2.2.6b $(SAGE_LOCAL)/libtool-2.2.8 $(SAGE_LOCAL)/libtool-2.2.10 $(SAGE_LOCAL)/libtool-2.4 $(SAGE_LOCAL)/libtool-2.4.2 $(SAGE_LOCAL)/libtool-2.4.3 - -######################################################################## - diff --git a/build/pkgs/autotools/SPKG.rst b/build/pkgs/autotools/SPKG.rst deleted file mode 100644 index 240889f2151..00000000000 --- a/build/pkgs/autotools/SPKG.rst +++ /dev/null @@ -1,76 +0,0 @@ -autotools -========= - -Description ------------ - -This package contains a recent version of Texinfo, GNU m4, and help2man. -It contains the git repository of autoconf, automake and libtool. - -For the latter 3 packages (commonly referred to as "autotools"), many -different versions are installed, by checking out the versions from the -git repo and building/installing them separately. Since the complete git -repository is shipped in the spkg, this does not require internet -access. - -For Texinfo, m4 and help2man, just one version is installed. These are -prerequisites for autotools. Moreover, Texinfo is often needed for -bootstrapping packages. Even though m4 is already a prerequisite of -Sage, autoconf requires an up-to-date version of GNU m4. - -The package makes wrapper scripts in $SAGE_LOCAL/bin for the various -autotools, which call the "correct" version. This means that, if a file -"configure" already exists in the current directory, the same autoconf -version is run which created the original file. Otherwise, the latest -version is run. The goal of all this is to make it easier to patch -configure.ac or Makefile.am files inside a spkg. By using the same -version of autotools as originally used, the patch files should be -relatively small. The environment variables AUTOCONF_VERSION, -AUTOMAKE_VERSION and LIBTOOL_VERSION can be used to override the chosen -version. - -License -------- - -GNU General Public License version 3 or later. - - -Upstream Contact ----------------- - -- http://www.gnu.org/software/texinfo/ -- http://www.gnu.org/software/m4/ -- http://www.gnu.org/software/help2man/ -- http://www.gnu.org/software/autoconf/ -- http://www.gnu.org/software/automake/ -- http://www.gnu.org/software/libtool/ - -Dependencies ------------- - -To install the package: - -- Perl -- Git - -To update the package: - -- Sage with autotools package installed -- Internet access - - -Special Update/Build Instructions ---------------------------------- - -The file spkg-src can be used to automatically create the upstream -tarball from the git repositories. This obviously requires internet -access. - -The file version-list defines the list of versions installed by this -spkg. If you edit this, you must update Makefile.build using the -spkg-write-makefile script. After optionally updating the git repos -using spkg-src, you need to run - - ./spkg-write-makefile >Makefile.build - -This must be run in a Sage shell, with the autotools spkg installed. diff --git a/build/pkgs/autotools/autofoo b/build/pkgs/autotools/autofoo deleted file mode 100644 index 485c4a02796..00000000000 --- a/build/pkgs/autotools/autofoo +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash - -# Script to automatically call the "right" version of @AUTOFOO@ -# installed within Sage. We read the @AUTOFOO@ output file(s) to -# determine the version from that file. Otherwise, we simply run the -# latest version. In all cases, the version can be overridden by the -# @AUTOVAR@ environment variable. - -v="$@AUTOVAR@" - -if [ -z "$v" ]; then - for v_file in @AUTOFILES@; do - v=`exec 2>/dev/null; sed -n <$v_file \ - 's/^\(.*generated.*@AUTOFOO@\( *version\)*\|version=\)[ "]*\([0-9][-0-9a-z.]*\)/\3=/i; T; s/[.]*=.*//; p; q;'` - if [ -n "$v" ]; then break; fi - done -fi - -# Default version -if [ -z "$v" ]; then - v=@DEFAULT_VERSION@ -fi - -prog=`basename "$0"` -exec "$SAGE_LOCAL/@AUTOFOO@-$v/bin/$prog" "$@" diff --git a/build/pkgs/autotools/checksums.ini b/build/pkgs/autotools/checksums.ini deleted file mode 100644 index 63449e97680..00000000000 --- a/build/pkgs/autotools/checksums.ini +++ /dev/null @@ -1,4 +0,0 @@ -tarball=autotools-VERSION.tar.bz2 -sha1=55943c621770cd7309ad12ce76c631893f7c66c8 -md5=f9742a0f469197a5b80dfa301b79c57d -cksum=311232283 diff --git a/build/pkgs/autotools/dependencies b/build/pkgs/autotools/dependencies deleted file mode 100644 index 3b812ffa6b6..00000000000 --- a/build/pkgs/autotools/dependencies +++ /dev/null @@ -1,5 +0,0 @@ -ncurses git xz - ----------- -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/autotools/install-info.exe.manifest b/build/pkgs/autotools/install-info.exe.manifest deleted file mode 100755 index aaaa2c391f8..00000000000 --- a/build/pkgs/autotools/install-info.exe.manifest +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - diff --git a/build/pkgs/autotools/latest_version b/build/pkgs/autotools/latest_version deleted file mode 100755 index f2ce2558cd7..00000000000 --- a/build/pkgs/autotools/latest_version +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env sage-system-python -# -# Read a whitespace-separated list of version numbers on stdin -# and output the latest version. -# -# A version number is a list of numbers separated by dots, followed -# by an optional alphanumeric string (there may or may not be a dot -# before this string). The numbers must not have leading zeros. -# Typical examples: "5.4.3a" or "1.10.rc0" -# -# Any word in the input which does not start with a digit, is ignored. -# Any word which does start with a digit, but is not of the required -# form, is an error. Trailing alphanumeric strings are chopped off and -# ignored; they don't appear in the output. -# -# AUTHOR: Jeroen Demeyer (2012-10-01) -# - -# Make this script compatible with Python 3. -from __future__ import print_function - - -def version_to_tuple(v): - """ - Convert a version number like "5.4.3a" to a tuple (5,4,3). - """ - n = "" # Current number as string - t = [] # List of numbers - for c in v: - if c.isdigit(): - n += c - elif c == ".": - if len(n) == 0: - raise ValueError("Empty number in version string '{}'".format(v)) - if n[0] == '0' and len(n) >= 2: - raise ValueError("Leading zeros not allowed in version string '{}'".format(v)) - t.append(int(n)) - n = "" - elif c.isalpha(): - break - else: - raise ValueError("Illegal character '{}' in version string '{}'".format(c,v)) - if len(n) > 0: - t.append(int(n)) - return tuple(t) - -def tuple_to_version(t): - """ - Convert a tuple like (5,4,3) to a version number "5.4.3" - """ - return str.join(".", [str(x) for x in t]) - - -import sys -L = sys.stdin.read().split() - -debug = ' '.join(L) - -L = [version_to_tuple(s) for s in L if len(s) > 0 and s[0].isdigit()] -if len(L) == 0: - sys.exit(0) - -L = sorted(L, reverse=True) -ver = tuple_to_version(L[0]) -debug = debug + ' => ' + ver - -print(ver) -print(debug, file=sys.stderr) diff --git a/build/pkgs/autotools/package-version.txt b/build/pkgs/autotools/package-version.txt deleted file mode 100644 index 0e03b2d382b..00000000000 --- a/build/pkgs/autotools/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -20141105.p0 diff --git a/build/pkgs/autotools/patches/texinfo-libtinfo.patch b/build/pkgs/autotools/patches/texinfo-libtinfo.patch deleted file mode 100644 index 74113f6c2e4..00000000000 --- a/build/pkgs/autotools/patches/texinfo-libtinfo.patch +++ /dev/null @@ -1,15 +0,0 @@ -* Our ncurses package is built using configure option --with-termlib, which causes tgetent and friends to be put into the separate library libtinfo, not libncurses. -* The ancient texinfo 4.13 that is used by our autotools package (with comment "texinfo 5.x breaks building old versions of autotools...") does not know about libtinfo. - -diff -r -u texinfo-4.13.orig/configure texinfo-4.13/configure ---- src.orig/texinfo-4.13/configure 2008-09-18 11:46:26.000000000 -0700 -+++ src/texinfo-4.13/configure 2016-10-18 00:04:15.000000000 -0700 -@@ -17477,7 +17477,7 @@ - # rather ncurses. So we check for it. - TERMLIBS= - # Check for termlib before termcap because Solaris termcap needs libucb. --TERMLIB_VARIANTS="ncurses curses termlib termcap terminfo" -+TERMLIB_VARIANTS="ncurses tinfo curses termlib termcap terminfo" - for termlib in ${TERMLIB_VARIANTS}; do - as_ac_Lib=`$as_echo "ac_cv_lib_${termlib}''_tgetent" | $as_tr_sh` - { $as_echo "$as_me:$LINENO: checking for tgetent in -l${termlib}" >&5 diff --git a/build/pkgs/autotools/spkg-install.in b/build/pkgs/autotools/spkg-install.in deleted file mode 100644 index 567bfa43610..00000000000 --- a/build/pkgs/autotools/spkg-install.in +++ /dev/null @@ -1,120 +0,0 @@ -set -e - -if [ -z "$SAGE_LOCAL" ]; then - echo >&2 "SAGE_LOCAL undefined ... exiting" - echo >&2 "Maybe run 'sage --sh'?" - exit 1 -fi - -# Check that git is installed -if ! git --version &>/dev/null; then - echo >&2 "git is not installed, try running" - echo >&2 " sage -i git" - exit 3 -fi - -# Create an empty git repo here, otherwise the autotools installers -# get confused (they try to take version info from git if possible) -git init - - -SRC=`pwd`/src -BUILD=`pwd`/build - -# Mac OS X 10.11.5 installs GNU m4 1.4.6 as both "m4" and "gm4". -# This is too old to bootstrap libtool 1.4.3. -# The configure script prefers "gm4" to "m4" and thus does not -# find the m4 from SageMath. -# The following environment variable makes sure we use the m4 from -# SageMath. See trac #21047. -export M4="$SAGE_LOCAL/bin/m4" - -cd "$SRC" - -######################################################################## -# Remove old installed versions -######################################################################## - -cd "$SAGE_LOCAL" -rm -rf autoconf-* automake-* libtool-* -cd bin -rm -f m4 makeinfo help2man autoconf autoheader autom4te autoreconf \ - autoscan automake aclocal libtool libtoolize - -######################################################################## -# Install wrapper scripts in $SAGE_LOCAL/bin -######################################################################## - -# Determine the default versions of the various autotools, which is the -# last version in the list from version-list. -source "$SRC/../version-list" -for x in $autoconf_versions; do autoconf_latest=$x ; done -for x in $automake_versions; do automake_latest=$x ; done -for x in $libtool_versions; do libtool_latest=$x ; done - -# We install scripts for autoconf,... based on the generic "autofoo" script -cd "$SAGE_LOCAL/bin" -sed <"$SRC/../autofoo" >autoconf \ - "s/@AUTOFOO@/autoconf/; s/@AUTOFILES@/configure/; s/@AUTOVAR@/AUTOCONF_VERSION/; s/@DEFAULT_VERSION@/${autoconf_latest}/" -sed <"$SRC/../autofoo" >automake \ - "s/@AUTOFOO@/automake/; s/@AUTOFILES@/Makefile.in/; s/@AUTOVAR@/AUTOMAKE_VERSION/; s/@DEFAULT_VERSION@/${automake_latest}/" -sed <"$SRC/../autofoo" >libtool \ - "s/@AUTOFOO@/libtool/; s/@AUTOFILES@/ltmain.sh/; s/@AUTOVAR@/LIBTOOL_VERSION/; s/@DEFAULT_VERSION@/${libtool_latest}/" - -# Correct permissions -for prog in autoconf automake libtool; do - chmod 0755 $prog -done - -# Make symlinks -for prog in autoheader autom4te autoreconf autoscan; do - ln -s autoconf $prog -done -ln -s automake aclocal -ln -s libtool libtoolize - -# Make symlinks for some non-exact version matches -cd "$SAGE_LOCAL" -ln -s autoconf-2.13.rc1 autoconf-2.4 -ln -s autoconf-2.13.rc1 autoconf-2.13 -ln -s autoconf-2.60 autoconf-2.59a -ln -s autoconf-2.60 autoconf-2.59c -ln -s libtool-2.2.4 libtool-2.2.3a -ln -s libtool-2.2.8 libtool-2.2.7a - -######################################################################## -# Copy the Makefile and build everything -######################################################################## - -mkdir -p "$BUILD" -cd "$BUILD" -( - echo "SRC = $SRC" - echo "SAGE_LOCAL = $SAGE_LOCAL" - # Force the use of bash as shell (/bin/sh on OpenSolaris has - # problems with very long command lines used in some make rules). - echo "SHELL = bash" - echo - cat "$SRC/../Makefile.build" -) >Makefile - -$MAKE - -# Install symlinks bin/aclocal-AM_API_VERSION and bin/automake-AM_API_VERSION. -# (am__api_version). These are required for autoreconf to work (Trac #21047). -cd "$SAGE_LOCAL"/bin -for x in $automake_versions; do - ln -sf ../automake-$x/bin/automake-* ../automake-$x/bin/aclocal-* . -done - -# Some older versions of automake don't create this directory at install time -# because there aren't any files in it by default; however aclocal crashes if -# the directory is missing; https://trac.sagemath.org/ticket/21526 -for x in $automake_versions; do - aclocal_system_dir="$SAGE_LOCAL/automake-$x/share/aclocal" - if [ ! -d "$aclocal_system_dir" ]; then - mkdir -p "$aclocal_system_dir" - # Place a dummy file so that the directory at least isn't empty - touch "$aclocal_system_dir/README" - fi -done diff --git a/build/pkgs/autotools/spkg-src b/build/pkgs/autotools/spkg-src deleted file mode 100755 index 233e7b4a745..00000000000 --- a/build/pkgs/autotools/spkg-src +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env bash - -set -e - -if [ -z "$SAGE_ROOT" ]; then - echo >&2 "SAGE_ROOT undefined ... exiting" - echo >&2 "Maybe run 'sage --sh'?" - exit 1 -fi - -cd "$SAGE_ROOT" - -TARGET=autotools-`cat build/pkgs/autotools/package-version.txt` - -rm -rf upstream/$TARGET -mkdir -p upstream/$TARGET -cd upstream/$TARGET - - -echo "Downloading m4 sources..." -sage-download-file http://ftp.gnu.org/gnu/m4/m4-1.4.17.tar.xz | tar xJf - - -echo "Downloading help2man sources..." -sage-download-file http://ftp.gnu.org/gnu/help2man/help2man-1.46.4.tar.xz | tar xJf - - -echo "Downloading texinfo sources..." -# texinfo 5.x breaks building old versions of autotools... -sage-download-file http://ftp.gnu.org/gnu/texinfo/texinfo-4.13.tar.lzma | tar xJf - - -git clone git://git.sv.gnu.org/gnulib -git clone --no-checkout git://git.sv.gnu.org/autoconf -git clone --no-checkout git://git.sv.gnu.org/automake -git clone --no-checkout git://git.sv.gnu.org/libtool - - -cd "$SAGE_ROOT/upstream" -tar cjf $TARGET.tar.bz2 $TARGET -rm -rf $TARGET - -echo "New autotools tarball is ready in $SAGE_ROOT/upstream/$TARGET.tar.bz2" diff --git a/build/pkgs/autotools/spkg-write-makefile b/build/pkgs/autotools/spkg-write-makefile deleted file mode 100755 index 2e2189a3466..00000000000 --- a/build/pkgs/autotools/spkg-write-makefile +++ /dev/null @@ -1,227 +0,0 @@ -#!/usr/bin/env bash -# -# Write a Makefile for the autotools spkg. This actually requires a -# Sage with autotools installed, so run this from within a Sage shell. -# This script also requires git. -# -# Typical usage: -# ./spkg-write-makefile >Makefile.build -# - -set -e - -if [ -z "$SAGE_ROOT" ]; then - echo >&2 "SAGE_ROOT undefined ... exiting" - echo >&2 "Maybe run 'sage --sh'?" - exit 1 -fi - -# Sanity check that AUTOCONF_VERSION and AUTOMAKE_VERSION works -if ! env "AUTOCONF_VERSION=2.62" autoconf --version | grep >/dev/null '2[.]62'; then - echo >&2 "The environment variable AUTOCONF_VERSION does not seem to work." - echo >&2 "Make sure you are running $0 within a Sage shell" - echo >&2 "with the autotools spkg installed." - exit 3 -fi -if ! env "AUTOMAKE_VERSION=1.9.6" aclocal --version | grep >/dev/null '1[.]9[.]6'; then - echo >&2 "The environment variable AUTOMAKE_VERSION does not seem to work." - echo >&2 "Make sure you are running $0 within a Sage shell" - echo >&2 "with the autotools spkg installed." - exit 3 -fi -if ! env "LIBTOOL_VERSION=1.5.26" libtool --version | grep >/dev/null '1[.]5[.]26'; then - echo >&2 "The environment variable LIBTOOL_VERSION does not seem to work." - echo >&2 "Make sure you are running $0 within a Sage shell" - echo >&2 "with the autotools spkg installed." - exit 3 -fi - -export PATH="$SAGE_ROOT/build/pkgs/autotools:$PATH" - - -# Read versions -source version-list - -# Extract upstream autotools tarball -cd "$SAGE_ROOT" -PKG=autotools-`cat build/pkgs/autotools/package-version.txt` -mkdir -p "$SAGE_LOCAL/tmp/sage" -cd "$SAGE_LOCAL/tmp/sage" -tar xjf "$SAGE_ROOT/upstream/$PKG.tar.bz2" -cd $PKG - -cat <&2 "Processing $p-$v" - cd $p - - # Find out the correct tag for version $v - tag=`git tag -l | grep -i -x -e "v$v" -e "release-$v" -e "$p-$v" | head -1` - if [ -z "$tag" ]; then - echo >&2 "Cannot find tag for $p-$v" - exit 3 - fi - - # Checkout the version given by the tag (and remove all garbage) - git checkout -f $tag - git clean -f -d -x -q - - deps="\$(SAGE_LOCAL)/bin/m4 \$(SAGE_LOCAL)/bin/makeinfo" - ac_ver= - am_ver= - if cat configure.* | grep help2man >/dev/null; then - deps="$deps \$(SAGE_LOCAL)/bin/help2man" - fi - if [ -f configure.ac ]; then - # Minimum required version of Automake - if [ ! -f configure ]; then - # libtool-2.4.3 requires some gnulib files - if [ -d gnulib ]; then - cp -a ../gnulib/build-aux . - fi - # Run aclocal, such that AM_INIT_AUTOMAKE is available. - if [ -d m4 ]; then - aclocal -I m4 - else - aclocal - fi - # Require at least version 1.9.6, a reasonable default. - am_ver=`( echo 1.9.6; autoconf --trace='AM_INIT_AUTOMAKE:$1' configure.ac ) | latest_version` - # Run the *correct* version of aclocal, such that we do - # not introduce unneeded AC_PREREQ() definitions. - if [ -d m4 ]; then - env "AUTOMAKE_VERSION=$am_ver" aclocal -I m4 - else - env "AUTOMAKE_VERSION=$am_ver" aclocal - fi - fi - - # Minimum required version of Autoconf: always consider - # AC_PREREQ for Automake, even if "configure" exists. - if [ ! -f configure ] || [ $p = automake ]; then - # Require at least version 2.59, a reasonable default. - ac_ver=`( echo 2.59; autoconf --trace='AC_PREREQ:$1' configure.ac ) | latest_version` - fi - - # Automake 1.10 thinks it only needs autoconf 2.59, when in fact it needs 2.60. Fix it up. - if [ $p = automake ] && [ $v = 1.10 ]; then - ac_ver=2.60 - fi - - # Minimum required version of libtool. - # Empty by default. - lt_ver=`( autoconf --trace='LT_PREREQ:$1' configure.ac ) | latest_version` - fi - if [ -n "$ac_ver" ]; then - deps="$deps \$(SAGE_LOCAL)/autoconf-$ac_ver" - fi - if [ -n "$am_ver" ]; then - deps="$deps \$(SAGE_LOCAL)/automake-$am_ver" - fi - if [ -n "$lt_ver" ]; then - deps="$deps \$(SAGE_LOCAL)/libtool-$lt_ver" - fi - - # Figure out how to bootstrap - if [ -f configure ]; then - bootstrap= - elif [ -d gnulib ]; then - bootstrap="bash bootstrap --skip-git --skip-po --gnulib-srcdir=../../src/gnulib && " - elif [ -f bootstrap.sh ]; then - bootstrap="bash -c 'set -e; source bootstrap.sh' && " - elif [ -f bootstrap ]; then - bootstrap="bash -c 'set -e; source bootstrap' && " - else - bootstrap="autoreconf -i -I m4 && " - fi - - if [ -f autoheader.sh ]; then - # Work around Autoconf bootstrap bug - bootstrap="${bootstrap}touch autoupdate.sh && " - fi - - # Write make rules - echo "# Extract sources from git repository serially" - echo "$p-$v/.tarball-version: $prevextract" - echo -e "\t( cd \$(SRC)/$p && git archive --format=tar --prefix=$p-$v/ $tag ) | tar xf -" - echo -e "\techo $v >$p-$v/.tarball-version" - if [ $p = libtool -a ! -f .serial ] ; then - # The file .serial would be generated at "make dist" time. It is used in ltversion.m4. - # If .serial is missing, ltmversion.m4 will be malformed, causing the following warning - # when the user uses autoreconf. - # m4/ltversion.m4:12: warning: ill-formed serial number 'ltversion.m4', - # expecting a version string with only digits and dots - # See Trac #21047. - # Since we don't do "make dist" but rather build from a repository check-out, we have to - # supply the .serial file ourselves. The following recipe is from libtool's Makefile.am. - echo -e "\techo $( git log --pretty=oneline | wc -l | sed 's|[\t ]||g ' ) > $p-$v/.serial" - fi - echo - - echo "\$(SAGE_LOCAL)/$p-$v: $p-$v/.tarball-version $deps" - echo -e "\texport MAKE='\$(MAKE) -j1' ; \\\\" - [ -z "$lt_ver" ] || echo -e "\texport LIBTOOL_VERSION=$lt_ver ; \\\\" - [ -z "$ac_ver" ] || echo -e "\texport AUTOCONF_VERSION=$ac_ver ; \\\\" - [ -z "$am_ver" ] || echo -e "\texport AUTOMAKE_VERSION=$am_ver ; \\\\" - echo -e "\tcd $p-$v && ${bootstrap}\\\\" - echo -e "\t ./configure --prefix=\"\$(SAGE_LOCAL)/$p-$v\" && \\\\" - echo -e "\t \$\$MAKE && \$\$MAKE install" - echo -e "\t# Remove all files except for the .* files" - echo -e "\t[ \"\$\$SAGE_KEEP_BUILT_SPKGS\" = yes ] || rm -rf $p-$v/*" - echo - - prevextract="$p-$v/.tarball-version" - all="$all \$(SAGE_LOCAL)/$p-$v" - - cd .. # Back to upstream source directory - done - echo "$all" - echo - echo "########################################################################" - echo -} - -write_make_rules autoconf $autoconf_versions -write_make_rules automake $automake_versions -write_make_rules libtool $libtool_versions - -cd "$SAGE_LOCAL/tmp/sage" -rm -rf $PKG diff --git a/build/pkgs/autotools/type b/build/pkgs/autotools/type deleted file mode 100644 index 9839eb20815..00000000000 --- a/build/pkgs/autotools/type +++ /dev/null @@ -1 +0,0 @@ -experimental diff --git a/build/pkgs/autotools/version-list b/build/pkgs/autotools/version-list deleted file mode 100644 index c4a2f2ee385..00000000000 --- a/build/pkgs/autotools/version-list +++ /dev/null @@ -1,23 +0,0 @@ -# This file defines the versions installed by this spkg. If you edit -# this, re-create Makefile.build using -# -# ./spkg-write-makefile >Makefile.build -# -# The order of the versions is irrelevant, except that the last version -# is the one which will be used by default. -# - -autoconf_versions=" - 2.13.rc1 2.57 2.58 2.59 2.60 2.61 2.62 2.63 2.64 2.65 2.66 2.67 - 2.68 2.69" - -automake_versions=" - 1.9 1.9.1 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.10 1.10.1 1.10.2 1.10.3 - 1.11 1.11.1 1.11.2 1.11.3 1.11.4 1.11.5 1.11.6 1.12 1.12.1 1.12.2 - 1.12.3 1.12.4 1.12.5 1.12.6 1.13 1.13.1 1.13.2 1.13.3 1.13.4 - 1.14 1.14.1" - -libtool_versions=" - 1.5.20 1.5.22 1.5.24 1.5.26 - 2.2.4 2.2.6 2.2.6b 2.2.8 2.2.10 - 2.4 2.4.2 2.4.3" From eb03b0e5b97af048f1562af83537abe4c2e47376 Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Mon, 1 Jun 2020 20:21:18 -0700 Subject: [PATCH 205/300] Allocate m as defaultdict rather than array --- src/sage/modular/hypergeometric_misc.pxd | 2 +- src/sage/modular/hypergeometric_misc.pyx | 2 +- src/sage/modular/hypergeometric_motive.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/modular/hypergeometric_misc.pxd b/src/sage/modular/hypergeometric_misc.pxd index b601a29db24..9d2d48875ce 100644 --- a/src/sage/modular/hypergeometric_misc.pxd +++ b/src/sage/modular/hypergeometric_misc.pxd @@ -1,4 +1,4 @@ from cpython cimport array -cpdef hgm_coeffs(long long p, int f, int prec, gamma, array.array m, int D, +cpdef hgm_coeffs(long long p, int f, int prec, gamma, m, int D, gtable, int gtable_prec, bint use_longs) diff --git a/src/sage/modular/hypergeometric_misc.pyx b/src/sage/modular/hypergeometric_misc.pyx index df44371d263..eee3053417d 100644 --- a/src/sage/modular/hypergeometric_misc.pyx +++ b/src/sage/modular/hypergeometric_misc.pyx @@ -2,7 +2,7 @@ Some utility routines for the hypergeometric motives package that benefit significantly from Cythonization. """ -cpdef hgm_coeffs(long long p, int f, int prec, gamma, array.array m, int D, +cpdef hgm_coeffs(long long p, int f, int prec, gamma, m, int D, gtable, int gtable_prec, bint use_longs): r""" Compute coefficients for the hypergeometric trace formula. diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index 169f211209a..78ea2c4d8dd 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -1233,7 +1233,7 @@ def padic_H_value(self, p, f, t, prec=None, cache_p=False): if q > 2 ** 31: raise ValueError("p^f cannot exceed 2^31") - m = array.array('i', [0]) * int(q - 1) + m = defaultdict(int) for b in beta: u = b * (q - 1) if u.is_integer(): m[u] += 1 From a02a614ca3d98e4b9e76cf21d23a8efe96d78b98 Mon Sep 17 00:00:00 2001 From: vipul79321 Date: Tue, 2 Jun 2020 10:55:42 +0530 Subject: [PATCH 206/300] minor changes and improved consistency --- src/sage/graphs/graph.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 42fdb1ab79b..81407b84877 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -5344,7 +5344,7 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None, by_weight = True elif by_weight: def weight_function(e): - return e[2] + return e[2] if e[2] else 1 if algorithm is None: if dist_dict is not None: @@ -5438,8 +5438,8 @@ def radius(self, by_weight=False, algorithm='DHV', weight_function=None, - ``algorithm`` -- string (default: ``'DHV'``). - - ``'DHV'`` - Radius computation is done using algorithm proposed - in [Dragan2018]_. For more information see method + - ``'DHV'`` - Radius computation is done using the algorithm + proposed in [Dragan2018]_. For more information see method :func:`sage.graphs.distances_all_pairs.radius_DHV` and :func:`sage.graphs.base.boost_graph.radius_DHV`. From d9c90d1dbe213ce1711f5f2b2aef68cf313f60ba Mon Sep 17 00:00:00 2001 From: dcoudert Date: Tue, 2 Jun 2020 09:15:22 +0200 Subject: [PATCH 207/300] trac #29715: fix documentation --- src/sage/graphs/graph.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 81407b84877..d639d1671d1 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -5438,13 +5438,12 @@ def radius(self, by_weight=False, algorithm='DHV', weight_function=None, - ``algorithm`` -- string (default: ``'DHV'``). - - ``'DHV'`` - Radius computation is done using the algorithm - proposed in [Dragan2018]_. For more information see method - :func:`sage.graphs.distances_all_pairs.radius_DHV` and - :func:`sage.graphs.base.boost_graph.radius_DHV`. + - ``'DHV'`` - Radius computation is done using the algorithm proposed + in [Dragan2018]_. For more information see method + :func:`sage.graphs.distances_all_pairs.radius_DHV` and + :func:`sage.graphs.base.boost_graph.radius_DHV`. - - see method - :meth:`eccentricity` for the list of remaining algorithms + - see method :meth:`eccentricity` for the list of remaining algorithms - ``weight_function`` -- function (default: ``None``); a function that takes as input an edge ``(u, v, l)`` and outputs its weight. If not From d8a1c50f2044b42edd8f136bc89168a1eb858b6c Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 2 Jun 2020 17:21:23 +1000 Subject: [PATCH 208/300] Fixing doctests and making _vector_ and from_vector methods more consistent. --- ...ite_dimensional_lie_algebras_with_basis.py | 4 +-- ...ite_dimensional_lie_algebras_with_basis.py | 14 ++++---- .../finite_dimensional_modules_with_basis.py | 15 ++++----- src/sage/categories/lie_algebras.py | 4 +-- .../categories/lie_algebras_with_basis.py | 4 +-- src/sage/categories/modules_with_basis.py | 32 +++++++++---------- src/sage/combinat/free_module.py | 7 ++-- .../modules/with_basis/indexed_element.pyx | 7 ++-- 8 files changed, 46 insertions(+), 41 deletions(-) diff --git a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py index 5218f15acf6..c5719350a6e 100644 --- a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py @@ -281,7 +281,7 @@ def module(self): """ return self._M - def from_vector(self, v): + def from_vector(self, v, order=None): """ Return the element of ``self`` corresponding to the vector ``v`` in ``self.module()``. @@ -369,7 +369,7 @@ def lift(self): gens = UEA.gens() return UEA.sum(c * gens[i] for i, c in self.value.items()) - def to_vector(self): + def to_vector(self, order=None): """ Return ``self`` as a vector in ``self.parent().module()``. diff --git a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py index 31d7479e511..d4edc0bd3c0 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -221,7 +221,7 @@ def _dense_free_module(self, R=None): module = _dense_free_module - def from_vector(self, v): + def from_vector(self, v, order=None): """ Return the element of ``self`` corresponding to the vector ``v`` in ``self.module()``. @@ -239,9 +239,10 @@ def from_vector(self, v): sage: parent(u) is L True """ + if order is None: + order = self._basis_ordering B = self.basis() - return self.sum(v[i] * B[k] for i,k in enumerate(self._basis_ordering) - if v[i] != 0) + return self.sum(v[i] * B[k] for i,k in enumerate(order) if v[i] != 0) def killing_matrix(self, x, y): r""" @@ -1455,7 +1456,7 @@ def adjoint_matrix(self): # In #11111 (more or less) by using matrix of a morphi return matrix(self.base_ring(), [P.bracket(self, b).to_vector() for b in basis]) - def to_vector(self): + def to_vector(self, order=None): """ Return the vector in ``g.module()`` corresponding to the element ``self`` of ``g`` (where ``g`` is the parent of @@ -1495,8 +1496,9 @@ def to_vector(self): mc = self.monomial_coefficients(copy=False) M = self.parent().module() B = M.basis() - return M.sum(mc[k] * B[i] for i,k in enumerate(self.parent()._basis_ordering) - if k in mc) + if order is None: + order = self.parent()._basis_ordering + return M.sum(mc[k] * B[i] for i,k in enumerate(order) if k in mc) _vector_ = to_vector diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index e09c9b1f6e1..4696c2d424c 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -285,7 +285,7 @@ def from_vector(self, vector, order=None): order = range(self.dimension()) return self._from_dict({order[i]: c for i,c in vector.iteritems()}) - def echelon_form(self, elements, row_reduced=False, support_order=None): + def echelon_form(self, elements, row_reduced=False, order=None): r""" Return a basis in echelon form of the subspace spanned by a finite set of elements. @@ -295,6 +295,8 @@ def echelon_form(self, elements, row_reduced=False, support_order=None): - ``elements`` -- a list or finite iterable of elements of ``self`` - ``row_reduced`` -- (default: ``False``) whether to compute the basis for the row reduced echelon form + - ``order`` -- (optional) either something that can + be converted into a tuple or a key function OUTPUT: @@ -335,11 +337,10 @@ def echelon_form(self, elements, row_reduced=False, support_order=None): sage: C.echelon_form([x[0] - x[1], 2*x[1] - 2*x[2], x[0] - x[2]]) [x[0] - x[2], x[1] - x[2]] """ - order = self.get_order() - if support_order is not None: - self.set_order(self._support_order(support_order)) + if order is not None: + order = self._compute_support_order(order) from sage.matrix.constructor import matrix - mat = matrix(self.base_ring(), [g._vector_() for g in elements]) + mat = matrix(self.base_ring(), [g._vector_(order=order) for g in elements]) # Echelonizing a matrix over a field returned the rref if row_reduced and self.base_ring() not in Fields(): try: @@ -348,9 +349,7 @@ def echelon_form(self, elements, row_reduced=False, support_order=None): raise ValueError("unable to compute the row reduced echelon form") else: mat.echelonize() - ret = [self.from_vector(vec) for vec in mat if vec] - if support_order is not None: - self.set_order(order) + ret = [self.from_vector(vec, order=order) for vec in mat if vec] return ret class ElementMethods: diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index 9d8f09d0613..51408b3bd10 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): + def from_vector(self, v, order=None): """ Return the element of ``self`` corresponding to the vector ``v`` in ``self.module()``. @@ -842,7 +842,7 @@ def _bracket_(self, y): """ @abstract_method(optional=True) - def to_vector(self): + def to_vector(self, order=None): """ Return the vector in ``g.module()`` corresponding to the element ``self`` of ``g`` (where ``g`` is the parent of diff --git a/src/sage/categories/lie_algebras_with_basis.py b/src/sage/categories/lie_algebras_with_basis.py index f93830476ed..9cc23084381 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): + def from_vector(self, v, order=None): """ Return the element of ``self`` corresponding to the vector ``v`` in ``self.module()``. @@ -194,7 +194,7 @@ def term(ml, mr): return P.sum(cl * cr * term(ml, mr) for ml, cl in self for mr, cr in y) - def to_vector(self): + def to_vector(self, order=None): """ Return the vector in ``g.module()`` corresponding to the element ``self`` of ``g`` (where ``g`` is the parent of diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index d7233a723f0..ba8a1be9e0d 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -594,7 +594,7 @@ def _repr_(self): name = "Free module generated by {}".format(self.basis().keys()) return name + " over {}".format(self.base_ring()) - def _support_order(self, elements, support_order=None): + def _compute_support_order(self, elements, support_order=None): """ Return the support of a set of elements in ``self`` sorted in some order. @@ -612,11 +612,11 @@ def _support_order(self, elements, support_order=None): sage: V = CombinatorialFreeModule(QQ, range(10), prefix='x') sage: B = V.basis() sage: elts = [B[0] - 2*B[3], B[5] + 2*B[0], B[2], B[3], B[1] + B[2] + B[8]] - sage: V._support_order(elts) + sage: V._compute_support_order(elts) (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) - sage: V._support_order(elts, [1,2,0,4,3,5,9,8,7,6]) + sage: V._compute_support_order(elts, [1,2,0,4,3,5,9,8,7,6]) (1, 2, 0, 4, 3, 5, 9, 8, 7, 6) - sage: V._support_order(elts, lambda x: -x) + sage: V._compute_support_order(elts, lambda x: -x) (8, 5, 3, 2, 1, 0) An infinite dimensional module:: @@ -624,17 +624,17 @@ def _support_order(self, elements, support_order=None): sage: V = CombinatorialFreeModule(QQ, ZZ, prefix='z') sage: B = V.basis() sage: elts = [B[0] - 2*B[3], B[5] + 2*B[0], B[2], B[3], B[1] + B[2] + B[8]] - sage: V._support_order(elts) + sage: V._compute_support_order(elts) (0, 1, 2, 3, 5, 8) - sage: V._support_order(elts, [1,2,0,4,3,5,9,8,7,6]) + sage: V._compute_support_order(elts, [1,2,0,4,3,5,9,8,7,6]) (1, 2, 0, 4, 3, 5, 9, 8, 7, 6) - sage: V._support_order(elts, lambda x: -x) + sage: V._compute_support_order(elts, lambda x: -x) (8, 5, 3, 2, 1, 0) """ if support_order is None: try: support_order = self.get_order() - except (ValueError, TypeError, NotImplementedError): + except (ValueError, TypeError, NotImplementedError, AttributeError): support_order = set() for y in elements: support_order.update(y.support()) @@ -644,14 +644,14 @@ def _support_order(self, elements, support_order=None): pass try: support_order = tuple(support_order) - except (ValueError, TypeError, NotImplementedError): + except (ValueError, TypeError): support = set() for y in elements: support.update(y.support()) support_order = sorted(support, key=support_order) return tuple(support_order) - def echelon_form(self, elements, row_reduced=False, support_order=None): + def echelon_form(self, elements, row_reduced=False, order=None): r""" Return a basis in echelon form of the subspace spanned by a finite set of elements. @@ -661,7 +661,7 @@ def echelon_form(self, elements, row_reduced=False, support_order=None): - ``elements`` -- a list or finite iterable of elements of ``self`` - ``row_reduced`` -- (default: ``False``) whether to compute the basis for the row reduced echelon form - - ``support_order`` -- (optional) either something that can + - ``order`` -- (optional) either something that can be converted into a tuple or a key function OUTPUT: @@ -678,10 +678,10 @@ def echelon_form(self, elements, row_reduced=False, support_order=None): sage: C.echelon_form([z[0] - z[1], 2*z[1] - 2*z[2], z[0] - z[2]]) [z[0] - z[2], z[1] - z[2]] """ - support_order = self._support_order(elements, support_order) + order = self._compute_support_order(elements, order) from sage.matrix.constructor import matrix - mat = matrix(self.base_ring(), [[g[s] for s in support_order] for g in elements]) + mat = matrix(self.base_ring(), [[g[s] for s in order] for g in elements]) # Echelonizing a matrix over a field returned the rref if row_reduced and self.base_ring() not in Fields(): try: @@ -690,7 +690,7 @@ def echelon_form(self, elements, row_reduced=False, support_order=None): raise ValueError("unable to compute the row reduced echelon form") else: mat.echelonize() - return [self._from_dict({support_order[i]: c for i, c in enumerate(vec) if c}, + return [self._from_dict({order[i]: c for i, c in enumerate(vec) if c}, remove_zeros=False) for vec in mat if vec] @@ -860,9 +860,9 @@ def submodule(self, gens, check=True, already_echelonized=False, sage: TestSuite(Y).run() sage: TestSuite(center).run() """ - support_order = self._support_order(gens, support_order) + support_order = self._compute_support_order(gens, support_order) if not already_echelonized: - gens = self.echelon_form(gens, unitriangular, support_order=support_order) + gens = self.echelon_form(gens, unitriangular, order=support_order) from sage.modules.with_basis.subquotient import SubmoduleWithBasis return SubmoduleWithBasis(gens, ambient=self, diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index a7b316aeb3b..81ce0a9aa29 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -955,7 +955,7 @@ def _order_key(self, x): """ return self._rank_basis(x) - def from_vector(self, vector): + def from_vector(self, vector, order=None): """ Build an element of ``self`` from a (sparse) vector. @@ -970,8 +970,9 @@ def from_vector(self, vector): sage: a == b True """ - cc = self.get_order() - return self._from_dict({cc[index]: coeff for (index,coeff) in vector.items()}) + if order is None: + order = self.get_order() + return self._from_dict({order[index]: coeff for (index,coeff) in vector.items()}) def sum(self, iter_of_elements): """ diff --git a/src/sage/modules/with_basis/indexed_element.pyx b/src/sage/modules/with_basis/indexed_element.pyx index 94d57d67e2c..4026f1947b5 100644 --- a/src/sage/modules/with_basis/indexed_element.pyx +++ b/src/sage/modules/with_basis/indexed_element.pyx @@ -664,13 +664,14 @@ cdef class IndexedFreeModuleElement(ModuleElement): return self.base_ring().zero() return res - def _vector_(self, new_base_ring=None): + def _vector_(self, new_base_ring=None, order=None): """ Returns ``self`` as a dense vector INPUT: - ``new_base_ring`` -- a ring (default: ``None``) + - ``order`` -- (optional) an ordering of the support of ``self`` OUTPUT: a dense :func:`FreeModule` vector @@ -735,8 +736,10 @@ cdef class IndexedFreeModuleElement(ModuleElement): dense_free_module = self._parent._dense_free_module(new_base_ring) d = self._monomial_coefficients zero = dense_free_module.base_ring().zero() + if order is None: + order = self._parent.get_order() return dense_free_module.element_class(dense_free_module, - [d.get(m, zero) for m in self._parent.get_order()], + [d.get(m, zero) for m in order], coerce=True, copy=False) to_vector = _vector_ From a44162166f72f1a74aef86b04cac7aa99fd2e5c2 Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Tue, 2 Jun 2020 04:43:21 -0700 Subject: [PATCH 209/300] Code cleanup --- src/sage/modular/hypergeometric_motive.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index 78ea2c4d8dd..2ca511d499a 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -61,8 +61,6 @@ from collections import defaultdict from itertools import combinations -import array - from sage.arith.misc import divisors, gcd, euler_phi, moebius, is_prime from sage.arith.misc import gauss_sum, kronecker_symbol from sage.combinat.integer_vector_weighted import WeightedIntegerVectors @@ -1098,7 +1096,8 @@ def gauss_table(self, p, f, prec): """ try: prec1, gtab = self._gauss_table[p, f] - if prec1 < prec: raise KeyError + if prec1 < prec: + raise KeyError except KeyError: use_longs = (p ** prec < 2 ** 31) gtab = gauss_table(p, f, prec, use_longs) @@ -1217,7 +1216,6 @@ def padic_H_value(self, p, f, t, prec=None, cache_p=False): ....: print(H.padic_H_value(373, 4, 2)) ....: except ValueError: ....: print("Overflow detected") - ....: Overflow detected REFERENCES: @@ -1236,7 +1234,8 @@ def padic_H_value(self, p, f, t, prec=None, cache_p=False): m = defaultdict(int) for b in beta: u = b * (q - 1) - if u.is_integer(): m[u] += 1 + if u.is_integer(): + m[u] += 1 M = self.M_value() D = -min(self.zigzag(x, flip_beta=True) for x in alpha + beta) # also: D = (self.weight() + 1 - m[0]) // 2 From e495db83ee3a3c6062af53777603221a57077b7b Mon Sep 17 00:00:00 2001 From: vipul79321 Date: Wed, 3 Jun 2020 00:14:09 +0530 Subject: [PATCH 210/300] updated according to last commit --- src/sage/graphs/base/boost_graph.pyx | 20 ++++++++++++++------ src/sage/graphs/graph.py | 4 ++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/sage/graphs/base/boost_graph.pyx b/src/sage/graphs/base/boost_graph.pyx index 8a18d3eb6c2..36db9ff0b1c 100644 --- a/src/sage/graphs/base/boost_graph.pyx +++ b/src/sage/graphs/base/boost_graph.pyx @@ -1604,7 +1604,7 @@ cpdef min_cycle_basis(g_sage, weight_function=None, by_weight=False): orth_set[j] = orth_set[j] ^ base return cycle_basis -cpdef radius_DHV(g, weight_function=None): +cpdef radius_DHV(g, weight_function=None, check_weight=True): r""" Return the radius of weighted graph `g`. @@ -1619,7 +1619,11 @@ cpdef radius_DHV(g, weight_function=None): - ``weight_function`` -- function (default: ``None``); a function that associates a weight to each edge. If ``None`` (default), the weights of - ``g`` are used, if available, otherwise all edges have weight 1. + ``g`` are used, if ``g.weighted()==True``, otherwise all edges have + weight 1. + + - ``check_weight`` -- boolean (default: ``True``); if ``True``, we check + that the ``weight_function`` outputs a number for each edge EXAMPLES:: @@ -1658,6 +1662,9 @@ cpdef radius_DHV(g, weight_function=None): if n <= 1: return 0 + if weight_function and check_weight: + g._check_weight_function(weight_function) + cdef bint negative_weight = False if weight_function is not None: @@ -1666,10 +1673,11 @@ cpdef radius_DHV(g, weight_function=None): negative_weight = True break else: - for _,_,w in g.edge_iterator(): - if w and float(w) < 0: - negative_weight = True - break + if g.weighted(): + for _,_,w in g.edge_iterator(): + if w and float(w) < 0: + negative_weight = True + break # These variables are automatically deleted when the function terminates. cdef dict v_to_int = {vv: vi for vi, vv in enumerate(g)} diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index d639d1671d1..d583b9e3c94 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -5486,6 +5486,10 @@ def radius(self, by_weight=False, algorithm='DHV', weight_function=None, if weight_function is not None: by_weight = True + if by_weight and not weight_function: + def weight_function(e): + return 1 if e[2] is None else e[2] + if not algorithm: algorithm = 'DHV' From fd6dee61ca094c0b34961f41d6ef357def6ead5e Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Mon, 1 Jun 2020 18:44:43 +0200 Subject: [PATCH 211/300] 9792: fix some details --- src/sage/rings/morphism.pyx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/morphism.pyx b/src/sage/rings/morphism.pyx index 6f46ea59eba..a8156a6590f 100644 --- a/src/sage/rings/morphism.pyx +++ b/src/sage/rings/morphism.pyx @@ -1125,7 +1125,7 @@ cdef class RingHomomorphism(RingMap): ... NotImplementedError: base rings must be equal """ - return self._inverse_image_ideal(self.codomain().ideal()) + return self._inverse_image_ideal(self.codomain().zero_ideal()) def lift(self, x=None): """ @@ -2224,9 +2224,11 @@ cdef class RingHomomorphism_cover(RingHomomorphism): Lift an element from the quotient to the cover ring of this ring homomorphism. - sage: Q. = QQ['x,y'].quotient('x + y') - sage: Q.cover().inverse_image(x) - -y + EXAMPLES:: + + sage: Q. = QQ['x,y'].quotient('x + y') + sage: Q.cover().inverse_image(u) + -y """ return b.lift() @@ -2651,7 +2653,7 @@ cdef class FrobeniusEndomorphism_generic(RingHomomorphism): def _tensor_product_ring(B, A): """ - Construct a quotient ring representating the tensor product of two rings + Construct a quotient ring representing the tensor product of two rings over a common base ring. Allowed arguments are polynomial rings, quotient rings, number fields and From bc8119f90fd742a98010f8f7e7604df2bcae2d96 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 3 Jun 2020 15:37:54 +1000 Subject: [PATCH 212/300] Doing some cleanup to pass doctests, better test coverage, and lazy importing the catalog. --- src/doc/en/reference/references/index.rst | 4 + src/sage/combinat/all.py | 3 +- src/sage/combinat/path_tableaux/__init__.py | 1 + src/sage/combinat/path_tableaux/catalog.py | 21 +- src/sage/combinat/path_tableaux/dyck_path.py | 161 +++++----- .../combinat/path_tableaux/path_tableau.py | 288 ++++++++++-------- 6 files changed, 255 insertions(+), 223 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index fdac52eda90..ee097d788ee 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -5354,6 +5354,10 @@ REFERENCES: .. [Wer1998] Annette Werner, Local heights on abelian varieties and rigid analytic uniformization, Doc. Math. 3 (1998), 301-319. +.. [Wes2017] Bruce Westbury. + *Coboundary categories and local rules*, + The Electronic Journal of Combinatorics, *25* (2018) + .. [WFYTP2008] \D. Watanable, S. Furuya, H. Yoshida, K. Takaragi, and B. Preneel, *A new keystream generator MUGI*; in FSE, (2002), pp. 179-194. diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 40d38df2674..40f1e598466 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -235,4 +235,5 @@ 'GrowthDiagramYoungFibonacci', 'GrowthDiagramSylvester']) # Path Tableaux -from .path_tableaux.catalog import * +lazy_import('sage.combinat.path_tableaux', 'catalog', as_='path_tableaux') + diff --git a/src/sage/combinat/path_tableaux/__init__.py b/src/sage/combinat/path_tableaux/__init__.py index 56171bce5a0..fdc452fb850 100644 --- a/src/sage/combinat/path_tableaux/__init__.py +++ b/src/sage/combinat/path_tableaux/__init__.py @@ -5,3 +5,4 @@ - :ref:`sage.combinat.path_tableaux.path_tableau` - :ref:`sage.combinat.path_tableaux.dyck_path` """ + diff --git a/src/sage/combinat/path_tableaux/catalog.py b/src/sage/combinat/path_tableaux/catalog.py index 534af80a45d..b161eb5261b 100644 --- a/src/sage/combinat/path_tableaux/catalog.py +++ b/src/sage/combinat/path_tableaux/catalog.py @@ -1,20 +1,23 @@ r""" Catalog of Path Tableaux -The ``path_tableaux`` object may be used to access examples of various algebras -currently implemented in Sage. Using tab-completion on this object is an -easy way to discover and quickly create the path tableaux that are available -(as listed here). +The ``path_tableaux`` object may be used to access examples of various path +tableau objects currently implemented in Sage. Using tab-completion on this +object is an easy way to discover and quickly create the path tableaux that +are available (as listed here). Let ```` indicate pressing the tab key. So begin by typing -``algebras.`` to the see the currently implemented named path tableaux. +``path_tableaux.`` to the see the currently implemented path tableaux. -- :class:`path_tableaux.DyckPaths +- :class:`~sage.combinat.path_tableaux.path_tableau.CylindricalDiagram` +- :class:`~sage.combinat.path_tableaux.dyck_path.DyckPath` +- :class:`~sage.combinat.path_tableaux.dyck_path.DyckPaths` """ from sage.misc.lazy_import import lazy_import -lazy_import('sage.combinat.path_tableaux.path_tableau', ['PathTableau', 'PathTableaux', 'CylindricalDiagram']) -lazy_import('sage.combinat.path_tableaux.dyck_path', ['DyckPath','DyckPaths']) +lazy_import('sage.combinat.path_tableaux.path_tableau', ['CylindricalDiagram']) +lazy_import('sage.combinat.path_tableaux.dyck_path', ['DyckPath', 'DyckPaths']) + +del lazy_import -#del absolute_import diff --git a/src/sage/combinat/path_tableaux/dyck_path.py b/src/sage/combinat/path_tableaux/dyck_path.py index 5a0ee63aaca..38d337e957f 100644 --- a/src/sage/combinat/path_tableaux/dyck_path.py +++ b/src/sage/combinat/path_tableaux/dyck_path.py @@ -2,9 +2,9 @@ Dyck Paths This is an implementation of the abstract base class -:class:`sage.combinat.pathtableau.pathtableaux`. -This is the simplest implementation of PathTableaux and is included to -provide a convenient test case and for pedagogical purposes. +:class:`sage.combinat.path_tableaux.path_tableau.PathTableau`. +This is the simplest implementation of a path tableau and is included +to provide a convenient test case and for pedagogical purposes. In this implementation we have sequences of nonnegative integers. These are required to be the heights Dyck words (except that we do not require @@ -15,28 +15,6 @@ AUTHORS: - Bruce Westbury (2018): initial version - -Here we illustrate the slogan that promotion = rotation. - -EXAMPLES:: - - sage: t = DyckPath([0,1,2,3,2,1,0]) - sage: t.to_perfect_matching() - [(0, 5), (1, 4), (2, 3)] - - sage: t = t.promotion() - sage: t.to_perfect_matching() - [(0, 3), (1, 2), (4, 5)] - - sage: t = t.promotion() - sage: t.to_perfect_matching() - [(0, 1), (2, 5), (3, 4)] - - sage: t = t.promotion() - sage: t.to_perfect_matching() - [(0, 5), (1, 4), (2, 3)] - - sage: TestSuite(t).run() """ #***************************************************************************** @@ -46,10 +24,9 @@ # 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.list_clone import ClonableArray from sage.combinat.path_tableaux.path_tableau import PathTableau, PathTableaux from sage.combinat.combinatorial_map import combinatorial_map from sage.combinat.dyck_word import DyckWord @@ -74,22 +51,43 @@ class DyckPath(PathTableau): EXAMPLES:: - sage: DyckPath([0,1,2,1,0]) + sage: path_tableaux.DyckPath([0,1,2,1,0]) [0, 1, 2, 1, 0] sage: w = DyckWord([1,1,0,0]) - sage: DyckPath(w) + sage: path_tableaux.DyckPath(w) [0, 1, 2, 1, 0] - sage: p = PerfectMatching([(1,2),(3,4)]) - sage: DyckPath(p) + sage: p = PerfectMatching([(1,2), (3,4)]) + sage: path_tableaux.DyckPath(p) [0, 1, 0, 1, 0] - sage: t = Tableau([[1,2],[3,4]]) - sage: DyckPath(t) - [0, 1, 2, 1, 0] - """ + sage: t = Tableau([[1,2,4],[3,5,6]]) + sage: path_tableaux.DyckPath(t) + [0, 1, 2, 1, 2, 1, 0] + + sage: st = SkewTableau([[None, 1,4],[2,3]]) + sage: path_tableaux.DyckPath(st) + [1, 2, 1, 0, 1] + + Here we illustrate the slogan that promotion = rotation:: + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) + sage: t.to_perfect_matching() + [(0, 5), (1, 4), (2, 3)] + + sage: t = t.promotion() + sage: t.to_perfect_matching() + [(0, 3), (1, 2), (4, 5)] + + sage: t = t.promotion() + sage: t.to_perfect_matching() + [(0, 1), (2, 5), (3, 4)] + + sage: t = t.promotion() + sage: t.to_perfect_matching() + [(0, 5), (1, 4), (2, 3)] + """ @staticmethod def __classcall_private__(cls, ot): r""" @@ -98,14 +96,10 @@ def __classcall_private__(cls, ot): TESTS:: - sage: t = DyckPath([0,1,2,1,0]) + sage: t = path_tableaux.DyckPath([0,1,2,1,0]) sage: t.parent() - sage: t.category() - Category of elements of - sage: type(t) - """ return DyckPaths()(ot) @@ -113,49 +107,38 @@ def __init__(self, parent, ot, check=True): r""" Initialize a Dyck path. - INPUT: + TESTS:: - Can be any of: + sage: D = path_tableaux.DyckPath(Tableau([[1,2], [3,4]])) + sage: TestSuite(D).run() - * word of nonnegative integers with successive differences '\pm 1' - * a DyckWord - * a noncrossing perfect matching - * a two row standard tableau - * a two row standard skew tab;eau + sage: D = path_tableaux.DyckPath(PerfectMatching([(1,4), (2,3), (5,6)])) + sage: TestSuite(D).run() - TESTS:: + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) + sage: TestSuite(t).run() - sage: DyckPath([0,1,2,1,0]) - [0, 1, 2, 1, 0] - sage: DyckPath(DyckWord([1, 0, 1, 0])) - [0, 1, 0, 1, 0] - sage: DyckPath(PerfectMatching([(1, 4), (2, 3), (5, 6)])) - [0, 1, 2, 1, 0, 1, 0] - sage: DyckPath(Tableau([[1,2,4],[3,5,6]])) - [0, 1, 2, 1, 2, 1, 0] - sage: DyckPath(SkewTableau([[None, 1,4],[2,3]])) - [1, 2, 1, 0, 1] - sage: DyckPath(PerfectMatching([(1, 3), (2, 4), (5, 6)])) + sage: path_tableaux.DyckPath(PerfectMatching([(1, 3), (2, 4), (5, 6)])) Traceback (most recent call last): ... ValueError: the perfect matching must be non crossing - sage: DyckPath(Tableau([[1,2,5],[3,5,6]])) + sage: path_tableaux.DyckPath(Tableau([[1,2,5],[3,5,6]])) Traceback (most recent call last): ... ValueError: the tableau must be standard - sage: DyckPath(Tableau([[1,2,4],[3,5,6],[7]])) + sage: path_tableaux.DyckPath(Tableau([[1,2,4],[3,5,6],[7]])) Traceback (most recent call last): ... ValueError: the tableau must have at most two rows - sage: DyckPath(SkewTableau([[None, 1,4],[2,3],[5]])) + sage: path_tableaux.DyckPath(SkewTableau([[None, 1,4],[2,3],[5]])) Traceback (most recent call last): ... ValueError: the skew tableau must have at most two rows - sage: DyckPath([0,1,2.5,1,0]) + sage: path_tableaux.DyckPath([0,1,2.5,1,0]) Traceback (most recent call last): ... ValueError: [0, 1, 2.50000000000000, 1, 0] is not a sequence of integers - sage: DyckPath(Partition([3,2,1])) + sage: path_tableaux.DyckPath(Partition([3,2,1])) Traceback (most recent call last): ... ValueError: invalid input [3, 2, 1] @@ -196,7 +179,7 @@ def __init__(self, parent, ot, check=True): if len(a) == 1: w[i] = a[0] else: - w[i] = a[0]-a[1] + w[i] = a[0] - a[1] elif isinstance(ot, (list,tuple)): try: @@ -207,19 +190,20 @@ def __init__(self, parent, ot, check=True): if w is None: raise ValueError("invalid input %s" % ot) - ClonableArray.__init__(self, parent, w, check=check) + PathTableau.__init__(self, parent, w, check=check) def check(self): - """ Checks that ``self`` is a valid path. + """ + Checks that ``self`` is a valid path. TESTS:: - sage: DyckPath([0,1,0,-1,0]) # indirect doctest + sage: path_tableaux.DyckPath([0,1,0,-1,0]) # indirect doctest Traceback (most recent call last): ... ValueError: [0, 1, 0, -1, 0] has a negative entry - sage: DyckPath([0,1,3,1,0]) # indirect doctest + sage: path_tableaux.DyckPath([0,1,3,1,0]) # indirect doctest Traceback (most recent call last): ... ValueError: [0, 1, 3, 1, 0] is not a Dyck path @@ -232,7 +216,7 @@ def check(self): raise ValueError( "%s is not a Dyck path" % str(self) ) def local_rule(self,i): - """ + r""" This has input a list of objects. This method first takes the list of objects of length three consisting of the `(i-1)`-st, `i`-th and `(i+1)`-term and applies the rule. It then replaces @@ -240,13 +224,13 @@ def local_rule(self,i): EXAMPLES:: - sage: t = DyckPath([0,1,2,3,2,1,0]) + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) sage: t.local_rule(3) [0, 1, 2, 1, 2, 1, 0] TESTS:: - sage: t = DyckPath([0,1,2,3,2,1,0]) + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) sage: t.local_rule(0) Traceback (most recent call last): ... @@ -258,7 +242,6 @@ def local_rule(self,i): ... ValueError: 6 is not a valid integer """ - def _rule(x): """ This is the rule on a sequence of three letters. @@ -279,10 +262,10 @@ def is_skew(self): EXAMPLES:: - sage: DyckPath([0,1,2,1]).is_skew() + sage: path_tableaux.DyckPath([0,1,2,1]).is_skew() False - sage: DyckPath([1,0,1,2,1]).is_skew() + sage: path_tableaux.DyckPath([1,0,1,2,1]).is_skew() True """ return self[0] != 0 @@ -294,11 +277,11 @@ def to_DyckWord(self): EXAMPLES:: - sage: c = DyckPath([0,1,2,1,0]) + sage: c = path_tableaux.DyckPath([0,1,2,1,0]) sage: c.to_DyckWord() [1, 1, 0, 0] """ - return DyckWord(heights_sequence = list(self)) + return DyckWord(heights_sequence=list(self)) def descents(self): r""" @@ -306,7 +289,7 @@ def descents(self): EXAMPLES:: - sage: DyckPath([0,1,2,1,2,1,0,1,0]).descents() + sage: path_tableaux.DyckPath([0,1,2,1,2,1,0,1,0]).descents() {3, 6} """ result = set() @@ -323,10 +306,10 @@ def to_word(self): EXAMPLES:: - sage: DyckPath([1,0,1,2,1]).to_word() + sage: path_tableaux.DyckPath([1,0,1,2,1]).to_word() [0, 1, 1, 0] """ - return [ (self[i+1]-self[i]+1)/2 for i in range(self.size()-1) ] + return [(self[i+1] - self[i] + 1) // 2 for i in range(self.size()-1)] def to_perfect_matching(self): r""" @@ -334,12 +317,12 @@ def to_perfect_matching(self): EXAMPLES:: - sage: DyckPath([0,1,2,1,2,1,0,1,0]).to_perfect_matching() + sage: path_tableaux.DyckPath([0,1,2,1,2,1,0,1,0]).to_perfect_matching() [(0, 5), (1, 2), (3, 4), (6, 7)] TESTS:: - sage: DyckPath([1,2,1,2,1,0,1]).to_perfect_matching() + sage: path_tableaux.DyckPath([1,2,1,2,1,0,1]).to_perfect_matching() Traceback (most recent call last): ... ValueError: [1, 2, 1, 2, 1, 0, 1] does not start at 0 @@ -361,21 +344,21 @@ def to_tableau(self): EXAMPLES:: - sage: T = DyckPath([0,1,2,3,2,3]) + sage: T = path_tableaux.DyckPath([0,1,2,3,2,3]) sage: T.to_tableau() [[1, 2, 3, 5], [4]] - sage: U = DyckPath([2,3,2,3]) + sage: U = path_tableaux.DyckPath([2,3,2,3]) sage: U.to_tableau() [[None, None, 1, 3], [2]] """ w = self.to_word() - top = [ i+1 for i, a in enumerate(w) if a == 1 ] - bot = [ i+1 for i, a in enumerate(w) if a == 0 ] + top = [i + 1 for i, a in enumerate(w) if a == 1] + bot = [i + 1 for i, a in enumerate(w) if a == 0] if self.is_skew(): - return SkewTableau([[None]*self[0]+top,bot]) + return SkewTableau([[None]*self[0]+top, bot]) else: - return StandardTableau([top,bot]) + return StandardTableau([top, bot]) class DyckPaths(PathTableaux): """ diff --git a/src/sage/combinat/path_tableaux/path_tableau.py b/src/sage/combinat/path_tableaux/path_tableau.py index 1713ef76c57..7b25583aa22 100644 --- a/src/sage/combinat/path_tableaux/path_tableau.py +++ b/src/sage/combinat/path_tableaux/path_tableau.py @@ -1,14 +1,14 @@ r""" Path Tableaux -This is an abstract base class for using local rules to construct rectification -and the action of the cactus group, [Wes2017]_ +This is an abstract base class for using local rules to construct +rectification and the action of the cactus group [Wes2017]_. -This is an effective version -of the Henriques-Kamnitzer construction of the action of the cactus -group on tensor powers of a crystal. This is a generalisation of -the Fomin growth rules which are an effective version of the operations -on standard tableaux which were previously constructed using jeu-de-taquin. +This is a construction of the Henriques-Kamnitzer construction of +the action of the cactus group on tensor powers of a crystal. This is +also a generalisation of the Fomin growth rules, which are a version of +the operations on standard tableaux which were previously constructed +using jeu-de-taquin. The basic operations are rectification, evacuation and promotion. Rectification of standard skew tableaux agrees with the rectification @@ -17,9 +17,7 @@ REFERENCES: -.. [Wes2017] Bruce Westbury. - *Coboundary categories and local rules*, - The Electronic Journal of Combinatorics, *25* (2018) +- [Wes2017]_ AUTHORS: @@ -33,10 +31,9 @@ # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** -from six import add_metaclass from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.misc.abstract_method import abstract_method from sage.categories.sets_cat import Sets @@ -49,12 +46,11 @@ #from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets #from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -@add_metaclass(InheritComparisonClasscallMetaclass) -class PathTableau(ClonableArray): - """ - This is the abstract base class for path tableaux. +class PathTableau(ClonableArray, metaclass=InheritComparisonClasscallMetaclass): + r""" + This is the abstract base class for a path tableau. """ - @abstract_method(optional=False) + @abstract_method def local_rule(self,i): r""" This is the abstract local rule defined in any coboundary category. @@ -66,7 +62,7 @@ def local_rule(self,i): EXAMPLES:: - sage: t = DyckPath([0,1,2,3,2,1,0]) + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) sage: t.local_rule(3) [0, 1, 2, 1, 2, 1, 0] """ @@ -79,7 +75,7 @@ def size(self): EXAMPLES:: - sage: t = DyckPath([0,1,2,3,2,1,0]) + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) sage: t.size() 7 """ @@ -91,7 +87,7 @@ def initial_shape(self): EXAMPLES:: - sage: t = DyckPath([0,1,2,3,2,1,0]) + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) sage: t.initial_shape() 0 """ @@ -103,7 +99,7 @@ def final_shape(self): EXAMPLES:: - sage: t = DyckPath([0,1,2,3,2,1,0]) + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) sage: t.final_shape() 0 """ @@ -117,7 +113,7 @@ def promotion(self): EXAMPLES:: - sage: t = DyckPath([0,1,2,3,2,1,0]) + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) sage: t.promotion() [0, 1, 2, 1, 0, 1, 0] """ @@ -133,34 +129,33 @@ def evacuation(self): EXAMPLES:: - sage: t = DyckPath([0,1,2,3,2,1,0]) + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) sage: t.evacuation() [0, 1, 2, 3, 2, 1, 0] """ if self.size() < 3: return self - T = self - L = list(T) + L = list(self) result = [] + P = self.parent() for i in range(len(self)): - T = self.parent()(L).promotion() - L = list(T) + L = list(P(L).promotion()) result.append( L.pop() ) result.reverse() - return self.parent()(result) + return P(result) - def commutor(self,other,verbose=False): + def commutor(self, other, verbose=False): r""" - Return the commutor of ``self`` with ``other`` + Return the commutor of ``self`` with ``other``. If ``verbose=True`` then the function will print the rectangle. EXAMPLES:: - sage: t1 = DyckPath([0,1,2,3,2,1,0]) - sage: t2 = DyckPath([0,1,2,1,0]) + sage: t1 = path_tableaux.DyckPath([0,1,2,3,2,1,0]) + sage: t2 = path_tableaux.DyckPath([0,1,2,1,0]) sage: t1.commutor(t2) ([0, 1, 2, 1, 0], [0, 1, 2, 3, 2, 1, 0]) sage: t1.commutor(t2,verbose=True) @@ -175,38 +170,40 @@ def commutor(self,other,verbose=False): TESTS:: - sage: t1 = DyckPath([]) - sage: t2 = DyckPath([0,1,2,1,0]) + sage: t1 = path_tableaux.DyckPath([]) + sage: t2 = path_tableaux.DyckPath([0,1,2,1,0]) sage: t1.commutor(t2) Traceback (most recent call last): ... ValueError: this requires nonempty lists - sage: t1 = DyckPath([0,1,2,3,2,1,0]) - sage: t2 = DyckPath([]) + sage: t1 = path_tableaux.DyckPath([0,1,2,3,2,1,0]) + sage: t2 = path_tableaux.DyckPath([]) sage: t1.commutor(t2) Traceback (most recent call last): ... ValueError: this requires nonempty lists - sage: t1 = DyckPath([0,1,2,3,2,1]) - sage: t2 = DyckPath([0,1,2,1,0]) + sage: t1 = path_tableaux.DyckPath([0,1,2,3,2,1]) + sage: t2 = path_tableaux.DyckPath([0,1,2,1,0]) sage: t1.commutor(t2) Traceback (most recent call last): ... - ValueError: [0, 1, 2, 3, 2, 1],[0, 1, 2, 1, 0] is not a composable pair + ValueError: [0, 1, 2, 3, 2, 1], [0, 1, 2, 1, 0] is not a composable pair """ n = len(self) m = len(other) if n == 0 or m == 0: raise ValueError("this requires nonempty lists") if n == 1 or m == 1: - return (other,self) + return (other, self) + + P = self.parent() row = list(other) col = list(self) if col[-1] != row[0]: - raise ValueError("%s,%s is not a composable pair" % (self,other)) + raise ValueError("%s, %s is not a composable pair" % (self,other)) - path = self.parent()(col + row[1:]) + path = P(col + row[1:]) for i in range(1,n): if verbose: @@ -216,25 +213,21 @@ def commutor(self,other,verbose=False): if verbose: print(path[:m]) - - return (self.parent()(path[:m]),self.parent()(path[m-1:])) + return (P(path[:m]), P(path[m-1:])) def cactus(self,i,j): r""" - Return the action of the generators of the cactus group on ``self``. - These generators are involutions and are usually denoted by - 's_{i,j}'. + Return the action of the generator `s_{i,j}` of the cactus + group on ``self``. INPUT: ``i`` -- a positive integer - ``j`` -- a positive integer weakly greater than ``i`` - EXAMPLES:: - sage: t = DyckPath([0,1,2,3,2,1,0]) + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) sage: t.cactus(1,5) [0, 1, 0, 1, 2, 1, 0] @@ -248,7 +241,7 @@ def cactus(self,i,j): TESTS:: - sage: t = DyckPath([0,1,2,3,2,1,0]) + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) sage: t.cactus(1,8) Traceback (most recent call last): ... @@ -281,7 +274,7 @@ def _test_involution_rule(self, **options): TESTS:: - sage: t = DyckPath([0,1,2,3,2,1,0]) + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) sage: t._test_involution_rule() """ tester = self._tester(**options) @@ -295,12 +288,12 @@ def _test_involution_cactus(self, **options): TESTS:: - sage: t = DyckPath([0,1,2,3,2,1,0]) + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) sage: t._test_involution_cactus() """ tester = self._tester(**options) - for i in range(2,self.size()+1): - tester.assertTrue(self.cactus(1,i).cactus(1,i) == self) + for i in range(2, self.size()+1): + tester.assertEqual(self.cactus(1,i).cactus(1,i), self) def _test_promotion(self, **options): """ @@ -308,12 +301,12 @@ def _test_promotion(self, **options): TESTS:: - sage: t = DyckPath([0,1,2,3,2,1,0]) + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) sage: t._test_promotion() """ tester = self._tester(**options) - n = self.size()-1 - tester.assertTrue(self.cactus(1,n-1).cactus(1,n).promotion() == self) + n = self.size() - 1 + tester.assertEqual(self.cactus(1,n-1).cactus(1,n).promotion(), self) def _test_commutation(self, **options): """ @@ -321,7 +314,7 @@ def _test_commutation(self, **options): TESTS:: - sage: t = DyckPath([0,1,2,3,2,1,0]) + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) sage: t._test_commutation() """ from itertools import combinations @@ -329,11 +322,11 @@ def _test_commutation(self, **options): n = self.size() if n < 5: - return True - for i,j,r,s in combinations(range(1,n+1),4): - lhs = self.cactus(i,j).cactus(r,s) - rhs = self.cactus(r,s).cactus(i,j) - tester.assertTrue(lhs == rhs) + return + for i,j,r,s in combinations(range(1,n+1), 4): + lhs = self.cactus(i, j).cactus(r, s) + rhs = self.cactus(r, s).cactus(i, j) + tester.assertEqual(lhs, rhs) def _test_coboundary(self, **options): """ @@ -341,7 +334,7 @@ def _test_coboundary(self, **options): TESTS:: - sage: t = DyckPath([0,1,2,3,2,1,0]) + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) sage: t._test_coboundary() """ from itertools import combinations @@ -349,11 +342,11 @@ def _test_coboundary(self, **options): n = self.size() if n < 4: - return True - for i,j,r,s in combinations(range(1,n+3),4): - lhs = self.cactus(i,s-2).cactus(j-1,r-1) - rhs = self.cactus(i+s-r-1,i+s-j-1).cactus(i,s-2) - tester.assertTrue(lhs == rhs) + return + for i,j,r,s in combinations(range(1,n+3), 4): + lhs = self.cactus(i, s-2).cactus(j-1, r-1) + rhs = self.cactus(i+s-r-1, i+s-j-1).cactus(i, s-2) + tester.assertEqual(lhs, rhs) def orbit(self): r""" @@ -361,7 +354,7 @@ def orbit(self): EXAMPLES:: - sage: t = DyckPath([0,1,2,3,2,1,0]) + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) sage: t.orbit() {[0, 1, 0, 1, 0, 1, 0], [0, 1, 0, 1, 2, 1, 0], @@ -369,19 +362,17 @@ def orbit(self): [0, 1, 2, 1, 2, 1, 0], [0, 1, 2, 3, 2, 1, 0]} """ - orb = set([]) rec = set([self]) - new = set([]) - while rec != set([]): + while rec: + new = set([]) for a in rec: - for i in range(2,self.size()): - b = a.cactus(1,i) + for i in range(2, self.size()): + b = a.cactus(1, i) if (b not in orb) and (b not in rec): new.add(b) orb = orb.union(rec) rec = new.copy() - new = set([]) return orb @@ -397,7 +388,7 @@ def dual_equivalence_graph(self): EXAMPLES:: - sage: s = DyckPath([0,1,2,3,2,3,2,1,0]) + sage: s = path_tableaux.DyckPath([0,1,2,3,2,3,2,1,0]) sage: s.dual_equivalence_graph().adjacency_matrix() [0 1 1 1 0 1 0 1 1 0 0 0 0 0] [1 0 1 1 1 1 1 0 1 0 0 1 1 0] @@ -413,7 +404,7 @@ def dual_equivalence_graph(self): [0 1 1 1 0 0 1 1 1 1 1 0 1 1] [0 1 0 1 1 1 0 1 1 1 1 1 0 1] [0 0 0 0 1 0 1 0 0 1 1 1 1 0] - sage: s = DyckPath([0,1,2,3,2,1,0]) + sage: s = path_tableaux.DyckPath([0,1,2,3,2,1,0]) sage: sorted(s.dual_equivalence_graph().edges()) [([0, 1, 0, 1, 0, 1, 0], [0, 1, 0, 1, 2, 1, 0], '4,7'), ([0, 1, 0, 1, 0, 1, 0], [0, 1, 2, 1, 0, 1, 0], '2,5'), @@ -444,74 +435,122 @@ class PathTableaux(UniqueRepresentation,Parent): """ def __init__(self): """ - Initializes the abstract class of all PathTableaux + Initialize ``self``. TESTS:: - sage: t = DyckPath([0,1,2,1,0]) - sage: t.parent() # indirect test - + sage: t = path_tableaux.DyckPath([0,1,2,1,0]) + sage: TestSuite(t).run() """ Parent.__init__(self, category=Sets()) def _element_constructor_(self, *args, **kwds): r""" - Constructs an object as an element of ``self``, if possible. + Construct an object as an element of ``self``, if possible. TESTS:: - sage: DyckPath([0,1,2,1,0]) # indirect doctest + sage: path_tableaux.DyckPath([0,1,2,1,0]) # indirect doctest [0, 1, 2, 1, 0] """ return self.element_class(self, *args, **kwds) class CylindricalDiagram(SageObject): + r""" + Cylindrical growth diagrams. + + EXAMPLES:: + + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) + sage: path_tableaux.CylindricalDiagram(t) + [0, 1, 2, 3, 2, 1, 0] + ['', 0, 1, 2, 1, 0, 1, 0] + ['', '', 0, 1, 0, 1, 2, 1, 0] + ['', '', '', 0, 1, 2, 3, 2, 1, 0] + ['', '', '', '', 0, 1, 2, 1, 0, 1, 0] + ['', '', '', '', '', 0, 1, 0, 1, 2, 1, 0] + ['', '', '', '', '', '', 0, 1, 2, 3, 2, 1, 0] """ - A class for cylindrical growth diagrams. - - """ - def __init__(self,T): + def __init__(self, T): """ - Initialise an object of ``self`` from the PathTableau object T + Initialize ``self`` from the + :class:`~sage.combinat.path_tableaux.path_tableau.PathTableau` + object ``T``. TESTS:: - sage: t = DyckPath([0,1,2,3,2,1,0]) - sage: CylindricalDiagram(t) - [0, 1, 2, 3, 2, 1, 0] - ['', 0, 1, 2, 1, 0, 1, 0] - ['', '', 0, 1, 0, 1, 2, 1, 0] - ['', '', '', 0, 1, 2, 3, 2, 1, 0] - ['', '', '', '', 0, 1, 2, 1, 0, 1, 0] - ['', '', '', '', '', 0, 1, 0, 1, 2, 1, 0] - ['', '', '', '', '', '', 0, 1, 2, 3, 2, 1, 0] + sage: T = path_tableaux.DyckPath([0,1,2,3,2,1,0]) + sage: D = path_tableaux.CylindricalDiagram(T) + sage: TestSuite(D).run() - sage: CylindricalDiagram(2) + sage: path_tableaux.CylindricalDiagram(2) Traceback (most recent call last): ... ValueError: 2 must be a path tableau """ - if not isinstance(T,PathTableau): + if not isinstance(T, PathTableau): raise ValueError('{0} must be a path tableau'.format(str(T))) n = len(T) - result = [[None]*(2*n-1)]*n + result = [[None]*(2*n-1)] * n for i in range(n): result[i] = [""]*i + list(T) T = T.promotion() + self.path_tableau = T self.diagram = result - def __repr__(self): - """ - Return a string representation of ``self`` + def _repr_(self): + r""" + Return a string representation of ``self``. TESTS:: - sage: print(DyckPath([0,1,2,1,2,1,0])) # indirect test - [0, 1, 2, 1, 2, 1, 0] + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) + sage: path_tableaux.CylindricalDiagram(t) + [0, 1, 2, 3, 2, 1, 0] + ['', 0, 1, 2, 1, 0, 1, 0] + ['', '', 0, 1, 0, 1, 2, 1, 0] + ['', '', '', 0, 1, 2, 3, 2, 1, 0] + ['', '', '', '', 0, 1, 2, 1, 0, 1, 0] + ['', '', '', '', '', 0, 1, 0, 1, 2, 1, 0] + ['', '', '', '', '', '', 0, 1, 2, 3, 2, 1, 0] """ dg = self.diagram - return ' '+str(dg[0])+''.join('\n ' + str(x) for x in dg[1:]) + return ' ' + str(dg[0]) + ''.join('\n ' + str(x) for x in dg[1:]) + + def __eq__(self, other): + """ + Check equality. + + EXAMPLES:: + + sage: t1 = path_tableaux.DyckPath([0,1,2,3,2,1,0]) + sage: T1 = path_tableaux.CylindricalDiagram(t1) + sage: t2 = path_tableaux.DyckPath([0,1,2,1,2,1,0]) + sage: T2 = path_tableaux.CylindricalDiagram(t2) + sage: T1 == T2 + False + sage: T1 == path_tableaux.CylindricalDiagram(t1) + True + """ + return isinstance(other, CylindricalDiagram) and self.diagram == other.diagram + + def __ne__(self, other): + """ + Check inequality. + + EXAMPLES:: + + sage: t1 = path_tableaux.DyckPath([0,1,2,3,2,1,0]) + sage: T1 = path_tableaux.CylindricalDiagram(t1) + sage: t2 = path_tableaux.DyckPath([0,1,2,1,2,1,0]) + sage: T2 = path_tableaux.CylindricalDiagram(t2) + sage: T1 != T2 + True + sage: T1 != path_tableaux.CylindricalDiagram(t1) + False + """ + return not (self == other) def _latex_(self): r""" @@ -519,8 +558,8 @@ def _latex_(self): EXAMPLES:: - sage: t = DyckPath([0,1,2,3,2,1,0]) - sage: latex(CylindricalDiagram(t)) + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) + sage: latex(path_tableaux.CylindricalDiagram(t)) \begin{array}{ccccccccccccc} 0 & 1 & 2 & 3 & 2 & 1 & 0\\ & 0 & 1 & 2 & 1 & 0 & 1 & 0\\ @@ -539,24 +578,25 @@ def _latex_(self): return result def __len__(self): - """Return the length of ``self`` + r""" + Return the length of ``self``. TESTS:: - sage: t = DyckPath([0,1,2,3,2,1,0]) - sage: len(CylindricalDiagram(t)) + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) + sage: len(path_tableaux.CylindricalDiagram(t)) 7 """ return len(self.diagram) def _ascii_art_(self): - """ + r""" Return an ascii art representation of ``self`` TESTS:: - sage: t = DyckPath([0,1,2,3,2,1,0]) - sage: ascii_art(CylindricalDiagram(t)) + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) + sage: ascii_art(path_tableaux.CylindricalDiagram(t)) 0 1 2 3 2 1 0 0 1 2 1 0 1 0 0 1 0 1 2 1 0 @@ -571,13 +611,13 @@ def _ascii_art_(self): return AsciiArt(S) def _unicode_art_(self): - """ + r""" Return a unicode art representation of ``self`` TESTS:: - sage: t = DyckPath([0,1,2,3,2,1,0]) - sage: unicode_art(CylindricalDiagram(t)) + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) + sage: unicode_art(path_tableaux.CylindricalDiagram(t)) 0 1 2 3 2 1 0 0 1 2 1 0 1 0 0 1 0 1 2 1 0 @@ -592,13 +632,13 @@ def _unicode_art_(self): return UnicodeArt(S) def pp(self): - """ + r""" A pretty print utility method. EXAMPLES:: - sage: t = DyckPath([0,1,2,3,2,1,0]) - sage: CylindricalDiagram(t).pp() + sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) + sage: path_tableaux.CylindricalDiagram(t).pp() 0 1 2 3 2 1 0 0 1 2 1 0 1 0 0 1 0 1 2 1 0 @@ -606,6 +646,6 @@ def pp(self): 0 1 2 1 0 1 0 0 1 0 1 2 1 0 0 1 2 3 2 1 0 - """ print('\n'.join(' '.join('{:0<}'.format(a) for a in x) for x in self.diagram )) + From 9501a4a70a5ac6eab7ced68917a5c92e18a38730 Mon Sep 17 00:00:00 2001 From: vipul79321 Date: Wed, 3 Jun 2020 11:10:28 +0530 Subject: [PATCH 213/300] minor correction --- src/sage/graphs/graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index d583b9e3c94..772834cd7e3 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -5344,7 +5344,7 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None, by_weight = True elif by_weight: def weight_function(e): - return e[2] if e[2] else 1 + return 1 if e[2] is None else e[2] if algorithm is None: if dist_dict is not None: From bfd9fedc42fe0b770edf87cf56e488a21e6099ca Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 2 Jun 2020 23:15:14 -0700 Subject: [PATCH 214/300] src/sage: Move OptionalExtension options (except tdlib, coxeter) from src/module_list.py to distutils directives --- src/module_list.py | 11 +---------- src/sage/graphs/bliss.pyx | 4 ++++ src/sage/graphs/mcqd.pyx | 2 ++ src/sage/interfaces/primecount.pyx | 2 ++ src/sage/libs/fes.pyx | 3 +++ src/sage/libs/meataxe.pyx | 2 ++ src/sage/libs/sirocco.pyx | 3 +++ src/sage/matrix/matrix_gfpn_dense.pyx | 2 ++ 8 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/module_list.py b/src/module_list.py index d7b5f459cf0..a0111134391 100644 --- a/src/module_list.py +++ b/src/module_list.py @@ -403,13 +403,10 @@ def uname_specific(name, value, alternative): OptionalExtension("sage.graphs.mcqd", ["sage/graphs/mcqd.pyx"], - language = "c++", package = 'mcqd'), OptionalExtension("sage.graphs.bliss", ["sage/graphs/bliss.pyx"], - language = "c++", - libraries = ['bliss'], package = 'bliss'), Extension('sage.graphs.planarity', @@ -527,8 +524,6 @@ def uname_specific(name, value, alternative): OptionalExtension("sage.libs.fes", ["sage/libs/fes.pyx"], - language = "c", - libraries = ['fes'], package = 'fes'), Extension('sage.libs.flint.flint', @@ -560,9 +555,7 @@ def uname_specific(name, value, alternative): OptionalExtension('sage.libs.sirocco', sources = ["sage/libs/sirocco.pyx"], - libraries = ["sirocco"], - package="sirocco", - language = 'c++'), + package="sirocco"), Extension('*', ['sage/libs/linbox/*.pyx']), @@ -583,7 +576,6 @@ def uname_specific(name, value, alternative): OptionalExtension("sage.libs.meataxe", sources = ['sage/libs/meataxe.pyx'], - libraries = ['mtx'], package = 'meataxe'), Extension('*', ['sage/libs/pari/*.pyx']), @@ -894,7 +886,6 @@ def uname_specific(name, value, alternative): OptionalExtension("sage.matrix.matrix_gfpn_dense", sources = ['sage/matrix/matrix_gfpn_dense.pyx'], - libraries = ['mtx'], package = 'meataxe'), Extension('sage.matrix.misc', diff --git a/src/sage/graphs/bliss.pyx b/src/sage/graphs/bliss.pyx index 7bfa4018643..d21c034a6e3 100644 --- a/src/sage/graphs/bliss.pyx +++ b/src/sage/graphs/bliss.pyx @@ -1,3 +1,7 @@ +# distutils: language = c++ +# distutils: libraries = bliss +# sage_setup: package = sage-bliss + r""" Interface with bliss: graph (iso/auto)morphism diff --git a/src/sage/graphs/mcqd.pyx b/src/sage/graphs/mcqd.pyx index 0ed4ac68959..e768d36fc8e 100644 --- a/src/sage/graphs/mcqd.pyx +++ b/src/sage/graphs/mcqd.pyx @@ -1,3 +1,5 @@ +# distutils: language = c++ +# sage_setup: package = sage-mcqd from sage.ext.memory_allocator cimport MemoryAllocator diff --git a/src/sage/interfaces/primecount.pyx b/src/sage/interfaces/primecount.pyx index 6f0fea413f8..9f2ed88e0e8 100644 --- a/src/sage/interfaces/primecount.pyx +++ b/src/sage/interfaces/primecount.pyx @@ -1,3 +1,5 @@ +# sage_setup: package = sage-primecount + r""" Interface to the primecount library """ diff --git a/src/sage/libs/fes.pyx b/src/sage/libs/fes.pyx index 3cc2e35c8c0..06a8db7f62e 100644 --- a/src/sage/libs/fes.pyx +++ b/src/sage/libs/fes.pyx @@ -1,3 +1,6 @@ +# distutils: language = c +# distutils: libraries = fes +# sage_setup: distribution = sage-fes """ Binding for the FES library diff --git a/src/sage/libs/meataxe.pyx b/src/sage/libs/meataxe.pyx index 7549e55e0d9..f6fc4be1585 100644 --- a/src/sage/libs/meataxe.pyx +++ b/src/sage/libs/meataxe.pyx @@ -1,3 +1,5 @@ +# distutils: libraries = mtx +# sage_setup: distribution = sage-meataxe #***************************************************************************** # Copyright (C) 2017 Simon King # diff --git a/src/sage/libs/sirocco.pyx b/src/sage/libs/sirocco.pyx index f3b4fabbc90..fecf69bfb1b 100644 --- a/src/sage/libs/sirocco.pyx +++ b/src/sage/libs/sirocco.pyx @@ -1,4 +1,7 @@ #cython: boundscheck=False, wraparound=False +# distutils: libraries = sirocco +# distutils: language = c++ +# sage_setup: distribution = sage-sirocco r""" Cython wrapper for sirocco library diff --git a/src/sage/matrix/matrix_gfpn_dense.pyx b/src/sage/matrix/matrix_gfpn_dense.pyx index ed9c0aaf09f..42af34dc10b 100644 --- a/src/sage/matrix/matrix_gfpn_dense.pyx +++ b/src/sage/matrix/matrix_gfpn_dense.pyx @@ -1,3 +1,5 @@ +# distutils: libraries = mtx +# sage_setup: distribution = sage-meataxe r""" Dense Matrices over `\mathbb F_q`, with `q<255`. From 0940b3f579221645c6a3a2941181961229d37ea6 Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Wed, 3 Jun 2020 07:03:16 -0700 Subject: [PATCH 215/300] Move cimport of array out of hypergeometric_misc.pxd --- src/sage/modular/hypergeometric_misc.pxd | 2 -- src/sage/modular/hypergeometric_misc.pyx | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/modular/hypergeometric_misc.pxd b/src/sage/modular/hypergeometric_misc.pxd index 9d2d48875ce..00bf9a97e9a 100644 --- a/src/sage/modular/hypergeometric_misc.pxd +++ b/src/sage/modular/hypergeometric_misc.pxd @@ -1,4 +1,2 @@ -from cpython cimport array - cpdef hgm_coeffs(long long p, int f, int prec, gamma, m, int D, gtable, int gtable_prec, bint use_longs) diff --git a/src/sage/modular/hypergeometric_misc.pyx b/src/sage/modular/hypergeometric_misc.pyx index eee3053417d..93e2eb34257 100644 --- a/src/sage/modular/hypergeometric_misc.pyx +++ b/src/sage/modular/hypergeometric_misc.pyx @@ -2,6 +2,8 @@ Some utility routines for the hypergeometric motives package that benefit significantly from Cythonization. """ +from cpython cimport array + cpdef hgm_coeffs(long long p, int f, int prec, gamma, m, int D, gtable, int gtable_prec, bint use_longs): r""" From 6909e239c75532c164653749ac6e761fcebafce6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 21 May 2020 22:31:28 -0700 Subject: [PATCH 216/300] build/pkgs/coxeter3/distros/fedora.txt: New --- build/pkgs/coxeter3/distros/fedora.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 build/pkgs/coxeter3/distros/fedora.txt diff --git a/build/pkgs/coxeter3/distros/fedora.txt b/build/pkgs/coxeter3/distros/fedora.txt new file mode 100644 index 00000000000..3cfeb2f9fa0 --- /dev/null +++ b/build/pkgs/coxeter3/distros/fedora.txt @@ -0,0 +1 @@ +coxeter coxeter-devel coxeter-tools From 2b060ae616fdd86495dc396eb333422c5dd5fa82 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 2 Jun 2020 22:30:25 -0700 Subject: [PATCH 217/300] src/module_list.py: Move OptionalExtension options for sage.libs.coxeter3.coxeter to distutils directive --- src/module_list.py | 4 +--- src/sage/libs/coxeter3/coxeter.pyx | 4 ++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/module_list.py b/src/module_list.py index d7b5f459cf0..d3b4d4bb08a 100644 --- a/src/module_list.py +++ b/src/module_list.py @@ -517,9 +517,7 @@ def uname_specific(name, value, alternative): OptionalExtension('sage.libs.coxeter3.coxeter', sources = ['sage/libs/coxeter3/coxeter.pyx'], - include_dirs = [os.path.join(SAGE_INC, 'coxeter')], - language="c++", - libraries = ['coxeter3'], +# include_dirs = [os.path.join(SAGE_INC, 'coxeter')], package = 'coxeter3'), Extension('sage.libs.ecl', diff --git a/src/sage/libs/coxeter3/coxeter.pyx b/src/sage/libs/coxeter3/coxeter.pyx index b6fbfccab4f..8fe6453ed44 100644 --- a/src/sage/libs/coxeter3/coxeter.pyx +++ b/src/sage/libs/coxeter3/coxeter.pyx @@ -1,4 +1,8 @@ # -*- coding: utf-8 -*- +# distutils: language = c++ +# distutils: libraries = coxeter3 +# sage_setup: distribution = sage-coxeter3 + """ Low level part of the interface to Fokko Ducloux's Coxeter 3 library From 4f0d07df87b853db3b7dfa4d0ee5d5deefa69d6b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 2 Jun 2020 22:45:27 -0700 Subject: [PATCH 218/300] src/sage/libs/coxeter3/decl.pxd: Add coxeter/ prefix to all header includes; src/module_list.py: remove include_dirs option --- src/module_list.py | 1 - src/sage/libs/coxeter3/decl.pxd | 30 +++++++++++++++--------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/module_list.py b/src/module_list.py index d3b4d4bb08a..ec7de971c74 100644 --- a/src/module_list.py +++ b/src/module_list.py @@ -517,7 +517,6 @@ def uname_specific(name, value, alternative): OptionalExtension('sage.libs.coxeter3.coxeter', sources = ['sage/libs/coxeter3/coxeter.pyx'], -# include_dirs = [os.path.join(SAGE_INC, 'coxeter')], package = 'coxeter3'), Extension('sage.libs.ecl', diff --git a/src/sage/libs/coxeter3/decl.pxd b/src/sage/libs/coxeter3/decl.pxd index b8978ffbb0d..56002154226 100644 --- a/src/sage/libs/coxeter3/decl.pxd +++ b/src/sage/libs/coxeter3/decl.pxd @@ -8,17 +8,17 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -cdef extern from "globals.h": +cdef extern from "coxeter/globals.h": ctypedef unsigned long Ulong ######## # Bits # ######## -cdef extern from "bits.h": +cdef extern from "coxeter/bits.h": ctypedef Ulong LFlags -cdef extern from "coxtypes.h" namespace "coxtypes": +cdef extern from "coxeter/coxtypes.h" namespace "coxtypes": ctypedef unsigned short Rank ctypedef Ulong CoxSize # should hold at least 32 bits ctypedef Ulong BettiNbr # should hold at least 32 bits @@ -46,7 +46,7 @@ cdef extern from "coxtypes.h" namespace "coxtypes": ################ # String # ################ -cdef extern from "io.h" namespace "io": +cdef extern from "coxeter/io.h" namespace "io": cdef cppclass c_String "io::String": c_String() c_String(char* s) @@ -59,7 +59,7 @@ cdef extern from "io.h" namespace "io": ############## # Type # ############## -cdef extern from "type.h": +cdef extern from "coxeter/type.h": cdef cppclass c_Type "coxeter::Type": c_Type() c_Type(char* s) @@ -69,13 +69,13 @@ cdef extern from "type.h": ############## # Bits # ############## -cdef extern from "bits.h" namespace "bits": +cdef extern from "coxeter/bits.h" namespace "bits": Generator firstBit(Ulong n) ################## # CoxGraph # ################## -cdef extern from "graph.h" namespace "graph": +cdef extern from "coxeter/graph.h" namespace "graph": ctypedef unsigned short CoxEntry ctypedef struct c_CoxGraph "graph::CoxGraph": pass @@ -83,19 +83,19 @@ cdef extern from "graph.h" namespace "graph": ############### # KLPol # ############### -cdef extern from "kl.h" namespace "kl": +cdef extern from "coxeter/kl.h" namespace "kl": cdef cppclass c_KLPol "kl::KLPol": const unsigned short& operator[](Ulong j) unsigned long deg() int isZero() -cdef extern from "polynomials.h" namespace "polynomials": +cdef extern from "coxeter/polynomials.h" namespace "polynomials": c_String klpoly_append "polynomials::append"(c_String str, c_KLPol, char* x) ################## # List # ################## -cdef extern from "list.h" namespace "list": +cdef extern from "coxeter/list.h" namespace "list": cdef cppclass c_List_CoxWord "list::List ": c_List_CoxWord() c_List_CoxWord(Ulong len) @@ -106,7 +106,7 @@ cdef extern from "list.h" namespace "list": ################### # CoxGroup # ################### -cdef extern from "coxgroup.h": +cdef extern from "coxeter/coxgroup.h": cdef cppclass c_CoxGroup "coxeter::CoxGroup": c_CoxGroup() c_CoxGroup(c_Type t, Rank r) @@ -139,16 +139,16 @@ cdef extern from "coxgroup.h": ##################### # Interactive # ##################### -cdef extern from "interactive.h" namespace "interactive": +cdef extern from "coxeter/interactive.h" namespace "interactive": c_CoxGroup* coxeterGroup(c_Type x, Rank l) -cdef extern from "constants.h": +cdef extern from "coxeter/constants.h": void initConstants() ############################### # Finite Coxeter groups # ############################### -cdef extern from "fcoxgroup.h" namespace "fcoxgroup": +cdef extern from "coxeter/fcoxgroup.h" namespace "fcoxgroup": ctypedef struct c_FiniteCoxGroup "fcoxgroup::FiniteCoxGroup": void fullContext() bint isFullContext() @@ -161,5 +161,5 @@ cdef extern from "fcoxgroup.h" namespace "fcoxgroup": ###################### # Sage specific # ###################### -cdef extern from "sage.h" namespace "sage": +cdef extern from "coxeter/sage.h" namespace "sage": void interval(c_List_CoxWord& l, c_CoxGroup& W, c_CoxWord& g, c_CoxWord& h) From 1497f3f08d580fb6579e8316f3e4b05d5e8d81b8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 3 Jun 2020 09:39:10 -0700 Subject: [PATCH 219/300] build/pkgs/coxeter3/spkg-configure.m4: New --- build/pkgs/coxeter3/spkg-configure.m4 | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 build/pkgs/coxeter3/spkg-configure.m4 diff --git a/build/pkgs/coxeter3/spkg-configure.m4 b/build/pkgs/coxeter3/spkg-configure.m4 new file mode 100644 index 00000000000..108c76503c2 --- /dev/null +++ b/build/pkgs/coxeter3/spkg-configure.m4 @@ -0,0 +1,21 @@ +SAGE_SPKG_CONFIGURE([coxeter3], [ + AC_LANG_PUSH(C++) + AC_MSG_CHECKING([for library coxeter3]) + SAVE_LIBS="$LIBS" + LIBS="$LIBS -lcoxeter3" + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[ + #include + #include + ]], [[ + coxeter::CoxGroup *g = interactive::coxeterGroup("B", 2); + ]]) + ], [ + AC_MSG_RESULT([yes]) + ], [ + AC_MSG_RESULT([no]) + sage_spkg_install_coxeter3=yes + ]) + LIBS="$SAVE_LIBS" + AC_LANG_POP(C++) +]) From 8f9d62761bbab1efc8206985e25c93a2e09bd8ba Mon Sep 17 00:00:00 2001 From: vipul79321 Date: Wed, 3 Jun 2020 22:53:02 +0530 Subject: [PATCH 220/300] made corrections --- src/sage/graphs/graph.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 772834cd7e3..95e8f36b73b 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -5363,7 +5363,7 @@ def weight_function(e): if algorithm is None: algorithm = 'Dijkstra_Boost' - if v is None: + if v is None or all(u in self for u in v): # If we want to use BFS, we use the Cython routine if algorithm == 'BFS': if by_weight: @@ -5501,7 +5501,7 @@ def weight_function(e): from sage.graphs.distances_all_pairs import radius_DHV return radius_DHV(self) - return min(self.eccentricity(v=list(self), by_weight=by_weight, + return min(self.eccentricity(v=None,by_weight=by_weight, weight_function=weight_function, check_weight=check_weight, algorithm=algorithm)) From 0bd21a1f02ef0a74782f66aba621f40c3eb68467 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 3 Jun 2020 11:08:11 -0700 Subject: [PATCH 221/300] src/module_list.py: Implement uname_specific flags using cython_aliases --- src/module_list.py | 13 +------------ src/sage/env.py | 12 ++++++++++++ src/sage/libs/libecm.pyx | 2 ++ 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/module_list.py b/src/module_list.py index d7b5f459cf0..bea455a3b90 100644 --- a/src/module_list.py +++ b/src/module_list.py @@ -116,14 +116,6 @@ ############################################################# from sage_setup.optional_extension import OptionalExtension -UNAME = os.uname() - -def uname_specific(name, value, alternative): - if name in UNAME[0]: - return value - else: - return alternative - ext_modules = [ @@ -573,10 +565,7 @@ def uname_specific(name, value, alternative): language = 'c++'), Extension('sage.libs.libecm', - sources = ['sage/libs/libecm.pyx'], - libraries = ['ecm'], - extra_link_args = uname_specific("Linux", ["-Wl,-z,noexecstack"], - [])), + sources = ['sage/libs/libecm.pyx']), Extension('sage.libs.lrcalc.lrcalc', sources = ["sage/libs/lrcalc/lrcalc.pyx"]), diff --git a/src/sage/env.py b/src/sage/env.py index 18d86fe6c49..1aba25a1ed1 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -424,6 +424,18 @@ def cython_aliases(): aliases[var + "LIBEXTRA"] = list(filter(lambda s: not s.startswith(('-l','-L')), pkgconfig.libs(lib).split())) aliases[var + "LIBRARIES"] = pc['libraries'] + # uname-specific flags + UNAME = os.uname() + + def uname_specific(name, value, alternative): + if name in UNAME[0]: + return value + else: + return alternative + + aliases["LINUX_NOEXECSTACK"] = uname_specific("Linux", ["-Wl,-z,noexecstack"], + []) + # LinBox needs special care because it actually requires C++11 with # GNU extensions: -std=c++11 does not work, you need -std=gnu++11 # (this is true at least with GCC 7.2.0). diff --git a/src/sage/libs/libecm.pyx b/src/sage/libs/libecm.pyx index 41a788aca3f..1deacb45b39 100644 --- a/src/sage/libs/libecm.pyx +++ b/src/sage/libs/libecm.pyx @@ -1,3 +1,5 @@ +# distutils: libraries = ecm +# distutils: extra_link_args = LINUX_NOEXECSTACK r""" The Elliptic Curve Method for Integer Factorization (ECM) From 3542258fe33f184b33e1963eb94ab87b60271b0e Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Wed, 3 Jun 2020 14:15:21 -0700 Subject: [PATCH 222/300] Add error handling to padic_H_value, H_value; utility functions --- src/sage/modular/hypergeometric_motive.py | 104 +++++++++++++++++++--- 1 file changed, 94 insertions(+), 10 deletions(-) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index 2ca511d499a..8c039ef1d74 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -648,6 +648,21 @@ def gamma_list(self): resu += [sgn(n) * v] * abs(n) return resu + def wild_primes(self): + r""" + Return the wild primes. + + EXAMPLES:: + + sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp + sage: Hyp(cyclotomic=([3],[4])).wild_primes() + [2, 3] + sage: Hyp(cyclotomic=([2,2,2,2,3,3,3,6,6],[1,1,4,5,9])).wild_primes() + [2, 3, 5] + """ + gamma = self.gamma_array() + return sorted(list(set([p for n in gamma.keys() for (p, _) in n.factor()]))) + def zigzag(self, x, flip_beta=False): r""" Count ``alpha``'s at most ``x`` minus ``beta``'s at most ``x``. @@ -1214,9 +1229,23 @@ def padic_H_value(self, p, f, t, prec=None, cache_p=False): sage: H = Hyp(alpha_beta=([1/5,2/5,3/5,4/5,1/5,2/5,3/5,4/5], [1/4,3/4,1/7,2/7,3/7,4/7,5/7,6/7])) sage: try: ....: print(H.padic_H_value(373, 4, 2)) - ....: except ValueError: - ....: print("Overflow detected") - Overflow detected + ....: except ValueError as s: + ....: print(s) + p^f cannot exceed 2^31 + + Check error handling for wild and tame primes:: + + sage: H = Hyp(alpha_beta=([1/5,2/5,3/5,4/5,1/5,2/5,3/5,4/5], [1/4,3/4,1/7,2/7,3/7,4/7,5/7,6/7])) + sage: try: + ....: print(H.padic_H_value(5, 1, 2)) + ....: except NotImplementedError as s: + ....: print(s) + p is wild + sage: try: + ....: print(H.padic_H_value(3, 1, 3)) + ....: except NotImplementedError as s: + ....: print(s) + p is tame REFERENCES: @@ -1225,6 +1254,13 @@ def padic_H_value(self, p, f, t, prec=None, cache_p=False): alpha = self._alpha beta = self._beta t = QQ(t) + if not is_prime(p): + raise ValueError('p not prime') + if not all(x.denominator() % p for x in self._alpha + self._beta): + raise NotImplementedError('p is wild') + if (t.numerator()*t.denominator() % p == 0 or (t-1) % p == 0): + raise NotImplementedError('p is tame') + if 0 in alpha: return self._swap.padic_H_value(p, f, ~t, prec) q = p ** f @@ -1263,6 +1299,8 @@ def padic_H_value(self, p, f, t, prec=None, cache_p=False): resu = ZZ(-1) ** m[0] * sigma / (1 - q) return IntegerModRing(p**prec)(resu).lift_centered() + trace = padic_H_value + @cached_method def H_value(self, p, f, t, ring=None): """ @@ -1324,6 +1362,31 @@ def H_value(self, p, f, t, ring=None): sage: [H2.H_value(5,1,QQ(i)) for i in range(2,5)] [-4, 1, -4] + TESTS: + + Check issue from :trac:`29778`:: + + sage: H = Hyp(alpha_beta=([1/5,2/5,3/5,4/5,1/5,2/5,3/5,4/5], [1/4,3/4,1/7,2/7,3/7,4/7,5/7,6/7])) + sage: try: + ....: print(H.padic_H_value(373, 4, 2)) + ....: except ValueError as s: + ....: print(s) + p^f cannot exceed 2^31 + + Check error handling for wild and tame primes:: + + sage: H = Hyp(alpha_beta=([1/5,2/5,3/5,4/5,1/5,2/5,3/5,4/5], [1/4,3/4,1/7,2/7,3/7,4/7,5/7,6/7])) + sage: try: + ....: print(H.padic_H_value(5, 1, 2)) + ....: except NotImplementedError as s: + ....: print(s) + p is wild + sage: try: + ....: print(H.padic_H_value(3, 1, 3)) + ....: except NotImplementedError as s: + ....: print(s) + p is tame + REFERENCES: - [BeCoMe]_ (Theorem 1.3) @@ -1332,6 +1395,13 @@ def H_value(self, p, f, t, ring=None): alpha = self._alpha beta = self._beta t = QQ(t) + if not is_prime(p): + raise ValueError('p not prime') + if not all(x.denominator() % p for x in self._alpha + self._beta): + raise NotImplementedError('p is wild') + if (t.numerator()*t.denominator() % p == 0 or (t-1) % p == 0): + raise NotImplementedError('p is tame') + if 0 in alpha: return self._swap.H_value(p, f, ~t, ring) if ring is None: @@ -1507,18 +1577,32 @@ def euler_factor(self, t, p, cache_p=False): sage: H = Hyp(alpha_beta=([1/5,2/5,3/5,4/5,1/5,2/5,3/5,4/5], [1/4,3/4,1/7,2/7,3/7,4/7,5/7,6/7])) sage: try: ....: print(H.euler_factor(2, 373)) - ....: except ValueError: - ....: print("Overflow detected") - ....: - Overflow detected + ....: except ValueError as s: + ....: print(s) + p^f cannot exceed 2^31 + + Check error handling for wild and tame primes:: + + sage: H = Hyp(alpha_beta=([1/5,2/5,3/5,4/5,1/5,2/5,3/5,4/5], [1/4,3/4,1/7,2/7,3/7,4/7,5/7,6/7])) + sage: try: + ....: print(H.euler_factor(2, 5)) + ....: except NotImplementedError as s: + ....: print(s) + p is wild + sage: try: + ....: print(H.euler_factor(3, 3)) + ....: except NotImplementedError as s: + ....: print(s) + p is tame REFERENCES: - [Roberts2015]_ - [Watkins]_ """ - if t not in QQ or t in [0, 1]: - raise ValueError('wrong t') + t = QQ(t) + if t in [0, 1]: + raise ValueError('invalid t') alpha = self._alpha if 0 in alpha: return self._swap.euler_factor(~t, p) @@ -1527,7 +1611,7 @@ def euler_factor(self, t, p, cache_p=False): raise ValueError('p not prime') if not all(x.denominator() % p for x in self._alpha + self._beta): raise NotImplementedError('p is wild') - if (t.valuation(p) or (t - 1).valuation(p) > 0): + if (t.numerator()*t.denominator() % p == 0 or (t-1) % p == 0): raise NotImplementedError('p is tame') # now p is good d = self.degree() From 28219340dd0eb3d939dcd0c7e9fbc89133490a0c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 3 Jun 2020 14:39:15 -0700 Subject: [PATCH 223/300] Fix sage_setup directives: Use distribution, not package --- src/sage/graphs/bliss.pyx | 2 +- src/sage/graphs/mcqd.pyx | 2 +- src/sage/interfaces/primecount.pyx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/graphs/bliss.pyx b/src/sage/graphs/bliss.pyx index d21c034a6e3..0448766d1f0 100644 --- a/src/sage/graphs/bliss.pyx +++ b/src/sage/graphs/bliss.pyx @@ -1,6 +1,6 @@ # distutils: language = c++ # distutils: libraries = bliss -# sage_setup: package = sage-bliss +# sage_setup: distribution = sage-bliss r""" Interface with bliss: graph (iso/auto)morphism diff --git a/src/sage/graphs/mcqd.pyx b/src/sage/graphs/mcqd.pyx index e768d36fc8e..c903ab9f9eb 100644 --- a/src/sage/graphs/mcqd.pyx +++ b/src/sage/graphs/mcqd.pyx @@ -1,5 +1,5 @@ # distutils: language = c++ -# sage_setup: package = sage-mcqd +# sage_setup: distribution = sage-mcqd from sage.ext.memory_allocator cimport MemoryAllocator diff --git a/src/sage/interfaces/primecount.pyx b/src/sage/interfaces/primecount.pyx index 9f2ed88e0e8..45a80c648dd 100644 --- a/src/sage/interfaces/primecount.pyx +++ b/src/sage/interfaces/primecount.pyx @@ -1,4 +1,4 @@ -# sage_setup: package = sage-primecount +# sage_setup: distribution = sage-primecount r""" Interface to the primecount library From 700ce3be48cf6fbabf549c218dab3c9b57c4affc Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Mon, 11 May 2020 18:03:22 +0100 Subject: [PATCH 224/300] spkg-configure for palp --- build/pkgs/palp/distros/arch.txt | 1 + build/pkgs/palp/distros/conda.txt | 1 + build/pkgs/palp/distros/debian.txt | 1 + build/pkgs/palp/distros/fedora.txt | 1 + build/pkgs/palp/spkg-configure.m4 | 4 ++++ 5 files changed, 8 insertions(+) create mode 100644 build/pkgs/palp/distros/arch.txt create mode 100644 build/pkgs/palp/distros/conda.txt create mode 100644 build/pkgs/palp/distros/debian.txt create mode 100644 build/pkgs/palp/distros/fedora.txt create mode 100644 build/pkgs/palp/spkg-configure.m4 diff --git a/build/pkgs/palp/distros/arch.txt b/build/pkgs/palp/distros/arch.txt new file mode 100644 index 00000000000..f037baef346 --- /dev/null +++ b/build/pkgs/palp/distros/arch.txt @@ -0,0 +1 @@ +palp diff --git a/build/pkgs/palp/distros/conda.txt b/build/pkgs/palp/distros/conda.txt new file mode 100644 index 00000000000..f037baef346 --- /dev/null +++ b/build/pkgs/palp/distros/conda.txt @@ -0,0 +1 @@ +palp diff --git a/build/pkgs/palp/distros/debian.txt b/build/pkgs/palp/distros/debian.txt new file mode 100644 index 00000000000..f037baef346 --- /dev/null +++ b/build/pkgs/palp/distros/debian.txt @@ -0,0 +1 @@ +palp diff --git a/build/pkgs/palp/distros/fedora.txt b/build/pkgs/palp/distros/fedora.txt new file mode 100644 index 00000000000..f037baef346 --- /dev/null +++ b/build/pkgs/palp/distros/fedora.txt @@ -0,0 +1 @@ +palp diff --git a/build/pkgs/palp/spkg-configure.m4 b/build/pkgs/palp/spkg-configure.m4 new file mode 100644 index 00000000000..bb82b78c8c6 --- /dev/null +++ b/build/pkgs/palp/spkg-configure.m4 @@ -0,0 +1,4 @@ +SAGE_SPKG_CONFIGURE([palp], [ + AC_PATH_PROG([PALP], [poly.x]) + AS_IF([test -z "$ac_cv_path_PALP"], [sage_spkg_install_palp=yes]) +]) From ad8ca4de3dcb1b9b217c5363443dbfe113d84a1b Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 4 Jun 2020 09:18:40 +1000 Subject: [PATCH 225/300] Fixing the docbuild by having the correct files listed. --- src/doc/en/reference/combinat/module_list.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst index f3ce3d79aca..0104d503baa 100644 --- a/src/doc/en/reference/combinat/module_list.rst +++ b/src/doc/en/reference/combinat/module_list.rst @@ -171,7 +171,8 @@ Comprehensive Module list sage/combinat/output sage/combinat/parallelogram_polyomino sage/combinat/parking_functions - sage/combinat/path_tableaux/catalan + sage/combinat/path_tableaux/catalog + sage/combinat/path_tableaux/dyck_path sage/combinat/path_tableaux/path_tableau sage/combinat/plane_partition sage/combinat/partition From c050f63986b5292814ff24de3b9e4288c3221cb0 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 4 Jun 2020 10:19:17 +1000 Subject: [PATCH 226/300] Fixing a memory leak in mat * vec over GF(2). --- src/sage/matrix/matrix_mod2_dense.pyx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sage/matrix/matrix_mod2_dense.pyx b/src/sage/matrix/matrix_mod2_dense.pyx index a468e36fe56..6a21e923215 100644 --- a/src/sage/matrix/matrix_mod2_dense.pyx +++ b/src/sage/matrix/matrix_mod2_dense.pyx @@ -595,20 +595,18 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) """ cdef mzd_t *tmp + VS = VectorSpace(self._base_ring, self._nrows) if not isinstance(v, Vector_mod2_dense): - M = VectorSpace(self._base_ring, self._nrows) - v = M(v) + v = VS(v) if self.ncols() != v.degree(): raise ArithmeticError("number of columns of matrix must equal degree of vector") - VS = VectorSpace(self._base_ring, self._nrows) # If the vector is 0-dimensional, the result will be the 0-vector if not self.ncols(): return VS.zero() cdef Vector_mod2_dense c = Vector_mod2_dense.__new__(Vector_mod2_dense) sig_str("matrix allocation failed") c._init(self._nrows, VS) - c._entries = mzd_init(1, self._nrows) if c._entries.nrows and c._entries.ncols: tmp = mzd_init(self._nrows, 1) _mzd_mul_naive(tmp, self._entries, (v)._entries, 0) From 23aeff8f4b8ca383c80321f849600c8f29474288 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 4 Jun 2020 11:10:51 +1000 Subject: [PATCH 227/300] Adding some more documentation. --- src/doc/en/reference/references/index.rst | 10 ++++++++++ src/sage/combinat/diagram_algebras.py | 20 +++++++++++++++----- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 9c1d07c13b9..af6c8e4b701 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1978,6 +1978,13 @@ REFERENCES: *Fifth Annual Graph Drawing Contest*; http://www.merl.com/papers/docs/TR98-16.pdf +.. [Eny2012] \J. Enyang. *Jucys-Murphy elements and a presentation + for the partition algebra*. J. Algebraic Combin. + **37** (2012) no 3, 401--454. + +.. [Eny2013] \J. Enyang. *A seminormal form for partition algebras*. + J. Combin. Theory Series A **120** (2013) 1737--1785. + .. [EP2013] David Einstein, James Propp. *Combinatorial, piecewise-linear, and birational homomesy for products of two chains*. :arxiv:`1310.5294v1`. @@ -2729,6 +2736,9 @@ REFERENCES: Operations", Annual ACM Symposium on Theory of Computing, Proceedings of the Fourth Annual ACM Symposium on Theory of Computing, pp. 108--118, 1972 +.. [HR2005] Tom Halverson and Arun Ram. *Partition algebras*. + Euro. J. Combin. **26** (2005) 869--921. + .. [HR2016] Clemens Heuberger and Roswitha Rissner, "Computing `J`-Ideals of a Matrix Over a Principal Ideal Domain", :arxiv:`1611.10308`, 2016. diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index b1079300338..6ba8a9597e0 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -2766,8 +2766,11 @@ def s(self, i): @cached_method def sigma(self, i): r""" - Return the element `\sigma_i` from [Cre2020]_ - (with the index `i` divided by 2). + Return the element `\sigma_i` from [Eny2012]_ of ``self``. + + .. NOTE:: + + In [Cre2020]_ and [Eny2013]_, these are the elements `\sigma_{2i}`. EXAMPLES:: @@ -2836,17 +2839,24 @@ def sigma(self, i): @cached_method def jucys_murphy_element(self, i): r""" - Return the ``i``-th Jucys-Murphy element `L_i` of ``self``. + Return the ``i``-th Jucys-Murphy element `L_{2i}` from [Eny2012]_ + of ``self``. ALGORITHM: - We use the recursive definition given in [Cre2020]_ - (except we divide the indices by 2). + We use the recursive definition for `L_{2i}` given in [Cre2020]_. + See also [Eny2012]_ and [Eny2013]_. + + .. NOTE:: + + `L_{1/2}` and `L_1` differs from [HR2005]_. EXAMPLES: sage: R. = QQ[] sage: P3 = PartitionAlgebra(3, n) + sage: P3.jucys_murphy_element(1/2) + 0 sage: P3.jucys_murphy_element(1) P{{-3, 3}, {-2, 2}, {-1}, {1}} sage: P3.jucys_murphy_element(2) From 5da0b8851817b98ad91df9c3588440362f2df176 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 4 Jun 2020 11:19:24 +1000 Subject: [PATCH 228/300] Catching bad i's earlier. --- src/sage/combinat/diagram_algebras.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 6ba8a9597e0..3cc0f254b8c 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -2807,6 +2807,9 @@ def sigma(self, i): ....: for i in range(1,k)) True """ + if i <= 0 or i >= self._k: + raise ValueError("i must be an (half) integer between 1 and {}".format((2*self._k-1)/2)) + half = QQ.one() / 2 if i in ZZ: if i == 1: @@ -2907,6 +2910,9 @@ def jucys_murphy_element(self, i): ....: == P.e(2*i/2) * P.L(2*i/2) for i in range(1,k)) True """ + if i <= 0 or i > self._k: + raise ValueError("i must be an (half) integer between 1/2 and {}".format(2*self._k)) + half = QQ.one() / 2 if i in ZZ: if i == 1: From c79fc1b959060ab8f07fe5eb2526249e028f7244 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Thu, 4 Jun 2020 10:50:53 +0100 Subject: [PATCH 229/300] inner loop macro --- build/pkgs/palp/spkg-configure.m4 | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/build/pkgs/palp/spkg-configure.m4 b/build/pkgs/palp/spkg-configure.m4 index bb82b78c8c6..29a43a387ab 100644 --- a/build/pkgs/palp/spkg-configure.m4 +++ b/build/pkgs/palp/spkg-configure.m4 @@ -1,4 +1,14 @@ +AC_DEFUN([SAGE_TEST_PALP_PROGS], [ + AC_PATH_PROG(PALP[$1], [[$1].x]) + AS_IF([test x$PALP[$1] = x], [sage_spkg_install_palp=yes]) + m4_foreach([suff], [4, 5, 6, 11], [ + AC_PATH_PROG(PALP[$1]suff, [[$1][-]suff[d.x]]) + AS_IF([test x$PALP[$1]suff = x], [sage_spkg_install_palp=yes]) + ]) +]) + SAGE_SPKG_CONFIGURE([palp], [ - AC_PATH_PROG([PALP], [poly.x]) - AS_IF([test -z "$ac_cv_path_PALP"], [sage_spkg_install_palp=yes]) + dnl m4_foreach([palpprog], [[poly], [class], [nef], [cws]], [ + SAGE_TEST_PALP_PROGS(poly) + dnl ]) ]) From 4a6ec7012007e4417801e73666631f572ac107ff Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Thu, 4 Jun 2020 11:25:30 +0100 Subject: [PATCH 230/300] getting quoting right everywhere --- build/pkgs/palp/spkg-configure.m4 | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/build/pkgs/palp/spkg-configure.m4 b/build/pkgs/palp/spkg-configure.m4 index 29a43a387ab..f44c857ccbd 100644 --- a/build/pkgs/palp/spkg-configure.m4 +++ b/build/pkgs/palp/spkg-configure.m4 @@ -1,14 +1,10 @@ -AC_DEFUN([SAGE_TEST_PALP_PROGS], [ - AC_PATH_PROG(PALP[$1], [[$1].x]) - AS_IF([test x$PALP[$1] = x], [sage_spkg_install_palp=yes]) - m4_foreach([suff], [4, 5, 6, 11], [ - AC_PATH_PROG(PALP[$1]suff, [[$1][-]suff[d.x]]) - AS_IF([test x$PALP[$1]suff = x], [sage_spkg_install_palp=yes]) - ]) -]) - SAGE_SPKG_CONFIGURE([palp], [ - dnl m4_foreach([palpprog], [[poly], [class], [nef], [cws]], [ - SAGE_TEST_PALP_PROGS(poly) - dnl ]) + m4_foreach([palpprog], [[poly], [class], [nef], [cws]], [ + AC_PATH_PROG(PALP[]palpprog, [palpprog.x]) + AS_IF([test x$PALP[]palpprog = x], [sage_spkg_install_palp=yes]) + m4_foreach([suff], [4, 5, 6, 11], [ + AC_PATH_PROG(PALP[]palpprog[]suff, [palpprog[-]suff[d.x]]) + AS_IF([test x$PALP[]palpprog[]suff = x], [sage_spkg_install_palp=yes]) + ]) + ]) ]) From 295901a638b8e54afabbb7e1bb7ac1b99dd5d226 Mon Sep 17 00:00:00 2001 From: Kiran Kedlaya Date: Thu, 4 Jun 2020 07:47:25 -0700 Subject: [PATCH 231/300] Simplify wild_primes --- src/sage/modular/hypergeometric_motive.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index 8c039ef1d74..b15d149cb42 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -661,7 +661,7 @@ def wild_primes(self): [2, 3, 5] """ gamma = self.gamma_array() - return sorted(list(set([p for n in gamma.keys() for (p, _) in n.factor()]))) + return sorted(set([p for n in gamma.keys() for (p, _) in n.factor()])) def zigzag(self, x, flip_beta=False): r""" From 2437136be053d0ef9e44de79c0ed2cec512dbd4e Mon Sep 17 00:00:00 2001 From: vipul79321 Date: Thu, 4 Jun 2020 23:23:17 +0530 Subject: [PATCH 232/300] Fixed for negative edge weights --- src/sage/graphs/base/boost_graph.pyx | 44 +++++++++------------------- src/sage/graphs/graph.py | 13 ++++---- 2 files changed, 22 insertions(+), 35 deletions(-) diff --git a/src/sage/graphs/base/boost_graph.pyx b/src/sage/graphs/base/boost_graph.pyx index 36db9ff0b1c..8df37d25dbf 100644 --- a/src/sage/graphs/base/boost_graph.pyx +++ b/src/sage/graphs/base/boost_graph.pyx @@ -1646,9 +1646,9 @@ cpdef radius_DHV(g, weight_function=None, check_weight=True): sage: G = Graph(2) sage: radius_DHV(G) +Infinity - sage: G = Graph([(0, 1, 1)]) + sage: G = Graph([(0, 1, 2)],weighted=True) sage: radius_DHV(G) - 1.0 + 2.0 sage: G = DiGraph(1) sage: radius_DHV(G) Traceback (most recent call last): @@ -1665,19 +1665,15 @@ cpdef radius_DHV(g, weight_function=None, check_weight=True): if weight_function and check_weight: g._check_weight_function(weight_function) - cdef bint negative_weight = False - if weight_function is not None: for e in g.edge_iterator(): if float(weight_function(e)) < 0: - negative_weight = True - break - else: - if g.weighted(): - for _,_,w in g.edge_iterator(): - if w and float(w) < 0: - negative_weight = True - break + raise ValueError("graphs contains negative weights, use Johnson_Boost instead") + elif g.weighted(): + for _,_,w in g.edge_iterator(): + if w and float(w) < 0: + raise ValueError("graphs contains negative weights, use Johnson_Boost instead") + # These variables are automatically deleted when the function terminates. cdef dict v_to_int = {vv: vi for vi, vv in enumerate(g)} @@ -1704,16 +1700,9 @@ cpdef radius_DHV(g, weight_function=None, check_weight=True): while LB < UB: # 1) pick vertex with minimum eccentricity lower bound # and compute its eccentricity - if negative_weight: - sig_on() - distances = g_boost.bellman_ford_shortest_paths(source).distances - sig_off() - if not distances.size(): - raise ValueError("the graph contains a negative cycle") - else: - sig_on() - distances = g_boost.dijkstra_shortest_paths(source).distances - sig_off() + sig_on() + distances = g_boost.dijkstra_shortest_paths(source).distances + sig_off() # Determine the eccentricity of source and its antipode, that is a # vertex at largest distance from source @@ -1732,14 +1721,9 @@ cpdef radius_DHV(g, weight_function=None, check_weight=True): break # 2) Compute distances from antipode - if negative_weight: - sig_on() - distances = g_boost.bellman_ford_shortest_paths(antipode).distances - sig_off() - else: - sig_on() - distances = g_boost.dijkstra_shortest_paths(antipode).distances - sig_off() + sig_on() + distances = g_boost.dijkstra_shortest_paths(antipode).distances + sig_off() # 3) Use distances from antipode to improve eccentricity lower bounds. # We also determine the next source diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 95e8f36b73b..f5c1f50d714 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -5363,7 +5363,10 @@ def weight_function(e): if algorithm is None: algorithm = 'Dijkstra_Boost' - if v is None or all(u in self for u in v): + if v is not None and not isinstance(v, list): + v = [v] + + if v is None or all(u in v for u in self): # If we want to use BFS, we use the Cython routine if algorithm == 'BFS': if by_weight: @@ -5388,8 +5391,6 @@ def weight_function(e): raise ValueError("algorithm '" + algorithm + "' works only if all" + " eccentricities are needed") - if not isinstance(v, list): - v = [v] ecc = {} from sage.rings.infinity import Infinity @@ -5439,7 +5440,8 @@ def radius(self, by_weight=False, algorithm='DHV', weight_function=None, - ``algorithm`` -- string (default: ``'DHV'``). - ``'DHV'`` - Radius computation is done using the algorithm proposed - in [Dragan2018]_. For more information see method + in [Dragan2018]_. Works for graph with non-negative edge weights. + For more information see method :func:`sage.graphs.distances_all_pairs.radius_DHV` and :func:`sage.graphs.base.boost_graph.radius_DHV`. @@ -5496,7 +5498,8 @@ def weight_function(e): if algorithm == 'DHV': if by_weight: from sage.graphs.base.boost_graph import radius_DHV - return radius_DHV(self, weight_function=weight_function) + return radius_DHV(self, weight_function=weight_function, + check_weight=check_weight) else: from sage.graphs.distances_all_pairs import radius_DHV return radius_DHV(self) From 0ab58ab1a16bedf5e936fbe60ec40e9df64d062a Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 5 Jun 2020 12:19:43 +1000 Subject: [PATCH 233/300] Making JM elements work for half partition algebras. --- src/sage/combinat/diagram_algebras.py | 85 ++++++++++++++++++++++----- 1 file changed, 71 insertions(+), 14 deletions(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 3cc0f254b8c..accf2e7e987 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -43,7 +43,7 @@ from sage.misc.flatten import flatten from sage.misc.misc_c import prod from sage.rings.all import ZZ, QQ -from sage.functions.other import ceil +from sage.functions.other import floor, ceil import itertools @@ -2719,6 +2719,13 @@ def e(self, i): Traceback (most recent call last): ... ValueError: i must be an (half) integer between 1/2 and 5/2 + + sage: P2h = PartitionAlgebra(5/2,n) + sage: [P2h.e(k/2) for k in range(1,5)] + [P{{-3, 3}, {-2, 2}, {-1}, {1}}, + P{{-3, 3}, {-2, -1, 1, 2}}, + P{{-3, 3}, {-2}, {-1, 1}, {2}}, + P{{-3, -2, 2, 3}, {-1, 1}}] """ if i <= 0 or i >= self._k: raise ValueError("i must be an (half) integer between 1/2 and {}".format((2*self._k-1)/2)) @@ -2726,12 +2733,12 @@ def e(self, i): SP = B.keys() if i in ZZ: i -= 1 - D = [[-j, j] for j in range(1, self._k+1)] + D = [[-j, j] for j in range(1, ceil(self._k)+1)] D[i] += D.pop(i+1) return B[SP(D)] else: i = ceil(i) - D = [[-j, j] for j in range(1, self._k+1)] + D = [[-j, j] for j in range(1, ceil(self._k)+1)] D[i-1] = [-i] D.append([i]) return B[SP(D)] @@ -2749,16 +2756,15 @@ def s(self, i): P{{-3, 3}, {-2, 1}, {-1, 2}} sage: P3.s(2) P{{-3, 2}, {-2, 3}, {-1, 1}} - sage: P3.s(3) - Traceback (most recent call last): - ... - ValueError: i must be an integer between 1 and 2 + + sage: R. = ZZ[] + sage: P2h = PartitionAlgebra(5/2,n) + sage: P2h.s(1) + P{{-3, 3}, {-2, 1}, {-1, 2}} """ - if i < 1 or i >= self._k: - raise ValueError("i must be an integer between 1 and {}".format(self._k-1)) B = self.basis() SP = B.keys() - D = [[-j, j] for j in range(1, self._k+1)] + D = [[-j, j] for j in range(1, ceil(self._k)+1)] D[i-1] = [-(i+1), i] D[i] = [-i, i+1] return B[SP(D)] @@ -2798,13 +2804,29 @@ def sigma(self, i): ....: for i in range(1,2*k)) True sage: all(P.sigma(i)*P.sigma(i+1/2) == P.sigma(i+1/2)*P.sigma(i) == P.s(i) - ....: for i in range(1,k)) + ....: for i in range(1,floor(k))) + True + sage: all(P.sigma(i)*P.e(i) == P.e(i)*P.sigma(i) == P.e(i) + ....: for i in range(1,floor(k))) + True + sage: all(P.sigma(i+1/2)*P.e(i) == P.e(i)*P.sigma(i+1/2) == P.e(i) + ....: for i in range(1,floor(k))) + True + + sage: k = 9/2 + sage: R. = QQ[] + sage: P = PartitionAlgebra(k, x) + sage: all(P.sigma(i/2).dual() == P.sigma(i/2) + ....: for i in range(1,2*k-1)) + True + sage: all(P.sigma(i)*P.sigma(i+1/2) == P.sigma(i+1/2)*P.sigma(i) == P.s(i) + ....: for i in range(1,k-1/2)) True sage: all(P.sigma(i)*P.e(i) == P.e(i)*P.sigma(i) == P.e(i) - ....: for i in range(1,k)) + ....: for i in range(1,floor(k))) True sage: all(P.sigma(i+1/2)*P.e(i) == P.e(i)*P.sigma(i+1/2) == P.e(i) - ....: for i in range(1,k)) + ....: for i in range(1,floor(k))) True """ if i <= 0 or i >= self._k: @@ -2909,9 +2931,44 @@ def jucys_murphy_element(self, i): sage: all(P.e(2*i/2) * P.e((2*i+1)/2) * P.sigma((2*i+1)/2) ....: == P.e(2*i/2) * P.L(2*i/2) for i in range(1,k)) True + + The same tests for a half integer partition algebra:: + + sage: k = 9/2 + sage: R. = QQ[] + sage: P = PartitionAlgebra(k, n) + sage: L = [P.L(i/2) for i in range(1,2*k+1)] + sage: all(x.dual() == x for x in L) + True + sage: all(x * y == y * x for x in L for y in L) # long time + True + sage: Lsum = sum(L) + sage: gens = [P.s(i) for i in range(1,k-1/2)] + sage: gens += [P.e(i/2) for i in range(1,2*k)] + sage: all(x * Lsum == Lsum * x for x in gens) + True + sage: all(P.e((2*i+1)/2) * P.sigma(2*i/2) * P.e((2*i+1)/2) + ....: == (n - P.L((2*i-1)/2)) * P.e((2*i+1)/2) for i in range(1,floor(k))) + True + sage: all(P.e(i/2) * (P.L(i/2) + P.L((i+1)/2)) + ....: == (P.L(i/2) + P.L((i+1)/2)) * P.e(i/2) + ....: == n * P.e(i/2) for i in range(1,2*k)) + True + sage: all(P.sigma(2*i/2) * P.e((2*i-1)/2) * P.e(2*i/2) + ....: == P.L(2*i/2) * P.e(2*i/2) for i in range(1,ceil(k))) + True + sage: all(P.e(2*i/2) * P.e((2*i-1)/2) * P.sigma(2*i/2) + ....: == P.e(2*i/2) * P.L(2*i/2) for i in range(1,ceil(k))) + True + sage: all(P.sigma((2*i+1)/2) * P.e((2*i+1)/2) * P.e(2*i/2) + ....: == P.L(2*i/2) * P.e(2*i/2) for i in range(1,floor(k))) + True + sage: all(P.e(2*i/2) * P.e((2*i+1)/2) * P.sigma((2*i+1)/2) + ....: == P.e(2*i/2) * P.L(2*i/2) for i in range(1,floor(k))) + True """ if i <= 0 or i > self._k: - raise ValueError("i must be an (half) integer between 1/2 and {}".format(2*self._k)) + raise ValueError("i must be an (half) integer between 1/2 and {}".format(self._k)) half = QQ.one() / 2 if i in ZZ: From 68b10e1e6665892edad775e6b9b18e93afc3d637 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Fri, 5 Jun 2020 12:44:36 +0200 Subject: [PATCH 234/300] keep dictionaries ordered for doctesting --- src/sage/doctest/forker.py | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py index c93d1f2d995..838f1a60130 100644 --- a/src/sage/doctest/forker.py +++ b/src/sage/doctest/forker.py @@ -51,6 +51,7 @@ from dis import findlinestarts from queue import Empty import gc +import IPython.lib.pretty import sage.misc.randstate as randstate from .util import Timer, RecordingDict, count_noun @@ -86,6 +87,32 @@ exc is not OSError ] +def _sorted_dict_pprinter_factory(start, end): + """ + Modified version of :func:`IPython.lib.pretty._dict_pprinter_factory` + that sorts the keys of dictionaries for printing. + + EXAMPLES:: + + sage: {2: 0, 1: 0} # indirect doctest + {1: 0, 2: 0} + """ + def inner(obj, p, cycle): + if cycle: + return p.text('{...}') + step = len(start) + p.begin_group(step, start) + keys = obj.keys() + keys = IPython.lib.pretty._sorted_for_pprint(keys) + for idx, key in p._enumerate(keys): + if idx: + p.text(',') + p.breakable() + p.pretty(key) + p.text(': ') + p.pretty(obj[key]) + p.end_group(step, end) + return inner def init_sage(): @@ -185,11 +212,11 @@ def init_sage(): # IPython's pretty printer sorts the repr of dicts by their keys by default # (or their keys' str() if they are not otherwise orderable). However, it # disables this for CPython 3.6+ opting to instead display dicts' "natural" - # insertion order, which is preserved in those versions). This makes for - # inconsistent results with Python 2 tests that return dicts, so here we - # force the Python 2 style dict printing - import IPython.lib.pretty - IPython.lib.pretty.DICT_IS_ORDERED = False + # insertion order, which is preserved in those versions). + # However, this order is random in some instances. + # Also modifications of code may affect the order. + # So here we fore sorted dict printing. + IPython.lib.pretty.for_type(dict, _sorted_dict_pprinter_factory('{', '}')) # Switch on extra debugging from sage.structure.debug_options import debug From eba97928a60e528781a984c9737a1611dd021128 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Fri, 5 Jun 2020 14:02:45 -0400 Subject: [PATCH 235/300] insert missing colon --- src/sage/combinat/diagram_algebras.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index accf2e7e987..1b3076b8928 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -2876,7 +2876,7 @@ def jucys_murphy_element(self, i): `L_{1/2}` and `L_1` differs from [HR2005]_. - EXAMPLES: + EXAMPLES:: sage: R. = QQ[] sage: P3 = PartitionAlgebra(3, n) From 3aa2e106185110ae0de25f7379b4bf1f12286078 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Fri, 5 Jun 2020 14:51:23 -0400 Subject: [PATCH 236/300] additions to documentation --- src/sage/combinat/diagram_algebras.py | 28 ++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 1b3076b8928..ad4b5f9a086 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -2699,6 +2699,14 @@ def e(self, i): r""" Return the element `e_i` in ``self``. + If `i = (2r+1)/2`, then `e_i` contains the blocks ``{r+1}`` and + ``{-r-1}``. If `i \in {\mathbb Z}`, then `e_i` contains the block + ``{-i, -i-1, i, i+1}``. Other blocks are of the form `{-j, j}`. + + INPUT: + + - ``i`` -- a half integer between 1/2 and `k` + EXAMPLES:: sage: R. = QQ[] @@ -2748,6 +2756,14 @@ def s(self, i): r""" Return the ``i``-th simple transposition `s_i` in ``self``. + Borrowing the notation from the symmetric group, the ``i``-th + simple transposition has blocks of the form ``{-i, i+1}``, + ``{-i-1, i}`` and ``{-j, j}`` for `j \notin \{ i, i+1 \}`. + + INPUT: + + - ``i`` -- an integer between 1 and `k-1` + EXAMPLES:: sage: R. = QQ[] @@ -2762,6 +2778,8 @@ def s(self, i): sage: P2h.s(1) P{{-3, 3}, {-2, 1}, {-1, 2}} """ + if not i in ZZ or i <= 0 or i >= self._k: + raise ValueError("i must be an integer between 1 and {}".format(self._k-1)) B = self.basis() SP = B.keys() D = [[-j, j] for j in range(1, ceil(self._k)+1)] @@ -2774,6 +2792,10 @@ def sigma(self, i): r""" Return the element `\sigma_i` from [Eny2012]_ of ``self``. + INPUT: + + - ``i`` -- a half integer between 1/2 and `k` + .. NOTE:: In [Cre2020]_ and [Eny2013]_, these are the elements `\sigma_{2i}`. @@ -2864,9 +2886,13 @@ def sigma(self, i): @cached_method def jucys_murphy_element(self, i): r""" - Return the ``i``-th Jucys-Murphy element `L_{2i}` from [Eny2012]_ + Return the ``i``-th Jucys-Murphy element `L_{i}` from [Eny2012]_. of ``self``. + INPUT: + + - ``i`` -- a half integer between 1/2 and `k` + ALGORITHM: We use the recursive definition for `L_{2i}` given in [Cre2020]_. From abb5607710a2a5cc5415423489fa452965cbef68 Mon Sep 17 00:00:00 2001 From: "E. Madison Bray" Date: Fri, 17 Jan 2020 16:59:59 +0000 Subject: [PATCH 237/300] Allow Sage to work with a system Python 3.6. Currently sage-the-distribution is tested against a minimum of Python 3.7, but we can support more system Pythons by supporting down to 3.6 with some minimal fixes to tests. --- build/bin/sage-spkg | 4 +++- build/pkgs/python3/spkg-configure.m4 | 8 ++++---- src/sage/all.py | 2 +- src/sage/combinat/subset.py | 17 ++++++++++++++++- src/sage/graphs/views.pyx | 1 + src/sage/misc/sagedoc.py | 2 +- src/sage/misc/sageinspect.py | 6 ++---- src/sage/symbolic/expression.pyx | 8 ++------ 8 files changed, 30 insertions(+), 18 deletions(-) diff --git a/build/bin/sage-spkg b/build/bin/sage-spkg index 6129555958a..bafc41cbbd5 100755 --- a/build/bin/sage-spkg +++ b/build/bin/sage-spkg @@ -68,7 +68,9 @@ #***************************************************************************** # Avoid surprises with character ranges [a-z] in regular expressions -export LC_ALL=C +# See Trac #15791; some locales can produce different results for +# character ranges (use C.UTF-8 to ensure UTF-8 default encoding in Python) +export LC_ALL=C.UTF-8 usage() { diff --git a/build/pkgs/python3/spkg-configure.m4 b/build/pkgs/python3/spkg-configure.m4 index 6e576be828f..2989803eba9 100644 --- a/build/pkgs/python3/spkg-configure.m4 +++ b/build/pkgs/python3/spkg-configure.m4 @@ -10,14 +10,14 @@ SAGE_SPKG_CONFIGURE([python3], [ dnl Using Python 3 for Sage. Check if we can do venv with a system python3 dnl instead of building our own copy. check_modules="sqlite3, ctypes, math, hashlib, crypt, readline, socket, zlib, distutils.core" - AC_CACHE_CHECK([for python3 >= 3.7.3, < 3.8 with modules $check_modules], [ac_cv_path_PYTHON3], [ + AC_CACHE_CHECK([for python3 >= 3.6, < 3.8 with modules $check_modules], [ac_cv_path_PYTHON3], [ AC_MSG_RESULT([]) - AC_PATH_PROGS_FEATURE_CHECK([PYTHON3], [python3.7 python3], [ + AC_PATH_PROGS_FEATURE_CHECK([PYTHON3], [python3.7 python3.6 python3], [ AC_MSG_CHECKING([... whether $ac_path_PYTHON3 is good]) python3_version=`"$ac_path_PYTHON3" --version 2>&1 \ | $SED -n -e 's/\([[0-9]]*\.[[0-9]]*\.[[0-9]]*\).*/\1/p'` AS_IF([test -n "$python3_version"], [ - AX_COMPARE_VERSION([$python3_version], [ge], [3.7.3], [ + AX_COMPARE_VERSION([$python3_version], [ge], [3.6.0], [ AX_COMPARE_VERSION([$python3_version], [lt], [3.8.0], [ dnl Because the system python is not used directly but rather in a venv without site-packages, dnl we test whether the module will be available in a venv. @@ -118,7 +118,7 @@ EOF ac_path_PYTHON3_found=: AC_MSG_RESULT([yes]) dnl introduction for AC_MSG_RESULT printed by AC_CACHE_CHECK - AC_MSG_CHECKING([for python3 >= 3.7.3, < 3.8 with modules $check_modules]) + AC_MSG_CHECKING([for python3 >= 3.6, < 3.8 with modules $check_modules]) ], [ AC_MSG_RESULT([no, the version is in the supported range, and the modules can be imported, but distutils cannot build a C++ 11 extension]) ]) diff --git a/src/sage/all.py b/src/sage/all.py index 94337b48d5f..4fd711965d6 100644 --- a/src/sage/all.py +++ b/src/sage/all.py @@ -22,7 +22,7 @@ ....: 'IPython', 'prompt_toolkit', 'jedi', # sage dependencies ....: 'threading', 'multiprocessing', # doctest dependencies ....: '__main__', 'sage.doctest', # doctesting - ....: 'signal', 'enum', # may appear in Python 3 + ....: 'signal', 'enum', 'types' # may appear in Python 3 ....: ] sage: def is_not_allowed(frame): ....: module = inspect.getmodule(frame) diff --git a/src/sage/combinat/subset.py b/src/sage/combinat/subset.py index a81e7cffd11..9ef2781d7ea 100644 --- a/src/sage/combinat/subset.py +++ b/src/sage/combinat/subset.py @@ -357,7 +357,22 @@ def cardinality(self): """ return Integer(1) << self._s.cardinality() - __len__ = cardinality + def __len__(self): + r""" + Equivalent to ``self.cardinality()``. + + TESTS:: + + ``__len__`` should return a Python int; in Python 3.7+ this happens + automatically, but not on Python 3.6. + + sage: S = Subsets(Set([1,2,3])) + sage: len(S) + 8 + sage: type(len(S)) is int + True + """ + return int(self.cardinality()) def first(self): """ diff --git a/src/sage/graphs/views.pyx b/src/sage/graphs/views.pyx index b1ac7a27c4a..3c28b0de50e 100644 --- a/src/sage/graphs/views.pyx +++ b/src/sage/graphs/views.pyx @@ -611,6 +611,7 @@ cdef class EdgesView: elif i < 0: return list(self)[i] else: + i = int(i) # For Python < 3.7 where islice doesn't support non-int try: return next(islice(self, i, i + 1, 1)) except StopIteration: diff --git a/src/sage/misc/sagedoc.py b/src/sage/misc/sagedoc.py index 61d7a4c812d..5a3c06d3fd6 100644 --- a/src/sage/misc/sagedoc.py +++ b/src/sage/misc/sagedoc.py @@ -1064,7 +1064,7 @@ def search_src(string, extra1='', extra2='', extra3='', extra4='', sage: print(search_src(" fetch(", "def", interact=False)) # py3 Traceback (most recent call last): ... - re.error: missing ), unterminated subpattern at position 6 + error: missing ), unterminated subpattern at position 6 To fix this, *escape* the parenthesis with a backslash:: diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index 6251ec5742c..46d7cb9100b 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -1724,10 +1724,8 @@ def sage_formatargspec(args, varargs=None, varkw=None, defaults=None, sage: defaults = [3] sage: sage_formatargspec(args, defaults=defaults) '(a, b, c=3)' - sage: formatargspec(args, defaults=defaults) == sage_formatargspec(args, defaults=defaults) # py2 - True - sage: formatargspec(args, defaults=defaults) == sage_formatargspec(args, defaults=defaults) # py3 - doctest:...: DeprecationWarning: `formatargspec` is deprecated since Python 3.5. Use `signature` and the `Signature` object directly + sage: import warnings; warnings.simplefilter('ignore') # py3: ignore DeprecationWarning + sage: formatargspec(args, defaults=defaults) == sage_formatargspec(args, defaults=defaults) True """ def formatargandannotation(arg): diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 19da8508d27..b258064fcc8 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -5869,14 +5869,10 @@ cdef class Expression(CommutativeRingElement): Indexing directly with ``t[1]`` causes problems with numpy types. - sage: t[1] # py2 + sage: t[1] Traceback (most recent call last): ... - TypeError: 'sage.symbolic.expression.Expression' object does not support indexing - sage: t[1] # py3 - Traceback (most recent call last): - ... - TypeError: 'sage.symbolic.expression.Expression' object is not subscriptable + TypeError: 'sage.symbolic.expression.Expression' object ... """ if (is_a_symbol(self._gobj) or is_a_constant(self._gobj) or is_a_numeric(self._gobj)): From b1b378712d10cb15555889e8235d089f3cf0e391 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 6 Jun 2020 12:09:00 -0700 Subject: [PATCH 238/300] sage.env.cython_aliases: Fix for systems without zlib pc --- src/sage/env.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/env.py b/src/sage/env.py index 2bd582c82b1..e32f0c52f9b 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -394,14 +394,15 @@ def cython_aliases(): for lib in ['fflas-ffpack', 'givaro', 'gsl', 'linbox', 'Singular', 'libpng', 'gdlib', 'm4ri', 'zlib', 'cblas', 'lapack']: var = lib.upper().replace("-", "") + "_" - aliases[var + "CFLAGS"] = pkgconfig.cflags(lib).split() if lib == 'zlib': + aliases[var + "CFLAGS"] = "" try: pc = pkgconfig.parse('zlib') except pkgconfig.PackageNotFoundError: from collections import defaultdict pc = defaultdict(list, {'libraries': ['z']}) else: + aliases[var + "CFLAGS"] = pkgconfig.cflags(lib).split() pc = pkgconfig.parse(lib) # INCDIR should be redundant because the -I options are also # passed in CFLAGS From 741a4488a5ad7b8dde97f36226acac13c4a7c80b Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sun, 7 Jun 2020 11:01:07 +0100 Subject: [PATCH 239/300] Got doctests working after merge --- src/sage/combinat/path_tableaux/dyck_path.py | 2 +- src/sage/combinat/path_tableaux/frieze.py | 70 ++++++++++---------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/sage/combinat/path_tableaux/dyck_path.py b/src/sage/combinat/path_tableaux/dyck_path.py index 9e0212b92aa..ffea8cc97c7 100644 --- a/src/sage/combinat/path_tableaux/dyck_path.py +++ b/src/sage/combinat/path_tableaux/dyck_path.py @@ -27,7 +27,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.combinat.path_tableaux.path_tableau import PathTableau, PathTableaux +from sage.combinat.path_tableaux.path_tableau import PathTableau, PathTableaux, CylindricalDiagram from sage.combinat.combinatorial_map import combinatorial_map from sage.combinat.dyck_word import DyckWord from sage.combinat.perfect_matching import PerfectMatching diff --git a/src/sage/combinat/path_tableaux/frieze.py b/src/sage/combinat/path_tableaux/frieze.py index ab3fca12d21..2e22a0ed367 100644 --- a/src/sage/combinat/path_tableaux/frieze.py +++ b/src/sage/combinat/path_tableaux/frieze.py @@ -56,8 +56,8 @@ EXAMPLES:: - sage: t = FriezePattern([1,2,1,2,3,1]) - sage: CylindricalDiagram(t) + sage: t = path_tableaux.FriezePattern([1,2,1,2,3,1]) + sage: path_tableaux.CylindricalDiagram(t) [0, 1, 2, 1, 2, 3, 1, 0] ['', 0, 1, 1, 3, 5, 2, 1, 0] ['', '', 0, 1, 4, 7, 3, 2, 1, 0] @@ -69,8 +69,8 @@ sage: TestSuite(t).run() - sage: t = FriezePattern([1,2,7,5,3,7,4,1]) - sage: CylindricalDiagram(t) + sage: t = path_tableaux.FriezePattern([1,2,7,5,3,7,4,1]) + sage: path_tableaux.CylindricalDiagram(t) [0, 1, 2, 7, 5, 3, 7, 4, 1, 0] ['', 0, 1, 4, 3, 2, 5, 3, 1, 1, 0] ['', '', 0, 1, 1, 1, 3, 2, 1, 2, 1, 0] @@ -84,8 +84,8 @@ sage: TestSuite(t).run() - sage: t = FriezePattern([1,3,4,5,1]) - sage: CylindricalDiagram(t) + sage: t = path_tableaux.FriezePattern([1,3,4,5,1]) + sage: path_tableaux.CylindricalDiagram(t) [0, 1, 3, 4, 5, 1, 0] ['', 0, 1, 5/3, 7/3, 2/3, 1, 0] ['', '', 0, 1, 2, 1, 3, 1, 0] @@ -99,8 +99,8 @@ This constructs the examples from [TJ18]_ sage: K. = NumberField(x^2-3) - sage: t = FriezePattern([1,sqrt3,2,sqrt3,1,1], field=K) - sage: CylindricalDiagram(t) + sage: t = path_tableaux.FriezePattern([1,sqrt3,2,sqrt3,1,1], field=K) + sage: path_tableaux.CylindricalDiagram(t) [0, 1, sqrt3, 2, sqrt3, 1, 1, 0] ['', 0, 1, sqrt3, 2, sqrt3, sqrt3 + 1, 1, 0] ['', '', 0, 1, sqrt3, 2, sqrt3 + 2, sqrt3, 1, 0] @@ -113,8 +113,8 @@ sage: TestSuite(t).run() sage: K. = NumberField(x^2-2) - sage: t = FriezePattern([1,sqrt2,1,sqrt2,3,2*sqrt2,5,3*sqrt2,1], field=K) - sage: CylindricalDiagram(t) + sage: t = path_tableaux.FriezePattern([1,sqrt2,1,sqrt2,3,2*sqrt2,5,3*sqrt2,1], field=K) + sage: path_tableaux.CylindricalDiagram(t) [0, 1, sqrt2, 1, sqrt2, 3, 2*sqrt2, 5, 3*sqrt2, 1, 0] ['', 0, 1, sqrt2, 3, 5*sqrt2, 7, 9*sqrt2, 11, 2*sqrt2, 1, 0] ['', '', 0, 1, 2*sqrt2, 7, 5*sqrt2, 13, 8*sqrt2, 3, sqrt2, 1, 0] @@ -146,23 +146,23 @@ def __classcall_private__(cls, fp, field=QQ): EXAMPLES:: - sage: FriezePattern([1,2,1,2,3,1]) + sage: path_tableaux.FriezePattern([1,2,1,2,3,1]) [1, 2, 1, 2, 3, 1] TESTS:: - sage: FriezePattern(2) + sage: path_tableaux.FriezePattern(2) Traceback (most recent call last): ... ValueError: invalid input 2 sage: K. = NumberField(x^2-3) - sage: t = FriezePattern([1,sqrt3,2,sqrt3,1,1]) + sage: t = path_tableaux.FriezePattern([1,sqrt3,2,sqrt3,1,1]) Traceback (most recent call last): ... ValueError: [1, sqrt3, 2, sqrt3, 1, 1] is not a sequence in the field Rational Field - sage: FriezePattern([1,2,1,2,3,1],field=Integers()) + sage: path_tableaux.FriezePattern([1,2,1,2,3,1],field=Integers()) Traceback (most recent call last): ... ValueError: Integer Ring must be a field @@ -191,7 +191,7 @@ def check(self): TESTS:: - sage: FriezePattern([1,2,1,2,3,1]) # indirect test + sage: path_tableaux.FriezePattern([1,2,1,2,3,1]) # indirect test [1, 2, 1, 2, 3, 1] """ @@ -206,7 +206,7 @@ def _repr_(self): TESTS:: - sage: t = FriezePattern([1,2,1,2,3,1]) + sage: t = path_tableaux.FriezePattern([1,2,1,2,3,1]) sage: repr(t) == t._repr_() # indirect test True """ @@ -222,11 +222,11 @@ def local_rule(self,i): EXAMPLES:: - sage: t = FriezePattern([1,2,1,2,3,1]) + sage: t = path_tableaux.FriezePattern([1,2,1,2,3,1]) sage: t.local_rule(3) [1, 2, 5, 2, 3, 1] - sage: t = FriezePattern([1,2,1,2,3,1]) + sage: t = path_tableaux.FriezePattern([1,2,1,2,3,1]) sage: t.local_rule(0) Traceback (most recent call last): ... @@ -253,10 +253,10 @@ def is_skew(self): EXAMPLES:: - sage: FriezePattern([1,2,1,2,3,1]).is_skew() + sage: path_tableaux.FriezePattern([1,2,1,2,3,1]).is_skew() False - sage: FriezePattern([2,2,1,2,3,1]).is_skew() + sage: path_tableaux.FriezePattern([2,2,1,2,3,1]).is_skew() True """ return self[1] != 1 @@ -270,10 +270,10 @@ def width(self): EXAMPLES:: - sage: FriezePattern([1,2,1,2,3,1]).width() + sage: path_tableaux.FriezePattern([1,2,1,2,3,1]).width() 8 - sage: FriezePattern([1,2,1,2,3,4]).width() + sage: path_tableaux.FriezePattern([1,2,1,2,3,4]).width() """ @@ -294,14 +294,14 @@ def is_positive(self): EXAMPLES:: - sage: FriezePattern([1,2,7,5,3,7,4,1]).is_positive() + sage: path_tableaux.FriezePattern([1,2,7,5,3,7,4,1]).is_positive() True - sage: FriezePattern([1,-3,4,5,1]).is_positive() + sage: path_tableaux.FriezePattern([1,-3,4,5,1]).is_positive() False sage: K. = NumberField(x^2-3) - sage: FriezePattern([1,sqrt3,1],K).is_positive() + sage: path_tableaux.FriezePattern([1,sqrt3,1],K).is_positive() True """ @@ -313,10 +313,10 @@ def is_integral(self): EXAMPLES:: - sage: FriezePattern([1,2,7,5,3,7,4,1]).is_integral() + sage: path_tableaux.FriezePattern([1,2,7,5,3,7,4,1]).is_integral() True - sage: FriezePattern([1,3,4,5,1]).is_integral() + sage: path_tableaux.FriezePattern([1,3,4,5,1]).is_integral() False """ @@ -339,14 +339,14 @@ def triangulation(self): EXAMPLES:: - sage: FriezePattern([1,2,7,5,3,7,4,1]).triangulation() + sage: path_tableaux.FriezePattern([1,2,7,5,3,7,4,1]).triangulation() Graphics object consisting of 25 graphics primitives - sage: FriezePattern([1,2,1/7,5,3]).triangulation() + sage: path_tableaux.FriezePattern([1,2,1/7,5,3]).triangulation() Graphics object consisting of 12 graphics primitives sage: K. = NumberField(x^2-2) - sage: FriezePattern([1,sqrt2,1,sqrt2,3,2*sqrt2,5,3*sqrt2,1], field=K).triangulation() + sage: path_tableaux.FriezePattern([1,sqrt2,1,sqrt2,3,2*sqrt2,5,3*sqrt2,1], field=K).triangulation() Graphics object consisting of 24 graphics primitives """ @@ -394,7 +394,7 @@ def show(self,model='UHP'): EXAMPLES:: - sage: t = FriezePattern([1,2,7,5,3,7,4,1]) + sage: t = path_tableaux.FriezePattern([1,2,7,5,3,7,4,1]) sage: t.show() Graphics object consisting of 18 graphics primitives sage: t.show(model='UHP') @@ -432,10 +432,10 @@ def change_ring(self, R): EXAMPLES:: - sage: FriezePattern([1,2,7,5,3,7,4,1]).change_ring(RealField()) + sage: path_tableaux.FriezePattern([1,2,7,5,3,7,4,1]).change_ring(RealField()) [0.000000000000000, 1.00000000000000, ... 4.00000000000000, 1.00000000000000, 0.000000000000000] - sage: FriezePattern([1,2,7,5,3,7,4,1]).change_ring(GF(7)) + sage: path_tableaux.FriezePattern([1,2,7,5,3,7,4,1]).change_ring(GF(7)) Traceback (most recent call last): ... TypeError: no base extension defined @@ -448,7 +448,7 @@ def change_ring(self, R): class FriezePatterns(PathTableaux): """ - The parent class for FriezePattern. + The parent class for path_tableaux.FriezePattern. """ def __init__(self, field): """ @@ -456,7 +456,7 @@ def __init__(self, field): TESTS:: - sage: FriezePattern([1,1]).parent() # indirect test + sage: path_tableaux.FriezePattern([1,1]).parent() # indirect test """ From 3845d9df7c09aab7c745c75ddc3cac11ab6f84f4 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sun, 7 Jun 2020 12:19:36 +0100 Subject: [PATCH 240/300] Worked on Travis' comments --- src/doc/en/reference/references/index.rst | 12 ++ src/sage/combinat/path_tableaux/frieze.py | 227 ++++++++++------------ 2 files changed, 117 insertions(+), 122 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index ee097d788ee..43f17c1ee49 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1451,6 +1451,14 @@ REFERENCES: "Orange" https://csrc.nist.gov/CSRC/media/Projects/Lightweight-Cryptography/documents/round-1/spec-doc/orange-spec.pdf +.. [CoCo1] J.H. Conway, H.S.M. Coxeter + *Triangulated polygons and frieze patterns*, + The Mathematical Gazette (1973) 57 p.87-94 + +.. [CoCo2] J.H. Conway, H.S.M. Coxeter + *Triangulated polygons and frieze patterns (continued)*, + The Mathematical Gazette (1973) 57 p.175-183 + .. [Co1984] \J. Conway, Hexacode and tetracode - MINIMOG and MOG. *Computational group theory*, ed. M. Atkinson, Academic Press, 1984. @@ -2660,6 +2668,10 @@ REFERENCES: .. [Hoc] Winfried Hochstaettler, "About the Tic-Tac-Toe Matroid", preprint. +.. [HJ18] Thorsten Holm and Peter Jorgensen + *A p-angulated generalisation of Conway and Coxeter's theorem on frieze patterns*, + International Mathematics Research Notices (2018) + .. [Hopcroft1973] J. E. Hopcroft and R. E. Tarjan. *Dividing a Graph into Triconnected Components*, SIAM J. Comput., 2(3), 135–158 diff --git a/src/sage/combinat/path_tableaux/frieze.py b/src/sage/combinat/path_tableaux/frieze.py index 2e22a0ed367..51e27331365 100644 --- a/src/sage/combinat/path_tableaux/frieze.py +++ b/src/sage/combinat/path_tableaux/frieze.py @@ -9,22 +9,6 @@ In this implementation we have sequences of nonnegative integers. This follows [CoCo1]_ and [CoCo2]_ -REFERENCES: - -.. [CoCo1] J.H. Conway and H.S.M. Coxeter - *Triangulated polygons and frieze patterns*, - The Mathematical Gazette (1973) 57 p.87-94 - - -.. [CoCo2] J.H. Conway and H.S.M. Coxeter - *Triangulated polygons and frieze patterns (continued)*, - The Mathematical Gazette (1973) 57 p.175-183 - -.. [TJ18] Thorsten Holm and Peter Jorgensen - *A p-angulated generalisation of Conway and Coxeter's theorem on frieze patterns*, - International Mathematics Research Notices (2018) - - AUTHORS: - Bruce Westbury (2019): initial version @@ -52,88 +36,85 @@ ############################################################################### -""" - -EXAMPLES:: - - sage: t = path_tableaux.FriezePattern([1,2,1,2,3,1]) - sage: path_tableaux.CylindricalDiagram(t) - [0, 1, 2, 1, 2, 3, 1, 0] - ['', 0, 1, 1, 3, 5, 2, 1, 0] - ['', '', 0, 1, 4, 7, 3, 2, 1, 0] - ['', '', '', 0, 1, 2, 1, 1, 1, 1, 0] - ['', '', '', '', 0, 1, 1, 2, 3, 4, 1, 0] - ['', '', '', '', '', 0, 1, 3, 5, 7, 2, 1, 0] - ['', '', '', '', '', '', 0, 1, 2, 3, 1, 1, 1, 0] - ['', '', '', '', '', '', '', 0, 1, 2, 1, 2, 3, 1, 0] - - sage: TestSuite(t).run() - - sage: t = path_tableaux.FriezePattern([1,2,7,5,3,7,4,1]) - sage: path_tableaux.CylindricalDiagram(t) - [0, 1, 2, 7, 5, 3, 7, 4, 1, 0] - ['', 0, 1, 4, 3, 2, 5, 3, 1, 1, 0] - ['', '', 0, 1, 1, 1, 3, 2, 1, 2, 1, 0] - ['', '', '', 0, 1, 2, 7, 5, 3, 7, 4, 1, 0] - ['', '', '', '', 0, 1, 4, 3, 2, 5, 3, 1, 1, 0] - ['', '', '', '', '', 0, 1, 1, 1, 3, 2, 1, 2, 1, 0] - ['', '', '', '', '', '', 0, 1, 2, 7, 5, 3, 7, 4, 1, 0] - ['', '', '', '', '', '', '', 0, 1, 4, 3, 2, 5, 3, 1, 1, 0] - ['', '', '', '', '', '', '', '', 0, 1, 1, 1, 3, 2, 1, 2, 1, 0] - ['', '', '', '', '', '', '', '', '', 0, 1, 2, 7, 5, 3, 7, 4, 1, 0] - - sage: TestSuite(t).run() - - sage: t = path_tableaux.FriezePattern([1,3,4,5,1]) - sage: path_tableaux.CylindricalDiagram(t) - [0, 1, 3, 4, 5, 1, 0] - ['', 0, 1, 5/3, 7/3, 2/3, 1, 0] - ['', '', 0, 1, 2, 1, 3, 1, 0] - ['', '', '', 0, 1, 1, 4, 5/3, 1, 0] - ['', '', '', '', 0, 1, 5, 7/3, 2, 1, 0] - ['', '', '', '', '', 0, 1, 2/3, 1, 1, 1, 0] - ['', '', '', '', '', '', 0, 1, 3, 4, 5, 1, 0] - - sage: TestSuite(t).run() - -This constructs the examples from [TJ18]_ - - sage: K. = NumberField(x^2-3) - sage: t = path_tableaux.FriezePattern([1,sqrt3,2,sqrt3,1,1], field=K) - sage: path_tableaux.CylindricalDiagram(t) - [0, 1, sqrt3, 2, sqrt3, 1, 1, 0] - ['', 0, 1, sqrt3, 2, sqrt3, sqrt3 + 1, 1, 0] - ['', '', 0, 1, sqrt3, 2, sqrt3 + 2, sqrt3, 1, 0] - ['', '', '', 0, 1, sqrt3, sqrt3 + 2, 2, sqrt3, 1, 0] - ['', '', '', '', 0, 1, sqrt3 + 1, sqrt3, 2, sqrt3, 1, 0] - ['', '', '', '', '', 0, 1, 1, sqrt3, 2, sqrt3, 1, 0] - ['', '', '', '', '', '', 0, 1, sqrt3 + 1, sqrt3 + 2, sqrt3 + 2, sqrt3 + 1, 1, 0] - ['', '', '', '', '', '', '', 0, 1, sqrt3, 2, sqrt3, 1, 1, 0] - - sage: TestSuite(t).run() - - sage: K. = NumberField(x^2-2) - sage: t = path_tableaux.FriezePattern([1,sqrt2,1,sqrt2,3,2*sqrt2,5,3*sqrt2,1], field=K) - sage: path_tableaux.CylindricalDiagram(t) - [0, 1, sqrt2, 1, sqrt2, 3, 2*sqrt2, 5, 3*sqrt2, 1, 0] - ['', 0, 1, sqrt2, 3, 5*sqrt2, 7, 9*sqrt2, 11, 2*sqrt2, 1, 0] - ['', '', 0, 1, 2*sqrt2, 7, 5*sqrt2, 13, 8*sqrt2, 3, sqrt2, 1, 0] - ['', '', '', 0, 1, 2*sqrt2, 3, 4*sqrt2, 5, sqrt2, 1, sqrt2, 1, 0] - ['', '', '', '', 0, 1, sqrt2, 3, 2*sqrt2, 1, sqrt2, 3, 2*sqrt2, 1, 0] - ['', '', '', '', '', 0, 1, 2*sqrt2, 3, sqrt2, 3, 5*sqrt2, 7, 2*sqrt2, 1, 0] - ['', '', '', '', '', '', 0, 1, sqrt2, 1, 2*sqrt2, 7, 5*sqrt2, 3, sqrt2, 1, 0] - ['', '', '', '', '', '', '', 0, 1, sqrt2, 5, 9*sqrt2, 13, 4*sqrt2, 3, 2*sqrt2, 1, 0] - ['', '', '', '', '', '', '', '', 0, 1, 3*sqrt2, 11, 8*sqrt2, 5, 2*sqrt2, 3, sqrt2, 1, 0] - ['', '', '', '', '', '', '', '', '', 0, 1, 2*sqrt2, 3, sqrt2, 1, sqrt2, 1, sqrt2, 1, 0] - ['', '', '', '', '', '', '', '', '', '', 0, 1, sqrt2, 1, sqrt2, 3, 2*sqrt2, 5, 3*sqrt2, 1, 0] - - sage: TestSuite(t).run() -""" - @add_metaclass(InheritComparisonClasscallMetaclass) class FriezePattern(PathTableau): """ An instance is a sequence in the ground field. + + EXAMPLES:: + + sage: t = path_tableaux.FriezePattern([1,2,1,2,3,1]) + sage: path_tableaux.CylindricalDiagram(t) + [0, 1, 2, 1, 2, 3, 1, 0] + ['', 0, 1, 1, 3, 5, 2, 1, 0] + ['', '', 0, 1, 4, 7, 3, 2, 1, 0] + ['', '', '', 0, 1, 2, 1, 1, 1, 1, 0] + ['', '', '', '', 0, 1, 1, 2, 3, 4, 1, 0] + ['', '', '', '', '', 0, 1, 3, 5, 7, 2, 1, 0] + ['', '', '', '', '', '', 0, 1, 2, 3, 1, 1, 1, 0] + ['', '', '', '', '', '', '', 0, 1, 2, 1, 2, 3, 1, 0] + + sage: TestSuite(t).run() + + sage: t = path_tableaux.FriezePattern([1,2,7,5,3,7,4,1]) + sage: path_tableaux.CylindricalDiagram(t) + [0, 1, 2, 7, 5, 3, 7, 4, 1, 0] + ['', 0, 1, 4, 3, 2, 5, 3, 1, 1, 0] + ['', '', 0, 1, 1, 1, 3, 2, 1, 2, 1, 0] + ['', '', '', 0, 1, 2, 7, 5, 3, 7, 4, 1, 0] + ['', '', '', '', 0, 1, 4, 3, 2, 5, 3, 1, 1, 0] + ['', '', '', '', '', 0, 1, 1, 1, 3, 2, 1, 2, 1, 0] + ['', '', '', '', '', '', 0, 1, 2, 7, 5, 3, 7, 4, 1, 0] + ['', '', '', '', '', '', '', 0, 1, 4, 3, 2, 5, 3, 1, 1, 0] + ['', '', '', '', '', '', '', '', 0, 1, 1, 1, 3, 2, 1, 2, 1, 0] + ['', '', '', '', '', '', '', '', '', 0, 1, 2, 7, 5, 3, 7, 4, 1, 0] + + sage: TestSuite(t).run() + + sage: t = path_tableaux.FriezePattern([1,3,4,5,1]) + sage: path_tableaux.CylindricalDiagram(t) + [0, 1, 3, 4, 5, 1, 0] + ['', 0, 1, 5/3, 7/3, 2/3, 1, 0] + ['', '', 0, 1, 2, 1, 3, 1, 0] + ['', '', '', 0, 1, 1, 4, 5/3, 1, 0] + ['', '', '', '', 0, 1, 5, 7/3, 2, 1, 0] + ['', '', '', '', '', 0, 1, 2/3, 1, 1, 1, 0] + ['', '', '', '', '', '', 0, 1, 3, 4, 5, 1, 0] + + sage: TestSuite(t).run() + + This constructs the examples from [HJ18]_:: + + sage: K. = NumberField(x^2-3) + sage: t = path_tableaux.FriezePattern([1,sqrt3,2,sqrt3,1,1], field=K) + sage: path_tableaux.CylindricalDiagram(t) + [0, 1, sqrt3, 2, sqrt3, 1, 1, 0] + ['', 0, 1, sqrt3, 2, sqrt3, sqrt3 + 1, 1, 0] + ['', '', 0, 1, sqrt3, 2, sqrt3 + 2, sqrt3, 1, 0] + ['', '', '', 0, 1, sqrt3, sqrt3 + 2, 2, sqrt3, 1, 0] + ['', '', '', '', 0, 1, sqrt3 + 1, sqrt3, 2, sqrt3, 1, 0] + ['', '', '', '', '', 0, 1, 1, sqrt3, 2, sqrt3, 1, 0] + ['', '', '', '', '', '', 0, 1, sqrt3 + 1, sqrt3 + 2, sqrt3 + 2, sqrt3 + 1, 1, 0] + ['', '', '', '', '', '', '', 0, 1, sqrt3, 2, sqrt3, 1, 1, 0] + + sage: TestSuite(t).run() + + sage: K. = NumberField(x^2-2) + sage: t = path_tableaux.FriezePattern([1,sqrt2,1,sqrt2,3,2*sqrt2,5,3*sqrt2,1], field=K) + sage: path_tableaux.CylindricalDiagram(t) + [0, 1, sqrt2, 1, sqrt2, 3, 2*sqrt2, 5, 3*sqrt2, 1, 0] + ['', 0, 1, sqrt2, 3, 5*sqrt2, 7, 9*sqrt2, 11, 2*sqrt2, 1, 0] + ['', '', 0, 1, 2*sqrt2, 7, 5*sqrt2, 13, 8*sqrt2, 3, sqrt2, 1, 0] + ['', '', '', 0, 1, 2*sqrt2, 3, 4*sqrt2, 5, sqrt2, 1, sqrt2, 1, 0] + ['', '', '', '', 0, 1, sqrt2, 3, 2*sqrt2, 1, sqrt2, 3, 2*sqrt2, 1, 0] + ['', '', '', '', '', 0, 1, 2*sqrt2, 3, sqrt2, 3, 5*sqrt2, 7, 2*sqrt2, 1, 0] + ['', '', '', '', '', '', 0, 1, sqrt2, 1, 2*sqrt2, 7, 5*sqrt2, 3, sqrt2, 1, 0] + ['', '', '', '', '', '', '', 0, 1, sqrt2, 5, 9*sqrt2, 13, 4*sqrt2, 3, 2*sqrt2, 1, 0] + ['', '', '', '', '', '', '', '', 0, 1, 3*sqrt2, 11, 8*sqrt2, 5, 2*sqrt2, 3, sqrt2, 1, 0] + ['', '', '', '', '', '', '', '', '', 0, 1, 2*sqrt2, 3, sqrt2, 1, sqrt2, 1, sqrt2, 1, 0] + ['', '', '', '', '', '', '', '', '', '', 0, 1, sqrt2, 1, sqrt2, 3, 2*sqrt2, 5, 3*sqrt2, 1, 0] + + sage: TestSuite(t).run() """ @staticmethod @@ -168,7 +149,7 @@ def __classcall_private__(cls, fp, field=QQ): ValueError: Integer Ring must be a field """ if not field in Fields: - raise ValueError("{} must be a field".format(field)) + raise ValueError(f"{field} must be a field") w = None @@ -198,7 +179,7 @@ def check(self): def _repr_(self): """ - The representation of ''self''. + The representation of ``self``. This overides the iherited method. @@ -240,7 +221,7 @@ def _rule(x): return (x[0]*x[2]+1)/x[1] if not (i > 0 and i < len(self)-1 ): - raise ValueError("{} is not a valid integer".format(i)) + raise ValueError(f"{i} is not a valid integer") with self.clone() as result: result[i] = _rule(self[i-1:i+2]) @@ -263,9 +244,9 @@ def is_skew(self): def width(self): """ - Return the width of ''self''. + Return the width of ``self``. - If the first and last terms of 'self'are 1 then this is the length of 'self' + If the first and last terms of ``self`` are 1 then this is the length of ``self`` plus two and otherwise is undefined. EXAMPLES:: @@ -284,9 +265,9 @@ def width(self): def is_positive(self): """ - Return 'true' if all elements of ''self'' are positive. + Return 'true' if all elements of ``self`` are positive. - This implies that all entries of ''CylindricalDiagram(self)'' are positive. + This implies that all entries of ``CylindricalDiagram(self)`` are positive. Warning: There are orders on all fields. These may not be ordered fields as they may not be compatible with the field operations. This method is @@ -320,13 +301,11 @@ def is_integral(self): False """ + from sage.rings.all import ZZ n = len(self) cd = CylindricalDiagram(self).diagram for i, a in enumerate(cd): - v = a[i+1:n+i-2] - try: - v = [ Integer(k) for k in v ] - except TypeError: + if any(k not in ZZ for k in a[i+1:n+i-2]): return False return True @@ -335,7 +314,14 @@ def triangulation(self): r""" Plot a regular polygon with some diagonals. - If ''self'' is positive and integral then this will be a triangulation. + If ``self`` is positive and integral then this will be a triangulation. + + .. PLOT:: + :width: 600 px + + G = path_tableaux.FriezePattern([1,2,7,5,3,7,4,1]).triangulation() + p = graphics_array(G, 7, 6) + sphinx_plot(p) EXAMPLES:: @@ -348,7 +334,6 @@ def triangulation(self): sage: K. = NumberField(x^2-2) sage: path_tableaux.FriezePattern([1,sqrt2,1,sqrt2,3,2*sqrt2,5,3*sqrt2,1], field=K).triangulation() Graphics object consisting of 24 graphics primitives - """ n = len(self)-1 cd = CylindricalDiagram(self).diagram @@ -372,7 +357,7 @@ def triangulation(self): G.axes(False) return G - def show(self,model='UHP'): + def plot(self,model='UHP'): """ Plot the frieze as an ideal hyperbolic polygon. @@ -395,17 +380,15 @@ def show(self,model='UHP'): EXAMPLES:: sage: t = path_tableaux.FriezePattern([1,2,7,5,3,7,4,1]) - sage: t.show() - Graphics object consisting of 18 graphics primitives - sage: t.show(model='UHP') - Graphics object consisting of 18 graphics primitives - sage: t.show(model='PD') + sage: t.plot() + + sage: t.plot(model='UHP') + + sage: t.plot(model='PD') Traceback (most recent call last): ... TypeError: '>' not supported between instances of 'NotANumber' and 'Pi' - sage: t.show(model='KM') - Graphics object consisting of 18 graphics primitives - + sage: t.plot(model='KM') """ models = { 'UHP' : HyperbolicPlane().UHP(), @@ -413,8 +396,8 @@ def show(self,model='UHP'): 'KM' : HyperbolicPlane().KM(), } M = models.get(model) - if not M: - raise ValueError(f"{model} must be one of ''UHP'', ''PD'', ''KM''") + if M == None: + raise ValueError(f"{model} must be one of ``UHP``, ``PD``, ``KM``") U = HyperbolicPlane().UHP() cd = CylindricalDiagram(self).diagram @@ -422,13 +405,13 @@ def show(self,model='UHP'): den = cd[1][2:] vt = [ M(U.get_point(x/(x+y))) for x,y in zip(num,den) ] gd = [ M.get_geodesic(vt[i-1],vt[i]) for i in range(len(vt))] - return sum([a.plot() for a in gd],Graphics()) + sum([a.plot() for a in gd],Graphics()).plot() def change_ring(self, R): r""" - Return ''self'' as a frieze pattern with coefficients in ''R'' - assuming there is a canonical coerce map from the base ring of ''self'' - to ''R''. + Return ``self`` as a frieze pattern with coefficients in ``R`` + assuming there is a canonical coerce map from the base ring of ``self`` + to ``R``. EXAMPLES:: From 41cda76ad9c2996f793dd78a39ecd23639d6aeaf Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Sun, 7 Jun 2020 12:49:03 +0100 Subject: [PATCH 241/300] None --- src/sage/combinat/path_tableaux/frieze.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/path_tableaux/frieze.py b/src/sage/combinat/path_tableaux/frieze.py index 51e27331365..74943d0ed58 100644 --- a/src/sage/combinat/path_tableaux/frieze.py +++ b/src/sage/combinat/path_tableaux/frieze.py @@ -28,9 +28,8 @@ from sage.structure.parent import Parent from sage.categories.sets_cat import Sets from sage.combinat.path_tableaux.path_tableau import PathTableau, PathTableaux, CylindricalDiagram -from sage.rings.integer import Integer from sage.categories.fields import Fields -from sage.rings.all import QQ +from sage.rings.all import QQ, ZZ from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane from sage.plot.all import Graphics @@ -301,7 +300,6 @@ def is_integral(self): False """ - from sage.rings.all import ZZ n = len(self) cd = CylindricalDiagram(self).diagram for i, a in enumerate(cd): @@ -432,6 +430,11 @@ def change_ring(self, R): class FriezePatterns(PathTableaux): """ The parent class for path_tableaux.FriezePattern. + + TESTS:: + + sage: P = path_tableaux.FriezePatterns(QQ) + sage: TestSuite(P).run() """ def __init__(self, field): """ From 72e7cbb0873b00524eec152da1e5e3c4b20a4724 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 8 Jun 2020 10:39:27 +1000 Subject: [PATCH 242/300] Fixing the check for matrix type over GF(2^e). --- src/sage/matrix/matrix_gf2e_dense.pyx | 4 ++-- src/sage/matrix/matrix_space.py | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/sage/matrix/matrix_gf2e_dense.pyx b/src/sage/matrix/matrix_gf2e_dense.pyx index 420209cd273..acc30f4d2f5 100644 --- a/src/sage/matrix/matrix_gf2e_dense.pyx +++ b/src/sage/matrix/matrix_gf2e_dense.pyx @@ -1,5 +1,5 @@ """ -Dense matrices over `\GF{2^e}` for `2 <= e <= 10` using the M4RIE library +Dense matrices over `\GF{2^e}` for `2 \leq e \leq 16` using the M4RIE library The M4RIE library offers two matrix representations: @@ -201,7 +201,7 @@ cdef class Matrix_gf2e_dense(matrix_dense.Matrix_dense): def __init__(self, parent, entries=None, copy=None, bint coerce=True): r""" - Create new matrix over `GF(2^e)` for 2<=e<=10. + Create new matrix over `GF(2^e)` for `2 \leq e \leq 16`. INPUT: diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index 335e424b506..a8fc5e64493 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -133,6 +133,11 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): sage: get_matrix_class(ZZ, 3, 3, False, 'generic') + sage: get_matrix_class(GF(2^15), 3, 3, False, None) + + sage: get_matrix_class(GF(2^17), 3, 3, False, None) + + sage: get_matrix_class(GF(2), 2, 2, False, 'm4ri') sage: get_matrix_class(GF(4), 2, 2, False, 'm4ri') @@ -215,9 +220,9 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): return matrix_complex_double_dense.Matrix_complex_double_dense if sage.rings.finite_rings.finite_field_constructor.is_FiniteField(R): - if R.order() == 2 and R.order() <= 65536: + if R.order() == 2: return matrix_mod2_dense.Matrix_mod2_dense - if R.characteristic() == 2: + if R.characteristic() == 2 and R.order() <= 65536: # 65536 == 2^16 return matrix_gf2e_dense.Matrix_gf2e_dense if (not R.is_prime_field()) and R.order() < 256: From b8bf1caff7de6c0812d172ff9e980b70e0ec6777 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 9 Jun 2020 10:06:37 +1000 Subject: [PATCH 243/300] Some documentation and minor tweaks. --- src/sage/combinat/posets/posets.py | 86 ++++++++++++++++-------------- 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 8ef0162693f..50ad543df81 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -1632,15 +1632,17 @@ def spectrum(self, a): r""" Return the `a`-spectrum of this poset. - The `a`-spectrum in this poset is the list of integers whose - `i`-th position contains the number of linear extensions of this poset + The `a`-spectrum in a poset `P` is the list of integers whose + `i`-th position contains the number of linear extensions of `P` that have `a` in the `i`-th location. INPUT: - - ``a`` -- an element of this poset. + - ``a`` -- an element of this poset - OUTPUT: The `a`-spectrum of this poset, returned as a list. + OUTPUT: + + The `a`-spectrum of this poset, returned as a list. EXAMPLES:: @@ -1662,10 +1664,10 @@ def spectrum(self, a): sage: P.spectrum(6) Traceback (most recent call last): ... - ValueError: Input element is not in poset! + ValueError: input element is not in poset """ if a not in self: - raise ValueError("Input element is not in poset!") + raise ValueError("input element is not in poset") a_spec = [0] * len(self) for L in self.linear_extensions(): @@ -1688,16 +1690,18 @@ def _glue_spectra(a_spec, b_spec, orientation): INPUT: - - ``a_spec`` -- list; the `a`-spectrum of a poset `P`. + - ``a_spec`` -- list; the `a`-spectrum of a poset `P` - - ``b_spec`` -- list; the `b`-spectrum of a poset `Q`. + - ``b_spec`` -- list; the `b`-spectrum of a poset `Q` - - ``orientation`` -- boolean; ``True`` if `a < b`, ``False`` otherwise. + - ``orientation`` -- boolean; ``True`` if `a < b`, ``False`` otherwise - OUTPUT: The `a`-spectrum (or `b`-spectrum, depending on orientation), - returned as a list, of the poset which is a disjoint union - of `P` and `Q`, together with the additional - covering relation `a < b`. + OUTPUT: + + The `a`-spectrum (or `b`-spectrum, depending on orientation), + returned as a list, of the poset which is a disjoint union + of `P` and `Q`, together with the additional + covering relation `a < b`. EXAMPLES:: @@ -1714,7 +1718,7 @@ def _glue_spectra(a_spec, b_spec, orientation): """ new_a_spec = [] - if orientation is False: + if not orientation: a_spec, b_spec = b_spec, a_spec p = len(a_spec) @@ -1734,21 +1738,20 @@ def _glue_spectra(a_spec, b_spec, orientation): def _split(self, a, b): r""" - Return the two connected components obtained by deleting the covering relation - `a < b` from a poset whose Hasse diagram is a tree. + Return the two connected components obtained by deleting the covering + relation `a < b` from a poset whose Hasse diagram is a tree. This is a helper method for :meth:`atkinson`. INPUT: - - ``self`` -- a poset. - - - ``a`` -- an element of the poset. + - ``a`` -- an element of the poset + - ``b`` -- an element of the poset which covers ``a`` - - ``b`` -- an element of the poset which covers ``a``. + OUTPUT: - OUTPUT: A list containing two posets which are the connected components - of this poset after deleting the covering relation `a < b`. + A list containing two posets which are the connected components + of this poset after deleting the covering relation `a < b`. EXAMPLES:: @@ -1766,13 +1769,13 @@ def _split(self, a, b): sage: P._split(0, 1) Traceback (most recent call last): ... - ValueError: Wrong number of connected components after the covering relation is deleted! + ValueError: wrong number of connected components after the covering relation is deleted sage: P = Poset({0: [1], 1: [], 2: []}) sage: P._split(0, 1) Traceback (most recent call last): ... - ValueError: Wrong number of connected components after the covering relation is deleted! + ValueError: wrong number of connected components after the covering relation is deleted """ covers = self.cover_relations() covers.remove([a, b]) @@ -1780,7 +1783,7 @@ def _split(self, a, b): components = split_poset.connected_components() if not len(components) == 2: - raise ValueError("Wrong number of connected components after the covering relation is deleted!") + raise ValueError("wrong number of connected components after the covering relation is deleted") c1, c2 = components if a in c2: @@ -1796,11 +1799,11 @@ def _spectrum_of_tree(self, a): INPUT: - - ``self`` -- a poset for which the underlying undirected graph is a tree. + - ``a`` -- an element of the poset - - ``a`` -- an element of the poset. + OUTPUT: - OUTPUT: The `a`-spectrum of this poset, returned as a list. + The `a`-spectrum of this poset, returned as a list. EXAMPLES:: @@ -1824,18 +1827,17 @@ def _spectrum_of_tree(self, a): b = upper_covers[0] orientation = True else: - (a, b) = (self.lower_covers(a)[0], a) + (a, b) = (lower_covers[0], a) orientation = False P, Q = self._split(a, b) a_spec = P._spectrum_of_tree(a) b_spec = Q._spectrum_of_tree(b) return FinitePoset._glue_spectra(a_spec, b_spec, orientation) - def atkinson(self, a): r""" - Return the `a`-spectrum of a poset whose Hasse diagram is cycle-free as - an undirected graph. + Return the `a`-spectrum of a poset whose Hasse diagram is + cycle-free as an undirected graph. Given an element `a` in a poset `P`, the `a`-spectrum is the list of integers whose `i`-th term contains the number of linear extensions of @@ -1843,11 +1845,13 @@ def atkinson(self, a): INPUT: - - ``self`` -- a poset for which the underlying undirected graph is a forest. + - ``self`` -- a poset whose Hasse diagram is a forest - - ``a`` -- an element of the poset. + - ``a`` -- an element of the poset + + OUTPUT: - OUTPUT: The `a`-spectrum of this poset, returned as a list. + The `a`-spectrum of this poset, returned as a list. EXAMPLES:: @@ -1869,23 +1873,23 @@ def atkinson(self, a): sage: P.atkinson(6) Traceback (most recent call last): ... - ValueError: Input element is not in poset! + ValueError: input element is not in poset sage: P = posets.BooleanLattice(2) sage: P.atkinson(1) Traceback (most recent call last): ... - ValueError: This poset is not a forest. + ValueError: this poset is not a forest .. NOTE:: This function is the implementation of the algorithm from [At1990]_. """ if a not in self: - raise ValueError("Input element is not in poset!") + raise ValueError("input element is not in poset") - if not self.hasse_diagram().to_undirected().is_forest(): - raise ValueError("This poset is not a forest.") + if not self._hasse_diagram.to_undirected().is_forest(): + raise ValueError("this poset is not a forest") n = self.cardinality() @@ -1901,7 +1905,7 @@ def atkinson(self, a): a_spec = main._spectrum_of_tree(a) - if remainder_poset.cardinality() == 0: + if not remainder_poset.cardinality(): return a_spec b = remainder_poset.an_element() From 5ea3aef2923a5a9c0030244bddaac0fc3abacd73 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 9 Jun 2020 10:30:02 +1000 Subject: [PATCH 244/300] Adding new public methods to the list of poset methods. --- src/sage/combinat/posets/posets.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 50ad543df81..f52c04a3fe0 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -256,6 +256,8 @@ :meth:`~FinitePoset.rank` | Return the rank of an element, or the rank of the poset. :meth:`~FinitePoset.rank_function` | Return a rank function of the poset, if it exists. :meth:`~FinitePoset.unwrap` | Unwraps an element of this poset. + :meth:`~FinitePoset.atkinson` | Return the `a`-spectrum of a poset whose undirected Hasse diagram is a forest. + :meth:`~FinitePoset.spectrum` | Return the `a`-spectrum of this poset. Classes and functions --------------------- From 321e2bf0cb7ab489ac7362eae607698c7ec37347 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Tue, 9 Jun 2020 13:54:12 +1200 Subject: [PATCH 245/300] Bump to 3.0.4 --- build/pkgs/sphinx/checksums.ini | 6 +++--- build/pkgs/sphinx/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/sphinx/checksums.ini b/build/pkgs/sphinx/checksums.ini index a2150308444..c7cb3178005 100644 --- a/build/pkgs/sphinx/checksums.ini +++ b/build/pkgs/sphinx/checksums.ini @@ -1,5 +1,5 @@ tarball=Sphinx-VERSION.tar.gz -sha1=781b9233902d92244be8f9537db3a4bd79a90df0 -md5=d5d0f61059c8ddb01b12e80a9e61adcb -cksum=3158798019 +sha1=deec61ab1240d359d24f6d08b28724b4f2547448 +md5=d998c1884c00cc93e9eede88e7864524 +cksum=4289730124 upstream_url=https://pypi.io/packages/source/s/sphinx/Sphinx-VERSION.tar.gz diff --git a/build/pkgs/sphinx/package-version.txt b/build/pkgs/sphinx/package-version.txt index e8c8fdf4b74..3da40e303a9 100644 --- a/build/pkgs/sphinx/package-version.txt +++ b/build/pkgs/sphinx/package-version.txt @@ -1 +1 @@ -3.0.3.p0 +3.0.4.p0 From 83629f54979e58d77c1ce7deb5122b90e9ef4b41 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 8 Jun 2020 19:54:11 -0700 Subject: [PATCH 246/300] sage.libs.glpk.error: Add documentation discouraging users from using GLPKError --- src/sage/libs/glpk/error.pyx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/sage/libs/glpk/error.pyx b/src/sage/libs/glpk/error.pyx index f7046b3ec45..cae63387d48 100644 --- a/src/sage/libs/glpk/error.pyx +++ b/src/sage/libs/glpk/error.pyx @@ -21,7 +21,10 @@ from sage.numerical.mip import MIPSolverException class GLPKError(MIPSolverException): """ - An error raised by the GLPK library. + A low-level error that is raised by ``sage_glpk_term_hook``. + + The GLPK API considers these errors non-recoverable. User code should not try + to catch this exception. EXAMPLES:: @@ -68,6 +71,13 @@ def setup_glpk_error_handler(): Setup the GLPK error handler. Called automatically when this module is imported at Sage startup. + We install this error handler so that an error does not lead to + an immediate error exit of the process. Instead, we raise a + ``GLPKError`` for the convenience of developers. + + The GLPK API considers errors non-recoverable. + Therefore, user code should not try to catch this exception. + TESTS:: sage: cython(''' From 066b1e86daa1b6cf70643a8f72944f9197709dfe Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 8 Jun 2020 19:55:03 -0700 Subject: [PATCH 247/300] setup_glpk_error_handler: Disable doctest that tests the GLPK error recovery patch --- src/sage/libs/glpk/error.pyx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/libs/glpk/error.pyx b/src/sage/libs/glpk/error.pyx index cae63387d48..bf78ceee791 100644 --- a/src/sage/libs/glpk/error.pyx +++ b/src/sage/libs/glpk/error.pyx @@ -80,7 +80,8 @@ def setup_glpk_error_handler(): TESTS:: - sage: cython(''' + sage: cython( # optional - glpk_error_recovery_patch + .... ''' ....: # distutils: libraries = glpk z gmp ....: from cysignals.signals cimport sig_on, sig_off ....: from sage.libs.glpk.env cimport glp_term_out From f898daf5cc95d851ce4289b8ac40807a2e5030d6 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 9 Jun 2020 17:32:00 +1000 Subject: [PATCH 248/300] Adding cup/cap a() generators and some class-level doc. --- src/sage/combinat/diagram_algebras.py | 79 ++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 7 deletions(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index ad4b5f9a086..1ad1b5dc08e 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -2228,6 +2228,26 @@ class PartitionAlgebra(DiagramBasis, UnitDiagramMixin): due to the fact that its natural basis is given by certain graphs often called diagrams. + There are a number of predefined elements for the partition algebra. + We define the cup/cap pair by :meth:`a()`. The simple transpositions + are denoted :meth:`s()`. Finally, we define elements :meth:`e()`, + where if `i = (2r+1)/2`, then ``e(i)`` contains the blocks `\{r+1\}` + and `\{-r-1\}` and if `i \in \ZZ`, then `e_i` contains the block + `\{-i, -i-1, i, i+1\}`, with all other blocks being `\{-j, j\}`. + So we have:: + + sage: P = PartitionAlgebra(4, 0) + sage: P.a(2) + P{{-4, 4}, {-3, -2}, {-1, 1}, {2, 3}} + sage: P.e(3/2) + P{{-4, 4}, {-3, 3}, {-2}, {-1, 1}, {2}} + sage: P.e(2) + P{{-4, 4}, {-3, -2, 2, 3}, {-1, 1}} + sage: P.e(5/2) + P{{-4, 4}, {-3}, {-2, 2}, {-1, 1}, {3}} + sage: P.s(2) + P{{-4, 4}, {-3, 2}, {-2, 3}, {-1, 1}} + An excellent reference for partition algebras and their various subalgebras (Brauer algebra, Temperley--Lieb algebra, etc) is the paper [HR2005]_. @@ -2694,14 +2714,55 @@ def _orbit_to_diagram_on_basis(self, d): * self([sum((list(d[i-1]) for i in p),[]) for p in sp]) for sp in SPd) + @cached_method + def a(self, i): + r""" + Return the element `a_i` in ``self``. + + The element `a_i` is the cap and cup at `(i, i+1)`, so it contains + the blocks `\{i, i+1\}`, `\{-i, -i-1\}`, and `\{-j, j\}` for all + `j \neq i, i+1`. + + INPUT: + + - ``i`` -- an integer between 1 and `k-1` + + EXAMPLES:: + + sage: R. = QQ[] + sage: P3 = PartitionAlgebra(3, n) + sage: P3.a(1) + P{{-3, 3}, {-2, -1}, {1, 2}} + sage: P3.a(2) + P{{-3, -2}, {-1, 1}, {2, 3}} + + sage: P3 = PartitionAlgebra(5/2, n) + sage: P3.a(1) + P{{-3, 3}, {-2, -1}, {1, 2}} + sage: P3.a(2) + Traceback (most recent call last): + ... + ValueError: i must be an integer between 1 and 1 + """ + if i <= 0 or i >= floor(self._k): + raise ValueError("i must be an integer between 1 and {}".format(floor(self._k)-1)) + B = self.basis() + SP = B.keys() + D = [[-j, j] for j in range(1, ceil(self._k)+1)] + D[i-1] = [i,i+1] + D[i] = [-i,-(i+1)] + return B[SP(D)] + + generator_a = a + @cached_method def e(self, i): r""" Return the element `e_i` in ``self``. - If `i = (2r+1)/2`, then `e_i` contains the blocks ``{r+1}`` and - ``{-r-1}``. If `i \in {\mathbb Z}`, then `e_i` contains the block - ``{-i, -i-1, i, i+1}``. Other blocks are of the form `{-j, j}`. + If `i = (2r+1)/2`, then `e_i` contains the blocks `\{r+1\}` and + `\{-r-1\}`. If `i \in \ZZ`, then `e_i` contains the block + `\{-i, -i-1, i, i+1\}`. Other blocks are of the form `\{-j, j\}`. INPUT: @@ -2751,14 +2812,16 @@ def e(self, i): D.append([i]) return B[SP(D)] + generator_e = e + @cached_method def s(self, i): r""" Return the ``i``-th simple transposition `s_i` in ``self``. - Borrowing the notation from the symmetric group, the ``i``-th - simple transposition has blocks of the form ``{-i, i+1}``, - ``{-i-1, i}`` and ``{-j, j}`` for `j \notin \{ i, i+1 \}`. + Borrowing the notation from the symmetric group, the `i`-th + simple transposition `s_i` has blocks of the form `\{-i, i+1\}`, + `\{-i-1, i\}` and `\{-j, j\}` for `j \notin \{ i, i+1 \}`. INPUT: @@ -2787,6 +2850,8 @@ def s(self, i): D[i] = [-i, i+1] return B[SP(D)] + generator_s = s + @cached_method def sigma(self, i): r""" @@ -2886,7 +2951,7 @@ def sigma(self, i): @cached_method def jucys_murphy_element(self, i): r""" - Return the ``i``-th Jucys-Murphy element `L_{i}` from [Eny2012]_. + Return the ``i``-th Jucys-Murphy element `L_i` from [Eny2012]_. of ``self``. INPUT: From 5a40643ffee3b8e04d96b2ea46abda345d08a18c Mon Sep 17 00:00:00 2001 From: zabrocki Date: Tue, 9 Jun 2020 11:27:35 -0400 Subject: [PATCH 249/300] delete HR2005 reference from diagram_algebras.py --- src/sage/combinat/diagram_algebras.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 1ad1b5dc08e..5a9ecd08d59 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -2483,11 +2483,6 @@ class PartitionAlgebra(DiagramBasis, UnitDiagramMixin): P{{-3, 2}, {-2, 1}, {-1, 3}} sage: A([2,3,1]) == A(S([2,3,1])) True - - REFERENCES: - - .. [HR2005] Tom Halverson and Arun Ram, *Partition algebras*. European - Journal of Combinatorics **26** (2005), 869--921. """ @staticmethod def __classcall_private__(cls, k, q, base_ring=None, prefix="P"): From 9427aa12355b28e359f8d7c263964e8390639d6c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 9 Jun 2020 09:58:11 -0700 Subject: [PATCH 250/300] src/sage/libs/glpk/error.pyx: Fixup doctest markup --- src/sage/libs/glpk/error.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/libs/glpk/error.pyx b/src/sage/libs/glpk/error.pyx index bf78ceee791..3808ab0cc2e 100644 --- a/src/sage/libs/glpk/error.pyx +++ b/src/sage/libs/glpk/error.pyx @@ -81,7 +81,7 @@ def setup_glpk_error_handler(): TESTS:: sage: cython( # optional - glpk_error_recovery_patch - .... ''' + ....: ''' ....: # distutils: libraries = glpk z gmp ....: from cysignals.signals cimport sig_on, sig_off ....: from sage.libs.glpk.env cimport glp_term_out From 2ed5a53f8f3805f54962a0ce908ba23f2cc375b6 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Tue, 9 Jun 2020 15:43:49 +0100 Subject: [PATCH 251/300] converting polytopes_db_4d into a new style package --- build/pkgs/polytopes_db_4d/SPKG.txt | 30 +++++++++++++++++++ build/pkgs/polytopes_db_4d/checksums.ini | 5 ++++ .../pkgs/polytopes_db_4d/package-version.txt | 1 + build/pkgs/polytopes_db_4d/spkg-install.in | 4 +++ .../polytopes_db_4d/spkg-legacy-uninstall.in | 2 ++ build/pkgs/polytopes_db_4d/type | 1 + 6 files changed, 43 insertions(+) create mode 100644 build/pkgs/polytopes_db_4d/SPKG.txt create mode 100644 build/pkgs/polytopes_db_4d/checksums.ini create mode 100644 build/pkgs/polytopes_db_4d/package-version.txt create mode 100755 build/pkgs/polytopes_db_4d/spkg-install.in create mode 100755 build/pkgs/polytopes_db_4d/spkg-legacy-uninstall.in create mode 100644 build/pkgs/polytopes_db_4d/type diff --git a/build/pkgs/polytopes_db_4d/SPKG.txt b/build/pkgs/polytopes_db_4d/SPKG.txt new file mode 100644 index 00000000000..4f00c8f6d20 --- /dev/null +++ b/build/pkgs/polytopes_db_4d/SPKG.txt @@ -0,0 +1,30 @@ += 4D Reflexive Polytopes Database = + +== Description == + +This package contains the database of 4-d reflexive polytopes with +Hodge numbers as index. + +Based on the original list by Maximilian Kreuzer and Harald Skarke +using their software PALP. + +== License == + +GPL v2+ + +== SPKG Maintainers == + +Volker Braun + +== Dependencies == + +None + +== Changelog == + +=== polytopes_db_3d-1.0 (Volker Braun, 2013 April 17) === + + * #14467: Initial version + + + diff --git a/build/pkgs/polytopes_db_4d/checksums.ini b/build/pkgs/polytopes_db_4d/checksums.ini new file mode 100644 index 00000000000..edfee6b7841 --- /dev/null +++ b/build/pkgs/polytopes_db_4d/checksums.ini @@ -0,0 +1,5 @@ +tarball=polytopes_db_4d-VERSION.spkg +sha1=c9779821e365df2d7f9bc684f9e2ec0e95fb8650 +md5=fe775a26fd7b2afc187e9bfabfb1b86a +cksum=3415837678 +upstream_url=http://ftp.sparcs.org/sage/spkg/huge/polytopes_db_4d-1.0.spkg diff --git a/build/pkgs/polytopes_db_4d/package-version.txt b/build/pkgs/polytopes_db_4d/package-version.txt new file mode 100644 index 00000000000..d3827e75a5c --- /dev/null +++ b/build/pkgs/polytopes_db_4d/package-version.txt @@ -0,0 +1 @@ +1.0 diff --git a/build/pkgs/polytopes_db_4d/spkg-install.in b/build/pkgs/polytopes_db_4d/spkg-install.in new file mode 100755 index 00000000000..e4c57278ca3 --- /dev/null +++ b/build/pkgs/polytopes_db_4d/spkg-install.in @@ -0,0 +1,4 @@ +POLYTOPES_DIR="$SAGE_SHARE"/reflexive_polytopes +mkdir -p "$POLYTOPES_DIR" +cd src/src +cp -r -p Hodge4d "$POLYTOPES_DIR"/ diff --git a/build/pkgs/polytopes_db_4d/spkg-legacy-uninstall.in b/build/pkgs/polytopes_db_4d/spkg-legacy-uninstall.in new file mode 100755 index 00000000000..00afd5f6e92 --- /dev/null +++ b/build/pkgs/polytopes_db_4d/spkg-legacy-uninstall.in @@ -0,0 +1,2 @@ +# Cleanup of previous installation +rm -rf "${SAGE_SHARE}/reflexive_polytopes/Hodge4d" diff --git a/build/pkgs/polytopes_db_4d/type b/build/pkgs/polytopes_db_4d/type new file mode 100644 index 00000000000..9839eb20815 --- /dev/null +++ b/build/pkgs/polytopes_db_4d/type @@ -0,0 +1 @@ +experimental From ced138e48c69e4d628774adf37830ff6c3ebd26d Mon Sep 17 00:00:00 2001 From: Emmanuel Charpentier Date: Tue, 9 Jun 2020 23:48:11 +0200 Subject: [PATCH 252/300] Doctests for definite integral using mathematica_free. --- src/sage/symbolic/integration/external.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sage/symbolic/integration/external.py b/src/sage/symbolic/integration/external.py index 764363ec8b8..d8c079bfaae 100644 --- a/src/sage/symbolic/integration/external.py +++ b/src/sage/symbolic/integration/external.py @@ -92,11 +92,23 @@ def mma_free_integrator(expression, v, a=None, b=None): sage: result.simplify_trig() # optional - internet -1/2*cos(y)*sin(y) + 1/2*y + :: + + Check that :trac:`14764` is resolved: + + sage: integrate(x^2, x, 0, 1, algorithm="mathematica_free") # optional - internet + 1/3 + sage: integrate(sin(x), [x, 0, pi], algorithm="mathematica_free") # optional - internet + 2 + sage: integrate(sqrt(x), (x, 0, 1), algorithm="mathematica_free") # optional - internet + 2/3 + :: sage: mma_free_integrator(exp(-x^2)*log(x), x) # optional - internet 1/2*sqrt(pi)*erf(x)*log(x) - x*hypergeometric((1/2, 1/2), (3/2, 3/2), -x^2) + """ math_expr = expression._mathematica_init_() variable = v._mathematica_init_() From 28024ac250757dce3b900e28caeacd65c235128e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 9 Jun 2020 13:59:10 -0700 Subject: [PATCH 253/300] src/sage/libs/glpk/error.pyx: Make doctest more flexible --- src/sage/libs/glpk/error.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/libs/glpk/error.pyx b/src/sage/libs/glpk/error.pyx index 3808ab0cc2e..f2fe043c6aa 100644 --- a/src/sage/libs/glpk/error.pyx +++ b/src/sage/libs/glpk/error.pyx @@ -108,8 +108,8 @@ def setup_glpk_error_handler(): sage: p.add_constraint(3*x + 2*y <= 6) sage: p.add_constraint(x >= 0) sage: p.set_objective(x + y) - sage: res = p.solve() - 0: obj = ... + sage: print('output'); res = p.solve() + output ... 0: obj = ... sage: res # rel tol 1e-15 2.4 """ From 8acdf34c0a5179daa4e6ee9ba4fc024b67f18ec2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 9 Jun 2020 23:56:20 -0700 Subject: [PATCH 254/300] Fixup doctest --- src/sage/libs/glpk/error.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/libs/glpk/error.pyx b/src/sage/libs/glpk/error.pyx index f2fe043c6aa..93d600ff6da 100644 --- a/src/sage/libs/glpk/error.pyx +++ b/src/sage/libs/glpk/error.pyx @@ -108,7 +108,7 @@ def setup_glpk_error_handler(): sage: p.add_constraint(3*x + 2*y <= 6) sage: p.add_constraint(x >= 0) sage: p.set_objective(x + y) - sage: print('output'); res = p.solve() + sage: print('output', flush=True); res = p.solve() output ... 0: obj = ... sage: res # rel tol 1e-15 2.4 From cb13ddb433735cd25e92a870385b9f7faa2875f1 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Wed, 10 Jun 2020 11:18:29 +0200 Subject: [PATCH 255/300] allow generators for Vrep/Hrep for backend normaliz --- src/sage/geometry/polyhedron/backend_normaliz.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index c293783e14e..ee3f793c7c7 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -332,12 +332,20 @@ def _convert_to_pynormaliz(x): [[7, 2], [1, 1]] sage: Pn._convert_to_pynormaliz([[1, 2], (3, 4)]) [[1, 2], [3, 4]] + + Check that :trac:`29836` is fixed:: + + sage: P = polytopes.simplex(backend='normaliz') + sage: K. = QuadraticField(2) + sage: P.dilation(sqrt2) + A 3-dimensional polyhedron in (Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.41...)^4 defined as the convex hull of 4 vertices """ def _QQ_pair(x): x = QQ(x) return [ int(x.numerator()), int(x.denominator())] from sage.rings.rational import Rational - if isinstance(x, list) or isinstance(x, tuple): + from types import GeneratorType + if isinstance(x, list) or isinstance(x, tuple) or isinstance(x, GeneratorType): return [ Polyhedron_normaliz._convert_to_pynormaliz(y) for y in x ] try: return int(ZZ(x)) From 18385a7c38275f3e3841ab2230b1e1465213ea09 Mon Sep 17 00:00:00 2001 From: Emmanuel Charpentier Date: Wed, 10 Jun 2020 11:41:56 +0200 Subject: [PATCH 256/300] Punctiation fic for doctests for definite integral using mathematica_free. --- src/sage/symbolic/integration/external.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/symbolic/integration/external.py b/src/sage/symbolic/integration/external.py index d8c079bfaae..0d6a3d39f5e 100644 --- a/src/sage/symbolic/integration/external.py +++ b/src/sage/symbolic/integration/external.py @@ -94,7 +94,7 @@ def mma_free_integrator(expression, v, a=None, b=None): :: - Check that :trac:`14764` is resolved: + Check that :trac:`14764` is resolved:: sage: integrate(x^2, x, 0, 1, algorithm="mathematica_free") # optional - internet 1/3 From 002e5436d235e9a6cd5dbde1b04356e33ac31afe Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Wed, 10 Jun 2020 17:15:37 +0200 Subject: [PATCH 257/300] added optional tag; small improvement --- src/sage/geometry/polyhedron/backend_normaliz.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index ee3f793c7c7..32bafa876e1 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -335,8 +335,8 @@ def _convert_to_pynormaliz(x): Check that :trac:`29836` is fixed:: - sage: P = polytopes.simplex(backend='normaliz') - sage: K. = QuadraticField(2) + sage: P = polytopes.simplex(backend='normaliz') # optional - pynormaliz + sage: K. = QuadraticField(2) # optional - pynormaliz sage: P.dilation(sqrt2) A 3-dimensional polyhedron in (Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.41...)^4 defined as the convex hull of 4 vertices """ @@ -345,7 +345,7 @@ def _QQ_pair(x): return [ int(x.numerator()), int(x.denominator())] from sage.rings.rational import Rational from types import GeneratorType - if isinstance(x, list) or isinstance(x, tuple) or isinstance(x, GeneratorType): + if isinstance(x, (list, tuple, GeneratorType)): return [ Polyhedron_normaliz._convert_to_pynormaliz(y) for y in x ] try: return int(ZZ(x)) From 926c9f32b7bcfcf673c92c3fa88cdfda5fb38197 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Thu, 11 Jun 2020 10:57:27 +0100 Subject: [PATCH 258/300] added quotes --- build/pkgs/palp/spkg-configure.m4 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/pkgs/palp/spkg-configure.m4 b/build/pkgs/palp/spkg-configure.m4 index f44c857ccbd..f4e293970ec 100644 --- a/build/pkgs/palp/spkg-configure.m4 +++ b/build/pkgs/palp/spkg-configure.m4 @@ -1,10 +1,10 @@ SAGE_SPKG_CONFIGURE([palp], [ m4_foreach([palpprog], [[poly], [class], [nef], [cws]], [ AC_PATH_PROG(PALP[]palpprog, [palpprog.x]) - AS_IF([test x$PALP[]palpprog = x], [sage_spkg_install_palp=yes]) + AS_IF([test "x$PALP[]palpprog" = "x"], [sage_spkg_install_palp=yes]) m4_foreach([suff], [4, 5, 6, 11], [ AC_PATH_PROG(PALP[]palpprog[]suff, [palpprog[-]suff[d.x]]) - AS_IF([test x$PALP[]palpprog[]suff = x], [sage_spkg_install_palp=yes]) + AS_IF([test "x$PALP[]palpprog[]suff" = "x"], [sage_spkg_install_palp=yes]) ]) ]) ]) From 58d6b868b6d6e06148b35f6518064d351c76ef50 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Thu, 11 Jun 2020 06:49:31 -0400 Subject: [PATCH 259/300] verson on Cre2020 reference --- src/doc/en/reference/references/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index af6c8e4b701..490cf37bf4a 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1568,7 +1568,7 @@ REFERENCES: games*. MIT Press, 2003. .. [Cre2020] Creedon, Samuel. *The center of the partition algebra*. - Preprint, :arxiv:`2005.00600` (2020). + Preprint, :arxiv:`2005.00600v1` (2020). .. [Cro1983] \M. Crochemore, Recherche linéaire d'un carré dans un mot, C. R. Acad. Sci. Paris Sér. I Math. 296 (1983) 14 From 67d6faea682779fdd3bd74b31ab5042635ee1444 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Thu, 11 Jun 2020 07:13:32 -0400 Subject: [PATCH 260/300] changes to documentation suggested by Darij --- src/sage/combinat/diagram_algebras.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 5a9ecd08d59..0303482bbdd 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -2715,8 +2715,8 @@ def a(self, i): Return the element `a_i` in ``self``. The element `a_i` is the cap and cup at `(i, i+1)`, so it contains - the blocks `\{i, i+1\}`, `\{-i, -i-1\}`, and `\{-j, j\}` for all - `j \neq i, i+1`. + the blocks `\{i, i+1\}`, `\{-i, -i-1\}`. Other blocks are of the + form `\{-j, j\}`. INPUT: @@ -2761,7 +2761,7 @@ def e(self, i): INPUT: - - ``i`` -- a half integer between 1/2 and `k` + - ``i`` -- a half integer between 1/2 and `k-1/2` EXAMPLES:: @@ -2816,7 +2816,7 @@ def s(self, i): Borrowing the notation from the symmetric group, the `i`-th simple transposition `s_i` has blocks of the form `\{-i, i+1\}`, - `\{-i-1, i\}` and `\{-j, j\}` for `j \notin \{ i, i+1 \}`. + `\{-i-1, i\}`. Other blocks are of the form `\{-j, j\}`. INPUT: @@ -2854,7 +2854,7 @@ def sigma(self, i): INPUT: - - ``i`` -- a half integer between 1/2 and `k` + - ``i`` -- a half integer between 1/2 and `k-1/2` .. NOTE:: @@ -2947,7 +2947,6 @@ def sigma(self, i): def jucys_murphy_element(self, i): r""" Return the ``i``-th Jucys-Murphy element `L_i` from [Eny2012]_. - of ``self``. INPUT: @@ -3071,8 +3070,8 @@ def jucys_murphy_element(self, i): return self.zero() L = self.jucys_murphy_element return (self.s(j) * L(i-1) * self.s(j) - - L(j)*self.e(j) - self.e(j)*L(j) - + (self._q*self.one() - L(i-1))*self.e(j) + - self.e(j)*L(j) + + (self._q*self.one() - L(i-1) - L(j))*self.e(j) + self.sigma(j)) L = jucys_murphy_element From 1ec6823d3edc368eea1764892fb0ad22762c6f91 Mon Sep 17 00:00:00 2001 From: zabrocki Date: Thu, 11 Jun 2020 07:20:07 -0400 Subject: [PATCH 261/300] delete Iwahori-Hecke algebra statement (without reference, may not be true) --- src/sage/combinat/diagram_algebras.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 0303482bbdd..42549925986 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -2221,9 +2221,6 @@ class PartitionAlgebra(DiagramBasis, UnitDiagramMixin): in which the product of two set partitions is simply given by their composition. - The Iwahori--Hecke algebra of type `A` (with a single parameter) is - naturally a subalgebra of the partition algebra. - The partition algebra is regarded as an example of a "diagram algebra" due to the fact that its natural basis is given by certain graphs often called diagrams. From b49f89a5c8429619d576a5c998b890dcf09f7b86 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Thu, 11 Jun 2020 16:45:01 +0100 Subject: [PATCH 262/300] make it optional --- build/pkgs/polytopes_db_4d/type | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/polytopes_db_4d/type b/build/pkgs/polytopes_db_4d/type index 9839eb20815..134d9bc32d5 100644 --- a/build/pkgs/polytopes_db_4d/type +++ b/build/pkgs/polytopes_db_4d/type @@ -1 +1 @@ -experimental +optional From 7db58ae715cb76ba7d1818361f2102a3ae233e6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20R=C3=BCth?= Date: Thu, 11 Jun 2020 19:20:31 +0200 Subject: [PATCH 263/300] Force misc-clean to run after sagelib-clean these two must not run in parallel or in reversed order since sagelib-clean needs files that misc-clean deletes --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f99ccfcdd7e..51238b25c4c 100644 --- a/Makefile +++ b/Makefile @@ -112,7 +112,9 @@ maintainer-clean: distclean bootstrap-clean # Remove everything that is not necessary to run Sage and pass all its # doctests. -micro_release: sagelib-clean misc-clean +micro_release: + $(MAKE) sagelib-clean + $(MAKE) misc-clean @echo "Stripping binaries ..." LC_ALL=C find local/lib local/bin -type f -exec strip '{}' ';' 2>&1 | grep -v "File format not recognized" | grep -v "File truncated" || true @echo "Removing sphinx artifacts..." From 333f55884845e63591a332a038f459313b5cb50b Mon Sep 17 00:00:00 2001 From: Stefan Grosser Date: Sat, 13 Jun 2020 15:20:55 -0400 Subject: [PATCH 264/300] moved helper functions for atkinson over to HasseDiagram --- src/sage/combinat/posets/hasse_diagram.py | 158 +++++++++++++++++++++ src/sage/combinat/posets/posets.py | 160 +--------------------- 2 files changed, 159 insertions(+), 159 deletions(-) diff --git a/src/sage/combinat/posets/hasse_diagram.py b/src/sage/combinat/posets/hasse_diagram.py index de9c28a785a..4c3dc52bd99 100644 --- a/src/sage/combinat/posets/hasse_diagram.py +++ b/src/sage/combinat/posets/hasse_diagram.py @@ -23,6 +23,7 @@ from sage.rings.finite_rings.finite_field_constructor import GF from sage.misc.lazy_attribute import lazy_attribute from sage.misc.cachefunc import cached_method +from sage.functions.other import binomial from sage.misc.rest_index_of_methods import gen_rest_table_index @@ -3169,5 +3170,162 @@ def is_congruence_normal(self): return True + @staticmethod + def _glue_spectra(a_spec, b_spec, orientation): + r""" + Return the `a`-spectrum of a poset by merging ``a_spec`` and ``b_spec``. + + ``a_spec`` and ``b_spec`` are the `a`-spectrum and `b`-spectrum of two different + posets (see :meth:`atkinson` for the definition of `a`-spectrum). + + The orientation determines whether `a < b` or `b < a` in the combined poset. + + This is a helper method for :meth:`atkinson`. + + INPUT: + + - ``a_spec`` -- list; the `a`-spectrum of a poset `P` + + - ``b_spec`` -- list; the `b`-spectrum of a poset `Q` + + - ``orientation`` -- boolean; ``True`` if `a < b`, ``False`` otherwise + + OUTPUT: + + The `a`-spectrum (or `b`-spectrum, depending on orientation), + returned as a list, of the poset which is a disjoint union + of `P` and `Q`, together with the additional + covering relation `a < b`. + + EXAMPLES:: + + sage: from sage.combinat.posets.hasse_diagram import HasseDiagram + sage: Pdata = [0, 1, 2, 0] + sage: Qdata = [1, 1, 0] + sage: HasseDiagram._glue_spectra(Pdata, Qdata, True) + [0, 20, 28, 18, 0, 0, 0] + + sage: Pdata = [0, 0, 2] + sage: Qdata = [0, 1] + sage: HasseDiagram._glue_spectra(Pdata, Qdata, False) + [0, 0, 0, 0, 8] + """ + new_a_spec = [] + + if not orientation: + a_spec, b_spec = b_spec, a_spec + + p = len(a_spec) + q = len(b_spec) + + for r in range(1, p+q+1): + new_a_spec.append(0) + for i in range(max(1, r-q), min(p, r) + 1): + k_val = binomial(r-1, i-1) * binomial(p+q-r, p-i) + if orientation: + inner_sum = sum(b_spec[j-1] for j in range(r-i + 1, len(b_spec) + 1)) + else: + inner_sum = sum(b_spec[j-1] for j in range(1, r-i + 1)) + new_a_spec[-1] = new_a_spec[-1] + (a_spec[i-1] * k_val * inner_sum) + + return new_a_spec + + def _split(self, a, b): + r""" + Return the two connected components obtained by deleting the covering + relation `a < b` from a Hasse diagram that is a tree. + + This is a helper method for :meth:`FinitePoset.atkinson`. + + INPUT: + + - ``a`` -- an element of the poset + - ``b`` -- an element of the poset which covers ``a`` + + OUTPUT: + + A list containing two posets which are the connected components + of this poset after deleting the covering relation `a < b`. + + EXAMPLES:: + + sage: H = HasseDiagram({0: [1, 2], 1: [], 2: []}) + sage: H._split(0, 1) + [Hasse diagram of a poset containing 2 elements, Hasse diagram of a poset containing 1 elements] + + sage: H = posets.ChainPoset(5)._hasse_diagram + sage: H._split(1, 2) + [Hasse diagram of a poset containing 2 elements, Hasse diagram of a poset containing 3 elements] + + TESTS:: + + sage: H = posets.BooleanLattice(3)._hasse_diagram + sage: H._split(0, 1) + Traceback (most recent call last): + ... + ValueError: wrong number of connected components after the covering relation is deleted + + sage: H = Poset({0: [1], 1: [], 2: []})._hasse_diagram + sage: H._split(0, 1) + Traceback (most recent call last): + ... + ValueError: wrong number of connected components after the covering relation is deleted + """ + split_hasse = self.copy(self) + split_hasse.delete_edge(a,b) + components = split_hasse.connected_components() + + if not len(components) == 2: + raise ValueError("wrong number of connected components after the covering relation is deleted") + + c1, c2 = components + if a in c2: + c1, c2 = c2, c1 + + return [self.subgraph(c1), self.subgraph(c2)] + + def _spectrum_of_tree(self, a): + r""" + Return the `a`-spectrum of a poset whose underlying graph is a tree. + + This is a helper method for :meth:`FinitePoset.atkinson`. + + INPUT: + + - ``a`` -- an element of the poset + + OUTPUT: + + The `a`-spectrum of this poset, returned as a list. + + EXAMPLES:: + + sage: H = Poset({0: [2], 1: [2], 2: [3, 4], 3: [], 4: []})._hasse_diagram + sage: H._spectrum_of_tree(0) + [2, 2, 0, 0, 0] + + sage: H = Poset({0: [2], 1: [2], 2: [3, 4], 3: [], 4: []})._hasse_diagram + sage: H._spectrum_of_tree(2) + [0, 0, 4, 0, 0] + + sage: H = Poset({0: [2], 1: [2], 2: [3, 4], 3: [], 4: []})._hasse_diagram + sage: H._spectrum_of_tree(3) + [0, 0, 0, 2, 2] + """ + upper_covers = self.neighbors_out(a) + lower_covers = self.neighbors_in(a) + if not upper_covers and not lower_covers: + return [1] + if upper_covers: + b = upper_covers[0] + orientation = True + else: + (a, b) = (lower_covers[0], a) + orientation = False + P, Q = self._split(a, b) + a_spec = P._spectrum_of_tree(a) + b_spec = Q._spectrum_of_tree(b) + return HasseDiagram._glue_spectra(a_spec, b_spec, orientation) + __doc__ = __doc__.format(INDEX_OF_FUNCTIONS=gen_rest_table_index(HasseDiagram)) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index f52c04a3fe0..5ded62f1856 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -1678,164 +1678,6 @@ def spectrum(self, a): return a_spec - @staticmethod - def _glue_spectra(a_spec, b_spec, orientation): - r""" - Return the `a`-spectrum of a poset by merging ``a_spec`` and ``b_spec``. - - ``a_spec`` and ``b_spec`` are the `a`-spectrum and `b`-spectrum of two different - posets (see :meth:`atkinson` for the definition of `a`-spectrum). - - The orientation determines whether `a < b` or `b < a` in the combined poset. - - This is a helper method for :meth:`atkinson`. - - INPUT: - - - ``a_spec`` -- list; the `a`-spectrum of a poset `P` - - - ``b_spec`` -- list; the `b`-spectrum of a poset `Q` - - - ``orientation`` -- boolean; ``True`` if `a < b`, ``False`` otherwise - - OUTPUT: - - The `a`-spectrum (or `b`-spectrum, depending on orientation), - returned as a list, of the poset which is a disjoint union - of `P` and `Q`, together with the additional - covering relation `a < b`. - - EXAMPLES:: - - sage: from sage.combinat.posets.posets import FinitePoset - sage: Pdata = [0, 1, 2, 0] - sage: Qdata = [1, 1, 0] - sage: FinitePoset._glue_spectra(Pdata, Qdata, True) - [0, 20, 28, 18, 0, 0, 0] - - sage: Pdata = [0, 0, 2] - sage: Qdata = [0, 1] - sage: FinitePoset._glue_spectra(Pdata, Qdata, False) - [0, 0, 0, 0, 8] - """ - new_a_spec = [] - - if not orientation: - a_spec, b_spec = b_spec, a_spec - - p = len(a_spec) - q = len(b_spec) - - for r in range(1, p+q+1): - new_a_spec.append(0) - for i in range(max(1, r-q), min(p, r) + 1): - k_val = binomial(r-1, i-1) * binomial(p+q-r, p-i) - if orientation: - inner_sum = sum(b_spec[j-1] for j in range(r-i + 1, len(b_spec) + 1)) - else: - inner_sum = sum(b_spec[j-1] for j in range(1, r-i + 1)) - new_a_spec[-1] = new_a_spec[-1] + (a_spec[i-1] * k_val * inner_sum) - - return new_a_spec - - def _split(self, a, b): - r""" - Return the two connected components obtained by deleting the covering - relation `a < b` from a poset whose Hasse diagram is a tree. - - This is a helper method for :meth:`atkinson`. - - INPUT: - - - ``a`` -- an element of the poset - - ``b`` -- an element of the poset which covers ``a`` - - OUTPUT: - - A list containing two posets which are the connected components - of this poset after deleting the covering relation `a < b`. - - EXAMPLES:: - - sage: P = Poset({0: [1, 2], 1: [], 2: []}) - sage: P._split(0, 1) - [Finite poset containing 2 elements, Finite poset containing 1 elements] - - sage: P = posets.ChainPoset(5) - sage: P._split(1, 2) - [Finite poset containing 2 elements, Finite poset containing 3 elements] - - TESTS:: - - sage: P = posets.BooleanLattice(3) - sage: P._split(0, 1) - Traceback (most recent call last): - ... - ValueError: wrong number of connected components after the covering relation is deleted - - sage: P = Poset({0: [1], 1: [], 2: []}) - sage: P._split(0, 1) - Traceback (most recent call last): - ... - ValueError: wrong number of connected components after the covering relation is deleted - """ - covers = self.cover_relations() - covers.remove([a, b]) - split_poset = Poset((self.list(), covers), cover_relations=True) - components = split_poset.connected_components() - - if not len(components) == 2: - raise ValueError("wrong number of connected components after the covering relation is deleted") - - c1, c2 = components - if a in c2: - c1, c2 = c2, c1 - - return [c1, c2] - - def _spectrum_of_tree(self, a): - r""" - Return the `a`-spectrum of a poset whose underlying graph is a tree. - - This is a helper method for :meth:`atkinson`. - - INPUT: - - - ``a`` -- an element of the poset - - OUTPUT: - - The `a`-spectrum of this poset, returned as a list. - - EXAMPLES:: - - sage: P = Poset({0: [2], 1: [2], 2: [3, 4], 3: [], 4: []}) - sage: P._spectrum_of_tree(0) - [2, 2, 0, 0, 0] - - sage: P = Poset({0: [2], 1: [2], 2: [3, 4], 3: [], 4: []}) - sage: P._spectrum_of_tree(2) - [0, 0, 4, 0, 0] - - sage: P = Poset({0: [2], 1: [2], 2: [3, 4], 3: [], 4: []}) - sage: P._spectrum_of_tree(3) - [0, 0, 0, 2, 2] - """ - upper_covers = self.upper_covers(a) - lower_covers = self.lower_covers(a) - if not upper_covers and not lower_covers: - return [1] - if upper_covers: - b = upper_covers[0] - orientation = True - else: - (a, b) = (lower_covers[0], a) - orientation = False - P, Q = self._split(a, b) - a_spec = P._spectrum_of_tree(a) - b_spec = Q._spectrum_of_tree(b) - return FinitePoset._glue_spectra(a_spec, b_spec, orientation) - def atkinson(self, a): r""" Return the `a`-spectrum of a poset whose Hasse diagram is @@ -1905,7 +1747,7 @@ def atkinson(self, a): else: remainder_poset = remainder_poset.disjoint_union(X) - a_spec = main._spectrum_of_tree(a) + a_spec = main._hasse_diagram._spectrum_of_tree(a) if not remainder_poset.cardinality(): return a_spec From 10d75ca7d8898a081192cd427e6bd7b7e730e85b Mon Sep 17 00:00:00 2001 From: Stefan Grosser Date: Sat, 13 Jun 2020 19:34:21 -0400 Subject: [PATCH 265/300] Fixed failing examples and tests. --- src/sage/combinat/posets/hasse_diagram.py | 21 +++++++++++---------- src/sage/combinat/posets/posets.py | 5 ++++- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/sage/combinat/posets/hasse_diagram.py b/src/sage/combinat/posets/hasse_diagram.py index 4c3dc52bd99..b4065d48387 100644 --- a/src/sage/combinat/posets/hasse_diagram.py +++ b/src/sage/combinat/posets/hasse_diagram.py @@ -3249,23 +3249,24 @@ def _split(self, a, b): EXAMPLES:: + sage: from sage.combinat.posets.hasse_diagram import HasseDiagram sage: H = HasseDiagram({0: [1, 2], 1: [], 2: []}) sage: H._split(0, 1) [Hasse diagram of a poset containing 2 elements, Hasse diagram of a poset containing 1 elements] - sage: H = posets.ChainPoset(5)._hasse_diagram + sage: H = HasseDiagram({0: [1], 1: [2], 2: [3], 3: [4], 4: []}) sage: H._split(1, 2) [Hasse diagram of a poset containing 2 elements, Hasse diagram of a poset containing 3 elements] TESTS:: - - sage: H = posets.BooleanLattice(3)._hasse_diagram + sage: from sage.combinat.posets.hasse_diagram import HasseDiagram + sage: H = HasseDiagram({0: [1,2,3], 1: [4, 5], 2: [4, 6], 3: [5, 6], 4: [7], 5: [7], 6: [7], 7: []}) sage: H._split(0, 1) Traceback (most recent call last): ... ValueError: wrong number of connected components after the covering relation is deleted - sage: H = Poset({0: [1], 1: [], 2: []})._hasse_diagram + sage: H = HasseDiagram({0: [1], 1: [], 2: []}) sage: H._split(0, 1) Traceback (most recent call last): ... @@ -3273,8 +3274,7 @@ def _split(self, a, b): """ split_hasse = self.copy(self) split_hasse.delete_edge(a,b) - components = split_hasse.connected_components() - + components = split_hasse.connected_components_subgraphs() if not len(components) == 2: raise ValueError("wrong number of connected components after the covering relation is deleted") @@ -3282,7 +3282,7 @@ def _split(self, a, b): if a in c2: c1, c2 = c2, c1 - return [self.subgraph(c1), self.subgraph(c2)] + return [c1, c2] def _spectrum_of_tree(self, a): r""" @@ -3300,15 +3300,16 @@ def _spectrum_of_tree(self, a): EXAMPLES:: - sage: H = Poset({0: [2], 1: [2], 2: [3, 4], 3: [], 4: []})._hasse_diagram + sage: from sage.combinat.posets.hasse_diagram import HasseDiagram + sage: H = HasseDiagram({0: [2], 1: [2], 2: [3, 4], 3: [], 4: []}) sage: H._spectrum_of_tree(0) [2, 2, 0, 0, 0] - sage: H = Poset({0: [2], 1: [2], 2: [3, 4], 3: [], 4: []})._hasse_diagram + sage: H = HasseDiagram({0: [2], 1: [2], 2: [3, 4], 3: [], 4: []}) sage: H._spectrum_of_tree(2) [0, 0, 4, 0, 0] - sage: H = Poset({0: [2], 1: [2], 2: [3, 4], 3: [], 4: []})._hasse_diagram + sage: H = HasseDiagram({0: [2], 1: [2], 2: [3, 4], 3: [], 4: []}) sage: H._spectrum_of_tree(3) [0, 0, 0, 2, 2] """ diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 5ded62f1856..cc40fbcbb61 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -1741,18 +1741,21 @@ def atkinson(self, a): components = self.connected_components() remainder_poset = Poset() + for X in components: if a in X: main = X else: remainder_poset = remainder_poset.disjoint_union(X) - a_spec = main._hasse_diagram._spectrum_of_tree(a) + hasse_a = main._element_to_vertex(a) + a_spec = main._hasse_diagram._spectrum_of_tree(hasse_a) if not remainder_poset.cardinality(): return a_spec b = remainder_poset.an_element() + b_spec = remainder_poset.atkinson(b) n_lin_exts = sum(b_spec) From 9d9fb2de492202f5cb9e1ffd74bbd53bdb0a4e40 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 20 Apr 2020 17:44:35 -0700 Subject: [PATCH 266/300] Makefile: Exit with error if not configured --- Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e0018ea790b..40d67914dc6 100644 --- a/Makefile +++ b/Makefile @@ -49,7 +49,11 @@ build/make/Makefile: configure $(SPKG_COLLECT_FILES) $(CONFIG_FILES:%=%.in) @if [ -x config.status ]; then \ ./config.status --recheck && ./config.status; \ else \ - ./configure $$PREREQ_OPTIONS; \ + echo >&2 '****************************************************************************'; \ + echo >&2 'error: Sage source tree is unconfigured. Please run "./configure" first.'; \ + echo >&2 'note: Type "./configure --help" to see the available configuration options.'; \ + echo >&2 '****************************************************************************'; \ + exit 1; \ fi # This is used to monitor progress towards Python 3 and prevent From 5ef691043410cbdec2374364306e3792fd0323ca Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 14 Jun 2020 06:39:58 -0700 Subject: [PATCH 267/300] Update README.md --- README.md | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 64318b4da6d..8621c29cbc8 100644 --- a/README.md +++ b/README.md @@ -424,12 +424,6 @@ The latter `build/make/Makefile` *is* generated by an autoconf-generated includes rules for building the Sage library itself (`make sagelib`), and for building and installing each of Sage's dependencies (e.g. `make python2`). -Although it's possible to manually run Sage's `configure` script if one wants -to provide some customizations (e.g. it is possible to select which BLAS -implementation to use), the top-level `Makefile` will run `configure` for you, -in order to build `build/make/Makefile` since it's a prerequisite for most of -Sage's make targets. - The `configure` script itself, if it is not already built, can be generated by running the `bootstrap` script (the latter requires _GNU autotools_ being installed). The top-level `Makefile` also takes care of this automatically. @@ -438,8 +432,9 @@ To summarize, running a command like `make python3` at the top-level of the source tree goes something like this: 1. `make python3` -2. run `./bootstrap` if `configure` does not exist -3. run `./configure` if `build/make/Makefile` does not exist +2. run `./bootstrap` if `configure` needs updating +3. run `./configure` with any previously configured options if `build/make/Makefile` + needs updating 4. `cd` into `build/make` and run the `install` script--this is little more than a front-end to running `make -f build/make/Makefile python3`, which sets some necessary environment variables and logs some information From 3fcba9001e4f3a020173c5aa9b62bb9aea7180bf Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Sun, 19 Apr 2020 15:45:48 -0700 Subject: [PATCH 268/300] trac 27826: remove __long__ methods, calls to long in doctests, and special-casing for 'long' in Python 3 doctesting --- .../quatalg/quaternion_algebra_element.pyx | 20 ------- src/sage/doctest/forker.py | 11 ++-- src/sage/interfaces/fricas.py | 9 --- src/sage/interfaces/gp.py | 11 ---- src/sage/interfaces/interface.py | 10 ---- src/sage/libs/mpmath/ext_main.pyx | 36 ------------ src/sage/libs/ntl/ntl_ZZ.pyx | 6 +- src/sage/libs/ntl/ntl_ZZ_p.pyx | 2 - src/sage/libs/ntl/ntl_ZZ_pE.pyx | 2 - src/sage/libs/pynac/pynac.pyx | 8 --- src/sage/misc/lazy_import.pyx | 13 ----- src/sage/misc/sage_input.py | 22 -------- src/sage/misc/superseded.py | 1 - src/sage/modules/free_module_element.pyx | 2 +- src/sage/rings/complex_double.pyx | 17 +----- src/sage/rings/complex_interval.pyx | 13 ----- src/sage/rings/complex_mpc.pyx | 23 -------- src/sage/rings/complex_number.pyx | 22 -------- .../rings/finite_rings/element_givaro.pyx | 2 - .../rings/finite_rings/element_pari_ffelt.pyx | 15 ----- src/sage/rings/finite_rings/integer_mod.pyx | 9 --- src/sage/rings/fraction_field_element.pyx | 12 ---- src/sage/rings/integer.pyx | 56 ++----------------- src/sage/rings/number_field/number_field.py | 2 - .../number_field/number_field_element.pyx | 26 --------- .../rings/polynomial/multi_polynomial.pyx | 15 ----- src/sage/rings/polynomial/plural.pyx | 2 - .../rings/polynomial/polynomial_element.pyx | 20 ------- .../polynomial_quotient_ring_element.py | 19 ------- .../rings/polynomial/polynomial_template.pxi | 17 ------ src/sage/rings/qqbar.py | 2 - src/sage/rings/quotient_ring_element.py | 12 ---- src/sage/rings/rational.pyx | 41 +++----------- src/sage/rings/rational_field.py | 9 +-- src/sage/rings/real_double.pyx | 14 ----- src/sage/rings/real_mpfr.pyx | 18 +----- src/sage/structure/coerce.pyx | 9 +-- src/sage/symbolic/expression.pyx | 9 --- src/sage/symbolic/ring.pyx | 2 +- 39 files changed, 27 insertions(+), 512 deletions(-) diff --git a/src/sage/algebras/quatalg/quaternion_algebra_element.pyx b/src/sage/algebras/quatalg/quaternion_algebra_element.pyx index a578badf0df..6b83bb4b70e 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra_element.pyx +++ b/src/sage/algebras/quatalg/quaternion_algebra_element.pyx @@ -263,26 +263,6 @@ cdef class QuaternionAlgebraElement_abstract(AlgebraElement): return int(self[0]) raise TypeError - def __long__(self): - """ - Try to coerce this quaternion to a Python long. - - EXAMPLES:: - - sage: A. = QuaternionAlgebra(-1,-2) - sage: long(A(-3)) - -3L - sage: long(A(-3/2)) - -1L - sage: long(-3 + i) - Traceback (most recent call last): - ... - TypeError - """ - if self.is_constant(): - return long(self[0]) - raise TypeError - def __float__(self): """ Try to coerce this quaternion to a Python float. diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py index c93d1f2d995..46345804e0d 100644 --- a/src/sage/doctest/forker.py +++ b/src/sage/doctest/forker.py @@ -2382,16 +2382,17 @@ class DocTestTask(object): ['cputime', 'err', 'failures', 'optionals', 'tests', 'walltime', 'walltime_skips'] """ - extra_globals = {'long': int} + extra_globals = {} """ Extra objects to place in the global namespace in which tests are run. Normally this should be empty but there are special cases where it may be useful. - In particular, on Python 3 add ``long`` as an alias for ``int`` so that - tests that use the ``long`` built-in (of which there are many) still pass. - We do this so that the test suite can run on Python 3 while Python 2 is - still the default. + For example, in Sage versions 9.1 and earlier, on Python 3 add + ``long`` as an alias for ``int`` so that tests that use the + ``long`` built-in (of which there are many) still pass. We did + this so that the test suite could run on Python 3 while Python 2 + was still the default. """ def __init__(self, source): diff --git a/src/sage/interfaces/fricas.py b/src/sage/interfaces/fricas.py index 336cc50a155..a35d640b64e 100644 --- a/src/sage/interfaces/fricas.py +++ b/src/sage/interfaces/fricas.py @@ -1011,15 +1011,6 @@ def __bool__(self): __nonzero__ = __bool__ - def __long__(self): - """ - TESTS:: - - sage: long(fricas('1')) # optional - fricas - 1L - """ - return long(self.sage()) - def __float__(self): """ TESTS:: diff --git a/src/sage/interfaces/gp.py b/src/sage/interfaces/gp.py index 304a2d418e3..f24d3b01a18 100644 --- a/src/sage/interfaces/gp.py +++ b/src/sage/interfaces/gp.py @@ -934,17 +934,6 @@ def is_string(self): """ return repr(self.type()) == 't_STR' - def __long__(self): - """ - Return Python long. - - EXAMPLES:: - - sage: long(gp(10)) - 10L - """ - return long(str(self)) - def __float__(self): """ Return Python float. diff --git a/src/sage/interfaces/interface.py b/src/sage/interfaces/interface.py index 616c13d94cf..60cd7375065 100644 --- a/src/sage/interfaces/interface.py +++ b/src/sage/interfaces/interface.py @@ -1319,16 +1319,6 @@ def __bool__(self): __nonzero__ = __bool__ - def __long__(self): - """ - EXAMPLES:: - - sage: m = maxima('1') - sage: long(m) - 1L - """ - return long(repr(self)) - def __float__(self): """ EXAMPLES:: diff --git a/src/sage/libs/mpmath/ext_main.pyx b/src/sage/libs/mpmath/ext_main.pyx index 298d289feea..ac89834fee6 100644 --- a/src/sage/libs/mpmath/ext_main.pyx +++ b/src/sage/libs/mpmath/ext_main.pyx @@ -1065,14 +1065,10 @@ cdef class Context: sage: class MyInt(int): ....: pass - sage: class MyLong(long): # py2 - ....: pass sage: class MyFloat(float): ....: pass sage: mag(MyInt(10)) 4 - sage: mag(MyLong(10)) # py2 - 4 """ cdef int typ @@ -1791,18 +1787,6 @@ cdef class mpf_base(mpnumber): """ return int(libmp.to_int(self._mpf_)) - def __long__(self): - """ - Support long conversion for derived classes :: - - sage: from mpmath import mpf - sage: from sage.libs.mpmath.ext_main import mpf_base - sage: class X(mpf_base): _mpf_ = mpf(3.25)._mpf_ - sage: long(X()) - 3L - """ - return long(self.__int__()) - def __float__(self): """ Support float conversion for derived classes :: @@ -2052,26 +2036,6 @@ cdef class mpf(mpf_base): MPF_to_fixed(tmp_mpz, &self.value, 0, True) return mpzi(tmp_mpz) - def __long__(self): - r""" - Convert this mpf value to a long. - - (Due to http://bugs.python.org/issue9869, to allow NZMATH to use - this Sage-modified version of mpmath, it is vital that we - return a long, not an int.) - - TESTS:: - - sage: import mpmath # py2 - sage: v = mpmath.mpf(2) # py2 - sage: class MyLong(long): # py2 - ....: pass - sage: MyLong(v) # py2 - 2L - """ - MPF_to_fixed(tmp_mpz, &self.value, 0, True) - return mpzl(tmp_mpz) - def __float__(self): """ Convert to a double-precision Python float :: diff --git a/src/sage/libs/ntl/ntl_ZZ.pyx b/src/sage/libs/ntl/ntl_ZZ.pyx index 7e040cd9c76..4df571ab6d7 100644 --- a/src/sage/libs/ntl/ntl_ZZ.pyx +++ b/src/sage/libs/ntl/ntl_ZZ.pyx @@ -62,8 +62,6 @@ cdef class ntl_ZZ(object): 12 sage: ntl.ZZ(Integer(95413094)) 95413094 - sage: ntl.ZZ(long(223895239852389582983)) - 223895239852389582983 sage: ntl.ZZ('-1') -1 sage: ntl.ZZ('1L') @@ -253,9 +251,7 @@ cdef class ntl_ZZ(object): sage: ntl.ZZ(10^30).__int__() 1000000000000000000000000000000L - sage: type(ntl.ZZ(10^30).__int__()) # py2 - - sage: type(ntl.ZZ(10^30).__int__()) # py3 + sage: type(ntl.ZZ(10^30).__int__()) """ return int(self._integer_()) diff --git a/src/sage/libs/ntl/ntl_ZZ_p.pyx b/src/sage/libs/ntl/ntl_ZZ_p.pyx index e03170bda00..a7900e47257 100644 --- a/src/sage/libs/ntl/ntl_ZZ_p.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_p.pyx @@ -92,8 +92,6 @@ cdef class ntl_ZZ_p(object): 1 sage: ntl.ZZ_p(Integer(95413094), c) 7 - sage: ntl.ZZ_p(long(223895239852389582988), c) - 5 sage: ntl.ZZ_p('-1', c) 10 diff --git a/src/sage/libs/ntl/ntl_ZZ_pE.pyx b/src/sage/libs/ntl/ntl_ZZ_pE.pyx index 7be19458c2d..504fd264f14 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pE.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pE.pyx @@ -76,8 +76,6 @@ cdef class ntl_ZZ_pE(object): [1 3] sage: c.ZZ_pE(Integer(95413094)) [7] - sage: c.ZZ_pE(long(223895239852389582988)) - [5] sage: c.ZZ_pE('[1]') [1] diff --git a/src/sage/libs/pynac/pynac.pyx b/src/sage/libs/pynac/pynac.pyx index 284cc17376d..0ebc8b5ff35 100644 --- a/src/sage/libs/pynac/pynac.pyx +++ b/src/sage/libs/pynac/pynac.pyx @@ -1106,8 +1106,6 @@ cdef bint py_is_integer(x): sage: py_is_integer(1r) True - sage: py_is_integer(long(1)) - True sage: py_is_integer(3^57) True sage: py_is_integer(SR(5)) @@ -1312,8 +1310,6 @@ def py_is_cinteger_for_doctest(x): sage: from sage.libs.pynac.pynac import py_is_cinteger_for_doctest sage: py_is_cinteger_for_doctest(1) True - sage: py_is_cinteger_for_doctest(long(-3)) - True sage: py_is_cinteger_for_doctest(I.pyobject()) True sage: py_is_cinteger_for_doctest(I.pyobject() - 3) @@ -1710,12 +1706,8 @@ cdef py_log(x): 3.141592653589793j sage: py_log(int(1)) 0.0 - sage: py_log(long(1)) - 0.0 sage: py_log(int(0)) -inf - sage: py_log(long(0)) - -inf sage: py_log(complex(0)) -inf sage: py_log(2) diff --git a/src/sage/misc/lazy_import.pyx b/src/sage/misc/lazy_import.pyx index 16f04bfe8d1..6e2c6624760 100644 --- a/src/sage/misc/lazy_import.pyx +++ b/src/sage/misc/lazy_import.pyx @@ -848,19 +848,6 @@ cdef class LazyImport(object): """ return int(self.get_object()) - def __long__(self): - """ - TESTS:: - - sage: sage.all.foo = 10 - sage: lazy_import('sage.all', 'foo') - sage: type(foo) - - sage: long(foo) - 10L - """ - return long(self.get_object()) - def __float__(self): """ TESTS:: diff --git a/src/sage/misc/sage_input.py b/src/sage/misc/sage_input.py index 80ddd888269..6c671e50f6e 100644 --- a/src/sage/misc/sage_input.py +++ b/src/sage/misc/sage_input.py @@ -392,24 +392,6 @@ def __call__(self, x, coerced=False): sage: sage_input(-11r, preparse=None, verify=True) # Verified -int(11) - sage: sage_input(long(-5), verify=True) # py2 - # Verified - -long(5) - sage: sage_input(long(-7), preparse=False, verify=True) - # Verified - -7L - sage: sage_input(long(11), preparse=None, verify=True) # py2 - # Verified - long(11) - sage: sage_input(long(2^70), verify=True) - # Verified - 1180591620717411303424r - sage: sage_input(-long(2^80), preparse=False, verify=True) - # Verified - -1208925819614629174706176 - sage: sage_input(long(2^75), preparse=None, verify=True) # py2 - # Verified - long(37778931862957161709568) sage: sage_input(float(-infinity), preparse=True, verify=True) # Verified -float(infinity) @@ -577,10 +559,6 @@ def int(self, n): sage: sib.result(sib.int(-3^50)) -717897987691852588770249 - sage: sib = SageInputBuilder() - sage: sib.result(sib.int(long(2^65))) - 36893488147419103232 - sage: sib = SageInputBuilder() sage: sib.result(sib.int(-42r)) -42 diff --git a/src/sage/misc/superseded.py b/src/sage/misc/superseded.py index 238c2013b24..a7c30d297ff 100644 --- a/src/sage/misc/superseded.py +++ b/src/sage/misc/superseded.py @@ -52,7 +52,6 @@ def _check_trac_number(trac_number): ... ValueError: 0 is not a valid trac issue number sage: _check_trac_number(int(10)) - sage: _check_trac_number(long(1000)) sage: _check_trac_number(10.0) Traceback (most recent call last): ... diff --git a/src/sage/modules/free_module_element.pyx b/src/sage/modules/free_module_element.pyx index c0d39da6968..9736dd09d34 100644 --- a/src/sage/modules/free_module_element.pyx +++ b/src/sage/modules/free_module_element.pyx @@ -385,7 +385,7 @@ def vector(arg0, arg1=None, arg2=None, sparse=None, immutable=False): (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) sage: v[3].parent() Integer Ring - sage: v = vector([float(23.4), int(2), complex(2+7*I), long(1)]); v + sage: v = vector([float(23.4), int(2), complex(2+7*I), 1]); v (23.4, 2.0, 2.0 + 7.0*I, 1.0) sage: v[1].parent() Complex Double Field diff --git a/src/sage/rings/complex_double.pyx b/src/sage/rings/complex_double.pyx index dc6662ddb4a..452e173126f 100644 --- a/src/sage/rings/complex_double.pyx +++ b/src/sage/rings/complex_double.pyx @@ -396,7 +396,7 @@ cdef class ComplexDoubleField_class(sage.rings.ring.Field): sage: CDF(1) + RR(1) 2.0 - sage: CDF.0 - CC(1) - long(1) - RR(1) - QQbar(1) + sage: CDF.0 - CC(1) - int(1) - RR(1) - QQbar(1) -4.0 + 1.0*I sage: CDF.has_coerce_map_from(ComplexField(20)) False @@ -926,21 +926,6 @@ cdef class ComplexDoubleElement(FieldElement): """ raise TypeError("can't convert complex to int; use int(abs(z))") - def __long__(self): - """ - Convert ``self`` to a ``long``. - - EXAMPLES:: - - sage: long(CDF(1,1)) # py2 - Traceback (most recent call last): - ... - TypeError: can't convert complex to long; use long(abs(z)) - sage: long(abs(CDF(1,1))) - 1L - """ - raise TypeError("can't convert complex to long; use long(abs(z))") - def __float__(self): """ Method for converting ``self`` to type ``float``. Called by the diff --git a/src/sage/rings/complex_interval.pyx b/src/sage/rings/complex_interval.pyx index 852728dc59a..920d0cd5178 100644 --- a/src/sage/rings/complex_interval.pyx +++ b/src/sage/rings/complex_interval.pyx @@ -1420,19 +1420,6 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): """ raise TypeError("can't convert complex interval to int") - def __long__(self): - """ - Convert ``self`` to a ``lon``. - - EXAMPLES:: - - sage: long(CIF(1,1)) # py2 - Traceback (most recent call last): - ... - TypeError: can't convert complex interval to long - """ - raise TypeError("can't convert complex interval to long") - def __float__(self): """ Convert ``self`` to a ``float``. diff --git a/src/sage/rings/complex_mpc.pyx b/src/sage/rings/complex_mpc.pyx index 84546c22398..108eb25989c 100644 --- a/src/sage/rings/complex_mpc.pyx +++ b/src/sage/rings/complex_mpc.pyx @@ -1132,29 +1132,6 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): """ raise TypeError("can't convert complex to int; use int(abs(z))") - def __long__(self): - r""" - Method for converting ``self`` to type ``long``. - - Called by the ``long`` function. Note that calling this method - returns an error since, in general, complex numbers cannot be - coerced into integers. - - EXAMPLES:: - - sage: MPC = MPComplexField() - sage: a = MPC(2,1) - sage: long(a) # py2 - Traceback (most recent call last): - ... - TypeError: can't convert complex to long; use long(abs(z)) - sage: a.__long__() # py2 - Traceback (most recent call last): - ... - TypeError: can't convert complex to long; use long(abs(z)) - """ - raise TypeError("can't convert complex to long; use long(abs(z))") - def __float__(self): r""" Method for converting ``self`` to type ``float``. diff --git a/src/sage/rings/complex_number.pyx b/src/sage/rings/complex_number.pyx index bc87388c1c6..526f88d2fd5 100644 --- a/src/sage/rings/complex_number.pyx +++ b/src/sage/rings/complex_number.pyx @@ -1119,28 +1119,6 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): """ raise TypeError("can't convert complex to int; use int(abs(z))") - def __long__(self): - r""" - Method for converting ``self`` to type ``long``. - - Called by the ``long`` function. Note that calling this method - returns an error since, in general, complex numbers cannot be - coerced into integers. - - EXAMPLES:: - - sage: a = ComplexNumber(2,1) - sage: long(a) # py2 - Traceback (most recent call last): - ... - TypeError: can't convert complex to long; use long(abs(z)) - sage: a.__long__() # py2 - Traceback (most recent call last): - ... - TypeError: can't convert complex to long; use long(abs(z)) - """ - raise TypeError("can't convert complex to long; use long(abs(z))") - def __float__(self): r""" Method for converting ``self`` to type ``float``. diff --git a/src/sage/rings/finite_rings/element_givaro.pyx b/src/sage/rings/finite_rings/element_givaro.pyx index 03607793acf..8d7ffd4f997 100644 --- a/src/sage/rings/finite_rings/element_givaro.pyx +++ b/src/sage/rings/finite_rings/element_givaro.pyx @@ -345,8 +345,6 @@ cdef class Cache_givaro(SageObject): 1 sage: k(int(2^100)) 1 - sage: k(long(2^100)) - 1 sage: k(-2^100) 2 diff --git a/src/sage/rings/finite_rings/element_pari_ffelt.pyx b/src/sage/rings/finite_rings/element_pari_ffelt.pyx index 7078ea926b7..10ffb313898 100644 --- a/src/sage/rings/finite_rings/element_pari_ffelt.pyx +++ b/src/sage/rings/finite_rings/element_pari_ffelt.pyx @@ -132,8 +132,6 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement): sage: K. = FiniteField(7^20, impl='pari_ffelt') sage: K(int(8)) 1 - sage: K(long(-2^300)) - 6 :: @@ -1165,19 +1163,6 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement): """ return int(self.lift()) - def __long__(self): - """ - Lift to a python long, if possible. - - EXAMPLES:: - - sage: k. = GF(3^17, impl='pari_ffelt') - sage: b = k(2) - sage: long(b) - 2L - """ - return long(self.lift()) - def __float__(self): """ Lift to a python float, if possible. diff --git a/src/sage/rings/finite_rings/integer_mod.pyx b/src/sage/rings/finite_rings/integer_mod.pyx index 5dfd814a87a..1db7fd83e63 100644 --- a/src/sage/rings/finite_rings/integer_mod.pyx +++ b/src/sage/rings/finite_rings/integer_mod.pyx @@ -2176,9 +2176,6 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): """ return int(self.lift()) - def __long__(self): - return long(self.lift()) - def __pow__(IntegerMod_gmp self, exp, m): # NOTE: m ignored, always use modulus of parent ring """ EXAMPLES:: @@ -2569,9 +2566,6 @@ cdef class IntegerMod_int(IntegerMod_abstract): """ return self.ivalue - def __long__(IntegerMod_int self): - return self.ivalue - def __lshift__(IntegerMod_int self, k): r""" Performs a left shift by ``k`` bits. @@ -3366,9 +3360,6 @@ cdef class IntegerMod_int64(IntegerMod_abstract): """ return self.ivalue - def __long__(IntegerMod_int64 self): - return self.ivalue - def __lshift__(IntegerMod_int64 self, k): r""" Performs a left shift by ``k`` bits. diff --git a/src/sage/rings/fraction_field_element.pyx b/src/sage/rings/fraction_field_element.pyx index 3e3c19bfa24..db4177ef2b3 100644 --- a/src/sage/rings/fraction_field_element.pyx +++ b/src/sage/rings/fraction_field_element.pyx @@ -773,18 +773,6 @@ cdef class FractionFieldElement(FieldElement): """ return Q(self.__numerator) / Q(self.__denominator) - def __long__(self): - """ - EXAMPLES:: - - sage: K. = Frac(QQ['x']) - sage: long(K(3)) - 3L - sage: long(K(3/5)) - 0L - """ - return long(int(self)) - def __pow__(self, right, dummy): r""" Returns self raised to the `right^{th}` power. diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 1879407eb16..d5597208565 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -373,8 +373,6 @@ def is_Integer(x): False sage: is_Integer(int(2)) False - sage: is_Integer(long(2)) - False sage: is_Integer('5') False """ @@ -489,7 +487,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): """ EXAMPLES:: - sage: a = long(-901824309821093821093812093810928309183091832091) + sage: a = int(-901824309821093821093812093810928309183091832091) sage: b = ZZ(a); b -901824309821093821093812093810928309183091832091 sage: ZZ(b) @@ -560,14 +558,10 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: class MyInt(int): ....: pass - sage: class MyLong(long): - ....: pass sage: class MyFloat(float): ....: pass sage: ZZ(MyInt(3)) 3 - sage: ZZ(MyLong(4)) - 4 sage: ZZ(MyFloat(5)) 5 @@ -1228,10 +1222,6 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): 10 sage: print(Integer(16938402384092843092843098243).hex()) 36bb1e3929d1a8fe2802f083 - sage: print(hex(long(16938402384092843092843098243))) - 0x36bb1e3929d1a8fe2802f083L - - TESTS:: sage: hex(Integer(16)) # py2 doctest:warning...: @@ -1843,9 +1833,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): Make sure it works when -n would overflow:: sage: most_neg_long = int(-sys.maxsize - 1) - sage: type(most_neg_long), type(-most_neg_long) # py2 - (, ) - sage: type(most_neg_long), type(-most_neg_long) # py3 + sage: type(most_neg_long), type(-most_neg_long) (, ) sage: 0 + most_neg_long == most_neg_long True @@ -3616,36 +3604,13 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): 99028390823409823904823098490238409823490820938L sage: int(-n) -99028390823409823904823098490238409823490820938L - sage: type(n.__int__()) # py2 - - sage: type(n.__int__()) # py3 + sage: type(n.__int__()) sage: int(-1), int(0), int(1) (-1, 0, 1) """ return mpz_get_pyintlong(self.value) - def __long__(self): - """ - Return the Python long corresponding to this Sage integer. - - EXAMPLES:: - - sage: n = 9023408290348092849023849820934820938490234290 - sage: long(n) - 9023408290348092849023849820934820938490234290L - sage: long(-n) - -9023408290348092849023849820934820938490234290L - sage: n = 920938 - sage: long(n) - 920938L - sage: n.__long__() # py2 - 920938L - sage: long(-1), long(0), long(1) - (-1L, 0L, 1L) - """ - return mpz_get_pylong(self.value) - def __float__(self): """ Return double precision floating point representation of this @@ -7241,9 +7206,7 @@ cdef class int_to_Z(Morphism): EXAMPLES:: sage: f = ZZ.coerce_map_from(int) - sage: type(f) # py2 - - sage: type(f) # py3 + sage: type(f) sage: f(5r) 5 @@ -7321,20 +7284,13 @@ cdef class long_to_Z(Morphism): """ EXAMPLES:: - sage: f = ZZ.coerce_map_from(long) # py2 - sage: f = ZZ.coerce_map_from(int) # py3 - sage: f # py2 - Native morphism: - From: Set of Python objects of class 'long' - To: Integer Ring - sage: f # py3 + sage: f = ZZ.coerce_map_from(int) + sage: f Native morphism: From: Set of Python objects of class 'int' To: Integer Ring sage: f(1rL) 1 - sage: f(-10000000000000000000001r) - -10000000000000000000001 """ def __init__(self): import sage.categories.homset diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 26e219c1ed1..7777c8c0906 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -7617,8 +7617,6 @@ def _coerce_map_from_(self, R): sage: S. = NumberField(x^3 + x + 1) sage: S.coerce(int(4)) # indirect doctest 4 - sage: S.coerce(long(7)) - 7 sage: S.coerce(-Integer(2)) -2 sage: z = S.coerce(-7/8); z, type(z) diff --git a/src/sage/rings/number_field/number_field_element.pyx b/src/sage/rings/number_field/number_field_element.pyx index 59bab07db08..9fbc509808a 100644 --- a/src/sage/rings/number_field/number_field_element.pyx +++ b/src/sage/rings/number_field/number_field_element.pyx @@ -2640,32 +2640,6 @@ cdef class NumberFieldElement(FieldElement): """ return int(self.polynomial()) - def __long__(self): - """ - Attempt to convert this number field element to a Python long, if - possible. - - EXAMPLES:: - - sage: K. = NumberField(x^10 - x - 1) - sage: long(a) # py2 - Traceback (most recent call last): - ... - TypeError: cannot coerce nonconstant polynomial to long - sage: long(K(1234)) # py2 - doctest:...: DeprecationWarning: converting polynomials to longs is deprecated, since long() will no longer be supported in Python 3 - See https://trac.sagemath.org/27675 for details. - 1234L - - The value does not have to be preserved, in the case of fractions. - - :: - - sage: long(K(393/29)) - 13L - """ - return long(self.polynomial()) - def __invert__(self): """ Returns the multiplicative inverse of self in the number field. diff --git a/src/sage/rings/polynomial/multi_polynomial.pyx b/src/sage/rings/polynomial/multi_polynomial.pyx index 51ada7c9699..50a671197e5 100644 --- a/src/sage/rings/polynomial/multi_polynomial.pyx +++ b/src/sage/rings/polynomial/multi_polynomial.pyx @@ -57,21 +57,6 @@ cdef class MPolynomial(CommutativeRingElement): return int(self.constant_coefficient()) raise TypeError(f"unable to convert non-constant polynomial {self} to an integer") - def __long__(self): - """ - TESTS:: - - sage: long(RR['x,y'](0)) # indirect doctest - 0L - sage: long(ZZ['x,y'].gen(0)) - Traceback (most recent call last): - ... - TypeError: unable to convert non-constant polynomial x to an integer - """ - if self.degree() <= 0: - return long(self.constant_coefficient()) - raise TypeError(f"unable to convert non-constant polynomial {self} to an integer") - def __float__(self): """ TESTS:: diff --git a/src/sage/rings/polynomial/plural.pyx b/src/sage/rings/polynomial/plural.pyx index 42001d4fcfa..1a691030fd6 100644 --- a/src/sage/rings/polynomial/plural.pyx +++ b/src/sage/rings/polynomial/plural.pyx @@ -434,8 +434,6 @@ cdef class NCPolynomialRing_plural(Ring): 17 sage: P(int(19)) 19 - sage: P(long(19)) - 19 TESTS: diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 3d657d1f94e..924cc719869 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -1634,26 +1634,6 @@ cdef class Polynomial(CommutativeAlgebraElement): """ raise NotImplementedError("only implemented for certain base rings") - def __long__(self): - """ - EXAMPLES:: - - sage: R. = ZZ[] - sage: f = x - 902384 - sage: long(f) # py2 - Traceback (most recent call last): - ... - TypeError: cannot coerce nonconstant polynomial to long - sage: long(R(939392920202)) # py2 - doctest:...: DeprecationWarning: converting polynomials to longs is deprecated, since long() will no longer be supported in Python 3 - See https://trac.sagemath.org/27675 for details. - 939392920202L - """ - if self.degree() > 0: - raise TypeError("cannot coerce nonconstant polynomial to long") - deprecation(27675, "converting polynomials to longs is deprecated, since long() will no longer be supported in Python 3") - return long(self.get_coeff_c(0)) - cpdef _mul_(self, right): """ EXAMPLES:: diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py index 6cb32231048..2ff3c915fce 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py @@ -445,25 +445,6 @@ def __invert__(self): c = g[0] return self.__class__(self.parent(), (~c)*a, check=False) - def __long__(self): - """ - Coerce this element to a long if possible. - - EXAMPLES:: - - sage: R. = PolynomialRing(QQ) - sage: S. = R.quotient(x^3-2) - sage: long(S(10)) # py2 - doctest:...: DeprecationWarning: converting polynomials to longs is deprecated, since long() will no longer be supported in Python 3 - See https://trac.sagemath.org/27675 for details. - 10L - sage: long(a) # py2 - Traceback (most recent call last): - ... - TypeError: cannot coerce nonconstant polynomial to long - """ - return long(self._polynomial) - def field_extension(self, names): r""" Given a polynomial with base ring a quotient ring, return a diff --git a/src/sage/rings/polynomial/polynomial_template.pxi b/src/sage/rings/polynomial/polynomial_template.pxi index cb31d25a839..412826e6eb4 100644 --- a/src/sage/rings/polynomial/polynomial_template.pxi +++ b/src/sage/rings/polynomial/polynomial_template.pxi @@ -500,23 +500,6 @@ cdef class Polynomial_template(Polynomial): celement_quorem(&q.x, &r.x, &(self).x, &right.x, (self)._cparent) return q,r - def __long__(self): - """ - EXAMPLES:: - - sage: P. = GF(2)[] - sage: int(x) - Traceback (most recent call last): - ... - ValueError: Cannot coerce polynomial with degree 1 to integer. - - sage: int(P(1)) - 1 - """ - if celement_len(&self.x, (self)._cparent) > 1: - raise ValueError("Cannot coerce polynomial with degree %d to integer."%(self.degree())) - return int(self[0]) - def __nonzero__(self): """ EXAMPLES:: diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index 7fc0cb99173..f9607061013 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -6030,8 +6030,6 @@ def __init__(self, x): sage: polygen(QQbar) / int(3) 1/3*x - sage: QQbar(int(7)) / QQbar(long(2)) - 7/2 """ if isinstance(x, (sage.rings.integer.Integer, sage.rings.rational.Rational)): diff --git a/src/sage/rings/quotient_ring_element.py b/src/sage/rings/quotient_ring_element.py index 5850da34287..09564e4c3eb 100644 --- a/src/sage/rings/quotient_ring_element.py +++ b/src/sage/rings/quotient_ring_element.py @@ -16,7 +16,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.structure.element import RingElement from sage.structure.richcmp import richcmp, rich_to_bool from sage.interfaces.singular import singular as singular_default @@ -516,17 +515,6 @@ def _rational_(self): except AttributeError: raise NotImplementedError - def __long__(self): - """ - EXAMPLES:: - - sage: R. = QQ[]; S. = R.quo(x^2 + y^2); type(a) - - sage: long(S(-3)) # indirect doctest - -3L - """ - return long(self.lift()) - def __neg__(self): """ EXAMPLES:: diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index 30b50ea4978..608a52421c7 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -380,8 +380,6 @@ def is_Rational(x): True sage: is_Rational(int(2)) False - sage: is_Rational(long(2)) - False sage: is_Rational('5') False """ @@ -2998,36 +2996,19 @@ cdef class Rational(sage.structure.element.FieldElement): #Define an alias for numerator numer = numerator - IF PY_MAJOR_VERSION <= 2: - def __int__(self): - """ - Convert this rational to a Python ``int``. - - This truncates ``self`` if ``self`` has a denominator (which is - consistent with Python's ``long(floats)``). - - EXAMPLES:: - - sage: int(7/3) - 2 - sage: int(-7/3) - -2 - """ - return int(self.__long__()) - - def __long__(self): + def __int__(self): """ - Convert this rational to a Python ``long`` (``int`` on Python 3). + Convert this rational to a Python ``int`` This truncates ``self`` if ``self`` has a denominator (which is consistent with Python's ``long(floats)``). EXAMPLES:: - sage: long(7/3) - 2L - sage: long(-7/3) - -2L + sage: int(7/1) + 7 + sage: int(7/2) + 3 """ cdef mpz_t x if mpz_cmp_si(mpq_denref(self.value),1) != 0: @@ -4271,11 +4252,7 @@ cdef class long_to_Q(Morphism): EXAMPLES:: - sage: sage.rings.rational.long_to_Q() # py2 - Native morphism: - From: Set of Python objects of class 'long' - To: Rational Field - sage: sage.rings.rational.long_to_Q() # py3 + sage: sage.rings.rational.long_to_Q() Native morphism: From: Set of Python objects of class 'int' To: Rational Field @@ -4293,9 +4270,7 @@ cdef class long_to_Q(Morphism): EXAMPLES:: sage: f = sage.rings.rational.long_to_Q() - sage: f(long(4)) # indirect doctest - 4 - sage: f(long(4^100)) + sage: f(4^100) 1606938044258990275541962092341162602522202993782792835301376 """ diff --git a/src/sage/rings/rational_field.py b/src/sage/rings/rational_field.py index 3e45f269934..ac42022267b 100644 --- a/src/sage/rings/rational_field.py +++ b/src/sage/rings/rational_field.py @@ -72,7 +72,7 @@ class RationalField(Singleton, number_field_base.NumberField): EXAMPLES:: - sage: a = long(901824309821093821093812093810928309183091832091) + sage: a = 901824309821093821093812093810928309183091832091 sage: b = QQ(a); b 901824309821093821093812093810928309183091832091 sage: QQ(b) @@ -361,13 +361,6 @@ def _coerce_map_from_(self, S): sage: f(44) 44 - :: - - sage: QQ.coerce_map_from(long) # indirect doctest py2 - Native morphism: - From: Set of Python objects of class 'long' - To: Rational Field - :: sage: L = Localization(ZZ, (3,5)) diff --git a/src/sage/rings/real_double.pyx b/src/sage/rings/real_double.pyx index 3011f32c645..0bbd103dbee 100644 --- a/src/sage/rings/real_double.pyx +++ b/src/sage/rings/real_double.pyx @@ -1588,20 +1588,6 @@ cdef class RealDoubleElement(FieldElement): """ return int(self._value) - def __long__(self): - """ - Returns long integer truncation of this real number. - - EXAMPLES:: - - sage: int(RDF(10e15)) - 10000000000000000L # 32-bit - 10000000000000000 # 64-bit - sage: long(RDF(2^100)) == 2^100 - True - """ - return long(self._value) - def _complex_mpfr_field_(self, CC): """ EXAMPLES:: diff --git a/src/sage/rings/real_mpfr.pyx b/src/sage/rings/real_mpfr.pyx index c4fc0f8836c..310d30c5468 100644 --- a/src/sage/rings/real_mpfr.pyx +++ b/src/sage/rings/real_mpfr.pyx @@ -719,7 +719,7 @@ cdef class RealField_class(sage.rings.ring.Field): TESTS:: - sage: 1.0 - ZZ(1) - int(1) - long(1) - QQ(1) - RealField(100)(1) - AA(1) - RLF(1) + sage: 1.0 - ZZ(1) - int(1) - 1 - QQ(1) - RealField(100)(1) - AA(1) - RLF(1) -6.00000000000000 sage: R = RR['x'] # Hold reference to avoid garbage collection, see Trac #24709 sage: R.get_action(ZZ) @@ -3116,22 +3116,6 @@ cdef class RealNumber(sage.structure.element.RingElement): mpfr_get_z(z.value, self.value, MPFR_RNDZ) return z.__int__() - def __long__(self): - """ - Returns Python long integer truncation of this real number. - - EXAMPLES:: - - sage: long(RR(pi)) - 3L - """ - if not mpfr_number_p(self.value): - raise ValueError('Cannot convert infinity or NaN to Python long') - - cdef Integer z = Integer() - mpfr_get_z(z.value, self.value, MPFR_RNDZ) - return z.__long__() - def __complex__(self): """ Return a Python complex number equal to ``self``. diff --git a/src/sage/structure/coerce.pyx b/src/sage/structure/coerce.pyx index 597b8bed278..dbe9f17cff0 100644 --- a/src/sage/structure/coerce.pyx +++ b/src/sage/structure/coerce.pyx @@ -111,8 +111,6 @@ cpdef py_scalar_parent(py_type): sage: from sage.structure.coerce import py_scalar_parent sage: py_scalar_parent(int) Integer Ring - sage: py_scalar_parent(long) # py2 - Integer Ring sage: py_scalar_parent(float) Real Double Field sage: py_scalar_parent(complex) @@ -208,9 +206,6 @@ cpdef py_scalar_to_element(x): sage: x = py_scalar_to_element(int(42)) sage: x, parent(x) (42, Integer Ring) - sage: x = py_scalar_to_element(long(42)) - sage: x, parent(x) - (42, Integer Ring) sage: x = py_scalar_to_element(float(42)) sage: x, parent(x) (42.0, Real Double Field) @@ -249,7 +244,7 @@ cpdef py_scalar_to_element(x): Test compatibility with :func:`py_scalar_parent`:: sage: from sage.structure.coerce import py_scalar_parent - sage: elt = [True, int(42), long(42), float(42), complex(42)] + sage: elt = [True, int(42), float(42), complex(42)] sage: for x in elt: ....: assert py_scalar_parent(type(x)) == py_scalar_to_element(x).parent() @@ -321,8 +316,6 @@ cpdef bint parent_is_integers(P) except -1: sage: from sage.structure.coerce import parent_is_integers sage: parent_is_integers(int) True - sage: parent_is_integers(long) - True sage: parent_is_integers(float) False sage: parent_is_integers(bool) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 19da8508d27..5b18ca6faee 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -1317,15 +1317,6 @@ cdef class Expression(CommutativeRingElement): else: return int(result) - def __long__(self): - """ - EXAMPLES:: - - sage: long(sin(2)*100) - 90L - """ - return long(int(self)) - def _rational_(self): """ EXAMPLES:: diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index 377e67a4528..f6b5d2eab4a 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -237,7 +237,7 @@ cdef class SymbolicRing(CommutativeRing): x + y0/y1 sage: x.subs(x=y0/y1) y0/y1 - sage: x + long(1) + sage: x + int(1) x + 1 If `a` is already in the symbolic expression ring, coercing returns From 2060aeae55f0c83641cfeffd1e79be3e8b3f6c1f Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 15 Jun 2020 09:53:46 +1000 Subject: [PATCH 269/300] Updating references based on compromise. --- src/doc/en/reference/references/index.rst | 2 +- src/sage/combinat/diagram_algebras.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 490cf37bf4a..af6c8e4b701 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1568,7 +1568,7 @@ REFERENCES: games*. MIT Press, 2003. .. [Cre2020] Creedon, Samuel. *The center of the partition algebra*. - Preprint, :arxiv:`2005.00600v1` (2020). + Preprint, :arxiv:`2005.00600` (2020). .. [Cro1983] \M. Crochemore, Recherche linéaire d'un carré dans un mot, C. R. Acad. Sci. Paris Sér. I Math. 296 (1983) 14 diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 42549925986..a8536779aaf 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -2874,7 +2874,7 @@ def sigma(self, i): + P{{-3, 1, 2}, {-2, -1, 3}} - P{{-3, 2}, {-2, -1, 1, 3}} + P{{-3, 2}, {-2, 3}, {-1, 1}} - We test the relations in Lemma 2.2.3(1) in [Cre2020]_:: + We test the relations in Lemma 2.2.3(1) in [Cre2020]_ (v1):: sage: k = 4 sage: R. = QQ[] @@ -2976,7 +2976,7 @@ def jucys_murphy_element(self, i): sage: P3.L(3/2) * P3.L(2) == P3.L(2) * P3.L(3/2) True - We test the relations in Lemma 2.2.3(2) in [Cre2020]_:: + We test the relations in Lemma 2.2.3(2) in [Cre2020]_ (v1):: sage: k = 4 sage: R. = QQ[] @@ -2992,7 +2992,7 @@ def jucys_murphy_element(self, i): sage: all(x * Lsum == Lsum * x for x in gens) True - Also the relations in Lemma 2.2.3(3) in [Cre2020]_:: + Also the relations in Lemma 2.2.3(3) in [Cre2020]_ (v1):: sage: all(P.e((2*i+1)/2) * P.sigma(2*i/2) * P.e((2*i+1)/2) ....: == (n - P.L((2*i-1)/2)) * P.e((2*i+1)/2) for i in range(1,k)) From 21f9d90bba887bbd2d734c41273d0f6a2f2596a5 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Mon, 15 Jun 2020 07:42:31 +0200 Subject: [PATCH 270/300] optional tag again --- src/sage/geometry/polyhedron/backend_normaliz.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index 32bafa876e1..32a21ca6c5f 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -337,7 +337,7 @@ def _convert_to_pynormaliz(x): sage: P = polytopes.simplex(backend='normaliz') # optional - pynormaliz sage: K. = QuadraticField(2) # optional - pynormaliz - sage: P.dilation(sqrt2) + sage: P.dilation(sqrt2) # optional - pynormaliz A 3-dimensional polyhedron in (Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.41...)^4 defined as the convex hull of 4 vertices """ def _QQ_pair(x): From 29732eb2fb42f54091606ee4ecc95d2bfffd3937 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Mon, 15 Jun 2020 13:29:03 +0100 Subject: [PATCH 271/300] Added _an_element_ --- src/sage/combinat/path_tableaux/dyck_path.py | 12 ++++++++++++ src/sage/combinat/path_tableaux/path_tableau.py | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/path_tableaux/dyck_path.py b/src/sage/combinat/path_tableaux/dyck_path.py index 9e0212b92aa..29fcf32796a 100644 --- a/src/sage/combinat/path_tableaux/dyck_path.py +++ b/src/sage/combinat/path_tableaux/dyck_path.py @@ -363,5 +363,17 @@ class DyckPaths(PathTableaux): """ The parent class for DyckPath. """ + + def _an_element_(self): + """ + Return an element of ``self``. + + EXAMPLES:: + + sage: path_tableaux.DyckPaths()._an_element_() + [0, 1, 2, 1, 0] + """ + return DyckPath([0,1,2,1,0]) + Element = DyckPath diff --git a/src/sage/combinat/path_tableaux/path_tableau.py b/src/sage/combinat/path_tableaux/path_tableau.py index 7b25583aa22..0e3331502e1 100644 --- a/src/sage/combinat/path_tableaux/path_tableau.py +++ b/src/sage/combinat/path_tableaux/path_tableau.py @@ -439,7 +439,7 @@ def __init__(self): TESTS:: - sage: t = path_tableaux.DyckPath([0,1,2,1,0]) + sage: t = path_tableaux.DyckPaths() sage: TestSuite(t).run() """ Parent.__init__(self, category=Sets()) From efa600698dcfb689c6a89a92d941ec9e1e7b9ee3 Mon Sep 17 00:00:00 2001 From: Bruce Westbury Date: Mon, 15 Jun 2020 13:51:59 +0100 Subject: [PATCH 272/300] Added _an_element_ --- src/sage/combinat/path_tableaux/frieze.py | 11 ++++++++ .../combinat/path_tableaux/path_tableau.py | 25 +++++++++++-------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/sage/combinat/path_tableaux/frieze.py b/src/sage/combinat/path_tableaux/frieze.py index 74943d0ed58..800d85138b6 100644 --- a/src/sage/combinat/path_tableaux/frieze.py +++ b/src/sage/combinat/path_tableaux/frieze.py @@ -450,4 +450,15 @@ def __init__(self, field): Parent.__init__(self, category=Sets()) + def _an_element_(self): + """ + Return an element of ``self``. + + EXAMPLES:: + + sage: path_tableaux.FriezePatterns(QQ)._an_element_() + [1, 1, 1] + """ + return FriezePattern([1,1,1]) + Element = FriezePattern diff --git a/src/sage/combinat/path_tableaux/path_tableau.py b/src/sage/combinat/path_tableaux/path_tableau.py index ea4601a22bc..ae181968c95 100644 --- a/src/sage/combinat/path_tableaux/path_tableau.py +++ b/src/sage/combinat/path_tableaux/path_tableau.py @@ -441,6 +441,9 @@ def __init__(self): sage: t = path_tableaux.DyckPaths() sage: TestSuite(t).run() + + sage: f = path_tableaux.FriezePatterns(QQ) + sage: TestSuite(f).run() """ Parent.__init__(self, category=Sets()) @@ -505,15 +508,15 @@ def _repr_(self): TESTS:: - sage: cd = CylindricalDiagram(DyckPath([0,1,2,1,2,1,0])) + sage: cd = path_tableaux.CylindricalDiagram(path_tableaux.DyckPath([0,1,2,1,2,1,0])) sage: repr(cd) == cd._repr_() # indirect test True - sage: cd = CylindricalDiagram(FriezePattern([1,3,4,5,1])) + sage: cd = path_tableaux.CylindricalDiagram(path_tableaux.FriezePattern([1,3,4,5,1])) sage: repr(cd) == cd._repr_() # indirect test True - sage: print(DyckPath([0,1,2,1,2,1,0])) # indirect test + sage: print(path_tableaux.DyckPath([0,1,2,1,2,1,0])) # indirect test [0, 1, 2, 1, 2, 1, 0] sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) @@ -581,8 +584,8 @@ def _latex_(self): & & & & & & 0 & 1 & 2 & 3 & 2 & 1 & 0 \end{array} - sage: t = FriezePattern([1,3,4,5,1]) - sage: latex(CylindricalDiagram(t)) + sage: t = path_tableaux.FriezePattern([1,3,4,5,1]) + sage: latex(path_tableaux.CylindricalDiagram(t)) \begin{array}{ccccccccccccc} 0 & 1 & 3 & 4 & 5 & 1 & 0\\ & 0 & 1 & \frac{5}{3} & \frac{7}{3} & \frac{2}{3} & 1 & 0\\ @@ -629,8 +632,8 @@ def _ascii_art_(self): 0 1 0 1 2 1 0 0 1 2 3 2 1 0 - sage: t = FriezePattern([1,3,4,5,1]) - sage: ascii_art(CylindricalDiagram(t)) + sage: t = path_tableaux.FriezePattern([1,3,4,5,1]) + sage: ascii_art(path_tableaux.CylindricalDiagram(t)) 0 1 3 4 5 1 0 0 1 5/3 7/3 2/3 1 0 0 1 2 1 3 1 0 @@ -660,8 +663,8 @@ def _unicode_art_(self): 0 1 0 1 2 1 0 0 1 2 3 2 1 0 - sage: t = FriezePattern([1,3,4,5,1]) - sage: unicode_art(CylindricalDiagram(t)) + sage: t = path_tableaux.FriezePattern([1,3,4,5,1]) + sage: unicode_art(path_tableaux.CylindricalDiagram(t)) 0 1 3 4 5 1 0 0 1 5/3 7/3 2/3 1 0 0 1 2 1 3 1 0 @@ -691,8 +694,8 @@ def pp(self): 0 1 0 1 2 1 0 0 1 2 3 2 1 0 - sage: t = FriezePattern([1,3,4,5,1]) - sage: CylindricalDiagram(t).pp() + sage: t = path_tableaux.FriezePattern([1,3,4,5,1]) + sage: path_tableaux.CylindricalDiagram(t).pp() 0 1 3 4 5 1 0 0 1 5/3 7/3 2/3 1 0 0 1 2 1 3 1 0 From 17342095391b824b8fe8ed56b7cfd3f1a9e949ee Mon Sep 17 00:00:00 2001 From: Antonio Rojas Date: Mon, 15 Jun 2020 22:18:30 +0200 Subject: [PATCH 273/300] Avoid using sympy private API --- src/sage/manifolds/calculus_method.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/manifolds/calculus_method.py b/src/sage/manifolds/calculus_method.py index a658551ee9f..3f3fec039ca 100644 --- a/src/sage/manifolds/calculus_method.py +++ b/src/sage/manifolds/calculus_method.py @@ -65,7 +65,7 @@ def _SR_to_Sympy(expression): """ # Nothing to do if expression is already a SymPy object: - if type(expression) in sympy.core.core.all_classes: + if isinstance(expression, sympy.Basic): return expression return SR(expression)._sympy_() From 3de4f74ac9211f4cde61c42e000192ef7907cc0e Mon Sep 17 00:00:00 2001 From: Stefan Grosser Date: Mon, 15 Jun 2020 19:52:50 -0400 Subject: [PATCH 274/300] changed boolean lattice to young diagram --- src/sage/combinat/posets/posets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index cc40fbcbb61..9d35fc7651a 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -1652,8 +1652,8 @@ def spectrum(self, a): sage: P.spectrum(2) [0, 0, 1, 0, 0] - sage: P = posets.BooleanLattice(3) - sage: P.spectrum(5) + sage: P = posets.YoungDiagramPoset(Partition([3,2,1])) + sage: P.spectrum(1) [0, 0, 0, 4, 12, 16, 16, 0] sage: P = posets.AntichainPoset(4) From 48a04ef9463b14674f3ece12bd3a2c1e8fddbf9b Mon Sep 17 00:00:00 2001 From: Stefan Grosser Date: Mon, 15 Jun 2020 20:28:21 -0400 Subject: [PATCH 275/300] Added full test with YoungDiagram --- src/sage/combinat/posets/posets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 9d35fc7651a..5625a295839 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -1653,8 +1653,8 @@ def spectrum(self, a): [0, 0, 1, 0, 0] sage: P = posets.YoungDiagramPoset(Partition([3,2,1])) - sage: P.spectrum(1) - [0, 0, 0, 4, 12, 16, 16, 0] + sage: P.spectrum((0,1)) + [0, 8, 6, 2, 0, 0] sage: P = posets.AntichainPoset(4) sage: P.spectrum(3) From bdf4b35a8e1acc544eb1c746c23a232603105afd Mon Sep 17 00:00:00 2001 From: Stefan Grosser Date: Mon, 15 Jun 2020 20:31:44 -0400 Subject: [PATCH 276/300] added back BooleanLattice example --- src/sage/combinat/posets/posets.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 5625a295839..c172f883d5d 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -1651,6 +1651,10 @@ def spectrum(self, a): sage: P = posets.ChainPoset(5) sage: P.spectrum(2) [0, 0, 1, 0, 0] + + sage: P = posets.BooleanLattice(3) + sage: P.spectrum(5) + [0, 0, 0, 4, 12, 16, 16, 0] sage: P = posets.YoungDiagramPoset(Partition([3,2,1])) sage: P.spectrum((0,1)) From d734de1617b0ab38a60d7bc2e27f8e77107bede4 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 17 Jun 2020 00:27:29 +0100 Subject: [PATCH 277/300] the correct precision of 6 digits after dot --- src/sage/modules/diamond_cutting.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/modules/diamond_cutting.py b/src/sage/modules/diamond_cutting.py index f76e024d4cd..4b649b33178 100644 --- a/src/sage/modules/diamond_cutting.py +++ b/src/sage/modules/diamond_cutting.py @@ -154,6 +154,7 @@ def diamond_cut(V, GM, C, verbose=False): (A vertex at (2), A vertex at (0)) """ # coerce to floats + from sage.misc.functional import round GM = GM.n() C = float(C) if verbose: @@ -223,7 +224,7 @@ def diamond_cut(V, GM, C, verbose=False): cut_count += 1 if verbose: print("\n%d) Cut using normal vector %s" % (cut_count, hv)) - hv = [QQ(elmt.n(digits=6)) for elmt in hv] + hv = [QQ(round(elmt,6)) for elmt in hv] inequalities.append(plane_inequality(hv)) if verbose: From d143ad03db68d3fb4f00a0a33f269fbc2da3a524 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 17 Jun 2020 10:28:11 +1000 Subject: [PATCH 278/300] Some fixes for frieze patterns and better drawing for cylindrical diagrams. --- src/sage/combinat/path_tableaux/dyck_path.py | 2 +- src/sage/combinat/path_tableaux/frieze.py | 244 +++++++++--------- .../combinat/path_tableaux/path_tableau.py | 142 +++++----- 3 files changed, 201 insertions(+), 187 deletions(-) diff --git a/src/sage/combinat/path_tableaux/dyck_path.py b/src/sage/combinat/path_tableaux/dyck_path.py index 3e6140a18a8..29fcf32796a 100644 --- a/src/sage/combinat/path_tableaux/dyck_path.py +++ b/src/sage/combinat/path_tableaux/dyck_path.py @@ -27,7 +27,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.combinat.path_tableaux.path_tableau import PathTableau, PathTableaux, CylindricalDiagram +from sage.combinat.path_tableaux.path_tableau import PathTableau, PathTableaux from sage.combinat.combinatorial_map import combinatorial_map from sage.combinat.dyck_word import DyckWord from sage.combinat.perfect_matching import PerfectMatching diff --git a/src/sage/combinat/path_tableaux/frieze.py b/src/sage/combinat/path_tableaux/frieze.py index 800d85138b6..108cc46fe41 100644 --- a/src/sage/combinat/path_tableaux/frieze.py +++ b/src/sage/combinat/path_tableaux/frieze.py @@ -1,13 +1,10 @@ r""" Frieze Patterns -This is an implementation of the abstract base class -:class:`sage.combinat.pathtableau.pathtableaux`. - This implements the original frieze patterns due to Conway and Coxeter. - -In this implementation we have sequences of nonnegative integers. -This follows [CoCo1]_ and [CoCo2]_ +Such a frieze pattern is considered as a sequence of nonnegative +integers following [CoCo1]_ and [CoCo2]_ using +:class:`sage.combinat.path_tableaux.path_tableau`. AUTHORS: @@ -30,55 +27,55 @@ from sage.combinat.path_tableaux.path_tableau import PathTableau, PathTableaux, CylindricalDiagram from sage.categories.fields import Fields from sage.rings.all import QQ, ZZ -from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane -from sage.plot.all import Graphics ############################################################################### @add_metaclass(InheritComparisonClasscallMetaclass) class FriezePattern(PathTableau): """ - An instance is a sequence in the ground field. + A frieze pattern. + + We encode a frieze pattern as a sequence in a fixed ground field. EXAMPLES:: sage: t = path_tableaux.FriezePattern([1,2,1,2,3,1]) sage: path_tableaux.CylindricalDiagram(t) - [0, 1, 2, 1, 2, 3, 1, 0] - ['', 0, 1, 1, 3, 5, 2, 1, 0] - ['', '', 0, 1, 4, 7, 3, 2, 1, 0] - ['', '', '', 0, 1, 2, 1, 1, 1, 1, 0] - ['', '', '', '', 0, 1, 1, 2, 3, 4, 1, 0] - ['', '', '', '', '', 0, 1, 3, 5, 7, 2, 1, 0] - ['', '', '', '', '', '', 0, 1, 2, 3, 1, 1, 1, 0] - ['', '', '', '', '', '', '', 0, 1, 2, 1, 2, 3, 1, 0] + [0, 1, 2, 1, 2, 3, 1, 0] + [ , 0, 1, 1, 3, 5, 2, 1, 0] + [ , , 0, 1, 4, 7, 3, 2, 1, 0] + [ , , , 0, 1, 2, 1, 1, 1, 1, 0] + [ , , , , 0, 1, 1, 2, 3, 4, 1, 0] + [ , , , , , 0, 1, 3, 5, 7, 2, 1, 0] + [ , , , , , , 0, 1, 2, 3, 1, 1, 1, 0] + [ , , , , , , , 0, 1, 2, 1, 2, 3, 1, 0] sage: TestSuite(t).run() sage: t = path_tableaux.FriezePattern([1,2,7,5,3,7,4,1]) sage: path_tableaux.CylindricalDiagram(t) - [0, 1, 2, 7, 5, 3, 7, 4, 1, 0] - ['', 0, 1, 4, 3, 2, 5, 3, 1, 1, 0] - ['', '', 0, 1, 1, 1, 3, 2, 1, 2, 1, 0] - ['', '', '', 0, 1, 2, 7, 5, 3, 7, 4, 1, 0] - ['', '', '', '', 0, 1, 4, 3, 2, 5, 3, 1, 1, 0] - ['', '', '', '', '', 0, 1, 1, 1, 3, 2, 1, 2, 1, 0] - ['', '', '', '', '', '', 0, 1, 2, 7, 5, 3, 7, 4, 1, 0] - ['', '', '', '', '', '', '', 0, 1, 4, 3, 2, 5, 3, 1, 1, 0] - ['', '', '', '', '', '', '', '', 0, 1, 1, 1, 3, 2, 1, 2, 1, 0] - ['', '', '', '', '', '', '', '', '', 0, 1, 2, 7, 5, 3, 7, 4, 1, 0] + [0, 1, 2, 7, 5, 3, 7, 4, 1, 0] + [ , 0, 1, 4, 3, 2, 5, 3, 1, 1, 0] + [ , , 0, 1, 1, 1, 3, 2, 1, 2, 1, 0] + [ , , , 0, 1, 2, 7, 5, 3, 7, 4, 1, 0] + [ , , , , 0, 1, 4, 3, 2, 5, 3, 1, 1, 0] + [ , , , , , 0, 1, 1, 1, 3, 2, 1, 2, 1, 0] + [ , , , , , , 0, 1, 2, 7, 5, 3, 7, 4, 1, 0] + [ , , , , , , , 0, 1, 4, 3, 2, 5, 3, 1, 1, 0] + [ , , , , , , , , 0, 1, 1, 1, 3, 2, 1, 2, 1, 0] + [ , , , , , , , , , 0, 1, 2, 7, 5, 3, 7, 4, 1, 0] sage: TestSuite(t).run() sage: t = path_tableaux.FriezePattern([1,3,4,5,1]) sage: path_tableaux.CylindricalDiagram(t) - [0, 1, 3, 4, 5, 1, 0] - ['', 0, 1, 5/3, 7/3, 2/3, 1, 0] - ['', '', 0, 1, 2, 1, 3, 1, 0] - ['', '', '', 0, 1, 1, 4, 5/3, 1, 0] - ['', '', '', '', 0, 1, 5, 7/3, 2, 1, 0] - ['', '', '', '', '', 0, 1, 2/3, 1, 1, 1, 0] - ['', '', '', '', '', '', 0, 1, 3, 4, 5, 1, 0] + [ 0, 1, 3, 4, 5, 1, 0] + [ , 0, 1, 5/3, 7/3, 2/3, 1, 0] + [ , , 0, 1, 2, 1, 3, 1, 0] + [ , , , 0, 1, 1, 4, 5/3, 1, 0] + [ , , , , 0, 1, 5, 7/3, 2, 1, 0] + [ , , , , , 0, 1, 2/3, 1, 1, 1, 0] + [ , , , , , , 0, 1, 3, 4, 5, 1, 0] sage: TestSuite(t).run() @@ -87,42 +84,42 @@ class FriezePattern(PathTableau): sage: K. = NumberField(x^2-3) sage: t = path_tableaux.FriezePattern([1,sqrt3,2,sqrt3,1,1], field=K) sage: path_tableaux.CylindricalDiagram(t) - [0, 1, sqrt3, 2, sqrt3, 1, 1, 0] - ['', 0, 1, sqrt3, 2, sqrt3, sqrt3 + 1, 1, 0] - ['', '', 0, 1, sqrt3, 2, sqrt3 + 2, sqrt3, 1, 0] - ['', '', '', 0, 1, sqrt3, sqrt3 + 2, 2, sqrt3, 1, 0] - ['', '', '', '', 0, 1, sqrt3 + 1, sqrt3, 2, sqrt3, 1, 0] - ['', '', '', '', '', 0, 1, 1, sqrt3, 2, sqrt3, 1, 0] - ['', '', '', '', '', '', 0, 1, sqrt3 + 1, sqrt3 + 2, sqrt3 + 2, sqrt3 + 1, 1, 0] - ['', '', '', '', '', '', '', 0, 1, sqrt3, 2, sqrt3, 1, 1, 0] + [ 0, 1, sqrt3, 2, sqrt3, 1, 1, 0] + [ , 0, 1, sqrt3, 2, sqrt3, sqrt3 + 1, 1, 0] + [ , , 0, 1, sqrt3, 2, sqrt3 + 2, sqrt3, 1, 0] + [ , , , 0, 1, sqrt3, sqrt3 + 2, 2, sqrt3, 1, 0] + [ , , , , 0, 1, sqrt3 + 1, sqrt3, 2, sqrt3, 1, 0] + [ , , , , , 0, 1, 1, sqrt3, 2, sqrt3, 1, 0] + [ , , , , , , 0, 1, sqrt3 + 1, sqrt3 + 2, sqrt3 + 2, sqrt3 + 1, 1, 0] + [ , , , , , , , 0, 1, sqrt3, 2, sqrt3, 1, 1, 0] sage: TestSuite(t).run() sage: K. = NumberField(x^2-2) sage: t = path_tableaux.FriezePattern([1,sqrt2,1,sqrt2,3,2*sqrt2,5,3*sqrt2,1], field=K) sage: path_tableaux.CylindricalDiagram(t) - [0, 1, sqrt2, 1, sqrt2, 3, 2*sqrt2, 5, 3*sqrt2, 1, 0] - ['', 0, 1, sqrt2, 3, 5*sqrt2, 7, 9*sqrt2, 11, 2*sqrt2, 1, 0] - ['', '', 0, 1, 2*sqrt2, 7, 5*sqrt2, 13, 8*sqrt2, 3, sqrt2, 1, 0] - ['', '', '', 0, 1, 2*sqrt2, 3, 4*sqrt2, 5, sqrt2, 1, sqrt2, 1, 0] - ['', '', '', '', 0, 1, sqrt2, 3, 2*sqrt2, 1, sqrt2, 3, 2*sqrt2, 1, 0] - ['', '', '', '', '', 0, 1, 2*sqrt2, 3, sqrt2, 3, 5*sqrt2, 7, 2*sqrt2, 1, 0] - ['', '', '', '', '', '', 0, 1, sqrt2, 1, 2*sqrt2, 7, 5*sqrt2, 3, sqrt2, 1, 0] - ['', '', '', '', '', '', '', 0, 1, sqrt2, 5, 9*sqrt2, 13, 4*sqrt2, 3, 2*sqrt2, 1, 0] - ['', '', '', '', '', '', '', '', 0, 1, 3*sqrt2, 11, 8*sqrt2, 5, 2*sqrt2, 3, sqrt2, 1, 0] - ['', '', '', '', '', '', '', '', '', 0, 1, 2*sqrt2, 3, sqrt2, 1, sqrt2, 1, sqrt2, 1, 0] - ['', '', '', '', '', '', '', '', '', '', 0, 1, sqrt2, 1, sqrt2, 3, 2*sqrt2, 5, 3*sqrt2, 1, 0] + [ 0, 1, sqrt2, 1, sqrt2, 3, 2*sqrt2, 5, 3*sqrt2, 1, 0] + [ , 0, 1, sqrt2, 3, 5*sqrt2, 7, 9*sqrt2, 11, 2*sqrt2, 1, 0] + [ , , 0, 1, 2*sqrt2, 7, 5*sqrt2, 13, 8*sqrt2, 3, sqrt2, 1, 0] + [ , , , 0, 1, 2*sqrt2, 3, 4*sqrt2, 5, sqrt2, 1, sqrt2, 1, 0] + [ , , , , 0, 1, sqrt2, 3, 2*sqrt2, 1, sqrt2, 3, 2*sqrt2, 1, 0] + [ , , , , , 0, 1, 2*sqrt2, 3, sqrt2, 3, 5*sqrt2, 7, 2*sqrt2, 1, 0] + [ , , , , , , 0, 1, sqrt2, 1, 2*sqrt2, 7, 5*sqrt2, 3, sqrt2, 1, 0] + [ , , , , , , , 0, 1, sqrt2, 5, 9*sqrt2, 13, 4*sqrt2, 3, 2*sqrt2, 1, 0] + [ , , , , , , , , 0, 1, 3*sqrt2, 11, 8*sqrt2, 5, 2*sqrt2, 3, sqrt2, 1, 0] + [ , , , , , , , , , 0, 1, 2*sqrt2, 3, sqrt2, 1, sqrt2, 1, sqrt2, 1, 0] + [ , , , , , , , , , , 0, 1, sqrt2, 1, sqrt2, 3, 2*sqrt2, 5, 3*sqrt2, 1, 0] sage: TestSuite(t).run() """ - @staticmethod def __classcall_private__(cls, fp, field=QQ): - """This is the preprocessing for creating friezes. + """ + This is the preprocessing for creating friezes. INPUT: - - a sequence of elements of the field ''field'' + - ``field`` -- a sequence of elements of the field EXAMPLES:: @@ -147,40 +144,36 @@ def __classcall_private__(cls, fp, field=QQ): ... ValueError: Integer Ring must be a field """ - if not field in Fields: + if field not in Fields: raise ValueError(f"{field} must be a field") - w = None - - if isinstance(fp, (list,tuple)): + if isinstance(fp, (list, tuple)): try: - w = [field(a) for a in fp] + fp = [field(a) for a in fp] except TypeError: raise ValueError(f"{fp} is not a sequence in the field {field}") - - if w is None: + else: raise ValueError(f"invalid input {fp}") - w.insert(0,field(0)) - w.append(field(0)) - return FriezePatterns(field)(tuple(w)) + fp.insert(0, field(0)) + fp.append(field(0)) + return FriezePatterns(field)(tuple(fp)) def check(self): """ - There is nothing to check. + Check that ``self`` is a valid frieze pattern. TESTS:: sage: path_tableaux.FriezePattern([1,2,1,2,3,1]) # indirect test [1, 2, 1, 2, 3, 1] - """ + # Nothing to check + pass def _repr_(self): """ - The representation of ``self``. - - This overides the iherited method. + Return the string representation of ``self``. This removes the leading and trailing zero. @@ -190,12 +183,13 @@ def _repr_(self): sage: repr(t) == t._repr_() # indirect test True """ - return (self[1:-1]).__repr__() + return repr(self[1:-1]) - - def local_rule(self,i): + def local_rule(self, i): r""" - This has input a list of objects. This method first takes + Return the `i`-th local rule on ``self``. + + This interprets ``self`` as a list of objects. This method first takes the list of objects of length three consisting of the `(i-1)`-st, `i`-th and `(i+1)`-term and applies the rule. It then replaces the `i`-th object by the object returned by the rule. @@ -212,14 +206,13 @@ def local_rule(self,i): ... ValueError: 0 is not a valid integer """ - def _rule(x): """ This is the rule on a sequence of three scalars. """ - return (x[0]*x[2]+1)/x[1] + return (x[0]*x[2]+1) / x[1] - if not (i > 0 and i < len(self)-1 ): + if not (i > 0 and i < len(self) - 1): raise ValueError(f"{i} is not a valid integer") with self.clone() as result: @@ -242,20 +235,19 @@ def is_skew(self): return self[1] != 1 def width(self): - """ + r""" Return the width of ``self``. - If the first and last terms of ``self`` are 1 then this is the length of ``self`` - plus two and otherwise is undefined. + If the first and last terms of ``self`` are 1 then this is the + length of ``self`` plus two and otherwise is undefined. EXAMPLES:: sage: path_tableaux.FriezePattern([1,2,1,2,3,1]).width() 8 - sage: path_tableaux.FriezePattern([1,2,1,2,3,4]).width() - - + sage: path_tableaux.FriezePattern([1,2,1,2,3,4]).width() is None + True """ if self[1] == 1 and self[-2] == 1: return len(self) @@ -263,14 +255,16 @@ def width(self): return None def is_positive(self): - """ - Return 'true' if all elements of ``self`` are positive. + r""" + Return ``True`` if all elements of ``self`` are positive. This implies that all entries of ``CylindricalDiagram(self)`` are positive. - Warning: There are orders on all fields. These may not be ordered fields - as they may not be compatible with the field operations. This method is - intended to be used with ordered fields only. + .. WARNING:: + + There are orders on all fields. These may not be ordered fields + as they may not be compatible with the field operations. This + method is intended to be used with ordered fields only. EXAMPLES:: @@ -283,9 +277,8 @@ def is_positive(self): sage: K. = NumberField(x^2-3) sage: path_tableaux.FriezePattern([1,sqrt3,1],K).is_positive() True - """ - return all(a>0 for a in self[1:-1]) + return all(a > 0 for a in self[1:-1]) def is_integral(self): r""" @@ -298,15 +291,10 @@ def is_integral(self): sage: path_tableaux.FriezePattern([1,3,4,5,1]).is_integral() False - """ n = len(self) cd = CylindricalDiagram(self).diagram - for i, a in enumerate(cd): - if any(k not in ZZ for k in a[i+1:n+i-2]): - return False - - return True + return all(all(k in ZZ for k in a[i+1:n+i-2]) for i, a in enumerate(cd)) def triangulation(self): r""" @@ -345,7 +333,7 @@ def triangulation(self): vt = [(cos(2*theta*pi/(n)), sin(2*theta*pi/(n))) for theta in range(n+1)] for i, p in enumerate(vt): - G += text(str(i),[1.05*p[0],1.05*p[1]]) + G += text(str(i), [1.05*p[0],1.05*p[1]]) for i, r in enumerate(cd): for j, a in enumerate(r[:n]): @@ -355,8 +343,8 @@ def triangulation(self): G.axes(False) return G - def plot(self,model='UHP'): - """ + def plot(self, model='UHP'): + r""" Plot the frieze as an ideal hyperbolic polygon. This is only defined up to isometry of the hyperbolic plane. @@ -364,11 +352,11 @@ def plot(self,model='UHP'): We are identifying the boundary of the hyperbolic plane with the real projective line. - The option ''model'' must be one of + The option ``model`` must be one of - * UHP, for the upper half plane model - * PD, for the Poincare disk model - * KM, for the Klein model + * ``'UHP'``, for the upper half plane model + * ``'PD'``, for the Poincare disk model + * ``'KM'``, for the Klein model The hyperboloid model is not an option as this does not implement boundary points. @@ -379,31 +367,36 @@ def plot(self,model='UHP'): sage: t = path_tableaux.FriezePattern([1,2,7,5,3,7,4,1]) sage: t.plot() + Graphics object consisting of 18 graphics primitives sage: t.plot(model='UHP') + Graphics object consisting of 18 graphics primitives sage: t.plot(model='PD') Traceback (most recent call last): ... TypeError: '>' not supported between instances of 'NotANumber' and 'Pi' sage: t.plot(model='KM') + Graphics object consisting of 18 graphics primitives """ + from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane + from sage.plot.plot import Graphics models = { - 'UHP' : HyperbolicPlane().UHP(), - 'PD' : HyperbolicPlane().PD(), - 'KM' : HyperbolicPlane().KM(), + 'UHP': HyperbolicPlane().UHP(), + 'PD': HyperbolicPlane().PD(), + 'KM': HyperbolicPlane().KM(), } - M = models.get(model) - if M == None: + if model not in models: raise ValueError(f"{model} must be one of ``UHP``, ``PD``, ``KM``") + M = models[model] U = HyperbolicPlane().UHP() cd = CylindricalDiagram(self).diagram num = cd[0][:-1] den = cd[1][2:] - vt = [ M(U.get_point(x/(x+y))) for x,y in zip(num,den) ] - gd = [ M.get_geodesic(vt[i-1],vt[i]) for i in range(len(vt))] - sum([a.plot() for a in gd],Graphics()).plot() + vt = [M(U.get_point(x / (x+y))) for x,y in zip(num, den)] + gd = [M.get_geodesic(vt[i-1], vt[i]) for i in range(len(vt))] + return sum([a.plot() for a in gd], Graphics()).plot() def change_ring(self, R): r""" @@ -421,9 +414,8 @@ def change_ring(self, R): ... TypeError: no base extension defined """ - - if R.has_coerce_map_from(self.parent().field): - return FriezePattern(list(self), field = R) + if R.has_coerce_map_from(self.parent().base_ring()): + return FriezePattern(list(self), field=R) else: raise TypeError("no base extension defined") @@ -431,10 +423,16 @@ class FriezePatterns(PathTableaux): """ The parent class for path_tableaux.FriezePattern. - TESTS:: + EXAMPLES:: sage: P = path_tableaux.FriezePatterns(QQ) - sage: TestSuite(P).run() + sage: fp = P((1, 1, 1)) + sage: fp + [1] + sage: path_tableaux.CylindricalDiagram(fp) + [1, 1, 1] + [ , 1, 2, 1] + [ , , 1, 1, 1] """ def __init__(self, field): """ @@ -442,13 +440,10 @@ def __init__(self, field): TESTS:: - sage: path_tableaux.FriezePattern([1,1]).parent() # indirect test - - + sage: P = path_tableaux.FriezePatterns(QQ) + sage: TestSuite(P).run() """ - self.field = field - - Parent.__init__(self, category=Sets()) + Parent.__init__(self, base=field, category=Sets()) def _an_element_(self): """ @@ -459,6 +454,7 @@ def _an_element_(self): sage: path_tableaux.FriezePatterns(QQ)._an_element_() [1, 1, 1] """ - return FriezePattern([1,1,1]) + return FriezePattern((1,1,1)) Element = FriezePattern + diff --git a/src/sage/combinat/path_tableaux/path_tableau.py b/src/sage/combinat/path_tableaux/path_tableau.py index ae181968c95..6cb7e30fbcf 100644 --- a/src/sage/combinat/path_tableaux/path_tableau.py +++ b/src/sage/combinat/path_tableaux/path_tableau.py @@ -466,13 +466,13 @@ class CylindricalDiagram(SageObject): sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) sage: path_tableaux.CylindricalDiagram(t) - [0, 1, 2, 3, 2, 1, 0] - ['', 0, 1, 2, 1, 0, 1, 0] - ['', '', 0, 1, 0, 1, 2, 1, 0] - ['', '', '', 0, 1, 2, 3, 2, 1, 0] - ['', '', '', '', 0, 1, 2, 1, 0, 1, 0] - ['', '', '', '', '', 0, 1, 0, 1, 2, 1, 0] - ['', '', '', '', '', '', 0, 1, 2, 3, 2, 1, 0] + [0, 1, 2, 3, 2, 1, 0] + [ , 0, 1, 2, 1, 0, 1, 0] + [ , , 0, 1, 0, 1, 2, 1, 0] + [ , , , 0, 1, 2, 3, 2, 1, 0] + [ , , , , 0, 1, 2, 1, 0, 1, 0] + [ , , , , , 0, 1, 0, 1, 2, 1, 0] + [ , , , , , , 0, 1, 2, 3, 2, 1, 0] """ def __init__(self, T): """ @@ -521,16 +521,20 @@ def _repr_(self): sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) sage: path_tableaux.CylindricalDiagram(t) - [0, 1, 2, 3, 2, 1, 0] - ['', 0, 1, 2, 1, 0, 1, 0] - ['', '', 0, 1, 0, 1, 2, 1, 0] - ['', '', '', 0, 1, 2, 3, 2, 1, 0] - ['', '', '', '', 0, 1, 2, 1, 0, 1, 0] - ['', '', '', '', '', 0, 1, 0, 1, 2, 1, 0] - ['', '', '', '', '', '', 0, 1, 2, 3, 2, 1, 0] - """ - dg = self.diagram - return ' ' + str(dg[0]) + ''.join('\n ' + str(x) for x in dg[1:]) + [0, 1, 2, 3, 2, 1, 0] + [ , 0, 1, 2, 1, 0, 1, 0] + [ , , 0, 1, 0, 1, 2, 1, 0] + [ , , , 0, 1, 2, 3, 2, 1, 0] + [ , , , , 0, 1, 2, 1, 0, 1, 0] + [ , , , , , 0, 1, 0, 1, 2, 1, 0] + [ , , , , , , 0, 1, 2, 3, 2, 1, 0] + """ + data = [[str(x) for x in row] for row in self.diagram] + if not data[0]: + data[0] = [''] # Put sometime there + max_width = max(max(len(x) for x in row) for row in data if row) + return '\n'.join('[' + ', '.join(' '*(max_width-len(x)) + x for x in row) + + ']' for row in data) def __eq__(self, other): """ @@ -624,28 +628,32 @@ def _ascii_art_(self): sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) sage: ascii_art(path_tableaux.CylindricalDiagram(t)) - 0 1 2 3 2 1 0 - 0 1 2 1 0 1 0 - 0 1 0 1 2 1 0 - 0 1 2 3 2 1 0 - 0 1 2 1 0 1 0 + 0 1 2 3 2 1 0 + 0 1 2 1 0 1 0 0 1 0 1 2 1 0 - 0 1 2 3 2 1 0 + 0 1 2 3 2 1 0 + 0 1 2 1 0 1 0 + 0 1 0 1 2 1 0 + 0 1 2 3 2 1 0 sage: t = path_tableaux.FriezePattern([1,3,4,5,1]) sage: ascii_art(path_tableaux.CylindricalDiagram(t)) - 0 1 3 4 5 1 0 - 0 1 5/3 7/3 2/3 1 0 - 0 1 2 1 3 1 0 - 0 1 1 4 5/3 1 0 - 0 1 5 7/3 2 1 0 - 0 1 2/3 1 1 1 0 - 0 1 3 4 5 1 0 - """ - from sage.typeset.ascii_art import AsciiArt - D = [ map(str,x) for x in self.diagram ] - S = [ ' '.join(x) for x in D ] - return AsciiArt(S) + 0 1 3 4 5 1 0 + 0 1 5/3 7/3 2/3 1 0 + 0 1 2 1 3 1 0 + 0 1 1 4 5/3 1 0 + 0 1 5 7/3 2 1 0 + 0 1 2/3 1 1 1 0 + 0 1 3 4 5 1 0 + """ + from sage.typeset.ascii_art import ascii_art + from sage.misc.misc_c import prod + data = [[ascii_art(x) for x in row] for row in self.diagram] + if not data[0]: + data[0] = [ascii_art('')] # Put sometime there + max_width = max(max(len(x) for x in row) for row in data if row) + return prod((sum((ascii_art(' '*(max_width-len(x)+1)) + x for x in row), ascii_art('')) + for row in data), ascii_art('')) def _unicode_art_(self): r""" @@ -655,28 +663,32 @@ def _unicode_art_(self): sage: t = path_tableaux.DyckPath([0,1,2,3,2,1,0]) sage: unicode_art(path_tableaux.CylindricalDiagram(t)) - 0 1 2 3 2 1 0 - 0 1 2 1 0 1 0 - 0 1 0 1 2 1 0 - 0 1 2 3 2 1 0 - 0 1 2 1 0 1 0 + 0 1 2 3 2 1 0 + 0 1 2 1 0 1 0 0 1 0 1 2 1 0 - 0 1 2 3 2 1 0 + 0 1 2 3 2 1 0 + 0 1 2 1 0 1 0 + 0 1 0 1 2 1 0 + 0 1 2 3 2 1 0 sage: t = path_tableaux.FriezePattern([1,3,4,5,1]) sage: unicode_art(path_tableaux.CylindricalDiagram(t)) - 0 1 3 4 5 1 0 - 0 1 5/3 7/3 2/3 1 0 - 0 1 2 1 3 1 0 - 0 1 1 4 5/3 1 0 - 0 1 5 7/3 2 1 0 - 0 1 2/3 1 1 1 0 - 0 1 3 4 5 1 0 - """ - from sage.typeset.unicode_art import UnicodeArt - D = [ map(str,x) for x in self.diagram ] - S = [ ' '.join(x) for x in D ] - return UnicodeArt(S) + 0 1 3 4 5 1 0 + 0 1 5/3 7/3 2/3 1 0 + 0 1 2 1 3 1 0 + 0 1 1 4 5/3 1 0 + 0 1 5 7/3 2 1 0 + 0 1 2/3 1 1 1 0 + 0 1 3 4 5 1 0 + """ + from sage.typeset.unicode_art import unicode_art + from sage.misc.misc_c import prod + data = [[unicode_art(x) for x in row] for row in self.diagram] + if not data[0]: + data[0] = [unicode_art('')] # Put sometime there + max_width = max(max(len(x) for x in row) for row in data if row) + return prod((sum((unicode_art(' '*(max_width-len(x)+1)) + x for x in row), unicode_art('')) + for row in data), unicode_art('')) def pp(self): r""" @@ -696,12 +708,18 @@ def pp(self): sage: t = path_tableaux.FriezePattern([1,3,4,5,1]) sage: path_tableaux.CylindricalDiagram(t).pp() - 0 1 3 4 5 1 0 - 0 1 5/3 7/3 2/3 1 0 - 0 1 2 1 3 1 0 - 0 1 1 4 5/3 1 0 - 0 1 5 7/3 2 1 0 - 0 1 2/3 1 1 1 0 - 0 1 3 4 5 1 0 - """ - print('\n'.join(' '.join('{!s}'.format(a) for a in x) for x in self.diagram )) + 0 1 3 4 5 1 0 + 0 1 5/3 7/3 2/3 1 0 + 0 1 2 1 3 1 0 + 0 1 1 4 5/3 1 0 + 0 1 5 7/3 2 1 0 + 0 1 2/3 1 1 1 0 + 0 1 3 4 5 1 0 + """ + data = [[str(x) for x in row] for row in self.diagram] + if not data[0]: + data[0] = [''] # Put sometime there + max_width = max(max(len(x) for x in row) for row in data if row) + print('\n'.join(' '.join(' '*(max_width-len(x)) + x for x in row) + for row in data)) + From 364d7b3ae7bf0678161426219b598f12253dc93b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 16 Jun 2020 21:46:52 -0700 Subject: [PATCH 279/300] Move SearchForest code to sage/sets/recursively_enumerated_set.pyx --- src/sage/combinat/backtrack.py | 656 +------------------ src/sage/sets/recursively_enumerated_set.pyx | 633 +++++++++++++++++- 2 files changed, 643 insertions(+), 646 deletions(-) diff --git a/src/sage/combinat/backtrack.py b/src/sage/combinat/backtrack.py index 57295d715f7..9d8d2ca0ba0 100644 --- a/src/sage/combinat/backtrack.py +++ b/src/sage/combinat/backtrack.py @@ -36,11 +36,6 @@ .. todo:: - - For now the code of :class:`SearchForest` is still in - ``sage/combinat/backtrack.py``. It should be moved in - ``sage/sets/recursively_enumerated_set.pyx`` into a class named - :class:`RecursivelyEnumeratedSet_forest` in a later ticket. - - Deprecate ``TransitiveIdeal`` and ``TransitiveIdealGraded``. - Once the deprecation has been there for enough time: delete @@ -67,36 +62,18 @@ from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.monoids import Monoids from sage.structure.parent import Parent -from sage.misc.prandom import randint -from sage.misc.abstract_method import abstract_method from sage.categories.commutative_additive_semigroups import ( CommutativeAdditiveSemigroups) from sage.structure.unique_representation import UniqueRepresentation from sage.rings.integer_ring import ZZ -from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_generic - - -def _imap_and_filter_none(function, iterable): - r""" - Return an iterator over the elements ``function(x)``, where ``x`` - iterates through ``iterable``, such that ``function(x)`` is not - ``None``. - - EXAMPLES:: - - sage: from sage.combinat.backtrack import _imap_and_filter_none - sage: p = _imap_and_filter_none(lambda x: x if is_prime(x) else None, range(15)) - sage: [next(p), next(p), next(p), next(p), next(p), next(p)] - [2, 3, 5, 7, 11, 13] - sage: p = _imap_and_filter_none(lambda x: x+x, ['a','b','c','d','e']) - sage: [next(p), next(p), next(p), next(p), next(p)] - ['aa', 'bb', 'cc', 'dd', 'ee'] - """ - for x in iterable: - x = function(x) - if x is not None: - yield x +from sage.sets.recursively_enumerated_set import ( + RecursivelyEnumeratedSet_generic, RecursivelyEnumeratedSet_forest) +from sage.misc.lazy_import import lazy_import +lazy_import("sage.sets.recursively_enumerated_set", + ["RecursivelyEnumeratedSet_forest", "search_forest_iterator"], + ["SearchForest", "search_forest_iterator"], + deprecation=16351) class GenericBacktracker(object): r""" @@ -154,621 +131,12 @@ def __iter__(self): if state is not None: stack.append( self._rec(obj, state) ) -def search_forest_iterator(roots, children, algorithm='depth'): - r""" - Return an iterator on the nodes of the forest having the given - roots, and where ``children(x)`` returns the children of the node ``x`` - of the forest. Note that every node of the tree is returned, - not simply the leaves. - - INPUT: - - - ``roots`` -- a list (or iterable) - - ``children`` -- a function returning a list (or iterable) - - ``algorithm`` -- ``'depth'`` or ``'breadth'`` (default: ``'depth'``) - - EXAMPLES: - - We construct the prefix tree of binary sequences of length at most - three, and enumerate its nodes:: - - sage: from sage.combinat.backtrack import search_forest_iterator - sage: list(search_forest_iterator([[]], lambda l: [l+[0], l+[1]] - ....: if len(l) < 3 else [])) - [[], [0], [0, 0], [0, 0, 0], [0, 0, 1], [0, 1], [0, 1, 0], - [0, 1, 1], [1], [1, 0], [1, 0, 0], [1, 0, 1], [1, 1], [1, 1, 0], [1, 1, 1]] - - By default, the nodes are iterated through by depth first search. - We can instead use a breadth first search (increasing depth):: - - sage: list(search_forest_iterator([[]], lambda l: [l+[0], l+[1]] - ....: if len(l) < 3 else [], - ....: algorithm='breadth')) - [[], - [0], [1], - [0, 0], [0, 1], [1, 0], [1, 1], - [0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], - [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]] - - This allows for iterating trough trees of infinite depth:: - - sage: it = search_forest_iterator([[]], lambda l: [l+[0], l+[1]], algorithm='breadth') - sage: [ next(it) for i in range(16) ] - [[], - [0], [1], [0, 0], [0, 1], [1, 0], [1, 1], - [0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], - [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1], - [0, 0, 0, 0]] - - Here is an iterator through the prefix tree of sequences of - letters in `0,1,2` without repetitions, sorted by length; the - leaves are therefore permutations:: - - sage: list(search_forest_iterator([[]], lambda l: [l + [i] for i in range(3) if i not in l], - ....: algorithm='breadth')) - [[], - [0], [1], [2], - [0, 1], [0, 2], [1, 0], [1, 2], [2, 0], [2, 1], - [0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]] - """ - # Little trick: the same implementation handles both depth and - # breadth first search. Setting position to -1 makes a depth search - # (you ask the children for the last node you met). Setting - # position on 0 makes a breadth search (enumerate all the - # descendants of a node before going on to the next father) - if algorithm == 'depth': - position = -1 - else: - position = 0 - - # Invariant: - # - for breadth first search: stack[i] contains an iterator over the nodes - # of depth ``i`` in the tree - # - for depth first search: stack[i] contains an iterator over the children - # of the node at depth ``i-1`` in the current branch (assuming a virtual - # father of all roots at depth ``-1``) - stack = [iter(roots)] - while stack: - try: - node = next(stack[position]) - except StopIteration: - # If there are no more, go back up the tree - # We also need to check if we've exhausted all - # possibilities - stack.pop(position) - continue - - yield node - stack.append( iter(children(node)) ) - -class SearchForest(Parent): - r""" - The enumerated set of the nodes of the forest having the given - ``roots``, and where ``children(x)`` returns the children of the - node ``x`` of the forest. - - See also :class:`GenericBacktracker`, :class:`TransitiveIdeal`, - and :class:`TransitiveIdealGraded`. - - INPUT: - - - ``roots`` -- a list (or iterable) - - ``children`` -- a function returning a list (or iterable, or iterator) - - ``post_process`` -- a function defined over the nodes of the - forest (default: no post processing) - - ``algorithm`` -- ``'depth'`` or ``'breadth'`` (default: ``'depth'``) - - ``category`` -- a category (default: :class:`EnumeratedSets`) - - The option ``post_process`` allows for customizing the nodes that - are actually produced. Furthermore, if ``f(x)`` returns ``None``, - then ``x`` won't be output at all. - - EXAMPLES: - - We construct the set of all binary sequences of length at most - three, and list them:: - - sage: from sage.combinat.backtrack import SearchForest - sage: S = SearchForest( [[]], - ....: lambda l: [l+[0], l+[1]] if len(l) < 3 else [], - ....: category=FiniteEnumeratedSets()) - sage: S.list() - [[], - [0], [0, 0], [0, 0, 0], [0, 0, 1], [0, 1], [0, 1, 0], [0, 1, 1], - [1], [1, 0], [1, 0, 0], [1, 0, 1], [1, 1], [1, 1, 0], [1, 1, 1]] - - ``SearchForest`` needs to be explicitly told that the set is - finite for the following to work:: - - sage: S.category() - Category of finite enumerated sets - sage: S.cardinality() - 15 - - We proceed with the set of all lists of letters in ``0,1,2`` - without repetitions, ordered by increasing length (i.e. using a - breadth first search through the tree):: - - sage: from sage.combinat.backtrack import SearchForest - sage: tb = SearchForest( [[]], - ....: lambda l: [l + [i] for i in range(3) if i not in l], - ....: algorithm = 'breadth', - ....: category=FiniteEnumeratedSets()) - sage: tb[0] - [] - sage: tb.cardinality() - 16 - sage: list(tb) - [[], - [0], [1], [2], - [0, 1], [0, 2], [1, 0], [1, 2], [2, 0], [2, 1], - [0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]] - - For infinite sets, this option should be set carefully to ensure - that all elements are actually generated. The following example - builds the set of all ordered pairs `(i,j)` of nonnegative - integers such that `j\leq 1`:: - - sage: from sage.combinat.backtrack import SearchForest - sage: I = SearchForest([(0,0)], - ....: lambda l: [(l[0]+1, l[1]), (l[0], 1)] - ....: if l[1] == 0 else [(l[0], l[1]+1)]) - - With a depth first search, only the elements of the form `(i,0)` - are generated:: - - sage: depth_search = I.depth_first_search_iterator() - sage: [next(depth_search) for i in range(7)] - [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0)] - - Using instead breadth first search gives the usual anti-diagonal - iterator:: - - sage: breadth_search = I.breadth_first_search_iterator() - sage: [next(breadth_search) for i in range(15)] - [(0, 0), - (1, 0), (0, 1), - (2, 0), (1, 1), (0, 2), - (3, 0), (2, 1), (1, 2), (0, 3), - (4, 0), (3, 1), (2, 2), (1, 3), (0, 4)] - - .. rubric:: Deriving subclasses - - The class of a parent `A` may derive from :class:`SearchForest` so - that `A` can benefit from enumeration tools. As a running example, - we consider the problem of enumerating integers whose binary - expansion have at most three nonzero digits. For example, `3 = - 2^1 + 2^0` has two nonzero digits. `15 = 2^3 + 2^2 + 2^1 + 2^0` - has four nonzero digits. In fact, `15` is the smallest integer - which is not in the enumerated set. - - To achieve this, we use ``SearchForest`` to enumerate binary tuples - with at most three nonzero digits, apply a post processing to - recover the corresponding integers, and discard tuples finishing - by zero. - - A first approach is to pass the ``roots`` and ``children`` - functions as arguments to :meth:`SearchForest.__init__`:: - - sage: from sage.combinat.backtrack import SearchForest - sage: class A(UniqueRepresentation, SearchForest): - ....: def __init__(self): - ....: SearchForest.__init__(self, [()], - ....: lambda x : [x+(0,), x+(1,)] if sum(x) < 3 else [], - ....: lambda x : sum(x[i]*2^i for i in range(len(x))) if sum(x) != 0 and x[-1] != 0 else None, - ....: algorithm = 'breadth', - ....: category=InfiniteEnumeratedSets()) - sage: MyForest = A(); MyForest - An enumerated set with a forest structure - sage: MyForest.category() - Category of infinite enumerated sets - sage: p = iter(MyForest) - sage: [next(p) for i in range(30)] - [1, 2, 3, 4, 6, 5, 7, 8, 12, 10, 14, 9, 13, 11, 16, 24, 20, 28, 18, 26, 22, 17, 25, 21, 19, 32, 48, 40, 56, 36] - - An alternative approach is to implement ``roots`` and ``children`` - as methods of the subclass (in fact they could also be attributes - of `A`). Namely, ``A.roots()`` must return an iterable containing - the enumeration generators, and ``A.children(x)`` must return an - iterable over the children of `x`. Optionally, `A` can have a - method or attribute such that ``A.post_process(x)`` returns the - desired output for the node ``x`` of the tree:: - - sage: from sage.combinat.backtrack import SearchForest - sage: class A(UniqueRepresentation, SearchForest): - ....: def __init__(self): - ....: SearchForest.__init__(self, algorithm = 'breadth', - ....: category=InfiniteEnumeratedSets()) - ....: - ....: def roots(self): - ....: return [()] - ....: - ....: def children(self, x): - ....: if sum(x) < 3: - ....: return [x+(0,), x+(1,)] - ....: else: - ....: return [] - ....: - ....: def post_process(self, x): - ....: if sum(x) == 0 or x[-1] == 0: - ....: return None - ....: else: - ....: return sum(x[i]*2^i for i in range(len(x))) - sage: MyForest = A(); MyForest - An enumerated set with a forest structure - sage: MyForest.category() - Category of infinite enumerated sets - sage: p = iter(MyForest) - sage: [next(p) for i in range(30)] - [1, 2, 3, 4, 6, 5, 7, 8, 12, 10, 14, 9, 13, 11, 16, 24, 20, 28, 18, 26, 22, 17, 25, 21, 19, 32, 48, 40, 56, 36] - - .. warning:: - - A :class:`SearchForest` instance is picklable if and only if - the input functions are themselves picklable. This excludes - anonymous or interactively defined functions:: - - sage: def children(x): - ....: return [x+1] - sage: S = SearchForest( [1], children, category=InfiniteEnumeratedSets()) - sage: dumps(S) - Traceback (most recent call last): - ... - PicklingError: Can't pickle <...function...>: attribute lookup ... failed - - Let us now fake ``children`` being defined in a Python module:: - - sage: import __main__ - sage: __main__.children = children - sage: S = SearchForest( [1], children, category=InfiniteEnumeratedSets()) - sage: loads(dumps(S)) - An enumerated set with a forest structure - """ - def __init__(self, roots = None, children = None, post_process = None, - algorithm = 'depth', facade = None, category=None): - r""" - TESTS:: - - sage: from sage.combinat.backtrack import SearchForest - sage: S = SearchForest(NN, lambda x : [], lambda x: x^2 if x.is_prime() else None) - sage: S.category() - Category of enumerated sets - """ - if roots is not None: - self._roots = roots - if children is not None: - self.children = children - if post_process is not None: - self.post_process = post_process - self._algorithm = algorithm - Parent.__init__(self, facade = facade, category = EnumeratedSets().or_subcategory(category)) - - __len__ = None - - def _repr_(self): - r""" - TESTS:: - - sage: from sage.combinat.backtrack import SearchForest - sage: SearchForest( [1], lambda x: [x+1]) - An enumerated set with a forest structure - """ - return "An enumerated set with a forest structure" - - def roots(self): - r""" - Return an iterable over the roots of ``self``. - - EXAMPLES:: - - sage: from sage.combinat.backtrack import SearchForest - sage: I = SearchForest([(0,0)], lambda l: [(l[0]+1, l[1]), (l[0], 1)] if l[1] == 0 else [(l[0], l[1]+1)]) - sage: [i for i in I.roots()] - [(0, 0)] - sage: I = SearchForest([(0,0),(1,1)], lambda l: [(l[0]+1, l[1]), (l[0], 1)] if l[1] == 0 else [(l[0], l[1]+1)]) - sage: [i for i in I.roots()] - [(0, 0), (1, 1)] - """ - return self._roots - - @abstract_method - def children(self, x): - r""" - Return the children of the element ``x`` - - The result can be a list, an iterable, an iterator, or even a - generator. - - EXAMPLES:: - - sage: from sage.combinat.backtrack import SearchForest - sage: I = SearchForest([(0,0)], lambda l: [(l[0]+1, l[1]), (l[0], 1)] if l[1] == 0 else [(l[0], l[1]+1)]) - sage: [i for i in I.children((0,0))] - [(1, 0), (0, 1)] - sage: [i for i in I.children((1,0))] - [(2, 0), (1, 1)] - sage: [i for i in I.children((1,1))] - [(1, 2)] - sage: [i for i in I.children((4,1))] - [(4, 2)] - sage: [i for i in I.children((4,0))] - [(5, 0), (4, 1)] - """ - - def __iter__(self): - r""" - Return an iterator over the elements of ``self``. - - EXAMPLES:: - - sage: from sage.combinat.backtrack import SearchForest - sage: def children(l): - ....: return [l+[0], l+[1]] - sage: C = SearchForest(([],), children) - sage: f = C.__iter__() - sage: next(f) - [] - sage: next(f) - [0] - sage: next(f) - [0, 0] - """ - iter = search_forest_iterator(self.roots(), - self.children, - algorithm = self._algorithm) - if hasattr(self, "post_process"): - iter = _imap_and_filter_none(self.post_process, iter) - return iter - - def depth_first_search_iterator(self): - r""" - Return a depth first search iterator over the elements of ``self`` - - EXAMPLES:: - - sage: from sage.combinat.backtrack import SearchForest - sage: f = SearchForest([[]], - ....: lambda l: [l+[0], l+[1]] if len(l) < 3 else []) - sage: list(f.depth_first_search_iterator()) - [[], [0], [0, 0], [0, 0, 0], [0, 0, 1], [0, 1], [0, 1, 0], [0, 1, 1], [1], [1, 0], [1, 0, 0], [1, 0, 1], [1, 1], [1, 1, 0], [1, 1, 1]] - """ - return iter(self) - - def breadth_first_search_iterator(self): - r""" - Return a breadth first search iterator over the elements of ``self`` - - EXAMPLES:: - - sage: from sage.combinat.backtrack import SearchForest - sage: f = SearchForest([[]], - ....: lambda l: [l+[0], l+[1]] if len(l) < 3 else []) - sage: list(f.breadth_first_search_iterator()) - [[], [0], [1], [0, 0], [0, 1], [1, 0], [1, 1], [0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]] - sage: S = SearchForest([(0,0)], - ....: lambda x : [(x[0], x[1]+1)] if x[1] != 0 else [(x[0]+1,0), (x[0],1)], - ....: post_process = lambda x: x if ((is_prime(x[0]) and is_prime(x[1])) and ((x[0] - x[1]) == 2)) else None) - sage: p = S.breadth_first_search_iterator() - sage: [next(p), next(p), next(p), next(p), next(p), next(p), next(p)] - [(5, 3), (7, 5), (13, 11), (19, 17), (31, 29), (43, 41), (61, 59)] - """ - iter = search_forest_iterator(self.roots(), self.children, algorithm='breadth') - if hasattr(self, "post_process"): - iter = _imap_and_filter_none(self.post_process, iter) - return iter - - def _elements_of_depth_iterator_rec(self, depth=0): - r""" - Return an iterator over the elements of ``self`` of given depth. - An element of depth `n` can be obtained applying `n` times the - children function from a root. This function is not affected - by post processing. - - EXAMPLES:: - - sage: from sage.combinat.backtrack import SearchForest - sage: I = SearchForest([(0,0)], lambda l: [(l[0]+1, l[1]), (l[0], 1)] if l[1] == 0 else [(l[0], l[1]+1)]) - sage: list(I._elements_of_depth_iterator_rec(8)) - [(8, 0), (7, 1), (6, 2), (5, 3), (4, 4), (3, 5), (2, 6), (1, 7), (0, 8)] - sage: I = SearchForest([[]], lambda l: [l+[0], l+[1]] if len(l) < 3 else []) - sage: list(I._elements_of_depth_iterator_rec(0)) - [[]] - sage: list(I._elements_of_depth_iterator_rec(1)) - [[0], [1]] - sage: list(I._elements_of_depth_iterator_rec(2)) - [[0, 0], [0, 1], [1, 0], [1, 1]] - sage: list(I._elements_of_depth_iterator_rec(3)) - [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]] - sage: list(I._elements_of_depth_iterator_rec(4)) - [] - """ - if depth == 0: - for node in self.roots(): - yield node - else: - for father in self._elements_of_depth_iterator_rec(depth - 1): - for node in self.children(father): - yield node - - def elements_of_depth_iterator(self, depth=0): - r""" - Return an iterator over the elements of ``self`` of given depth. - An element of depth `n` can be obtained applying `n` times the - children function from a root. - - EXAMPLES:: - - sage: from sage.combinat.backtrack import SearchForest - sage: S = SearchForest([(0,0)] , - ....: lambda x : [(x[0], x[1]+1)] if x[1] != 0 else [(x[0]+1,0), (x[0],1)], - ....: post_process = lambda x: x if ((is_prime(x[0]) and is_prime(x[1])) - ....: and ((x[0] - x[1]) == 2)) else None) - sage: p = S.elements_of_depth_iterator(8) - sage: next(p) - (5, 3) - sage: S = SearchForest(NN, lambda x : [], - ....: lambda x: x^2 if x.is_prime() else None) - sage: p = S.elements_of_depth_iterator(0) - sage: [next(p), next(p), next(p), next(p), next(p)] - [4, 9, 25, 49, 121] - """ - iter = self._elements_of_depth_iterator_rec(depth) - if hasattr(self, "post_process"): - iter = _imap_and_filter_none(self.post_process, iter) - return iter - - def __contains__(self, elt): - r""" - Return ``True`` if ``elt`` is in ``self``. - - .. warning:: - - This is achieved by iterating through the elements until - ``elt`` is found. In particular, this method will never - stop when ``elt`` is not in ``self`` and ``self`` is - infinite. - - EXAMPLES:: - - sage: from sage.combinat.backtrack import SearchForest - sage: S = SearchForest( [[]], lambda l: [l+[0], l+[1]] if len(l) < 3 else [], category=FiniteEnumeratedSets()) - sage: [4] in S - False - sage: [1] in S - True - sage: [1,1,1,1] in S - False - sage: all(S.__contains__(i) for i in iter(S)) - True - sage: S = SearchForest([1], lambda x: [x+1], category=InfiniteEnumeratedSets()) - sage: 1 in S - True - sage: 732 in S - True - sage: -1 in S # not tested : Will never stop - - The algorithm uses a random enumeration of the nodes of the - forest. This choice was motivated by examples in which both - depth first search and breadth first search failed. The - following example enumerates all ordered pairs of nonnegative - integers, starting from an infinite set of roots, where each - roots has an infinite number of children:: - - sage: from sage.combinat.backtrack import SearchForest - sage: S = SearchForest(Family(NN, lambda x : (x, 0)), - ....: lambda x : Family(PositiveIntegers(), lambda y : (x[0], y)) if x[1] == 0 else []) - sage: p = S.depth_first_search_iterator() - sage: [next(p), next(p), next(p), next(p), next(p), next(p), next(p)] - [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6)] - sage: p = S.breadth_first_search_iterator() - sage: [next(p), next(p), next(p), next(p), next(p), next(p), next(p)] - [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0)] - sage: (0,0) in S - True - sage: (1,1) in S - True - sage: (10,10) in S - True - sage: (42,18) in S - True - - We now consider the same set of all ordered pairs of - nonnegative integers but constructed in a different way. There - still are infinitely many roots, but each node has a single - child. From each root starts an infinite branch of breadth - `1`:: - - sage: S = SearchForest(Family(NN, lambda x : (x, 0)) , lambda x : [(x[0], x[1]+1)]) - sage: p = S.depth_first_search_iterator() - sage: [next(p), next(p), next(p), next(p), next(p), next(p), next(p)] - [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6)] - sage: p = S.breadth_first_search_iterator() - sage: [next(p), next(p), next(p), next(p), next(p), next(p), next(p)] - [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0)] - sage: (0,0) in S - True - sage: (1,1) in S - True - sage: (10,10) in S - True - sage: (37,11) in S - True - """ - stack = [iter(self.roots())] - while stack: - position = randint(0,len(stack)-1) - try: - node = next(stack[position]) - except StopIteration: - stack.pop(position) - continue - - if node == elt: - return True - stack.append( iter(self.children(node)) ) - return False - - def map_reduce(self, map_function = None, - reduce_function = None, - reduce_init = None): - r""" - Apply a Map/Reduce algorithm on ``self`` - - INPUT: - - - ``map_function`` -- a function from the element of ``self`` to some - set with a reduce operation (e.g.: a monoid). The default value is - the constant function ``1``. - - - ``reduce_function`` -- the reduce function (e.g.: the addition of a - monoid). The default value is ``+``. - - - ``reduce_init`` -- the initialisation of the reduction (e.g.: the - neutral element of the monoid). The default value is ``0``. - - .. note:: - - the effect of the default values is to compute the cardinality - of ``self``. - - EXAMPLES:: - - sage: seeds = [([i],i, i) for i in range(1,10)] - sage: def succ(t): - ....: list, sum, last = t - ....: return [(list + [i], sum + i, i) for i in range(1, last)] - sage: F = RecursivelyEnumeratedSet(seeds, succ, - ....: structure='forest', enumeration='depth') - - sage: y = var('y') - sage: def map_function(t): - ....: li, sum, _ = t - ....: return y ^ sum - sage: reduce_function = lambda x,y: x + y - sage: F.map_reduce(map_function, reduce_function, 0) - y^45 + y^44 + y^43 + 2*y^42 + 2*y^41 + 3*y^40 + 4*y^39 + 5*y^38 + 6*y^37 + 8*y^36 + 9*y^35 + 10*y^34 + 12*y^33 + 13*y^32 + 15*y^31 + 17*y^30 + 18*y^29 + 19*y^28 + 21*y^27 + 21*y^26 + 22*y^25 + 23*y^24 + 23*y^23 + 23*y^22 + 23*y^21 + 22*y^20 + 21*y^19 + 21*y^18 + 19*y^17 + 18*y^16 + 17*y^15 + 15*y^14 + 13*y^13 + 12*y^12 + 10*y^11 + 9*y^10 + 8*y^9 + 6*y^8 + 5*y^7 + 4*y^6 + 3*y^5 + 2*y^4 + 2*y^3 + y^2 + y - - Here is an example with the default values:: - - sage: F.map_reduce() - 511 - - .. SEEALSO:: :mod:`sage.parallel.map_reduce` - """ - import sage.parallel.map_reduce - return sage.parallel.map_reduce.RESetMapReduce( - forest = self, - map_function = map_function, - reduce_function = reduce_function, - reduce_init = reduce_init).run() - - -class PositiveIntegerSemigroup(UniqueRepresentation, SearchForest): +class PositiveIntegerSemigroup(UniqueRepresentation, RecursivelyEnumeratedSet_forest): r""" The commutative additive semigroup of positive integers. This class provides an example of algebraic structure which - inherits from :class:`SearchForest`. It builds the positive + inherits from :class:`RecursivelyEnumeratedSet_forest`. It builds the positive integers a la Peano, and endows it with its natural commutative additive semigroup structure. @@ -804,7 +172,7 @@ def __init__(self): sage: from sage.combinat.backtrack import PositiveIntegerSemigroup sage: PP = PositiveIntegerSemigroup() """ - SearchForest.__init__(self, facade = ZZ, category=(InfiniteEnumeratedSets(), CommutativeAdditiveSemigroups(), Monoids())) + RecursivelyEnumeratedSet_forest.__init__(self, facade = ZZ, category=(InfiniteEnumeratedSets(), CommutativeAdditiveSemigroups(), Monoids())) def roots(self): r""" @@ -869,7 +237,7 @@ class TransitiveIdeal(RecursivelyEnumeratedSet_generic): relation. The memory complexity is the depth, that is the maximal distance between a generator and an element of `S`. - See also :class:`SearchForest` and :class:`TransitiveIdealGraded`. + See also :class:`RecursivelyEnumeratedSet_forest` and :class:`TransitiveIdealGraded`. EXAMPLES:: @@ -990,7 +358,7 @@ class TransitiveIdealGraded(RecursivelyEnumeratedSet_generic): the relation. The memory complexity is the depth, that is the maximal distance between a generator and an element of `S`. - See also :class:`SearchForest` and :class:`TransitiveIdeal`. + See also :class:`RecursivelyEnumeratedSet_forest` and :class:`TransitiveIdeal`. EXAMPLES:: diff --git a/src/sage/sets/recursively_enumerated_set.pyx b/src/sage/sets/recursively_enumerated_set.pyx index bf13b02272f..dbb1db88dd3 100644 --- a/src/sage/sets/recursively_enumerated_set.pyx +++ b/src/sage/sets/recursively_enumerated_set.pyx @@ -176,7 +176,8 @@ Depth first search:: # **************************************************************************** from sage.structure.parent cimport Parent from sage.categories.enumerated_sets import EnumeratedSets -from sage.combinat.backtrack import SearchForest +from sage.misc.abstract_method import abstract_method +from sage.misc.prandom import randint from collections import deque @@ -1357,4 +1358,632 @@ cdef class RecursivelyEnumeratedSet_graded(RecursivelyEnumeratedSet_generic): return C -RecursivelyEnumeratedSet_forest = SearchForest +def _imap_and_filter_none(function, iterable): + r""" + Return an iterator over the elements ``function(x)``, where ``x`` + iterates through ``iterable``, such that ``function(x)`` is not + ``None``. + + EXAMPLES:: + + sage: from sage.sets.recursively_enumerated_set import _imap_and_filter_none + sage: p = _imap_and_filter_none(lambda x: x if is_prime(x) else None, range(15)) + sage: [next(p), next(p), next(p), next(p), next(p), next(p)] + [2, 3, 5, 7, 11, 13] + sage: p = _imap_and_filter_none(lambda x: x+x, ['a','b','c','d','e']) + sage: [next(p), next(p), next(p), next(p), next(p)] + ['aa', 'bb', 'cc', 'dd', 'ee'] + """ + for x in iterable: + x = function(x) + if x is not None: + yield x + +def search_forest_iterator(roots, children, algorithm='depth'): + r""" + Return an iterator on the nodes of the forest having the given + roots, and where ``children(x)`` returns the children of the node ``x`` + of the forest. Note that every node of the tree is returned, + not simply the leaves. + + INPUT: + + - ``roots`` -- a list (or iterable) + - ``children`` -- a function returning a list (or iterable) + - ``algorithm`` -- ``'depth'`` or ``'breadth'`` (default: ``'depth'``) + + EXAMPLES: + + We construct the prefix tree of binary sequences of length at most + three, and enumerate its nodes:: + + sage: from sage.sets.recursively_enumerated_set import search_forest_iterator + sage: list(search_forest_iterator([[]], lambda l: [l+[0], l+[1]] + ....: if len(l) < 3 else [])) + [[], [0], [0, 0], [0, 0, 0], [0, 0, 1], [0, 1], [0, 1, 0], + [0, 1, 1], [1], [1, 0], [1, 0, 0], [1, 0, 1], [1, 1], [1, 1, 0], [1, 1, 1]] + + By default, the nodes are iterated through by depth first search. + We can instead use a breadth first search (increasing depth):: + + sage: list(search_forest_iterator([[]], lambda l: [l+[0], l+[1]] + ....: if len(l) < 3 else [], + ....: algorithm='breadth')) + [[], + [0], [1], + [0, 0], [0, 1], [1, 0], [1, 1], + [0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], + [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]] + + This allows for iterating trough trees of infinite depth:: + + sage: it = search_forest_iterator([[]], lambda l: [l+[0], l+[1]], algorithm='breadth') + sage: [ next(it) for i in range(16) ] + [[], + [0], [1], [0, 0], [0, 1], [1, 0], [1, 1], + [0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], + [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1], + [0, 0, 0, 0]] + + Here is an iterator through the prefix tree of sequences of + letters in `0,1,2` without repetitions, sorted by length; the + leaves are therefore permutations:: + + sage: list(search_forest_iterator([[]], lambda l: [l + [i] for i in range(3) if i not in l], + ....: algorithm='breadth')) + [[], + [0], [1], [2], + [0, 1], [0, 2], [1, 0], [1, 2], [2, 0], [2, 1], + [0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]] + """ + # Little trick: the same implementation handles both depth and + # breadth first search. Setting position to -1 makes a depth search + # (you ask the children for the last node you met). Setting + # position on 0 makes a breadth search (enumerate all the + # descendants of a node before going on to the next father) + if algorithm == 'depth': + position = -1 + else: + position = 0 + + # Invariant: + # - for breadth first search: stack[i] contains an iterator over the nodes + # of depth ``i`` in the tree + # - for depth first search: stack[i] contains an iterator over the children + # of the node at depth ``i-1`` in the current branch (assuming a virtual + # father of all roots at depth ``-1``) + stack = [iter(roots)] + while stack: + try: + node = next(stack[position]) + except StopIteration: + # If there are no more, go back up the tree + # We also need to check if we've exhausted all + # possibilities + stack.pop(position) + continue + + yield node + stack.append( iter(children(node)) ) + +class RecursivelyEnumeratedSet_forest(Parent): + r""" + The enumerated set of the nodes of the forest having the given + ``roots``, and where ``children(x)`` returns the children of the + node ``x`` of the forest. + + See also :class:`sage.combinat.backtrack.GenericBacktracker`, + :class:`sage.combinat.backtrack.TransitiveIdeal`, and + :class:`sage.combinat.backtrack.TransitiveIdealGraded`. + + INPUT: + + - ``roots`` -- a list (or iterable) + - ``children`` -- a function returning a list (or iterable, or iterator) + - ``post_process`` -- a function defined over the nodes of the + forest (default: no post processing) + - ``algorithm`` -- ``'depth'`` or ``'breadth'`` (default: ``'depth'``) + - ``category`` -- a category (default: :class:`EnumeratedSets`) + + The option ``post_process`` allows for customizing the nodes that + are actually produced. Furthermore, if ``f(x)`` returns ``None``, + then ``x`` won't be output at all. + + EXAMPLES: + + We construct the set of all binary sequences of length at most + three, and list them:: + + sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest + sage: S = RecursivelyEnumeratedSet_forest( [[]], + ....: lambda l: [l+[0], l+[1]] if len(l) < 3 else [], + ....: category=FiniteEnumeratedSets()) + sage: S.list() + [[], + [0], [0, 0], [0, 0, 0], [0, 0, 1], [0, 1], [0, 1, 0], [0, 1, 1], + [1], [1, 0], [1, 0, 0], [1, 0, 1], [1, 1], [1, 1, 0], [1, 1, 1]] + + ``RecursivelyEnumeratedSet_forest`` needs to be explicitly told that the set is + finite for the following to work:: + + sage: S.category() + Category of finite enumerated sets + sage: S.cardinality() + 15 + + We proceed with the set of all lists of letters in ``0,1,2`` + without repetitions, ordered by increasing length (i.e. using a + breadth first search through the tree):: + + sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest + sage: tb = RecursivelyEnumeratedSet_forest( [[]], + ....: lambda l: [l + [i] for i in range(3) if i not in l], + ....: algorithm = 'breadth', + ....: category=FiniteEnumeratedSets()) + sage: tb[0] + [] + sage: tb.cardinality() + 16 + sage: list(tb) + [[], + [0], [1], [2], + [0, 1], [0, 2], [1, 0], [1, 2], [2, 0], [2, 1], + [0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]] + + For infinite sets, this option should be set carefully to ensure + that all elements are actually generated. The following example + builds the set of all ordered pairs `(i,j)` of nonnegative + integers such that `j\leq 1`:: + + sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest + sage: I = RecursivelyEnumeratedSet_forest([(0,0)], + ....: lambda l: [(l[0]+1, l[1]), (l[0], 1)] + ....: if l[1] == 0 else [(l[0], l[1]+1)]) + + With a depth first search, only the elements of the form `(i,0)` + are generated:: + + sage: depth_search = I.depth_first_search_iterator() + sage: [next(depth_search) for i in range(7)] + [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0)] + + Using instead breadth first search gives the usual anti-diagonal + iterator:: + + sage: breadth_search = I.breadth_first_search_iterator() + sage: [next(breadth_search) for i in range(15)] + [(0, 0), + (1, 0), (0, 1), + (2, 0), (1, 1), (0, 2), + (3, 0), (2, 1), (1, 2), (0, 3), + (4, 0), (3, 1), (2, 2), (1, 3), (0, 4)] + + .. rubric:: Deriving subclasses + + The class of a parent `A` may derive from :class:`RecursivelyEnumeratedSet_forest` so + that `A` can benefit from enumeration tools. As a running example, + we consider the problem of enumerating integers whose binary + expansion have at most three nonzero digits. For example, `3 = + 2^1 + 2^0` has two nonzero digits. `15 = 2^3 + 2^2 + 2^1 + 2^0` + has four nonzero digits. In fact, `15` is the smallest integer + which is not in the enumerated set. + + To achieve this, we use ``RecursivelyEnumeratedSet_forest`` to enumerate binary tuples + with at most three nonzero digits, apply a post processing to + recover the corresponding integers, and discard tuples finishing + by zero. + + A first approach is to pass the ``roots`` and ``children`` + functions as arguments to :meth:`RecursivelyEnumeratedSet_forest.__init__`:: + + sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest + sage: class A(UniqueRepresentation, RecursivelyEnumeratedSet_forest): + ....: def __init__(self): + ....: RecursivelyEnumeratedSet_forest.__init__(self, [()], + ....: lambda x : [x+(0,), x+(1,)] if sum(x) < 3 else [], + ....: lambda x : sum(x[i]*2^i for i in range(len(x))) if sum(x) != 0 and x[-1] != 0 else None, + ....: algorithm = 'breadth', + ....: category=InfiniteEnumeratedSets()) + sage: MyForest = A(); MyForest + An enumerated set with a forest structure + sage: MyForest.category() + Category of infinite enumerated sets + sage: p = iter(MyForest) + sage: [next(p) for i in range(30)] + [1, 2, 3, 4, 6, 5, 7, 8, 12, 10, 14, 9, 13, 11, 16, 24, 20, 28, 18, 26, 22, 17, 25, 21, 19, 32, 48, 40, 56, 36] + + An alternative approach is to implement ``roots`` and ``children`` + as methods of the subclass (in fact they could also be attributes + of `A`). Namely, ``A.roots()`` must return an iterable containing + the enumeration generators, and ``A.children(x)`` must return an + iterable over the children of `x`. Optionally, `A` can have a + method or attribute such that ``A.post_process(x)`` returns the + desired output for the node ``x`` of the tree:: + + sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest + sage: class A(UniqueRepresentation, RecursivelyEnumeratedSet_forest): + ....: def __init__(self): + ....: RecursivelyEnumeratedSet_forest.__init__(self, algorithm = 'breadth', + ....: category=InfiniteEnumeratedSets()) + ....: + ....: def roots(self): + ....: return [()] + ....: + ....: def children(self, x): + ....: if sum(x) < 3: + ....: return [x+(0,), x+(1,)] + ....: else: + ....: return [] + ....: + ....: def post_process(self, x): + ....: if sum(x) == 0 or x[-1] == 0: + ....: return None + ....: else: + ....: return sum(x[i]*2^i for i in range(len(x))) + sage: MyForest = A(); MyForest + An enumerated set with a forest structure + sage: MyForest.category() + Category of infinite enumerated sets + sage: p = iter(MyForest) + sage: [next(p) for i in range(30)] + [1, 2, 3, 4, 6, 5, 7, 8, 12, 10, 14, 9, 13, 11, 16, 24, 20, 28, 18, 26, 22, 17, 25, 21, 19, 32, 48, 40, 56, 36] + + .. warning:: + + A :class:`RecursivelyEnumeratedSet_forest` instance is picklable if and only if + the input functions are themselves picklable. This excludes + anonymous or interactively defined functions:: + + sage: def children(x): + ....: return [x+1] + sage: S = RecursivelyEnumeratedSet_forest( [1], children, category=InfiniteEnumeratedSets()) + sage: dumps(S) + Traceback (most recent call last): + ... + PicklingError: Can't pickle <...function...>: attribute lookup ... failed + + Let us now fake ``children`` being defined in a Python module:: + + sage: import __main__ + sage: __main__.children = children + sage: S = RecursivelyEnumeratedSet_forest( [1], children, category=InfiniteEnumeratedSets()) + sage: loads(dumps(S)) + An enumerated set with a forest structure + """ + def __init__(self, roots = None, children = None, post_process = None, + algorithm = 'depth', facade = None, category=None): + r""" + TESTS:: + + sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest + sage: S = RecursivelyEnumeratedSet_forest(NN, lambda x : [], lambda x: x^2 if x.is_prime() else None) + sage: S.category() + Category of enumerated sets + """ + if roots is not None: + self._roots = roots + if children is not None: + self.children = children + if post_process is not None: + self.post_process = post_process + self._algorithm = algorithm + Parent.__init__(self, facade = facade, category = EnumeratedSets().or_subcategory(category)) + + __len__ = None + + def _repr_(self): + r""" + TESTS:: + + sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest + sage: RecursivelyEnumeratedSet_forest( [1], lambda x: [x+1]) + An enumerated set with a forest structure + """ + return "An enumerated set with a forest structure" + + def roots(self): + r""" + Return an iterable over the roots of ``self``. + + EXAMPLES:: + + sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest + sage: I = RecursivelyEnumeratedSet_forest([(0,0)], lambda l: [(l[0]+1, l[1]), (l[0], 1)] if l[1] == 0 else [(l[0], l[1]+1)]) + sage: [i for i in I.roots()] + [(0, 0)] + sage: I = RecursivelyEnumeratedSet_forest([(0,0),(1,1)], lambda l: [(l[0]+1, l[1]), (l[0], 1)] if l[1] == 0 else [(l[0], l[1]+1)]) + sage: [i for i in I.roots()] + [(0, 0), (1, 1)] + """ + return self._roots + + @abstract_method + def children(self, x): + r""" + Return the children of the element ``x`` + + The result can be a list, an iterable, an iterator, or even a + generator. + + EXAMPLES:: + + sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest + sage: I = RecursivelyEnumeratedSet_forest([(0,0)], lambda l: [(l[0]+1, l[1]), (l[0], 1)] if l[1] == 0 else [(l[0], l[1]+1)]) + sage: [i for i in I.children((0,0))] + [(1, 0), (0, 1)] + sage: [i for i in I.children((1,0))] + [(2, 0), (1, 1)] + sage: [i for i in I.children((1,1))] + [(1, 2)] + sage: [i for i in I.children((4,1))] + [(4, 2)] + sage: [i for i in I.children((4,0))] + [(5, 0), (4, 1)] + """ + + def __iter__(self): + r""" + Return an iterator over the elements of ``self``. + + EXAMPLES:: + + sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest + sage: def children(l): + ....: return [l+[0], l+[1]] + sage: C = RecursivelyEnumeratedSet_forest(([],), children) + sage: f = C.__iter__() + sage: next(f) + [] + sage: next(f) + [0] + sage: next(f) + [0, 0] + """ + iter = search_forest_iterator(self.roots(), + self.children, + algorithm = self._algorithm) + if hasattr(self, "post_process"): + iter = _imap_and_filter_none(self.post_process, iter) + return iter + + def depth_first_search_iterator(self): + r""" + Return a depth first search iterator over the elements of ``self`` + + EXAMPLES:: + + sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest + sage: f = RecursivelyEnumeratedSet_forest([[]], + ....: lambda l: [l+[0], l+[1]] if len(l) < 3 else []) + sage: list(f.depth_first_search_iterator()) + [[], [0], [0, 0], [0, 0, 0], [0, 0, 1], [0, 1], [0, 1, 0], [0, 1, 1], [1], [1, 0], [1, 0, 0], [1, 0, 1], [1, 1], [1, 1, 0], [1, 1, 1]] + """ + return iter(self) + + def breadth_first_search_iterator(self): + r""" + Return a breadth first search iterator over the elements of ``self`` + + EXAMPLES:: + + sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest + sage: f = RecursivelyEnumeratedSet_forest([[]], + ....: lambda l: [l+[0], l+[1]] if len(l) < 3 else []) + sage: list(f.breadth_first_search_iterator()) + [[], [0], [1], [0, 0], [0, 1], [1, 0], [1, 1], [0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]] + sage: S = RecursivelyEnumeratedSet_forest([(0,0)], + ....: lambda x : [(x[0], x[1]+1)] if x[1] != 0 else [(x[0]+1,0), (x[0],1)], + ....: post_process = lambda x: x if ((is_prime(x[0]) and is_prime(x[1])) and ((x[0] - x[1]) == 2)) else None) + sage: p = S.breadth_first_search_iterator() + sage: [next(p), next(p), next(p), next(p), next(p), next(p), next(p)] + [(5, 3), (7, 5), (13, 11), (19, 17), (31, 29), (43, 41), (61, 59)] + """ + iter = search_forest_iterator(self.roots(), self.children, algorithm='breadth') + if hasattr(self, "post_process"): + iter = _imap_and_filter_none(self.post_process, iter) + return iter + + def _elements_of_depth_iterator_rec(self, depth=0): + r""" + Return an iterator over the elements of ``self`` of given depth. + An element of depth `n` can be obtained applying `n` times the + children function from a root. This function is not affected + by post processing. + + EXAMPLES:: + + sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest + sage: I = RecursivelyEnumeratedSet_forest([(0,0)], lambda l: [(l[0]+1, l[1]), (l[0], 1)] if l[1] == 0 else [(l[0], l[1]+1)]) + sage: list(I._elements_of_depth_iterator_rec(8)) + [(8, 0), (7, 1), (6, 2), (5, 3), (4, 4), (3, 5), (2, 6), (1, 7), (0, 8)] + sage: I = RecursivelyEnumeratedSet_forest([[]], lambda l: [l+[0], l+[1]] if len(l) < 3 else []) + sage: list(I._elements_of_depth_iterator_rec(0)) + [[]] + sage: list(I._elements_of_depth_iterator_rec(1)) + [[0], [1]] + sage: list(I._elements_of_depth_iterator_rec(2)) + [[0, 0], [0, 1], [1, 0], [1, 1]] + sage: list(I._elements_of_depth_iterator_rec(3)) + [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]] + sage: list(I._elements_of_depth_iterator_rec(4)) + [] + """ + if depth == 0: + for node in self.roots(): + yield node + else: + for father in self._elements_of_depth_iterator_rec(depth - 1): + for node in self.children(father): + yield node + + def elements_of_depth_iterator(self, depth=0): + r""" + Return an iterator over the elements of ``self`` of given depth. + An element of depth `n` can be obtained applying `n` times the + children function from a root. + + EXAMPLES:: + + sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest + sage: S = RecursivelyEnumeratedSet_forest([(0,0)] , + ....: lambda x : [(x[0], x[1]+1)] if x[1] != 0 else [(x[0]+1,0), (x[0],1)], + ....: post_process = lambda x: x if ((is_prime(x[0]) and is_prime(x[1])) + ....: and ((x[0] - x[1]) == 2)) else None) + sage: p = S.elements_of_depth_iterator(8) + sage: next(p) + (5, 3) + sage: S = RecursivelyEnumeratedSet_forest(NN, lambda x : [], + ....: lambda x: x^2 if x.is_prime() else None) + sage: p = S.elements_of_depth_iterator(0) + sage: [next(p), next(p), next(p), next(p), next(p)] + [4, 9, 25, 49, 121] + """ + iter = self._elements_of_depth_iterator_rec(depth) + if hasattr(self, "post_process"): + iter = _imap_and_filter_none(self.post_process, iter) + return iter + + def __contains__(self, elt): + r""" + Return ``True`` if ``elt`` is in ``self``. + + .. warning:: + + This is achieved by iterating through the elements until + ``elt`` is found. In particular, this method will never + stop when ``elt`` is not in ``self`` and ``self`` is + infinite. + + EXAMPLES:: + + sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest + sage: S = RecursivelyEnumeratedSet_forest( [[]], lambda l: [l+[0], l+[1]] if len(l) < 3 else [], category=FiniteEnumeratedSets()) + sage: [4] in S + False + sage: [1] in S + True + sage: [1,1,1,1] in S + False + sage: all(S.__contains__(i) for i in iter(S)) + True + sage: S = RecursivelyEnumeratedSet_forest([1], lambda x: [x+1], category=InfiniteEnumeratedSets()) + sage: 1 in S + True + sage: 732 in S + True + sage: -1 in S # not tested : Will never stop + + The algorithm uses a random enumeration of the nodes of the + forest. This choice was motivated by examples in which both + depth first search and breadth first search failed. The + following example enumerates all ordered pairs of nonnegative + integers, starting from an infinite set of roots, where each + roots has an infinite number of children:: + + sage: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest + sage: S = RecursivelyEnumeratedSet_forest(Family(NN, lambda x : (x, 0)), + ....: lambda x : Family(PositiveIntegers(), lambda y : (x[0], y)) if x[1] == 0 else []) + sage: p = S.depth_first_search_iterator() + sage: [next(p), next(p), next(p), next(p), next(p), next(p), next(p)] + [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6)] + sage: p = S.breadth_first_search_iterator() + sage: [next(p), next(p), next(p), next(p), next(p), next(p), next(p)] + [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0)] + sage: (0,0) in S + True + sage: (1,1) in S + True + sage: (10,10) in S + True + sage: (42,18) in S + True + + We now consider the same set of all ordered pairs of + nonnegative integers but constructed in a different way. There + still are infinitely many roots, but each node has a single + child. From each root starts an infinite branch of breadth + `1`:: + + sage: S = RecursivelyEnumeratedSet_forest(Family(NN, lambda x : (x, 0)) , lambda x : [(x[0], x[1]+1)]) + sage: p = S.depth_first_search_iterator() + sage: [next(p), next(p), next(p), next(p), next(p), next(p), next(p)] + [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6)] + sage: p = S.breadth_first_search_iterator() + sage: [next(p), next(p), next(p), next(p), next(p), next(p), next(p)] + [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0)] + sage: (0,0) in S + True + sage: (1,1) in S + True + sage: (10,10) in S + True + sage: (37,11) in S + True + """ + stack = [iter(self.roots())] + while stack: + position = randint(0,len(stack)-1) + try: + node = next(stack[position]) + except StopIteration: + stack.pop(position) + continue + + if node == elt: + return True + stack.append( iter(self.children(node)) ) + return False + + def map_reduce(self, map_function = None, + reduce_function = None, + reduce_init = None): + r""" + Apply a Map/Reduce algorithm on ``self`` + + INPUT: + + - ``map_function`` -- a function from the element of ``self`` to some + set with a reduce operation (e.g.: a monoid). The default value is + the constant function ``1``. + + - ``reduce_function`` -- the reduce function (e.g.: the addition of a + monoid). The default value is ``+``. + + - ``reduce_init`` -- the initialisation of the reduction (e.g.: the + neutral element of the monoid). The default value is ``0``. + + .. note:: + + the effect of the default values is to compute the cardinality + of ``self``. + + EXAMPLES:: + + sage: seeds = [([i],i, i) for i in range(1,10)] + sage: def succ(t): + ....: list, sum, last = t + ....: return [(list + [i], sum + i, i) for i in range(1, last)] + sage: F = RecursivelyEnumeratedSet(seeds, succ, + ....: structure='forest', enumeration='depth') + + sage: y = var('y') + sage: def map_function(t): + ....: li, sum, _ = t + ....: return y ^ sum + sage: reduce_function = lambda x,y: x + y + sage: F.map_reduce(map_function, reduce_function, 0) + y^45 + y^44 + y^43 + 2*y^42 + 2*y^41 + 3*y^40 + 4*y^39 + 5*y^38 + 6*y^37 + 8*y^36 + 9*y^35 + 10*y^34 + 12*y^33 + 13*y^32 + 15*y^31 + 17*y^30 + 18*y^29 + 19*y^28 + 21*y^27 + 21*y^26 + 22*y^25 + 23*y^24 + 23*y^23 + 23*y^22 + 23*y^21 + 22*y^20 + 21*y^19 + 21*y^18 + 19*y^17 + 18*y^16 + 17*y^15 + 15*y^14 + 13*y^13 + 12*y^12 + 10*y^11 + 9*y^10 + 8*y^9 + 6*y^8 + 5*y^7 + 4*y^6 + 3*y^5 + 2*y^4 + 2*y^3 + y^2 + y + + Here is an example with the default values:: + + sage: F.map_reduce() + 511 + + .. SEEALSO:: :mod:`sage.parallel.map_reduce` + """ + import sage.parallel.map_reduce + return sage.parallel.map_reduce.RESetMapReduce( + forest = self, + map_function = map_function, + reduce_function = reduce_function, + reduce_init = reduce_init).run() From 68f7bd58898294b46b2f76ba881d8a1ecc4f4d96 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 16 Jun 2020 22:27:22 -0700 Subject: [PATCH 280/300] sage.combinat.integer_vectors_mod_permgroup: Update to use RecursivelyEnumeratedSet_forest --- .../combinat/integer_vectors_mod_permgroup.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sage/combinat/integer_vectors_mod_permgroup.py b/src/sage/combinat/integer_vectors_mod_permgroup.py index 684c7508564..707fd871cf9 100644 --- a/src/sage/combinat/integer_vectors_mod_permgroup.py +++ b/src/sage/combinat/integer_vectors_mod_permgroup.py @@ -18,7 +18,7 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.structure.list_clone import ClonableIntArray -from sage.combinat.backtrack import SearchForest +from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest from sage.combinat.enumeration_mod_permgroup import is_canonical, orbit, canonical_children, canonical_representative_of_orbit_of @@ -230,7 +230,7 @@ def __classcall__(cls, G, sum=None, max_part=None, sgs=None): assert (max_part == NN(max_part)) return IntegerVectorsModPermutationGroup_with_constraints(G, sum, max_part, sgs=sgs) -class IntegerVectorsModPermutationGroup_All(UniqueRepresentation, SearchForest): +class IntegerVectorsModPermutationGroup_All(UniqueRepresentation, RecursivelyEnumeratedSet_forest): r""" A class for integer vectors enumerated up to the action of a permutation group. @@ -277,7 +277,7 @@ def __init__(self, G, sgs=None): Category of infinite enumerated quotients of sets sage: TestSuite(I).run() """ - SearchForest.__init__(self, algorithm = 'breadth', category = InfiniteEnumeratedSets().Quotients()) + RecursivelyEnumeratedSet_forest.__init__(self, algorithm = 'breadth', category = InfiniteEnumeratedSets().Quotients()) self._permgroup = G self.n = G.degree() @@ -369,7 +369,7 @@ def roots(self): r""" Returns the root of generation of ``self``. This method is required to build the tree structure of ``self`` which - inherits from the class :class:`~sage.combinat.backtrack.SearchForest`. + inherits from the class :class:`~sage.sets.recursively_enumerated_set.RecursivelyEnumeratedSet_forest`. EXAMPLES:: @@ -383,7 +383,7 @@ def children(self, x): r""" Returns the list of children of the element ``x``. This method is required to build the tree structure of ``self`` which - inherits from the class :class:`~sage.combinat.backtrack.SearchForest`. + inherits from the class :class:`~sage.sets.recursively_enumerated_set.RecursivelyEnumeratedSet_forest`. EXAMPLES:: @@ -558,7 +558,7 @@ def check(self): assert self.parent().is_canonical(self) -class IntegerVectorsModPermutationGroup_with_constraints(UniqueRepresentation, SearchForest): +class IntegerVectorsModPermutationGroup_with_constraints(UniqueRepresentation, RecursivelyEnumeratedSet_forest): r""" This class models finite enumerated sets of integer vectors with constraint enumerated up to the action of a permutation group. @@ -599,7 +599,7 @@ def __init__(self, G, d, max_part, sgs=None): sage: I = IntegerVectorsModPermutationGroup(PermutationGroup([[(1,2,3,4)]]), 6, max_part=4) """ - SearchForest.__init__(self, algorithm = 'breadth', category = (FiniteEnumeratedSets(), FiniteEnumeratedSets().Quotients())) + RecursivelyEnumeratedSet_forest.__init__(self, algorithm = 'breadth', category = (FiniteEnumeratedSets(), FiniteEnumeratedSets().Quotients())) self._permgroup = G self.n = G.degree() self._sum = d @@ -640,7 +640,7 @@ def roots(self): Returns the root of generation of ``self``.This method is required to build the tree structure of ``self`` which inherits from the class - :class:`~sage.combinat.backtrack.SearchForest`. + :class:`~sage.sets.recursively_enumerated_set.RecursivelyEnumeratedSet_forest`. EXAMPLES:: @@ -655,7 +655,7 @@ def children(self, x): Returns the list of children of the element ``x``. This method is required to build the tree structure of ``self`` which inherits from the class - :class:`~sage.combinat.backtrack.SearchForest`. + :class:`~sage.sets.recursively_enumerated_set.RecursivelyEnumeratedSet_forest`. EXAMPLES:: @@ -752,7 +752,7 @@ def __iter__(self): if self._max_part < 0: return self.elements_of_depth_iterator(self._sum) else: - SF = SearchForest((self([0]*(self.n), check=False),), + SF = RecursivelyEnumeratedSet_forest((self([0]*(self.n), check=False),), lambda x : [self(y, check=False) for y in canonical_children(self._sgs, x, self._max_part)], algorithm = 'breadth') if self._sum is None: From 1764ca414390717102378411166d3fd6da457d85 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 16 Jun 2020 22:33:39 -0700 Subject: [PATCH 281/300] Update remaining uses of SearchForest to use RecursivelyEnumeratedSet_forest --- src/sage/categories/affine_weyl_groups.py | 8 ++++---- src/sage/categories/coxeter_groups.py | 12 ++++++------ src/sage/combinat/posets/posets.py | 2 +- src/sage/combinat/subsets_pairwise.py | 6 +++--- src/sage/parallel/map_reduce.py | 19 +++++++------------ 5 files changed, 21 insertions(+), 26 deletions(-) diff --git a/src/sage/categories/affine_weyl_groups.py b/src/sage/categories/affine_weyl_groups.py index 5a550c8fa12..37dc4a2c9dc 100644 --- a/src/sage/categories/affine_weyl_groups.py +++ b/src/sage/categories/affine_weyl_groups.py @@ -104,7 +104,7 @@ def affine_grassmannian_elements_of_given_length(self, k): :meth:`AffineWeylGroups.ElementMethods.is_affine_grassmannian` """ - from sage.combinat.backtrack import SearchForest + from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest def select_length(pair): u, length = pair @@ -119,9 +119,9 @@ def succ(pair): u1.is_affine_grassmannian()): yield (u1, length + 1) return - return SearchForest(((self.one(), 0),), succ, algorithm='breadth', - category=FiniteEnumeratedSets(), - post_process=select_length) + return RecursivelyEnumeratedSet_forest(((self.one(), 0),), succ, algorithm='breadth', + category=FiniteEnumeratedSets(), + post_process=select_length) class ElementMethods: def is_affine_grassmannian(self): diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index 5826337bf17..91875a4a0f6 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -455,7 +455,7 @@ def weak_order_ideal(self, predicate, side="right", category=None): .. rubric:: Background - The weak order is returned as a :class:`SearchForest`. + The weak order is returned as a :class:`RecursivelyEnumeratedSet_forest`. This is achieved by assigning to each element `u1` of the ideal a single ancestor `u=u1 s_i`, where `i` is the smallest descent of `u`. @@ -474,7 +474,7 @@ def weak_order_ideal(self, predicate, side="right", category=None): sage: [x.length() for x in W] [0, 1, 1, 2, 2, 3] """ - from sage.combinat.backtrack import SearchForest + from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest def succ(u): for i in u.descents(positive=True, side=side): @@ -484,7 +484,7 @@ def succ(u): return from sage.categories.finite_coxeter_groups import FiniteCoxeterGroups default_category = FiniteEnumeratedSets() if self in FiniteCoxeterGroups() else EnumeratedSets() - return SearchForest((self.one(),), succ, algorithm='breadth', + return RecursivelyEnumeratedSet_forest((self.one(),), succ, algorithm='breadth', category=default_category.or_subcategory(category)) @cached_method @@ -1844,7 +1844,7 @@ def binary_factorizations(self, predicate=ConstantFunction(True)): sage: w0.binary_factorizations().category() Category of finite enumerated sets """ - from sage.combinat.backtrack import SearchForest + from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest W = self.parent() if not predicate(W.one()): from sage.sets.finite_enumerated_set import FiniteEnumeratedSet @@ -1857,8 +1857,8 @@ def succ(u_v): u1 = u * s[i] if i == u1.first_descent() and predicate(u1): yield (u1, s[i] * v) - return SearchForest(((W.one(), self),), succ, - category=FiniteEnumeratedSets()) + return RecursivelyEnumeratedSet_forest(((W.one(), self),), succ, + category=FiniteEnumeratedSets()) @cached_in_parent_method def bruhat_lower_covers(self): diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 2795700652b..eea0283d69f 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -4178,7 +4178,7 @@ def antichains(self, element_constructor=type([])): Internally, this uses :class:`sage.combinat.subsets_pairwise.PairwiseCompatibleSubsets` - and :class:`SearchForest`. At this point, iterating + and :class:`RecursivelyEnumeratedSet_forest`. At this point, iterating through this set is about twice slower than using :meth:`antichains_iterator` (tested on ``posets.AntichainPoset(15)``). The algorithm is the same diff --git a/src/sage/combinat/subsets_pairwise.py b/src/sage/combinat/subsets_pairwise.py index 7c6adde7eec..b126c5cf223 100644 --- a/src/sage/combinat/subsets_pairwise.py +++ b/src/sage/combinat/subsets_pairwise.py @@ -10,11 +10,11 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.sets.set import Set_object_enumerated -from sage.combinat.backtrack import SearchForest +from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest from sage.combinat.subset import Subsets -class PairwiseCompatibleSubsets(SearchForest): +class PairwiseCompatibleSubsets(RecursivelyEnumeratedSet_forest): r""" The set of all subsets of ``ambient`` whose elements satisfy ``predicate`` pairwise @@ -105,7 +105,7 @@ def __init__(self, ambient, predicate, maximal = False, element_class = Set_obje # TODO: use self.element_class for consistency # At this point (2011/03) TestSuite fails if we do so self._element_class = element_class - SearchForest.__init__(self, algorithm = 'depth', category = FiniteEnumeratedSets()) + RecursivelyEnumeratedSet_forest.__init__(self, algorithm = 'depth', category = FiniteEnumeratedSets()) def __eq__(self, other): """ diff --git a/src/sage/parallel/map_reduce.py b/src/sage/parallel/map_reduce.py index 159a5811d11..715a53a5cf8 100644 --- a/src/sage/parallel/map_reduce.py +++ b/src/sage/parallel/map_reduce.py @@ -7,8 +7,7 @@ over which one would like to perform the following kind of operations: * Compute the cardinality of a (very large) set defined recursively - (through a call to :class:`RecursivelyEnumeratedSet - of forest type`) + (through a call to :class:`RecursivelyEnumeratedSet_forest`) * More generally, compute any kind of generating series over this set @@ -40,8 +39,7 @@ How is this different from usual MapReduce ? -------------------------------------------- -This implementation is specific to :class:`RecursivelyEnumeratedSet -of forest type`, and uses its +This implementation is specific to :class:`RecursivelyEnumeratedSet_forest`, and uses its properties to do its job. Not only mapping and reducing but also **generating the elements** of `S` is done on different processors. @@ -58,8 +56,7 @@ sage: os.environ["SAGE_NUM_THREADS"] = '8' # not tested Second, you need the information necessary to describe a -:class:`RecursivelyEnumeratedSet of forest -type` representing your set `S` (see +:class:`RecursivelyEnumeratedSet_forest` representing your set `S` (see :mod:`sage.sets.recursively_enumerated_set`). Then, you need to provide a "map" function as well as a "reduce" function. Here are some examples: @@ -85,7 +82,7 @@ 2^17 Note that the map and reduce functions here have the default values of the - :meth:`sage.combinat.backtrack.SearchForest.map_reduce` method + :meth:`sage.sets.recursively_enumerated_set.RecursivelyEnumeratedSet_forest.map_reduce` method so that the number of elements can be obtained more simply with:: sage: S.map_reduce() @@ -191,7 +188,7 @@ q^10 + 4*q^9 + 9*q^8 + 15*q^7 + 20*q^6 + 22*q^5 + 20*q^4 + 15*q^3 + 9*q^2 + 4*q + 1 * **Listing the objects.** One can also compute the list of objects in a - :class:`RecursivelyEnumeratedSet of forest type` + :class:`RecursivelyEnumeratedSet_forest>` using :class:`RESetMapReduce`. As an example, we compute the set of numbers between 1 and 63, generated by their binary expansion:: @@ -372,8 +369,7 @@ instance of :class:`RESetMapReduce`) by a bunch of **worker** objects (instances of :class:`RESetMapReduceWorker`). -Each running map reduce instance works on a :class:`RecursivelyEnumeratedSet of -forest type` called here `C` and is +Each running map reduce instance works on a :class:`RecursivelyEnumeratedSet_forest>` called here `C` and is coordinated by a :class:`RESetMapReduce` object called the **master**. The master is in charge of launching the work, gathering the results and cleaning up at the end of the computation. It doesn't perform any computation @@ -887,8 +883,7 @@ class RESetMapReduce(object): Description of the set: - - either ``forest=f`` -- where ``f`` is a :class:`RecursivelyEnumeratedSet - of forest type` + - either ``forest=f`` -- where ``f`` is a :class:`RecursivelyEnumeratedSet_forest>` - or a triple ``roots, children, post_process`` as follows From 1ac0a095626cd70a1b5fabb59474ba3f37f47b12 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 16 Jun 2020 22:44:45 -0700 Subject: [PATCH 282/300] sage.combinat.backtrack: Remove deprecated class SearchForest --- src/sage/combinat/backtrack.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/sage/combinat/backtrack.py b/src/sage/combinat/backtrack.py index 9d8d2ca0ba0..2b3b3ab126d 100644 --- a/src/sage/combinat/backtrack.py +++ b/src/sage/combinat/backtrack.py @@ -10,9 +10,6 @@ Deprecated classes (use :func:`RecursivelyEnumeratedSet` instead): -- :class:`SearchForest`: Depth and breadth first - search through a tree described by a ``children`` function. - - :class:`TransitiveIdeal`: Depth first search through a graph described by a ``neighbours`` relation. @@ -21,10 +18,6 @@ Deprecation details: -- ``SearchForest(seeds, succ)`` keeps the same behavior as before - :trac:`6637` and is now the same as ``RecursivelyEnumeratedSet(seeds, - succ, structure='forest', enumeration='depth')``. - - ``TransitiveIdeal(succ, seeds)`` keeps the same behavior as before :trac:`6637` and is now the same as ``RecursivelyEnumeratedSet(seeds, succ, structure=None, enumeration='naive')``. @@ -69,18 +62,12 @@ from sage.sets.recursively_enumerated_set import ( RecursivelyEnumeratedSet_generic, RecursivelyEnumeratedSet_forest) -from sage.misc.lazy_import import lazy_import -lazy_import("sage.sets.recursively_enumerated_set", - ["RecursivelyEnumeratedSet_forest", "search_forest_iterator"], - ["SearchForest", "search_forest_iterator"], - deprecation=16351) - class GenericBacktracker(object): r""" A generic backtrack tool for exploring a search space organized as a tree, with branch pruning, etc. - See also :class:`SearchForest` and :class:`TransitiveIdeal` for + See also :class:`RecursivelyEnumeratedSet_forest` and :class:`TransitiveIdeal` for handling simple special cases. """ def __init__(self, initial_data, initial_state): From 908acba415758383bbc6092008276b9081ab782d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 16 Jun 2020 23:03:40 -0700 Subject: [PATCH 283/300] sage.combinat.backtrack: Remove deprecated classes TransitiveIdeal and TransitiveIdealGraded --- src/sage/combinat/backtrack.py | 261 +------------------ src/sage/sets/recursively_enumerated_set.pyx | 4 +- 2 files changed, 5 insertions(+), 260 deletions(-) diff --git a/src/sage/combinat/backtrack.py b/src/sage/combinat/backtrack.py index 2b3b3ab126d..7bf2aef3c30 100644 --- a/src/sage/combinat/backtrack.py +++ b/src/sage/combinat/backtrack.py @@ -1,38 +1,14 @@ r""" Backtracking -This library contains generic tools for constructing large sets whose +This library contains a generic tool for constructing large sets whose elements can be enumerated by exploring a search space with a (lazy) tree or graph structure. - :class:`GenericBacktracker`: Depth first search through a tree described by a ``children`` function, with branch pruning, etc. -Deprecated classes (use :func:`RecursivelyEnumeratedSet` instead): - -- :class:`TransitiveIdeal`: Depth first search through a - graph described by a ``neighbours`` relation. - -- :class:`TransitiveIdealGraded`: Breadth first search - through a graph described by a ``neighbours`` relation. - -Deprecation details: - -- ``TransitiveIdeal(succ, seeds)`` keeps the same behavior as before - :trac:`6637` and is now the same as ``RecursivelyEnumeratedSet(seeds, - succ, structure=None, enumeration='naive')``. - -- ``TransitiveIdealGraded(succ, seeds, max_depth)`` keeps the same behavior - as before :trac:`6637` and is now the same as - ``RecursivelyEnumeratedSet(seeds, succ, structure=None, - enumeration='breadth', max_depth=max_depth)``. - -.. todo:: - - - Deprecate ``TransitiveIdeal`` and ``TransitiveIdealGraded``. - - - Once the deprecation has been there for enough time: delete - ``TransitiveIdeal`` and ``TransitiveIdealGraded``. +This module has mostly been superseded by ``RecursivelyEnumeratedSet``. """ #***************************************************************************** @@ -51,16 +27,13 @@ # # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.categories.enumerated_sets import EnumeratedSets from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.monoids import Monoids -from sage.structure.parent import Parent from sage.categories.commutative_additive_semigroups import ( CommutativeAdditiveSemigroups) from sage.structure.unique_representation import UniqueRepresentation from sage.rings.integer_ring import ZZ -from sage.sets.recursively_enumerated_set import ( - RecursivelyEnumeratedSet_generic, RecursivelyEnumeratedSet_forest) +from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest class GenericBacktracker(object): r""" @@ -201,231 +174,3 @@ def one(self): 1 """ return self.first() - -class TransitiveIdeal(RecursivelyEnumeratedSet_generic): - r""" - Generic tool for constructing ideals of a relation. - - INPUT: - - - ``relation`` -- a function (or callable) returning a list (or iterable) - - ``generators`` -- a list (or iterable) - - Returns the set `S` of elements that can be obtained by repeated - application of ``relation`` on the elements of ``generators``. - - Consider ``relation`` as modeling a directed graph (possibly with - loops, cycles, or circuits). Then `S` is the ideal generated by - ``generators`` under this relation. - - Enumerating the elements of `S` is achieved by depth first search - through the graph. The time complexity is `O(n+m)` where `n` is - the size of the ideal, and `m` the number of edges in the - relation. The memory complexity is the depth, that is the maximal - distance between a generator and an element of `S`. - - See also :class:`RecursivelyEnumeratedSet_forest` and :class:`TransitiveIdealGraded`. - - EXAMPLES:: - - sage: from sage.combinat.backtrack import TransitiveIdeal - sage: [i for i in TransitiveIdeal(lambda i: [i+1] if i<10 else [], [0])] - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - - sage: [i for i in TransitiveIdeal(lambda i: [mod(i+1,3)], [0])] - [0, 1, 2] - sage: [i for i in TransitiveIdeal(lambda i: [mod(i+2,3)], [0])] - [0, 2, 1] - sage: [i for i in TransitiveIdeal(lambda i: [mod(i+2,10)], [0])] - [0, 2, 4, 6, 8] - sage: sorted(i for i in TransitiveIdeal(lambda i: [mod(i+3,10),mod(i+5,10)], [0])) - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - sage: sorted(i for i in TransitiveIdeal(lambda i: [mod(i+4,10),mod(i+6,10)], [0])) - [0, 2, 4, 6, 8] - sage: [i for i in TransitiveIdeal(lambda i: [mod(i+3,9)], [0,1])] - [0, 1, 3, 4, 6, 7] - - sage: [p for p in TransitiveIdeal(lambda x:[x],[Permutation([3,1,2,4]), Permutation([2,1,3,4])])] - [[2, 1, 3, 4], [3, 1, 2, 4]] - - We now illustrate that the enumeration is done lazily, by depth first - search:: - - sage: C = TransitiveIdeal(lambda x: [x-1, x+1], (-10, 0, 10)) - sage: f = C.__iter__() - sage: [ next(f) for i in range(6) ] - [0, 1, 2, 3, 4, 5] - - We compute all the permutations of 3:: - - sage: sorted(p for p in TransitiveIdeal(attrcall("permutohedron_succ"), [Permutation([1,2,3])])) - [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]] - - We compute all the permutations which are larger than [3,1,2,4], - [2,1,3,4] in the right permutohedron:: - - sage: sorted(p for p in TransitiveIdeal(attrcall("permutohedron_succ"), - ....: [Permutation([3,1,2,4]), Permutation([2,1,3,4])])) - [[2, 1, 3, 4], [2, 1, 4, 3], [2, 3, 1, 4], [2, 3, 4, 1], - [2, 4, 1, 3], [2, 4, 3, 1], [3, 1, 2, 4], [3, 1, 4, 2], - [3, 2, 1, 4], [3, 2, 4, 1], [3, 4, 1, 2], [3, 4, 2, 1], - [4, 2, 1, 3], [4, 2, 3, 1], [4, 3, 1, 2], [4, 3, 2, 1]] - - Using TransitiveIdeal people have been using the ``__contains__`` - method provided from the ``__iter__`` method. We need to make sure that - this continues to work:: - - sage: T = TransitiveIdeal(lambda a:[a+7,a+5], [0]) - sage: 12 in T - True - - """ - def __init__(self, succ, generators): - r""" - TESTS:: - - sage: from sage.combinat.backtrack import TransitiveIdeal - sage: C = TransitiveIdeal(factor, (1, 2, 3)) - sage: C._succ - - sage: C._generators - (1, 2, 3) - sage: loads(dumps(C)) # should test for equality with C, but equality is not implemented - """ - RecursivelyEnumeratedSet_generic.__init__(self, seeds=generators, successors=succ, enumeration='naive') - self._generators = self._seeds - self._succ = self.successors - - def __iter__(self): - r""" - Return an iterator on the elements of ``self``. - - TESTS:: - - sage: from sage.combinat.backtrack import TransitiveIdeal - sage: C = TransitiveIdeal(lambda x: [1,2], ()) - sage: list(C) # indirect doctest - [] - - sage: C = TransitiveIdeal(lambda x: [1,2], (1,)) - sage: list(C) # indirect doctest - [1, 2] - - sage: C = TransitiveIdeal(lambda x: [], (1,2)) - sage: list(C) # indirect doctest - [1, 2] - - """ - return self.naive_search_iterator() - -class TransitiveIdealGraded(RecursivelyEnumeratedSet_generic): - r""" - Generic tool for constructing ideals of a relation. - - INPUT: - - - ``relation`` -- a function (or callable) returning a list (or iterable) - - - ``generators`` -- a list (or iterable) - - - ``max_depth`` -- (Default: infinity) Specifies the maximal depth to - which elements are computed - - Return the set `S` of elements that can be obtained by repeated - application of ``relation`` on the elements of ``generators``. - - Consider ``relation`` as modeling a directed graph (possibly with - loops, cycles, or circuits). Then `S` is the ideal generated by - ``generators`` under this relation. - - Enumerating the elements of `S` is achieved by breadth first search - through the graph; hence elements are enumerated by increasing - distance from the generators. The time complexity is `O(n+m)` - where `n` is the size of the ideal, and `m` the number of edges in - the relation. The memory complexity is the depth, that is the - maximal distance between a generator and an element of `S`. - - See also :class:`RecursivelyEnumeratedSet_forest` and :class:`TransitiveIdeal`. - - EXAMPLES:: - - sage: from sage.combinat.backtrack import TransitiveIdealGraded - sage: [i for i in TransitiveIdealGraded(lambda i: [i+1] if i<10 else [], [0])] - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - - We now illustrate that the enumeration is done lazily, by breadth first search:: - - sage: C = TransitiveIdealGraded(lambda x: [x-1, x+1], (-10, 0, 10)) - sage: f = C.__iter__() - - The elements at distance 0 from the generators:: - - sage: sorted([ next(f) for i in range(3) ]) - [-10, 0, 10] - - The elements at distance 1 from the generators:: - - sage: sorted([ next(f) for i in range(6) ]) - [-11, -9, -1, 1, 9, 11] - - The elements at distance 2 from the generators:: - - sage: sorted([ next(f) for i in range(6) ]) - [-12, -8, -2, 2, 8, 12] - - The enumeration order between elements at the same distance is not specified. - - We compute all the permutations which are larger than [3,1,2,4] or - [2,1,3,4] in the permutohedron:: - - sage: sorted(p for p in TransitiveIdealGraded(attrcall("permutohedron_succ"), - ....: [Permutation([3,1,2,4]), Permutation([2,1,3,4])])) - [[2, 1, 3, 4], [2, 1, 4, 3], [2, 3, 1, 4], [2, 3, 4, 1], - [2, 4, 1, 3], [2, 4, 3, 1], [3, 1, 2, 4], [3, 1, 4, 2], - [3, 2, 1, 4], [3, 2, 4, 1], [3, 4, 1, 2], [3, 4, 2, 1], - [4, 2, 1, 3], [4, 2, 3, 1], [4, 3, 1, 2], [4, 3, 2, 1]] - """ - def __init__(self, succ, generators, max_depth=float("inf")): - r""" - TESTS:: - - sage: from sage.combinat.backtrack import TransitiveIdealGraded - sage: C = TransitiveIdealGraded(factor, (1, 2, 3)) - sage: C._succ - - sage: C._generators - (1, 2, 3) - sage: loads(dumps(C)) # should test for equality with C, but equality is not implemented - """ - RecursivelyEnumeratedSet_generic.__init__(self, seeds=generators, successors=succ, enumeration='breadth', max_depth=max_depth) - self._generators = self._seeds - self._succ = self.successors - - def __iter__(self): - r""" - Return an iterator on the elements of ``self``. - - TESTS:: - - sage: from sage.combinat.backtrack import TransitiveIdealGraded - sage: C = TransitiveIdealGraded(lambda x: [1,2], ()) - sage: list(C) # indirect doctest - [] - - sage: C = TransitiveIdealGraded(lambda x: [1,2], (1,)) - sage: list(C) # indirect doctest - [1, 2] - - sage: C = TransitiveIdealGraded(lambda x: [], (1,2)) - sage: list(C) # indirect doctest - [1, 2] - - :: - - sage: fn = lambda i: [i+1] if i<10 else [] - sage: C = TransitiveIdealGraded(fn, [0], max_depth=1) - sage: list(C) - [0, 1] - """ - return self.breadth_first_search_iterator() - diff --git a/src/sage/sets/recursively_enumerated_set.pyx b/src/sage/sets/recursively_enumerated_set.pyx index dbb1db88dd3..956ab126607 100644 --- a/src/sage/sets/recursively_enumerated_set.pyx +++ b/src/sage/sets/recursively_enumerated_set.pyx @@ -1473,8 +1473,8 @@ class RecursivelyEnumeratedSet_forest(Parent): node ``x`` of the forest. See also :class:`sage.combinat.backtrack.GenericBacktracker`, - :class:`sage.combinat.backtrack.TransitiveIdeal`, and - :class:`sage.combinat.backtrack.TransitiveIdealGraded`. + :class:`RecursivelyEnumeratedSet_graded`, and + :class:`RecursivelyEnumeratedSet_symmetric`. INPUT: From 1faa6aceeb6799ea31517c9b84b3e4164153e78d Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 17 Jun 2020 13:50:34 +0100 Subject: [PATCH 284/300] get rid of conversion to floats and round() --- src/sage/modules/diamond_cutting.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/sage/modules/diamond_cutting.py b/src/sage/modules/diamond_cutting.py index 4b649b33178..a64abfc0047 100644 --- a/src/sage/modules/diamond_cutting.py +++ b/src/sage/modules/diamond_cutting.py @@ -153,10 +153,6 @@ def diamond_cut(V, GM, C, verbose=False): sage: V.vertices() (A vertex at (2), A vertex at (0)) """ - # coerce to floats - from sage.misc.functional import round - GM = GM.n() - C = float(C) if verbose: print("Cut\n{}\nwith radius {}".format(GM, C)) @@ -224,7 +220,6 @@ def diamond_cut(V, GM, C, verbose=False): cut_count += 1 if verbose: print("\n%d) Cut using normal vector %s" % (cut_count, hv)) - hv = [QQ(round(elmt,6)) for elmt in hv] inequalities.append(plane_inequality(hv)) if verbose: From 685ac9bdb3b9451c97707add3118d63b1006f366 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 17 Jun 2020 19:38:25 +0100 Subject: [PATCH 285/300] adding test from trac #29866 --- src/sage/modules/free_module_integer.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sage/modules/free_module_integer.py b/src/sage/modules/free_module_integer.py index 0ab13d2a1ce..038bdb092bd 100644 --- a/src/sage/modules/free_module_integer.py +++ b/src/sage/modules/free_module_integer.py @@ -783,6 +783,17 @@ def closest_vector(self, t): ALGORITHM: Uses the algorithm from [MV2010]_. + + TESTS: + + Check that the example from :trac:`29866` works:: + + sage: from sage.modules.free_module_integer import IntegerLattice + sage: M = matrix(ZZ, [[20957228, -4966110], [9411844, 19625639]]) + sage: L = IntegerLattice(M) + sage: u = vector([-423434678248195, -18882583298608161305227077482]) + sage: L.closest_vector(u) in L + True """ voronoi_cell = self.voronoi_cell() From 99f0df74fa4b4b1c836b8b850ceeb516ef012d22 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Thu, 18 Jun 2020 08:49:56 +0100 Subject: [PATCH 286/300] remove unused import --- src/sage/modules/diamond_cutting.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/modules/diamond_cutting.py b/src/sage/modules/diamond_cutting.py index a64abfc0047..bb1f4e9f8c0 100644 --- a/src/sage/modules/diamond_cutting.py +++ b/src/sage/modules/diamond_cutting.py @@ -18,7 +18,6 @@ from sage.geometry.polyhedron.constructor import Polyhedron from sage.matrix.constructor import matrix, identity_matrix from sage.modules.free_module_element import vector -from sage.rings.rational_field import QQ from math import sqrt, floor, ceil From 57de3afb9854fbeb4c5cc7b4974502a72d098eea Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Thu, 18 Jun 2020 09:14:57 +0100 Subject: [PATCH 287/300] nauty update to 27r1 --- build/pkgs/nauty/checksums.ini | 9 +++++---- build/pkgs/nauty/package-version.txt | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/build/pkgs/nauty/checksums.ini b/build/pkgs/nauty/checksums.ini index c538968b6f7..644f4b75146 100644 --- a/build/pkgs/nauty/checksums.ini +++ b/build/pkgs/nauty/checksums.ini @@ -1,4 +1,5 @@ -tarball=nauty-VERSION.tar.gz -sha1=61d16a63e377fc61f2e00077bc0a537f7e5beb44 -md5=7a89ffd50fc7c690dc9eab321d7780f7 -cksum=1936541247 +tarball=nautyVERSION.tar.gz +sha1=c9fd2b4c99b8c624e430f3f4e1492a4219e3495e +md5=2ead635a417e20a18b3aabee83fac1ef +cksum=718823455 +upstream_url=http://pallini.di.uniroma1.it/nauty27r1.tar.gz diff --git a/build/pkgs/nauty/package-version.txt b/build/pkgs/nauty/package-version.txt index 04a3c70b7bb..d27393ab0ab 100644 --- a/build/pkgs/nauty/package-version.txt +++ b/build/pkgs/nauty/package-version.txt @@ -1 +1 @@ -26r1.p0 +27r1.p0 From 68856362d59b530bb7093573e9480811b2e80b6f Mon Sep 17 00:00:00 2001 From: Vincent Vanlaer Date: Thu, 18 Jun 2020 14:20:46 +0200 Subject: [PATCH 288/300] Provide raw latex to Jupyter for latex/pdf export --- src/sage/repl/rich_output/backend_ipython.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/repl/rich_output/backend_ipython.py b/src/sage/repl/rich_output/backend_ipython.py index a2c17e28413..38ae60ce70d 100644 --- a/src/sage/repl/rich_output/backend_ipython.py +++ b/src/sage/repl/rich_output/backend_ipython.py @@ -544,6 +544,7 @@ def displayhook(self, plain_text, rich_output): return ({u'text/plain': rich_output.unicode_art.get_unicode()}, {}) elif isinstance(rich_output, OutputLatex): return ({u'text/html': rich_output.mathjax(), + u'text/latex': rich_output.inline_equation(), u'text/plain': plain_text.text.get_unicode(), }, {}) elif isinstance(rich_output, OutputHtml): From a33de161588aaca79dc32470b130b5f128bc2b83 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 18 Jun 2020 12:39:52 -0700 Subject: [PATCH 289/300] build/pkgs/palp: Update to 2.11 --- build/pkgs/palp/checksums.ini | 9 +++++---- build/pkgs/palp/package-version.txt | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/build/pkgs/palp/checksums.ini b/build/pkgs/palp/checksums.ini index 28d9e0048e4..5de0d462b06 100644 --- a/build/pkgs/palp/checksums.ini +++ b/build/pkgs/palp/checksums.ini @@ -1,4 +1,5 @@ -tarball=palp-VERSION.tar.bz2 -sha1=2d13769d0d1639adbe23d00147506d15f490102c -md5=4c4ebdb4d56217c4db5c72f5427ab23a -cksum=3324978349 +tarball=palp-VERSION.tar.gz +sha1=99b0d8f7c998549f9f1be6302950659ff01bac77 +md5=b9508b9e08954215c88320d4a5940d91 +cksum=2027098672 +upstream_url=http://hep.itp.tuwien.ac.at/~kreuzer/CY/palp/palp-VERSION.tar.gz diff --git a/build/pkgs/palp/package-version.txt b/build/pkgs/palp/package-version.txt index 111d1f1c8d6..6a5fe6e8977 100644 --- a/build/pkgs/palp/package-version.txt +++ b/build/pkgs/palp/package-version.txt @@ -1 +1 @@ -2.1.p2 +2.11 From 5c7e5620e9f8d66f0d131a6bda9da3b923f8330d Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Fri, 19 Jun 2020 22:37:29 +0200 Subject: [PATCH 290/300] fix double description of hypercube --- src/sage/geometry/polyhedron/library.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index 7d2a1b8de20..b8a91815d28 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -3101,6 +3101,12 @@ def hypercube(self, dim, intervals=None, backend=None): sage: fc = polytopes.hypercube(4,backend='normaliz') # optional - pynormaliz sage: TestSuite(fc).run() # optional - pynormaliz + Check that :trac:`29904` is fixed:: + + sage: intervals = [[-2,2]] + sage: P = polytopes.hypercube(1, intervals, 'field') + sage: TestSuite(P).run() + If the dimension ``dim`` is not equal to the length of intervals, an error is raised:: @@ -3126,8 +3132,7 @@ def hypercube(self, dim, intervals=None, backend=None): Check that we set up the hypercube correctly:: - sage: ls = [randint(-100,100) for _ in range(4)] - sage: intervals = [[x, x+randint(1,50)] for x in ls] + sage: set_random_seed() sage: ls = [randint(-100,100) for _ in range(4)] sage: intervals = [[x, x+randint(1,50)] for x in ls] sage: P = polytopes.hypercube(4, intervals, backend='field') @@ -3184,7 +3189,7 @@ def hypercube(self, dim, intervals=None, backend=None): # An inequality -x_i + b_i >= 0 for i < dim # resp. x_{dim-i} - a_i >= 0 for i >= dim ieq_b = lambda i: intervals[i][1] if i < dim \ - else intervals[i-dim][0] + else -intervals[i-dim][0] else: raise ValueError("the dimension of the hypercube must match the number of intervals") From 3a462faebb336f77634aa9897ecdba866a5e6604 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 20 Jun 2020 09:12:25 +0200 Subject: [PATCH 291/300] trac #29740: review commit --- src/sage/graphs/line_graph.pyx | 55 ++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/src/sage/graphs/line_graph.pyx b/src/sage/graphs/line_graph.pyx index 1458189aad1..5dc94cfdc23 100644 --- a/src/sage/graphs/line_graph.pyx +++ b/src/sage/graphs/line_graph.pyx @@ -10,9 +10,9 @@ amounts to the following functions : :widths: 30, 70 :delim: | - :meth:`line_graph` | Computes the line graph of a given graph + :meth:`line_graph` | Return the line graph of a given graph :meth:`is_line_graph` | Check whether a graph is a line graph - :meth:`root_graph` | Computes the root graph corresponding to the given graph + :meth:`root_graph` | Return the root graph corresponding to the given graph Author: @@ -130,7 +130,7 @@ Functions def is_line_graph(g, certificate=False): r""" - Test whether the graph `g` is a line graph. + Check whether the graph `g` is a line graph. INPUT: @@ -225,14 +225,15 @@ def is_line_graph(g, certificate=False): if g.is_connected(): try: - # we test whether g is a line graph by trying to construct its root graph + # To check whether g is a line graph, we try to construct its root + # graph R, isom = root_graph(g) if certificate: return True, R, isom else: return True except ValueError as VE: - if str(VE) == "This graph is not a line graph !": + if str(VE) == "this graph is not a line graph !": # g is not a line graph if certificate: return False, get_certificate(g) @@ -240,7 +241,8 @@ def is_line_graph(g, certificate=False): return False raise VE - # g is not connected, so we apply the above procedure to each connected component + # g is not connected, so we apply the above procedure to each connected + # component from sage.graphs.graph import Graph R = Graph() for gg in g.connected_components_subgraphs(): @@ -248,7 +250,7 @@ def is_line_graph(g, certificate=False): RR, isom = root_graph(gg) R += RR except ValueError as VE: - if str(VE) == "This graph is not a line graph !": + if str(VE) == "this graph is not a line graph !": # gg is not a line graph if certificate: return False, get_certificate(gg) @@ -352,15 +354,15 @@ def line_graph(g, labels=True): cdef dict conflicts = {} cdef list elist = [] - self._scream_if_not_simple() - if self._directed: + g._scream_if_not_simple() + if g._directed: from sage.graphs.digraph import DiGraph G = DiGraph() - G.add_vertices(self.edge_iterator(labels=labels)) - for v in self: + G.add_vertices(g.edge_iterator(labels=labels)) + for v in g: # Connect appropriate incident edges of the vertex v - G.add_edges((e, f) for e in self.incoming_edge_iterator(v, labels=labels) - for f in self.outgoing_edge_iterator(v, labels=labels)) + G.add_edges((e, f) for e in g.incoming_edge_iterator(v, labels=labels) + for f in g.outgoing_edge_iterator(v, labels=labels)) return G else: from sage.graphs.all import Graph @@ -376,7 +378,7 @@ def line_graph(g, labels=True): # 1) List of vertices in the line graph - for e in self.edge_iterator(labels=labels): + for e in g.edge_iterator(labels=labels): if hash(e[0]) < hash(e[1]): elist.append(e) elif hash(e[0]) > hash(e[1]): @@ -390,11 +392,11 @@ def line_graph(g, labels=True): G.add_vertices(elist) # 2) adjacencies in the line graph - for v in self: + for v in g: elist = [] # Add the edge to the list, according to hashes, as previously - for e in self.edge_iterator(v, labels=labels): + for e in g.edge_iterator(v, labels=labels): if hash(e[0]) < hash(e[1]): elist.append(e) elif hash(e[0]) > hash(e[1]): @@ -413,7 +415,7 @@ def line_graph(g, labels=True): def root_graph(g, verbose=False): r""" - Compute the root graph corresponding to the given graph ``g`` + Return the root graph corresponding to the given graph ``g`` See the documentation of :mod:`sage.graphs.line_graph` to know how it works. @@ -426,8 +428,8 @@ def root_graph(g, verbose=False): .. WARNING:: - This code assumes that `g` is a line graph, and is a connected, undirected graph - without multiple edges. + This code assumes that `g` is a line graph, and is a connected, + undirected graph without multiple edges. TESTS: @@ -447,18 +449,19 @@ def root_graph(g, verbose=False): sage: root_graph(graphs.PetersenGraph()) Traceback (most recent call last): ... - ValueError: This graph is not a line graph ! + ValueError: this graph is not a line graph ! sage: root_graph(Graph('O{e[{}^~z`MDZBZBkXzE^')) Traceback (most recent call last): ... - ValueError: This graph is not a line graph ! + ValueError: this graph is not a line graph ! Small corner-cases:: sage: from sage.graphs.line_graph import root_graph sage: root_graph(graphs.CompleteGraph(3)) - (Complete bipartite graph of order 1+3: Graph on 4 vertices, {0: (0, 1), 1: (0, 2), 2: (0, 3)}) + (Complete bipartite graph of order 1+3: Graph on 4 vertices, + {0: (0, 1), 1: (0, 2), 2: (0, 3)}) sage: G, D = root_graph(graphs.OctahedralGraph()); G Complete graph: Graph on 4 vertices sage: G, D = root_graph(graphs.DiamondGraph()); G @@ -475,7 +478,7 @@ def root_graph(g, verbose=False): if not g.is_connected(): raise ValueError("g is not connected !") # is_line_graph expects a particular error message when g is not a line graph - not_line_graph = "This graph is not a line graph !" + not_line_graph = "this graph is not a line graph !" # Complete Graph ? if g.is_clique(): @@ -574,7 +577,7 @@ def root_graph(g, verbose=False): # If edge xy does not appear in any of the cliques associated with y if all(x not in C for C in v_cliques[y]): if len(v_cliques[y]) >= 2 or len(v_cliques[x]) >= 2: - raise ValueError("This graph is not a line graph !") + raise ValueError("this graph is not a line graph !") v_cliques[x].append((x, y)) v_cliques[y].append((x, y)) @@ -618,8 +621,8 @@ def root_graph(g, verbose=False): # We now build R R.add_edges(vertex_to_map.values()) - # If g is a line graph, then it is isomorphic to the line graph of the graph R that - # we have constructed, so we return R (and the isomorphism). + # If g is a line graph, then it is isomorphic to the line graph of the graph + # R that we have constructed, so we return R (and the isomorphism). is_isom, isom = g.is_isomorphic(R.line_graph(labels=False), certificate=True) if is_isom: return R, isom From f120e46e092ff0861735d4d5d8ab7b7d15f115d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 21 Jun 2020 08:29:49 +0200 Subject: [PATCH 292/300] remove very old deprecation warning from ticket 4492 --- src/sage/matrix/special.py | 108 ++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 63 deletions(-) diff --git a/src/sage/matrix/special.py b/src/sage/matrix/special.py index f27497a437c..f4a714096e0 100644 --- a/src/sage/matrix/special.py +++ b/src/sage/matrix/special.py @@ -818,14 +818,14 @@ def diagonal_matrix(arg0=None, arg1=None, arg2=None, sparse=True): except TypeError: raise TypeError('unable to determine number of entries for diagonal matrix construction') # sometimes catches a negative size - if not nrows is None and nentries > nrows: + if nrows is not None and nentries > nrows: raise ValueError('number of diagonal matrix entries (%s) exceeds the requested matrix size (%s)' % (nentries, nrows)) if nrows is None: nrows = nentries # provide a default ring for an empty list - if not len(entries) and ring is None: - ring = ZZ + if not entries and ring is None: + ring = ZZ # Convert entries to a list v over a common ring from sage.modules.free_module_element import prepare @@ -880,6 +880,7 @@ def identity_matrix(ring, n=0, sparse=False): ring = ZZ return matrix_space.MatrixSpace(ring, n, n, sparse)(1) + @matrix_method def lehmer(ring, n=0): r""" @@ -906,6 +907,7 @@ def lehmer(ring, n=0): ring = QQ return matrix_space.MatrixSpace(ring, n, n).matrix([[min(i, j)/max(i, j) for i in IntegerRange(1, n+1)] for j in IntegerRange(1, n+1)]) + @matrix_method def zero_matrix(ring, nrows=None, ncols=None, sparse=False): r""" @@ -949,6 +951,7 @@ def zero_matrix(ring, nrows=None, ncols=None, sparse=False): ring = ZZ return matrix_space.MatrixSpace(ring, nrows, ncols, sparse)(0) + @matrix_method def ones_matrix(ring, nrows=None, ncols=None, sparse=False): r""" @@ -1351,7 +1354,7 @@ def elementary_matrix(arg0, arg1=None, **kwds): """ import sage.structure.element # determine ring and matrix size - if not arg1 is None and not is_Ring(arg0): + if arg1 is not None and not is_Ring(arg0): raise TypeError('optional first parameter must be a ring, not {0}'.format(arg0)) scale = kwds.pop('scale', None) if is_Ring(arg0): @@ -1377,9 +1380,9 @@ def elementary_matrix(arg0, arg1=None, **kwds): col1 = kwds.pop('col1', None) if row1 is None and col1 is None: raise ValueError('row1 or col1 must be specified') - if not row1 is None and not col1 is None: + if row1 is not None and col1 is not None: raise ValueError('cannot specify both row1 and col1') - rowop = not row1 is None + rowop = row1 is not None if rowop: opstring = "row" row2 = kwds.pop('row2', None) @@ -1397,16 +1400,16 @@ def elementary_matrix(arg0, arg1=None, **kwds): row1 = Integer(row1) except TypeError: raise TypeError('{0} of elementary matrix must be an integer, not {1}'.format(opstring, row1)) - if row1 < 0 or row1 >= n : + if row1 < 0 or row1 >= n: raise ValueError('{0} of elementary matrix must be positive and smaller than {1}, not {2}'.format(opstring, n, row1)) - if not row2 is None: + if row2 is not None: try: row2 = Integer(row2) except TypeError: raise TypeError('{0} of elementary matrix must be an integer, not {1}'.format(opstring, row2)) - if row2 < 0 or row2 >= n : + if row2 < 0 or row2 >= n: raise ValueError('{0} of elementary matrix must be positive and smaller than {1}, not {2}'.format(opstring, n, row2)) - if not scale is None: + if scale is not None: try: scale = R(scale) except Exception: @@ -1417,16 +1420,16 @@ def elementary_matrix(arg0, arg1=None, **kwds): elem = identity_matrix(R, n, sparse=sparse) if row2 is None and scale is None: raise ValueError('insufficient parameters provided to construct elementary matrix') - elif not row2 is None and not scale is None: + elif row2 is not None and scale is not None: if row1 == row2: raise ValueError('cannot add a multiple of a {0} to itself'.format(opstring)) elem[row1, row2] = scale - elif not row2 is None and scale is None: + elif row2 is not None and scale is None: elem[row1, row1] = 0 elem[row2, row2] = 0 elem[row1, row2] = 1 elem[row2, row1] = 1 - elif row2 is None and not scale is None: + elif row2 is None and scale is not None: if scale == 0: raise ValueError('scale parameter of {0} of elementary matrix must be non-zero'.format(opstring)) elem[row1, row1] = scale @@ -1435,6 +1438,7 @@ def elementary_matrix(arg0, arg1=None, **kwds): else: return elem.transpose() + @matrix_method def circulant(v, sparse=None): r""" @@ -1563,6 +1567,7 @@ def _determine_block_matrix_grid(sub_matrices): return (row_heights, col_widths) + def _determine_block_matrix_rows(sub_matrices): """ For internal use. This tests if the matrices in sub_matrices @@ -1578,7 +1583,7 @@ def _determine_block_matrix_rows(sub_matrices): Non-zero scalars are considered to be square matrices of any size, and zeroes are considered to be zero matrices of any size. - A ValueError is raised if there is insufficient or + A ``ValueError`` is raised if there is insufficient or conflicting information. TESTS:: @@ -1593,9 +1598,8 @@ def _determine_block_matrix_rows(sub_matrices): ([2, 2], [0, 0], 4) """ total_width = None - - row_heights = [ None ] * len(sub_matrices) - zero_widths = [ 0 ] * len(sub_matrices) + row_heights = [None] * len(sub_matrices) + zero_widths = [0] * len(sub_matrices) # We first do a pass to see if we can determine the width unknowns = False @@ -1667,7 +1671,7 @@ def _determine_block_matrix_rows(sub_matrices): elif zero_state == 2: zero_state = 3 else: - scalars += 1 + scalars += 1 remaining_width = total_width - width # This remaining width has to be split over the @@ -1844,32 +1848,14 @@ def block_matrix(*args, **kwds): ... ValueError: insufficient information to determine submatrix widths - Historically, giving only a flat list of submatrices, whose number - was a perfect square, would create a new matrix by laying out the submatrices - in a square grid. This behavior is now deprecated. :: + Giving only a flat list of submatrices does not work:: sage: A = matrix(2, 3, range(6)) sage: B = matrix(3, 3, range(9)) sage: block_matrix([A, A, B, B]) - doctest:...: DeprecationWarning: invocation of block_matrix with just a list whose length is a perfect square is deprecated. See the documentation for details. - [0 1 2|0 1 2] - [3 4 5|3 4 5] - [-----+-----] - [0 1 2|0 1 2] - [3 4 5|3 4 5] - [6 7 8|6 7 8] - - Historically, a flat list of matrices whose number is not a perfect square, - with no specification of the number of rows or columns, would raise an error. - This behavior continues, but could be removed when the deprecation above is - completed. :: - - sage: A = matrix(2, 3, range(6)) - sage: B = matrix(3, 3, range(9)) - sage: block_matrix([A, A, A, B, B, B]) Traceback (most recent call last): ... - ValueError: must specify nrows or ncols for non-square block matrix. + ValueError: must specify either nrows or ncols TESTS:: @@ -1971,24 +1957,19 @@ def block_matrix(*args, **kwds): else: # A flat list # determine the block dimensions - n = ZZ(len(sub_matrices)) + n = len(sub_matrices) if nrows is None: if ncols is None: - if n.is_square(): - import warnings - warnings.warn("invocation of block_matrix with just a list whose length is a perfect square is deprecated. See the documentation for details.", DeprecationWarning, stacklevel=2) - nrows = ncols = n.sqrt() - else: - # this form (ie just a flat list) could be allowed once deprecated invocation (above) goes away - raise ValueError("must specify nrows or ncols for non-square block matrix.") + raise ValueError("must specify either nrows or ncols") else: - nrows = int(n/ncols) + nrows = n // ncols elif ncols is None: - ncols = int(n/nrows) + ncols = n // nrows if nrows * ncols != n: raise ValueError("given number of rows (%s), columns (%s) incompatible with number of submatrices (%s)" % (nrows, ncols, n)) # Now create a list of lists from this - sub_matrices = [ sub_matrices[i*ncols : (i+1)*ncols] for i in range(nrows) ] + sub_matrices = [sub_matrices[i * ncols: (i + 1) * ncols] + for i in range(nrows)] # At this point sub_matrices is a list of lists @@ -2021,7 +2002,6 @@ def block_matrix(*args, **kwds): if subdivide: raise ValueError(e) - if col_widths is None: # Try placing the matrices in rows instead # (Only if subdivide is False) @@ -2696,21 +2676,20 @@ def random_echelonizable_matrix(parent, rank, upper_bound=None, max_tries=100): matrix.add_multiple_of_row(0, randint(1,rows-1), randint(-3,3)) else: if rank == 1: # would be better just to have a special generator... - tries = 0 - while max(map(abs,matrix.list())) >= upper_bound: - matrix = random_rref_matrix(parent, rank) - tries += 1 - if tries > max_tries: # to prevent endless attempts - raise ValueError("tried "+str(max_tries)+" times to get a rank 1 random matrix. Try bigger upper_bound?") - matrix_copy = matrix - - rrr = range(len(matrix.pivots())-1,-1,-1) - for pivots in rrr: + tries = 0 + while max(abs(c) for c in matrix.list()) >= upper_bound: + matrix = random_rref_matrix(parent, rank) + tries += 1 + if tries > max_tries: # to prevent endless attempts + raise ValueError("tried "+str(max_tries)+" times to get a rank 1 random matrix. Try bigger upper_bound?") + matrix_copy = matrix + + for pivots in range(len(matrix.pivots()) - 1, -1, -1): # keep track of the pivot column positions from the pivot column with the largest index to # the one with the smallest. - row_index=0 + row_index = 0 tries = 0 - while row_index Date: Thu, 2 Jan 2020 21:32:10 +0100 Subject: [PATCH 293/300] some cleanup in rational.pyx (including removal of _cmp_) --- src/sage/rings/rational.pyx | 66 +++++++++++++++---------------------- 1 file changed, 26 insertions(+), 40 deletions(-) diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index 30b50ea4978..22d91b8c5c8 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -40,15 +40,15 @@ TESTS:: True """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2004, 2006 William Stein # Copyright (C) 2017 Vincent Delecroix <20100.delecroix@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** cimport cython from cpython cimport * @@ -56,7 +56,6 @@ from cpython.object cimport Py_EQ, Py_NE from cysignals.signals cimport sig_on, sig_off -import sys import operator import fractions @@ -886,19 +885,6 @@ cdef class Rational(sage.structure.element.FieldElement): return rich_to_bool_sgn(op, c) - cpdef int _cmp_(left, right) except -2: - r""" - TESTS:: - - sage: (2/3)._cmp_(3/4) - -1 - sage: (1/2)._cmp_(1/2) - 0 - """ - cdef int c - c = mpq_cmp((left).value, (right).value) - return (c > 0) - (c < 0) - def __copy__(self): """ Return a copy of ``self``. @@ -1191,7 +1177,7 @@ cdef class Rational(sage.structure.element.FieldElement): def local_height(self, p, prec=None): r""" - Returns the local height of this rational number at the prime `p`. + Return the local height of this rational number at the prime `p`. INPUT: @@ -1229,7 +1215,7 @@ cdef class Rational(sage.structure.element.FieldElement): def local_height_arch(self, prec=None): r""" - Returns the Archimedean local height of this rational number at the + Return the Archimedean local height of this rational number at the infinite place. INPUT: @@ -1265,7 +1251,7 @@ cdef class Rational(sage.structure.element.FieldElement): def global_height_non_arch(self, prec=None): r""" - Returns the total non-archimedean component of the height of this + Return the total non-archimedean component of the height of this rational number. INPUT: @@ -1308,7 +1294,7 @@ cdef class Rational(sage.structure.element.FieldElement): def global_height_arch(self, prec=None): r""" - Returns the total archimedean component of the height of this rational + Return the total archimedean component of the height of this rational number. INPUT: @@ -1341,7 +1327,7 @@ cdef class Rational(sage.structure.element.FieldElement): def global_height(self, prec=None): r""" - Returns the absolute logarithmic height of this rational number. + Return the absolute logarithmic height of this rational number. INPUT: @@ -1508,7 +1494,7 @@ cdef class Rational(sage.structure.element.FieldElement): def _bnfisnorm(self, K, proof=True, extra_primes=0): r""" - This gives the output of the PARI function :pari:`bnfisnorm`. + Return the output of the PARI function :pari:`bnfisnorm`. Tries to tell whether the rational number ``self`` is the norm of some element `y` in ``K``. Returns a pair `(a, b)` where @@ -1568,7 +1554,7 @@ cdef class Rational(sage.structure.element.FieldElement): def is_perfect_power(self, expected_value=False): r""" - Returns ``True`` if ``self`` is a perfect power. + Return ``True`` if ``self`` is a perfect power. INPUT: @@ -1772,7 +1758,7 @@ cdef class Rational(sage.structure.element.FieldElement): def val_unit(self, p): r""" - Returns a pair: the `p`-adic valuation of ``self``, and the `p`-adic + Return a pair: the `p`-adic valuation of ``self``, and the `p`-adic unit of ``self``, as a :class:`Rational`. We do not require the `p` be prime, but it must be at least 2. For @@ -1838,7 +1824,7 @@ cdef class Rational(sage.structure.element.FieldElement): def prime_to_S_part(self, S=[]): r""" - Returns ``self`` with all powers of all primes in ``S`` removed. + Return ``self`` with all powers of all primes in ``S`` removed. INPUT: @@ -2088,7 +2074,7 @@ cdef class Rational(sage.structure.element.FieldElement): def is_nth_power(self, int n): r""" - Returns ``True`` if self is an `n`-th power, else ``False``. + Return ``True`` if self is an `n`-th power, else ``False``. INPUT: @@ -2741,7 +2727,7 @@ cdef class Rational(sage.structure.element.FieldElement): def sign(self): """ - Returns the sign of this rational number, which is -1, 0, or 1 + Return the sign of this rational number, which is -1, 0, or 1 depending on whether this number is negative, zero, or positive respectively. @@ -2827,7 +2813,7 @@ cdef class Rational(sage.structure.element.FieldElement): def norm(self): r""" - Returns the norm from `\QQ` to `\QQ` of `x` (which is just `x`). This + Return the norm from `\QQ` to `\QQ` of `x` (which is just `x`). This was added for compatibility with :class:`NumberFields`. OUTPUT: @@ -2847,7 +2833,7 @@ cdef class Rational(sage.structure.element.FieldElement): def relative_norm(self): """ - Returns the norm from Q to Q of x (which is just x). This was added for compatibility with NumberFields + Return the norm from Q to Q of x (which is just x). This was added for compatibility with NumberFields EXAMPLES:: @@ -2861,7 +2847,7 @@ cdef class Rational(sage.structure.element.FieldElement): def absolute_norm(self): """ - Returns the norm from Q to Q of x (which is just x). This was added for compatibility with NumberFields + Return the norm from Q to Q of x (which is just x). This was added for compatibility with NumberFields EXAMPLES:: @@ -2875,7 +2861,7 @@ cdef class Rational(sage.structure.element.FieldElement): def trace(self): r""" - Returns the trace from `\QQ` to `\QQ` of `x` (which is just `x`). This + Return the trace from `\QQ` to `\QQ` of `x` (which is just `x`). This was added for compatibility with :class:`NumberFields`. OUTPUT: @@ -3041,7 +3027,7 @@ cdef class Rational(sage.structure.element.FieldElement): def denominator(self): """ - Returns the denominator of this rational number. + Return the denominator of this rational number. denom is an alias of denominator. EXAMPLES:: @@ -3364,7 +3350,7 @@ cdef class Rational(sage.structure.element.FieldElement): def round(Rational self, mode="away"): """ - Returns the nearest integer to ``self``, rounding away from 0 by + Return the nearest integer to ``self``, rounding away from 0 by default, for consistency with the builtin Python round. INPUT: @@ -3430,7 +3416,7 @@ cdef class Rational(sage.structure.element.FieldElement): def real(self): """ - Returns the real part of ``self``, which is ``self``. + Return the real part of ``self``, which is ``self``. EXAMPLES:: @@ -3441,7 +3427,7 @@ cdef class Rational(sage.structure.element.FieldElement): def imag(self): """ - Returns the imaginary part of ``self``, which is zero. + Return the imaginary part of ``self``, which is zero. EXAMPLES:: @@ -3485,7 +3471,7 @@ cdef class Rational(sage.structure.element.FieldElement): def _lcm(self, Rational other): """ - Returns the least common multiple, in the rational numbers, of ``self`` + Return the least common multiple, in the rational numbers, of ``self`` and ``other``. This function returns either 0 or 1 (as a rational number). @@ -3686,7 +3672,7 @@ cdef class Rational(sage.structure.element.FieldElement): sig_off() return x - def __lshift__(x,y): + def __lshift__(x, y): """ Left shift operator ``x << y``. @@ -3734,7 +3720,7 @@ cdef class Rational(sage.structure.element.FieldElement): sig_off() return x - def __rshift__(x,y): + def __rshift__(x, y): """ Right shift operator ``x >> y``. @@ -3787,7 +3773,7 @@ cdef class Rational(sage.structure.element.FieldElement): def __pari__(self): """ - Returns the PARI version of this rational number. + Return the PARI version of this rational number. EXAMPLES:: From ceb4c646dd2b01ce39d20450de49f9119dc9d402 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 21 Jun 2020 13:24:37 +0200 Subject: [PATCH 294/300] converting __richcmp__ to _richcmp_ --- src/sage/rings/rational.pyx | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index 22d91b8c5c8..4dff97b35f8 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -823,7 +823,7 @@ cdef class Rational(sage.structure.element.FieldElement): l = self.continued_fraction_list() return ContinuedFraction_periodic(l) - def __richcmp__(left, right, int op): + cpdef _richcmp_(left, right, int op): """ Compare two rational numbers. @@ -860,29 +860,13 @@ cdef class Rational(sage.structure.element.FieldElement): ....: assert (one1 >= one2) is True """ cdef int c - cdef mpz_t mpz_tmp - - assert isinstance(left, Rational) - - if isinstance(right, Rational): - if op == Py_EQ: - return mpq_equal((left).value, (right).value) - elif op == Py_NE: - return not mpq_equal((left).value, (right).value) - else: - c = mpq_cmp((left).value, (right).value) - elif isinstance(right, Integer): - c = mpq_cmp_z((left).value, (right).value) - elif isinstance(right, long): - mpz_init(mpz_tmp) - mpz_set_pylong(mpz_tmp, right) - c = mpq_cmp_z((left).value, mpz_tmp) - mpz_clear(mpz_tmp) - elif isinstance(right, int): - c = mpq_cmp_si((left).value, PyInt_AS_LONG(right), 1) - else: - return coercion_model.richcmp(left, right, op) - + if op == Py_EQ: + return mpq_equal((left).value, + (right).value) + elif op == Py_NE: + return not mpq_equal((left).value, + (right).value) + c = mpq_cmp((left).value, (right).value) return rich_to_bool_sgn(op, c) def __copy__(self): From c4e26712d8eb7ce2a5f63d32668efba9b0574711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 21 Jun 2020 13:30:47 +0200 Subject: [PATCH 295/300] some details in special matrices --- src/sage/matrix/special.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/sage/matrix/special.py b/src/sage/matrix/special.py index f4a714096e0..5bc4e4e116e 100644 --- a/src/sage/matrix/special.py +++ b/src/sage/matrix/special.py @@ -824,7 +824,7 @@ def diagonal_matrix(arg0=None, arg1=None, arg2=None, sparse=True): nrows = nentries # provide a default ring for an empty list - if not entries and ring is None: + if not len(entries) and ring is None: ring = ZZ # Convert entries to a list v over a common ring @@ -833,9 +833,7 @@ def diagonal_matrix(arg0=None, arg1=None, arg2=None, sparse=True): # Create a "diagonal" dictionary for matrix constructor # If nentries < nrows, diagonal is effectively padded with zeros at end - w = {} - for i in range(len(v)): - w[(i, i)] = v[i] + w = {(i, i): v[i] for i in range(len(v))} # Ship ring, matrix size, dictionary to matrix constructor if ring is None: @@ -1692,7 +1690,7 @@ def _determine_block_matrix_rows(sub_matrices): # if we don't know the height, and there are zeroes, # we can't determine the height raise ValueError("insufficient information to determine submatrix heights") - elif total_width % len(R) != 0: + elif total_width % len(R): raise ValueError("incompatible submatrix widths") else: height = int(total_width / len(R)) @@ -3497,7 +3495,7 @@ def hilbert(dim, ring=QQ): [1/5 1/6 1/7 1/8 1/9] """ def entries(i, j): - return 1 / (i + j + 1) + return ZZ.one() / (i + j + 1) return matrix(entries, nrows=dim, ncols=dim, ring=ring) From 1bfe30dffe9128f58c9110c2ebb594e52a7c40f5 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 21 Jun 2020 14:13:22 -0700 Subject: [PATCH 296/300] sage.env.cython_aliases: Another fix for macOS without zlib pc --- src/sage/env.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/env.py b/src/sage/env.py index e32f0c52f9b..4d38c82e84a 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -398,17 +398,20 @@ def cython_aliases(): aliases[var + "CFLAGS"] = "" try: pc = pkgconfig.parse('zlib') + libs = pkgconfig.libs(lib) except pkgconfig.PackageNotFoundError: from collections import defaultdict pc = defaultdict(list, {'libraries': ['z']}) + libs = "-lz" else: aliases[var + "CFLAGS"] = pkgconfig.cflags(lib).split() pc = pkgconfig.parse(lib) + libs = pkgconfig.libs(lib) # INCDIR should be redundant because the -I options are also # passed in CFLAGS aliases[var + "INCDIR"] = pc['include_dirs'] aliases[var + "LIBDIR"] = pc['library_dirs'] - aliases[var + "LIBEXTRA"] = list(filter(lambda s: not s.startswith(('-l','-L')), pkgconfig.libs(lib).split())) + aliases[var + "LIBEXTRA"] = list(filter(lambda s: not s.startswith(('-l','-L')), libs.split())) aliases[var + "LIBRARIES"] = pc['libraries'] # LinBox needs special care because it actually requires C++11 with From e1bf211177ee3b734a314493c9474d9cd7eec661 Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Mon, 22 Jun 2020 18:35:03 +0200 Subject: [PATCH 297/300] remove set_random_seed --- src/sage/geometry/polyhedron/library.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index b8a91815d28..6fc5d4d4fa9 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -3132,7 +3132,6 @@ def hypercube(self, dim, intervals=None, backend=None): Check that we set up the hypercube correctly:: - sage: set_random_seed() sage: ls = [randint(-100,100) for _ in range(4)] sage: intervals = [[x, x+randint(1,50)] for x in ls] sage: P = polytopes.hypercube(4, intervals, backend='field') From 542c3fcde6d838360d71a94ef88db1fde33f5662 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Sun, 15 Mar 2020 15:11:36 +0100 Subject: [PATCH 298/300] 29338: reduction from DLX to SAT --- src/sage/combinat/matrices/dancing_links.pyx | 101 +++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/src/sage/combinat/matrices/dancing_links.pyx b/src/sage/combinat/matrices/dancing_links.pyx index d1e407c8933..2f0a9ef9a4a 100644 --- a/src/sage/combinat/matrices/dancing_links.pyx +++ b/src/sage/combinat/matrices/dancing_links.pyx @@ -91,6 +91,7 @@ cdef extern from "dancing_links_c.h": int search_is_started() int search() +from sage.misc.cachefunc import cached_method cdef class dancing_linksWrapper: r""" @@ -891,6 +892,106 @@ cdef class dancing_linksWrapper: indices = [i for (i,row) in enumerate(self._rows) if column in row] return sum(val for (args_kwds, val) in nb_sol(indices)) + @cached_method + def to_sat_solver(self, solver=None): + r""" + Return the SAT solver solving an equivalent problem. + + Note that row index `i` in the dancing links solver corresponds to + the boolean variable index `ì+1` for the SAT solver to avoid + the variable index `0`. + + See also :mod:`sage.sat.solvers.satsolver`. + + INPUT: + + - ``solver`` -- string or ``None`` (default: ``None``), + possible values include ``'picosat'``, ``'cryptominisat'``, + ``'LP'``, ``'glucose'``, ``'glucose-syrup'``. + + OUTPUT: + + SAT solver instance + + EXAMPLES:: + + sage: from sage.combinat.matrices.dancing_links import dlx_solver + sage: rows = [[0,1,2], [0,2], [1], [3]] + sage: x = dlx_solver(rows) + sage: s = x.to_sat_solver() + + Using some optional SAT solvers:: + + sage: x.to_sat_solver('cryptominisat') # optional cryptominisat + CryptoMiniSat solver: 4 variables, 7 clauses. + + """ + from sage.sat.solvers.satsolver import SAT + s = SAT(solver) + + # Note that row number i is associated to SAT variable i+1 to + # avoid a variable zero + columns = [[] for _ in range(self.ncols())] + for i,row in enumerate(self.rows(), start=1): + for a in row: + columns[a].append(i) + + # At least one 1 in each column + for clause in columns: + s.add_clause(clause) + + # At most one 1 in each column + import itertools + for clause in columns: + for p,q in itertools.combinations(clause, 2): + sub_clause = [-p,-q] + s.add_clause(sub_clause) + + return s + + def one_solution_using_sat_solver(self, solver=None): + r""" + Return a solution found using a SAT solver. + + INPUT: + + - ``solver`` -- string or ``None`` (default: ``None``), + possible values include ``'picosat'``, ``'cryptominisat'``, + ``'LP'``, ``'glucose'``, ``'glucose-syrup'``. + + OUTPUT: + + list of rows or ``None`` if no solution is found + + .. NOTE:: + + When comparing the time taken by method `one_solution`, + have in mind that `one_solution_using_sat_solver` first + creates the SAT solver instance from the dancing links + solver. This copy of data may take many seconds depending on + the size of the problem. + + EXAMPLES:: + + sage: from sage.combinat.matrices.dancing_links import dlx_solver + sage: rows = [[0,1,2], [3,4,5], [0,1], [2,3,4,5], [0], [1,2,3,4,5]] + sage: d = dlx_solver(rows) + sage: solutions = [[0,1], [2,3], [4,5]] + sage: d.one_solution_using_sat_solver() in solutions + True + + Using optional solvers:: + + sage: s = d.one_solution_using_sat_solver('glucose') # optional glucose + sage: s in solutions # optional glucose + True + """ + sat_solver = self.to_sat_solver(solver) + solution = sat_solver() + if not solution: + raise ValueError('no solution found using SAT solver (={})'.format(solver)) + return [key for (key,val) in enumerate(solution, start=-1) if val] + def dlx_solver(rows): """ Internal-use wrapper for the dancing links C++ code. From 2e97345c41638ae8be5d8d7cac2737300883dfcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Labb=C3=A9?= Date: Wed, 24 Jun 2020 14:12:13 +0200 Subject: [PATCH 299/300] 29338:return None if no solution found --- src/sage/combinat/matrices/dancing_links.pyx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/matrices/dancing_links.pyx b/src/sage/combinat/matrices/dancing_links.pyx index 2f0a9ef9a4a..bfbc01819c9 100644 --- a/src/sage/combinat/matrices/dancing_links.pyx +++ b/src/sage/combinat/matrices/dancing_links.pyx @@ -985,11 +985,19 @@ cdef class dancing_linksWrapper: sage: s = d.one_solution_using_sat_solver('glucose') # optional glucose sage: s in solutions # optional glucose True + + When no solution is found:: + + sage: rows = [[0,1,2], [2,3,4,5], [0,1,2,3]] + sage: d = dlx_solver(rows) + sage: d.one_solution_using_sat_solver() is None + True + """ sat_solver = self.to_sat_solver(solver) solution = sat_solver() if not solution: - raise ValueError('no solution found using SAT solver (={})'.format(solver)) + return None return [key for (key,val) in enumerate(solution, start=-1) if val] def dlx_solver(rows): From 69d2b2da286b91b1752a1c63193f9e781780dbb4 Mon Sep 17 00:00:00 2001 From: Release Manager Date: Fri, 26 Jun 2020 17:39:22 +0200 Subject: [PATCH 300/300] Updated SageMath version to 9.2.beta2 --- VERSION.txt | 2 +- build/pkgs/configure/checksums.ini | 6 +++--- build/pkgs/configure/package-version.txt | 2 +- src/bin/sage-version.sh | 6 +++--- src/sage/version.py | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index d85786ed487..444bcb34712 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 9.2.beta1, Release Date: 2020-06-13 +SageMath version 9.2.beta2, Release Date: 2020-06-26 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 7c84377303a..4375c3aee32 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=a72105408547f47a5a59076231f390f05408188c -md5=888e32b2d7b7ca27df8913ae6d447665 -cksum=1768046564 +sha1=7c6e5982f299aeb5eaa1cc311bfed75c2387f6df +md5=1968f79d16a2f5cd1e3ae5add5e047e9 +cksum=2150519936 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 36ea0e0c5c6..04a79b8a531 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -15390c98a036d79f199be2b283f06b5d30757323 +d5756d46d6a6cdd8d481c0381dcfa9e7719ba711 diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index e0b573e5b87..a8b3f5583a4 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.2.beta1' -SAGE_RELEASE_DATE='2020-06-13' -SAGE_VERSION_BANNER='SageMath version 9.2.beta1, Release Date: 2020-06-13' +SAGE_VERSION='9.2.beta2' +SAGE_RELEASE_DATE='2020-06-26' +SAGE_VERSION_BANNER='SageMath version 9.2.beta2, Release Date: 2020-06-26' diff --git a/src/sage/version.py b/src/sage/version.py index 951db210d81..35eeafc5bf7 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.2.beta1' -date = '2020-06-13' -banner = 'SageMath version 9.2.beta1, Release Date: 2020-06-13' +version = '9.2.beta2' +date = '2020-06-26' +banner = 'SageMath version 9.2.beta2, Release Date: 2020-06-26'